| Index: tests/compiler/dart2js/field_type_inferer_test.dart
|
| diff --git a/tests/compiler/dart2js/field_type_inferer_test.dart b/tests/compiler/dart2js/field_type_inferer_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3fcbecea8f5fbc359118af6ff476cad243cd47b9
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js/field_type_inferer_test.dart
|
| @@ -0,0 +1,390 @@
|
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +#import("dart:uri");
|
| +
|
| +#import("../../../lib/compiler/implementation/js_backend/js_backend.dart");
|
| +#import("../../../lib/compiler/implementation/ssa/ssa.dart");
|
| +#import("../../../lib/compiler/implementation/scanner/scannerlib.dart");
|
| +
|
| +#import('compiler_helper.dart');
|
| +#import('parser_helper.dart');
|
| +
|
| +void compileAndFind(String code,
|
| + String className,
|
| + String memberName,
|
| + bool disableInlining,
|
| + check(compiler, element)) {
|
| + Uri uri = new Uri.fromComponents(scheme: 'source');
|
| + var compiler = compilerFor(code, uri);
|
| + compiler.runCompiler(uri);
|
| + compiler.disableInlining = disableInlining;
|
| + var cls = findElement(compiler, className);
|
| + var member = cls.lookupMember(buildSourceString(memberName));
|
| + return check(compiler.backend, member);
|
| +}
|
| +
|
| +const String TEST_1 = @"""
|
| + class A {
|
| + int f;
|
| + }
|
| + main() { new A(); }
|
| +""";
|
| +
|
| +const String TEST_2 = @"""
|
| + class A {
|
| + int f1;
|
| + int f2 = 1;
|
| + }
|
| + main() { new A(); }
|
| +""";
|
| +
|
| +const String TEST_3 = @"""
|
| + class A {
|
| + int f1;
|
| + int f2;
|
| + A() : f1 = 1;
|
| + }
|
| + main() { new A().f2 = 2; }
|
| +""";
|
| +
|
| +const String TEST_4 = @"""
|
| + class A {
|
| + int f1;
|
| + int f2;
|
| + A() : f1 = 1;
|
| + }
|
| + main() {
|
| + A a = new A();
|
| + a.f1 = "a";
|
| + a.f2 = "a";
|
| + }
|
| +""";
|
| +
|
| +const String TEST_5 = @"""
|
| + class A {
|
| + int f1 = 1;
|
| + int f2 = 1;
|
| + A(x) {
|
| + f1 = "1";
|
| + if (x) {
|
| + f2 = "1";
|
| + } else {
|
| + f2 = "2";
|
| + }
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +const String TEST_6 = @"""
|
| + class A {
|
| + int f1 = 1;
|
| + int f2 = 1;
|
| + A(x) {
|
| + f1 = "1";
|
| + if (x) {
|
| + f2 = "1";
|
| + } else {
|
| + f2 = "2";
|
| + }
|
| + if (x) {
|
| + f2 = new List();
|
| + } else {
|
| + f2 = new List();
|
| + }
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +const String TEST_7 = @"""
|
| + class A {
|
| + int f1 = 1;
|
| + int f2 = 1;
|
| + A(x) {
|
| + f1 = "1";
|
| + if (x) {
|
| + f2 = "1";
|
| + } else {
|
| + f2 = "2";
|
| + }
|
| + if (x) {
|
| + f1 = new List();
|
| + f2 = new List();
|
| + } else {
|
| + f2 = new List();
|
| + }
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +const String TEST_8 = @"""
|
| + class A {
|
| + int f;
|
| + A(x) {
|
| + if (x) {
|
| + f = "1";
|
| + } else {
|
| + }
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +const String TEST_9 = @"""
|
| + class A {
|
| + int f;
|
| + A(x) {
|
| + if (x) {
|
| + } else {
|
| + f = "1";
|
| + }
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +const String TEST_10 = @"""
|
| + class A {
|
| + int f;
|
| + A() {
|
| + f = 1;
|
| + }
|
| + m() => f + 1;
|
| + }
|
| + void f(x) { x.f = "2"; }
|
| + main() {
|
| + A a;
|
| + f(a);
|
| + a = new A();
|
| + a.m();
|
| + }
|
| +""";
|
| +
|
| +
|
| +const String TEST_11 = @"""
|
| + class S {
|
| + int fs = 1;
|
| + ms() { fs = 1; }
|
| + }
|
| +
|
| + class A extends S {
|
| + m() { ms(); }
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + a.m();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_12 = @"""
|
| + class S {
|
| + int fs = 1;
|
| + S() { fs = "2"; }
|
| + }
|
| +
|
| + class A extends S {
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_13 = @"""
|
| + class S {
|
| + int fs;
|
| + S() { fs = 1; }
|
| + }
|
| +
|
| + class A extends S {
|
| + A() { fs = 1; }
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_14 = @"""
|
| + class A {
|
| + var f;
|
| + A() { f = 1; }
|
| + A.other() { f = 2; }
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + a = new A.other();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_15 = @"""
|
| + class A {
|
| + var f;
|
| + A() { f = "1"; }
|
| + A.other() { f = new List(); }
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + a = new A.other();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_16 = @"""
|
| + class A {
|
| + var f;
|
| + A() { f = "1"; }
|
| + A.other() : f = 1 { }
|
| + }
|
| +
|
| + main() {
|
| + A a = new A();
|
| + a = new A.other();
|
| + }
|
| +""";
|
| +
|
| +const String TEST_17 = @"""
|
| + g([p]) => p.f = 1;
|
| + class A {
|
| + var f;
|
| + A(x) {
|
| + var a;
|
| + if (x) {
|
| + a = this;
|
| + } else {
|
| + a = g;
|
| + }
|
| + a();
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +// In this test this is only used in a field set (f3 = a) and therefore we infer
|
| +// types for f1, f2 and f3.
|
| +const String TEST_18 = @"""
|
| + class A {
|
| + var f1;
|
| + var f2;
|
| + var f3;
|
| + A(x) {
|
| + f1 = 1;
|
| + var a;
|
| + if (x) {
|
| + f2 = "1";
|
| + a = this;
|
| + } else {
|
| + a = 1;
|
| + f2 = "1";
|
| + }
|
| + f3 = a;
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +// In this test this is exposed through a(), and therefore we don't infer
|
| +// any types.
|
| +const String TEST_19 = @"""
|
| + class A {
|
| + var f1;
|
| + var f2;
|
| + var f3;
|
| + A(x) {
|
| + f1 = 1;
|
| + var a;
|
| + if (x) {
|
| + f2 = "1";
|
| + a = this;
|
| + } else {
|
| + a = 1;
|
| + f2 = "1";
|
| + }
|
| + f3 = a;
|
| + a();
|
| + }
|
| + }
|
| + main() {
|
| + new A(true);
|
| + new A(false);
|
| + }
|
| +""";
|
| +
|
| +void doTest(String test, bool disableInlining, Map<String, HType> fields) {
|
| + fields.forEach((String name, HType type) {
|
| + compileAndFind(
|
| + test,
|
| + 'A',
|
| + name,
|
| + disableInlining,
|
| + (backend, field) {
|
| + HType inferredType = backend.optimisticFieldType(field);
|
| + Expect.equals(type, inferredType);
|
| + });
|
| + });
|
| +}
|
| +
|
| +void runTest(String test, Map<String, HType> fields) {
|
| + doTest(test, false, fields);
|
| + doTest(test, true, fields);
|
| +}
|
| +
|
| +void test() {
|
| + runTest(TEST_1, {'f': HType.NULL});
|
| + runTest(TEST_2, {'f1': HType.NULL, 'f2': HType.INTEGER});
|
| + runTest(TEST_3, {'f1': HType.INTEGER, 'f2': HType.INTEGER_OR_NULL});
|
| + runTest(TEST_4, {'f1': HType.UNKNOWN, 'f2': HType.STRING_OR_NULL});
|
| + runTest(TEST_5, {'f1': HType.STRING, 'f2': HType.STRING});
|
| + runTest(TEST_6, {'f1': HType.STRING, 'f2': HType.EXTENDABLE_ARRAY});
|
| + runTest(TEST_7, {'f1': HType.INDEXABLE_PRIMITIVE,
|
| + 'f2': HType.EXTENDABLE_ARRAY});
|
| + runTest(TEST_8, {'f': HType.UNKNOWN});
|
| + runTest(TEST_9, {'f': HType.UNKNOWN});
|
| + runTest(TEST_10, {'f': HType.UNKNOWN});
|
| + runTest(TEST_11, {'fs': HType.INTEGER});
|
| + runTest(TEST_12, {'fs': HType.STRING});
|
| + // TODO(sgjesse): We should actually infer int.
|
| + runTest(TEST_13, {'fs': HType.UNKNOWN});
|
| + // TODO(sgjesse): We should actually infer int.
|
| + runTest(TEST_14, {'f': HType.UNKNOWN});
|
| + runTest(TEST_15, {'f': HType.UNKNOWN});
|
| + runTest(TEST_16, {'f': HType.UNKNOWN});
|
| + runTest(TEST_17, {'f': HType.UNKNOWN});
|
| + runTest(TEST_18, {'f1': HType.INTEGER,
|
| + 'f2': HType.STRING,
|
| + 'f3': HType.UNKNOWN});
|
| + runTest(TEST_19, {'f1': HType.UNKNOWN,
|
| + 'f2': HType.UNKNOWN,
|
| + 'f3': HType.UNKNOWN});
|
| +}
|
| +
|
| +void main() {
|
| + test();
|
| +}
|
|
|