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(); |
+} |