| Index: tests/compiler/dart2js/cpa_inference_test.dart
|
| diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
|
| deleted file mode 100644
|
| index 50e458bdc06f35bf8b9534c18a09135b7a423ea6..0000000000000000000000000000000000000000
|
| --- a/tests/compiler/dart2js/cpa_inference_test.dart
|
| +++ /dev/null
|
| @@ -1,2160 +0,0 @@
|
| -// 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:async';
|
| -import "package:expect/expect.dart";
|
| -import "package:async_helper/async_helper.dart";
|
| -import 'package:compiler/src/types/types.dart';
|
| -import 'package:compiler/src/inferrer/concrete_types_inferrer.dart';
|
| -import 'package:compiler/src/universe/call_structure.dart' show
|
| - CallStructure;
|
| -import 'package:compiler/src/universe/selector.dart' show
|
| - Selector;
|
| -
|
| -import "compiler_helper.dart";
|
| -import "type_mask_test_helper.dart";
|
| -
|
| -/**
|
| - * Finds the node corresponding to the last occurence of the substring
|
| - * [: identifier; :] in the program represented by the visited AST.
|
| - */
|
| -class VariableFinderVisitor extends Visitor {
|
| - final String identifier;
|
| - Node result;
|
| -
|
| - VariableFinderVisitor(this.identifier);
|
| -
|
| - visitSend(Send node) {
|
| - if (node.isPropertyAccess
|
| - && node.selector.asIdentifier().source == identifier) {
|
| - result = node;
|
| - } else {
|
| - node.visitChildren(this);
|
| - }
|
| - }
|
| -
|
| - visitNode(Node node) {
|
| - node.visitChildren(this);
|
| - }
|
| -}
|
| -
|
| -class AnalysisResult {
|
| - MockCompiler compiler;
|
| - ConcreteTypesInferrer inferrer;
|
| - Node ast;
|
| -
|
| - BaseType int;
|
| - BaseType double;
|
| - BaseType num;
|
| - BaseType bool;
|
| - BaseType string;
|
| - BaseType list;
|
| - BaseType growableList;
|
| - BaseType map;
|
| - BaseType nullType;
|
| - BaseType functionType;
|
| -
|
| - AnalysisResult(MockCompiler compiler) : this.compiler = compiler {
|
| - inferrer = compiler.typesTask.concreteTypesInferrer;
|
| - int = inferrer.baseTypes.intBaseType;
|
| - double = inferrer.baseTypes.doubleBaseType;
|
| - num = inferrer.baseTypes.numBaseType;
|
| - bool = inferrer.baseTypes.boolBaseType;
|
| - string = inferrer.baseTypes.stringBaseType;
|
| - list = inferrer.baseTypes.listBaseType;
|
| - growableList = inferrer.baseTypes.growableListBaseType;
|
| - map = inferrer.baseTypes.mapBaseType;
|
| - nullType = const NullBaseType();
|
| - functionType = inferrer.baseTypes.functionBaseType;
|
| - FunctionElement mainElement = compiler.mainApp.find('main');
|
| - ast = mainElement.node;
|
| - }
|
| -
|
| - BaseType base(String className) {
|
| - final source = className;
|
| - return new ClassBaseType(compiler.mainApp.find(source));
|
| - }
|
| -
|
| - /**
|
| - * Finds the [Node] corresponding to the last occurence of the substring
|
| - * [: identifier; :] in the program represented by the visited AST. For
|
| - * instance, returns the AST node representing [: foo; :] in
|
| - * [: main() { foo = 1; foo; } :].
|
| - */
|
| - Node findNode(String identifier) {
|
| - VariableFinderVisitor finder = new VariableFinderVisitor(identifier);
|
| - ast.accept(finder);
|
| - return finder.result;
|
| - }
|
| -
|
| - /**
|
| - * Finds the [Element] corresponding to [: className#fieldName :].
|
| - */
|
| - Element findField(String className, String fieldName) {
|
| - ClassElement element = compiler.mainApp.find(className);
|
| - return element.lookupLocalMember(fieldName);
|
| - }
|
| -
|
| - ConcreteType concreteFrom(List<BaseType> baseTypes) {
|
| - ConcreteType result = inferrer.emptyConcreteType;
|
| - for (final baseType in baseTypes) {
|
| - result = result.union(inferrer.singletonConcreteType(baseType));
|
| - }
|
| - // We make sure the concrete types expected by the tests don't default to
|
| - // dynamic because of widening.
|
| - assert(!result.isUnknown());
|
| - return result;
|
| - }
|
| -
|
| - /**
|
| - * Checks that the inferred type of the node corresponding to the last
|
| - * occurence of [: variable; :] in the program is the concrete type
|
| - * made of [baseTypes].
|
| - */
|
| - void checkNodeHasType(String variable, List<BaseType> baseTypes) {
|
| - Expect.equals(
|
| - concreteFrom(baseTypes),
|
| - inferrer.inferredTypes[findNode(variable)]);
|
| - }
|
| -
|
| - /**
|
| - * Checks that the inferred type of the node corresponding to the last
|
| - * occurence of [: variable; :] in the program is the unknown concrete type.
|
| - */
|
| - void checkNodeHasUnknownType(String variable) {
|
| - Expect.isTrue(inferrer.inferredTypes[findNode(variable)].isUnknown());
|
| - }
|
| -
|
| - /**
|
| - * Checks that [: className#fieldName :]'s inferred type is the concrete type
|
| - * made of [baseTypes].
|
| - */
|
| - void checkFieldHasType(String className, String fieldName,
|
| - List<BaseType> baseTypes) {
|
| - Expect.equals(
|
| - concreteFrom(baseTypes),
|
| - inferrer.inferredFieldTypes[findField(className, fieldName)]);
|
| - }
|
| -
|
| - /**
|
| - * Checks that [: className#fieldName :]'s inferred type is the unknown
|
| - * concrete type.
|
| - */
|
| - void checkFieldHasUknownType(String className, String fieldName) {
|
| - Expect.isTrue(
|
| - inferrer.inferredFieldTypes[findField(className, fieldName)]
|
| - .isUnknown());
|
| - }
|
| -
|
| - /** Checks that the inferred type for [selector] is [mask]. */
|
| - void checkSelectorHasType(Selector selector,
|
| - TypeMask mask,
|
| - TypeMask expectedMask) {
|
| - Expect.equals(expectedMask, inferrer.getTypeOfSelector(selector, mask));
|
| - }
|
| -}
|
| -
|
| -const String DYNAMIC = '"__dynamic_for_test"';
|
| -
|
| -Future<AnalysisResult> analyze(String code, {int maxConcreteTypeSize: 1000}) {
|
| - Uri uri = new Uri(scheme: 'dart', path: 'test');
|
| - MockCompiler compiler = new MockCompiler.internal(
|
| - enableConcreteTypeInference: true,
|
| - maxConcreteTypeSize: maxConcreteTypeSize);
|
| - compiler.diagnosticHandler = createHandler(compiler, code);
|
| - compiler.registerSource(uri, code);
|
| - compiler.typesTask.concreteTypesInferrer.testMode = true;
|
| - return compiler.runCompiler(uri).then((_) {
|
| - return new AnalysisResult(compiler);
|
| - });
|
| -}
|
| -
|
| -testDynamicBackDoor() {
|
| - final String source = """
|
| - main () {
|
| - var x = $DYNAMIC;
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasUnknownType('x');
|
| - });
|
| -}
|
| -
|
| -testVariableDeclaration() {
|
| - final String source = r"""
|
| - main() {
|
| - var v1;
|
| - var v2;
|
| - v2 = 1;
|
| - v1; v2;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('v1', [result.nullType]);
|
| - result.checkNodeHasType('v2', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testLiterals() {
|
| - final String source = r"""
|
| - main() {
|
| - var v1 = 42;
|
| - var v2 = 42.1;
|
| - var v3 = 'abc';
|
| - var v4 = true;
|
| - var v5 = null;
|
| - v1; v2; v3; v4; v5;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('v1', [result.int]);
|
| - result.checkNodeHasType('v2', [result.double]);
|
| - result.checkNodeHasType('v3', [result.string]);
|
| - result.checkNodeHasType('v4', [result.bool]);
|
| - result.checkNodeHasType('v5', [result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testRedefinition() {
|
| - final String source = r"""
|
| - main() {
|
| - var foo = 42;
|
| - foo = 'abc';
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testIfThenElse() {
|
| - final String source = r"""
|
| - main() {
|
| - var foo = 42;
|
| - if (true) {
|
| - foo = 'abc';
|
| - } else {
|
| - foo = false;
|
| - }
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string, result.bool]);
|
| - });
|
| -}
|
| -
|
| -testTernaryIf() {
|
| - final String source = r"""
|
| - main() {
|
| - var foo = 42;
|
| - foo = true ? 'abc' : false;
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string, result.bool]);
|
| - });
|
| -}
|
| -
|
| -testWhile() {
|
| - final String source = r"""
|
| - class A { f() => new B(); }
|
| - class B { f() => new C(); }
|
| - class C { f() => new A(); }
|
| - main() {
|
| - var bar = null;
|
| - var foo = new A();
|
| - while(bar = 42) {
|
| - foo = foo.f();
|
| - }
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType(
|
| - 'foo',
|
| - [result.base('A'), result.base('B'), result.base('C')]);
|
| - // Check that the condition is evaluated.
|
| - // TODO(polux): bar's type could be inferred to be {int} here.
|
| - result.checkNodeHasType('bar', [result.int, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testDoWhile() {
|
| - final String source = r"""
|
| - class A { f() => new B(); }
|
| - class B { f() => new C(); }
|
| - class C { f() => new A(); }
|
| - main() {
|
| - var bar = null;
|
| - var foo = new A();
|
| - do {
|
| - foo = foo.f();
|
| - } while (bar = 42);
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType(
|
| - 'foo',
|
| - [result.base('A'), result.base('B'), result.base('C')]);
|
| - // Check that the condition is evaluated.
|
| - result.checkNodeHasType('bar', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testFor1() {
|
| - final String source = r"""
|
| - class A { f() => new B(); }
|
| - class B { f() => new C(); }
|
| - class C { f() => new A(); }
|
| - main() {
|
| - var foo = new A();
|
| - for(;;) {
|
| - foo = foo.f();
|
| - }
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType(
|
| - 'foo',
|
| - [result.base('A'), result.base('B'), result.base('C')]);
|
| - });
|
| -}
|
| -
|
| -testFor2() {
|
| - final String source = r"""
|
| - class A { f() => new B(); test() => true; }
|
| - class B { f() => new A(); test() => true; }
|
| - main() {
|
| - var bar = null;
|
| - var foo = new A();
|
| - for(var i = new A(); bar = 42; i = i.f()) {
|
| - foo = i;
|
| - }
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.base('A'), result.base('B')]);
|
| - // Check that the condition is evaluated.
|
| - // TODO(polux): bar's type could be inferred to be {int} here.
|
| - result.checkNodeHasType('bar', [result.int, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testFor3() {
|
| - final String source = r"""
|
| - main() {
|
| - var i = 1;
|
| - for(;;) {
|
| - var x = 2;
|
| - i = x;
|
| - }
|
| - i;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('i', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testForIn() {
|
| - final String source = r"""
|
| - class MyIterator {
|
| - var counter = 0;
|
| -
|
| - moveNext() {
|
| - if (counter == 0) {
|
| - counter = 1;
|
| - return true;
|
| - } else if (counter == 1) {
|
| - counter = 2;
|
| - return true;
|
| - } else {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - get current => (counter == 1) ? "foo" : 42;
|
| - }
|
| -
|
| - class MyIterable {
|
| - get iterator => new MyIterator();
|
| - }
|
| -
|
| - main() {
|
| - var res;
|
| - for (var i in new MyIterable()) {
|
| - res = i;
|
| - }
|
| - res;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType('res',
|
| - [result.int, result.string, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testToplevelVariable() {
|
| - final String source = r"""
|
| - final top = 'abc';
|
| - class A {
|
| - f() => top;
|
| - }
|
| - main() {
|
| - var foo = top;
|
| - var bar = new A().f();
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string]);
|
| - result.checkNodeHasType('bar', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testToplevelVariable2() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - }
|
| - final top = new A().x;
|
| -
|
| - main() {
|
| - var a = new A();
|
| - a.x = 42;
|
| - a.x = "abc";
|
| - var foo = top;
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.nullType, result.int,
|
| - result.string]);
|
| - });
|
| -}
|
| -
|
| -testToplevelVariable3() {
|
| - final String source = r"""
|
| - var top = "a";
|
| -
|
| - f() => top;
|
| -
|
| - main() {
|
| - var foo = f();
|
| - var bar = top;
|
| - top = 42;
|
| - var baz = top;
|
| - foo; bar; baz;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - result.checkNodeHasType('bar', [result.int, result.string]);
|
| - result.checkNodeHasType('baz', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testNonRecusiveFunction() {
|
| - final String source = r"""
|
| - f(x, y) => true ? x : y;
|
| - main() { var foo = f(42, "abc"); foo; }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testMultipleReturns() {
|
| - final String source = r"""
|
| - f(x, y) {
|
| - if (true) return x;
|
| - else return y;
|
| - }
|
| - main() { var foo = f(42, "abc"); foo; }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testRecusiveFunction() {
|
| - final String source = r"""
|
| - f(x) {
|
| - if (true) return x;
|
| - else return f(true ? x : "abc");
|
| - }
|
| - main() { var foo = f(42); foo; }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testMutuallyRecusiveFunction() {
|
| - final String source = r"""
|
| - f() => true ? 42 : g();
|
| - g() => true ? "abc" : f();
|
| - main() { var foo = f(); foo; }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testSimpleSend() {
|
| - final String source = """
|
| - class A {
|
| - f(x) => x;
|
| - }
|
| - class B {
|
| - f(x) => 'abc';
|
| - }
|
| - class C {
|
| - f(x) => 3.14;
|
| - }
|
| - class D {
|
| - var f; // we check that this field is ignored in calls to dynamic.f()
|
| - D(this.f);
|
| - }
|
| - main() {
|
| - new B(); new D(42); // we instantiate B and D but not C
|
| - var foo = new A().f(42);
|
| - var bar = $DYNAMIC.f(42);
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - result.checkNodeHasType('bar', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testSendToThis1() {
|
| - final String source = r"""
|
| - class A {
|
| - A();
|
| - f() => g();
|
| - g() => 42;
|
| - }
|
| - main() {
|
| - var foo = new A().f();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testSendToThis2() {
|
| - final String source = r"""
|
| - class A {
|
| - foo() => this;
|
| - }
|
| - class B extends A {
|
| - bar() => foo();
|
| - }
|
| - main() {
|
| - var x = new B().bar();
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.base('B')]);
|
| - });
|
| -}
|
| -
|
| -testSendToThis3() {
|
| - final String source = r"""
|
| - class A {
|
| - bar() => 42;
|
| - foo() => bar();
|
| - }
|
| - class B extends A {
|
| - bar() => "abc";
|
| - }
|
| - main() {
|
| - var x = new B().foo();
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType('x', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testSendToThis4() {
|
| - final String source = """
|
| - class A {
|
| - bar() => 42;
|
| - foo() => bar();
|
| - }
|
| - class B extends A {
|
| - bar() => "abc";
|
| - }
|
| - main() {
|
| - new A(); new B(); // make A and B seen
|
| - var x = $DYNAMIC.foo();
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType('x', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testConstructor() {
|
| - final String source = r"""
|
| - class A {
|
| - var x, y, z;
|
| - A(this.x, a) : y = a { z = 'abc'; }
|
| - }
|
| - main() {
|
| - new A(42, 'abc');
|
| - new A(true, null);
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int, result.bool]);
|
| - result.checkFieldHasType('A', 'y', [result.string, result.nullType]);
|
| - result.checkFieldHasType('A', 'z', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testGetters() {
|
| - final String source = """
|
| - class A {
|
| - var x;
|
| - A(this.x);
|
| - get y => x;
|
| - get z => y;
|
| - }
|
| - class B {
|
| - var x;
|
| - B(this.x);
|
| - }
|
| - main() {
|
| - var a = new A(42);
|
| - var b = new B('abc');
|
| - var foo = a.x;
|
| - var bar = a.y;
|
| - var baz = a.z;
|
| - var qux = null.x;
|
| - var quux = $DYNAMIC.x;
|
| - foo; bar; baz; qux; quux;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - result.checkNodeHasType('bar', [result.int]);
|
| - result.checkNodeHasType('baz', [result.int]);
|
| - result.checkNodeHasType('qux', []);
|
| - result.checkNodeHasType('quux', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testDynamicGetters() {
|
| - final String source = """
|
| - class A {
|
| - get x => f();
|
| - f() => 42;
|
| - }
|
| - class B extends A {
|
| - f() => "abc";
|
| - }
|
| - main() {
|
| - new A(); new B(); // make A and B seen
|
| - var x = $DYNAMIC.x;
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testToplevelGetters() {
|
| - final String source = """
|
| - int _x = 42;
|
| - get x => _x;
|
| -
|
| - f() => x;
|
| -
|
| - main() {
|
| - var foo = f();
|
| - var bar = x;
|
| - _x = "a";
|
| - var baz = x;
|
| - foo; bar; baz;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - result.checkNodeHasType('bar', [result.int, result.string]);
|
| - result.checkNodeHasType('baz', [result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testSetters() {
|
| - final String source = """
|
| - class A {
|
| - var x;
|
| - var w;
|
| - A(this.x, this.w);
|
| - set y(a) { x = a; z = a; }
|
| - set z(a) { w = a; }
|
| - }
|
| - class B {
|
| - var x;
|
| - B(this.x);
|
| - }
|
| - main() {
|
| - var a = new A(42, 42);
|
| - var b = new B(42);
|
| - a.x = 'abc';
|
| - a.y = true;
|
| - null.x = 42; // should be ignored
|
| - $DYNAMIC.x = null;
|
| - $DYNAMIC.y = 3.14;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('B', 'x',
|
| - [result.int, // new B(42)
|
| - result.nullType]); // dynamic.x = null
|
| - result.checkFieldHasType('A', 'x',
|
| - [result.int, // new A(42, ...)
|
| - result.string, // a.x = 'abc'
|
| - result.bool, // a.y = true
|
| - result.nullType, // dynamic.x = null
|
| - result.double]); // dynamic.y = 3.14
|
| - result.checkFieldHasType('A', 'w',
|
| - [result.int, // new A(..., 42)
|
| - result.bool, // a.y = true
|
| - result.double]); // dynamic.y = 3.14
|
| - });
|
| -}
|
| -
|
| -testToplevelSetters() {
|
| - final String source = """
|
| - int _x = 42;
|
| - set x(y) => _x = y;
|
| -
|
| - f(y) { x = y; }
|
| -
|
| - main() {
|
| - var foo = _x;
|
| - x = "a";
|
| - var bar = _x;
|
| - f(true);
|
| - var baz = _x;
|
| - foo; bar; baz;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string, result.bool]);
|
| - result.checkNodeHasType('bar', [result.int, result.string, result.bool]);
|
| - result.checkNodeHasType('baz', [result.int, result.string, result.bool]);
|
| - });
|
| -}
|
| -
|
| -
|
| -testOptionalNamedParameters() {
|
| - final String source = r"""
|
| - class A {
|
| - var x, y, z, w;
|
| - A(this.x, {this.y, this.z, this.w});
|
| - }
|
| - class B {
|
| - var x, y;
|
| - B(this.x, {this.y});
|
| - }
|
| - class C {
|
| - var x, y;
|
| - C(this.x, {this.y});
|
| - }
|
| - class Test {
|
| - var a, b, c, d;
|
| - var e, f;
|
| - var g, h;
|
| -
|
| - Test(this.a, this.b, this.c, this.d,
|
| - this.e, this.f,
|
| - this.g, this.h);
|
| -
|
| - f1(x, {y, z, w}) {
|
| - a = x;
|
| - b = y;
|
| - c = z;
|
| - d = w;
|
| - }
|
| - f2(x, {y}) {
|
| - e = x;
|
| - f = y;
|
| - }
|
| - f3(x, {y}) {
|
| - g = x;
|
| - h = y;
|
| - }
|
| - }
|
| - class Foo {
|
| - }
|
| - main() {
|
| - // We want to test expiclitely for null later so we initialize all the
|
| - // fields of Test with a placeholder type: Foo.
|
| - var foo = new Foo();
|
| - var test = new Test(foo, foo, foo, foo, foo, foo, foo, foo);
|
| -
|
| - new A(42);
|
| - new A('abc', w: true, z: 42.1);
|
| - test.f1(42);
|
| - test.f1('abc', w: true, z: 42.1);
|
| -
|
| - new B('abc', y: true);
|
| - new B(1, 2); // too many positional arguments
|
| - test.f2('abc', y: true);
|
| - test.f2(1, 2); // too many positional arguments
|
| -
|
| - new C('abc', y: true);
|
| - new C(1, z: 2); // non-existing named parameter
|
| - test.f3('abc', y: true);
|
| - test.f3(1, z: 2); // non-existing named parameter
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| -
|
| - final foo = result.base('Foo');
|
| - final nil = result.nullType;
|
| -
|
| - result.checkFieldHasType('A', 'x', [result.int, result.string]);
|
| - result.checkFieldHasType('A', 'y', [nil]);
|
| - result.checkFieldHasType('A', 'z', [nil, result.double]);
|
| - result.checkFieldHasType('A', 'w', [nil, result.bool]);
|
| - result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
|
| - result.checkFieldHasType('Test', 'b', [foo, nil]);
|
| - result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
|
| - result.checkFieldHasType('Test', 'd', [foo, nil, result.bool]);
|
| -
|
| - result.checkFieldHasType('B', 'x', [result.string]);
|
| - result.checkFieldHasType('B', 'y', [result.bool]);
|
| - result.checkFieldHasType('Test', 'e', [foo, result.string]);
|
| - result.checkFieldHasType('Test', 'f', [foo, result.bool]);
|
| -
|
| - result.checkFieldHasType('C', 'x', [result.string]);
|
| - result.checkFieldHasType('C', 'y', [result.bool]);
|
| - result.checkFieldHasType('Test', 'g', [foo, result.string]);
|
| - result.checkFieldHasType('Test', 'h', [foo, result.bool]);
|
| - });
|
| -}
|
| -
|
| -testOptionalPositionalParameters() {
|
| - final String source = r"""
|
| - class A {
|
| - var x, y, z, w;
|
| - A(this.x, [this.y, this.z, this.w]);
|
| - }
|
| - class B {
|
| - var x, y;
|
| - B(this.x, [this.y]);
|
| - }
|
| - class Test {
|
| - var a, b, c, d;
|
| - var e, f;
|
| -
|
| - Test(this.a, this.b, this.c, this.d,
|
| - this.e, this.f);
|
| -
|
| - f1(x, [y, z, w]) {
|
| - a = x;
|
| - b = y;
|
| - c = z;
|
| - d = w;
|
| - }
|
| - f2(x, [y]) {
|
| - e = x;
|
| - f = y;
|
| - }
|
| - }
|
| - class Foo {
|
| - }
|
| - main() {
|
| - // We want to test expiclitely for null later so we initialize all the
|
| - // fields of Test with a placeholder type: Foo.
|
| - var foo = new Foo();
|
| - var test = new Test(foo, foo, foo, foo, foo, foo);
|
| -
|
| - new A(42);
|
| - new A('abc', true, 42.1);
|
| - test.f1(42);
|
| - test.f1('abc', true, 42.1);
|
| -
|
| - new B('a', true);
|
| - new B(1, 2, 3); // too many arguments
|
| - test.f2('a', true);
|
| - test.f2(1, 2, 3); // too many arguments
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| -
|
| - final foo = result.base('Foo');
|
| - final nil = result.nullType;
|
| -
|
| - result.checkFieldHasType('A', 'x', [result.int, result.string]);
|
| - result.checkFieldHasType('A', 'y', [nil, result.bool]);
|
| - result.checkFieldHasType('A', 'z', [nil, result.double]);
|
| - result.checkFieldHasType('A', 'w', [nil]);
|
| - result.checkFieldHasType('Test', 'a', [foo, result.int, result.string]);
|
| - result.checkFieldHasType('Test', 'b', [foo, nil, result.bool]);
|
| - result.checkFieldHasType('Test', 'c', [foo, nil, result.double]);
|
| - result.checkFieldHasType('Test', 'd', [foo, nil]);
|
| -
|
| - result.checkFieldHasType('B', 'x', [result.string]);
|
| - result.checkFieldHasType('B', 'y', [result.bool]);
|
| - result.checkFieldHasType('Test', 'e', [foo, result.string]);
|
| - result.checkFieldHasType('Test', 'f', [foo, result.bool]);
|
| - });
|
| -}
|
| -
|
| -testListLiterals() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - A(this.x);
|
| - }
|
| - main() {
|
| - var x = [];
|
| - var y = [1, "a", null, new A(42)];
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.growableList]);
|
| - result.checkNodeHasType('y', [result.growableList]);
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testMapLiterals() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - A(this.x);
|
| - }
|
| - main() {
|
| - var x = {};
|
| - var y = {'a': "foo", 'b': new A(42) };
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.map]);
|
| - result.checkNodeHasType('y', [result.map]);
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testReturn() {
|
| - final String source = r"""
|
| - f() { if (true) { return 1; }; return "a"; }
|
| - g() { f(); return; }
|
| - main() {
|
| - var x = f();
|
| - var y = g();
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.int, result.string]);
|
| - result.checkNodeHasType('y', [result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testNoReturn() {
|
| - final String source = r"""
|
| - f() { if (true) { return 1; }; }
|
| - g() { f(); }
|
| - main() {
|
| - var x = f();
|
| - var y = g();
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.int, result.nullType]);
|
| - result.checkNodeHasType('y', [result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testArithmeticOperators() {
|
| - String source(op) {
|
| - return """
|
| - main() {
|
| - var a = 1 $op 2;
|
| - var b = 1 $op 2.1;
|
| - var c = 1.1 $op 2;
|
| - var d = 1.1 $op 2.1;
|
| - var e = (1 $op 2.1) $op 1;
|
| - var f = 1 $op (1 $op 2.1);
|
| - var g = (1 $op 2.1) $op 1.1;
|
| - var h = 1.1 $op (1 $op 2);
|
| - var i = (1 $op 2) $op 1;
|
| - var j = 1 $op (1 $op 2);
|
| - var k = (1.1 $op 2.1) $op 1.1;
|
| - var l = 1.1 $op (1.1 $op 2.1);
|
| - a; b; c; d; e; f; g; h; i; j; k; l;
|
| - }""";
|
| - }
|
| - return Future.forEach(['+', '*', '-'], (String op) {
|
| - return analyze(source(op)).then((result) {
|
| - result.checkNodeHasType('a', [result.int]);
|
| - result.checkNodeHasType('b', [result.num]);
|
| - result.checkNodeHasType('c', [result.num]);
|
| - result.checkNodeHasType('d', [result.double]);
|
| - result.checkNodeHasType('e', [result.num]);
|
| - result.checkNodeHasType('f', [result.num]);
|
| - result.checkNodeHasType('g', [result.num]);
|
| - result.checkNodeHasType('h', [result.num]);
|
| - result.checkNodeHasType('i', [result.int]);
|
| - result.checkNodeHasType('j', [result.int]);
|
| - result.checkNodeHasType('k', [result.double]);
|
| - result.checkNodeHasType('l', [result.double]);
|
| - });
|
| - });
|
| -}
|
| -
|
| -testBooleanOperators() {
|
| - String source(op) {
|
| - return """
|
| - main() {
|
| - var a = true $op null;
|
| - var b = null $op true;
|
| - var c = 1 $op true;
|
| - var d = true $op "a";
|
| - a; b; c; d;
|
| - }""";
|
| - }
|
| - return Future.forEach(['&&', '||'], (String op) {
|
| - return analyze(source(op)).then((result) {
|
| - result.checkNodeHasType('a', [result.bool]);
|
| - result.checkNodeHasType('b', [result.bool]);
|
| - result.checkNodeHasType('c', [result.bool]);
|
| - result.checkNodeHasType('d', [result.bool]);
|
| - });
|
| - });
|
| -}
|
| -
|
| -testBooleanOperatorsShortCirtcuit() {
|
| - String source(op) {
|
| - return """
|
| - main() {
|
| - var x = null;
|
| - "foo" $op (x = 42);
|
| - x;
|
| - }""";
|
| - }
|
| - return Future.forEach(['&&', '||'], (String op) {
|
| - return analyze(source(op)).then((AnalysisResult result) {
|
| - result.checkNodeHasType('x', [result.nullType, result.int]);
|
| - });
|
| - });
|
| -}
|
| -
|
| -testOperators() {
|
| - final String source = r"""
|
| - class A {
|
| - operator <(x) => 42;
|
| - operator <<(x) => "a";
|
| - }
|
| - main() {
|
| - var x = new A() < "foo";
|
| - var y = new A() << "foo";
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.int]);
|
| - result.checkNodeHasType('y', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testSetIndexOperator() {
|
| - final String source = r"""
|
| - class A {
|
| - var witness1;
|
| - var witness2;
|
| - operator []=(i, x) { witness1 = i; witness2 = x; }
|
| - }
|
| - main() {
|
| - var x = new A()[42] = "abc";
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.string]);
|
| - result.checkFieldHasType('A', 'witness1', [result.int, result.nullType]);
|
| - result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testCompoundOperators1() {
|
| - final String source = r"""
|
| - class A {
|
| - operator +(x) => "foo";
|
| - }
|
| - main() {
|
| - var x1 = 1;
|
| - x1++;
|
| - var x2 = 1;
|
| - ++x2;
|
| - var x3 = 1;
|
| - x3 += 42;
|
| - var x4 = new A();
|
| - x4++;
|
| - var x5 = new A();
|
| - ++x5;
|
| - var x6 = new A();
|
| - x6 += true;
|
| -
|
| - x1; x2; x3; x4; x5; x6;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x1', [result.int]);
|
| - result.checkNodeHasType('x2', [result.int]);
|
| - result.checkNodeHasType('x3', [result.int]);
|
| - result.checkNodeHasType('x4', [result.string]);
|
| - result.checkNodeHasType('x5', [result.string]);
|
| - result.checkNodeHasType('x6', [result.string]);
|
| - });
|
| -}
|
| -
|
| -
|
| -testCompoundOperators2() {
|
| - final String source = r"""
|
| - class A {
|
| - var xx;
|
| - var yy;
|
| - var witness1;
|
| - var witness2;
|
| - var witness3;
|
| - var witness4;
|
| -
|
| - A(this.xx, this.yy);
|
| - get x { witness1 = "foo"; return xx; }
|
| - set x(a) { witness2 = "foo"; xx = a; }
|
| - get y { witness3 = "foo"; return yy; }
|
| - set y(a) { witness4 = "foo"; yy = a; }
|
| - }
|
| - main () {
|
| - var a = new A(1, 1);
|
| - a.x++;
|
| - a.y++;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'xx', [result.int]);
|
| - result.checkFieldHasType('A', 'yy', [result.int]);
|
| - result.checkFieldHasType('A', 'witness1', [result.string, result.nullType]);
|
| - result.checkFieldHasType('A', 'witness2', [result.string, result.nullType]);
|
| - result.checkFieldHasType('A', 'witness3', [result.string, result.nullType]);
|
| - result.checkFieldHasType('A', 'witness4', [result.string, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testInequality() {
|
| - final String source = r"""
|
| - class A {
|
| - var witness;
|
| - operator ==(x) { witness = "foo"; return "abc"; }
|
| - }
|
| - class B {
|
| - operator ==(x) { throw "error"; }
|
| - }
|
| - main() {
|
| - var foo = 1 != 2;
|
| - var bar = (new A() != 2);
|
| - var baz = (new B() != 2);
|
| - foo; bar; baz;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.bool]);
|
| - result.checkNodeHasType('bar', [result.bool]);
|
| - // TODO(polux): could be even better: empty
|
| - result.checkNodeHasType('baz', [result.bool]);
|
| - result.checkFieldHasType('A', 'witness', [result.string, result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testFieldInitialization1() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - var y = 1;
|
| - }
|
| - class B extends A {
|
| - var z = "foo";
|
| - }
|
| - main () {
|
| - // we need to access y and z once to trigger their analysis
|
| - new B().y;
|
| - new B().z;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.nullType]);
|
| - result.checkFieldHasType('A', 'y', [result.int]);
|
| - result.checkFieldHasType('B', 'z', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testFieldInitialization2() {
|
| - final String source = r"""
|
| - var top = 42;
|
| - class A {
|
| - var x = top;
|
| - }
|
| - main () {
|
| - // we need to access X once to trigger its analysis
|
| - new A().x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testFieldInitialization3() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - }
|
| - f() => new A().x;
|
| - class B {
|
| - var x = new A().x;
|
| - var y = f();
|
| - }
|
| - main () {
|
| - var foo = new B().x;
|
| - var bar = new B().y;
|
| - new A().x = "a";
|
| - foo; bar;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - // checks that B.B is set as a reader of A.x
|
| - result.checkFieldHasType('B', 'x', [result.nullType, result.string]);
|
| - // checks that B.B is set as a caller of f
|
| - result.checkFieldHasType('B', 'y', [result.nullType, result.string]);
|
| - // checks that readers of x are notified by changes in x's type
|
| - result.checkNodeHasType('foo', [result.nullType, result.string]);
|
| - // checks that readers of y are notified by changes in y's type
|
| - result.checkNodeHasType('bar', [result.nullType, result.string]);
|
| - });
|
| -}
|
| -
|
| -testLists() {
|
| - final String source = """
|
| - class A {}
|
| - class B {}
|
| - class C {}
|
| - class D {}
|
| - class E {}
|
| - class F {}
|
| - class G {}
|
| -
|
| - main() {
|
| - var l1 = [new A()];
|
| - var l2 = [];
|
| - l1['a'] = new B(); // raises an error, so B should not be recorded
|
| - l1[1] = new C();
|
| - l1.add(new D());
|
| - l1.insert('a', new E()); // raises an error, so E should not be recorded
|
| - l1.insert(1, new F());
|
| - $DYNAMIC[1] = new G();
|
| - var x1 = l1[1];
|
| - var x2 = l2[1];
|
| - var x3 = l1['foo']; // raises an error, should return empty
|
| - var x4 = l1.removeAt(1);
|
| - var x5 = l2.removeAt(1);
|
| - var x6 = l1.removeAt('a'); // raises an error, should return empty
|
| - var x7 = l1.removeLast();
|
| - var x8 = l2.removeLast();
|
| - x1; x2; x3; x4; x5; x6; x7; x8;
|
| - }""";
|
| - return analyze(source).then((result) {
|
| - final expectedTypes = ['A', 'C', 'D', 'F', 'G'].map(result.base).toList();
|
| - result.checkNodeHasType('x1', expectedTypes);
|
| - result.checkNodeHasType('x2', expectedTypes);
|
| - result.checkNodeHasType('x3', []);
|
| - result.checkNodeHasType('x4', expectedTypes);
|
| - result.checkNodeHasType('x5', expectedTypes);
|
| - result.checkNodeHasType('x6', []);
|
| - result.checkNodeHasType('x7', expectedTypes);
|
| - result.checkNodeHasType('x8', expectedTypes);
|
| - });
|
| -}
|
| -
|
| -testListWithCapacity() {
|
| - final String source = r"""
|
| - main() {
|
| - var l = new List(10);
|
| - var x = [][0];
|
| - x;
|
| - }""";
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testEmptyList() {
|
| - final String source = r"""
|
| - main() {
|
| - var l = new List();
|
| - var x = l[0];
|
| - x;
|
| - }""";
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', []);
|
| - });
|
| -}
|
| -
|
| -testSendWithWrongArity() {
|
| - final String source = r"""
|
| - f(x) { }
|
| - class A { g(x) { } }
|
| - main () {
|
| - var x = f();
|
| - var y = f(1, 2);
|
| - var z = new A().g();
|
| - var w = new A().g(1, 2);
|
| - x; y; z; w;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - // TODO(polux): It would be better if x and y also had the empty type. This
|
| - // requires a change in SimpleTypeInferrerVisitor.visitStaticSend which
|
| - // would impact the default type inference and possibly break dart2js.
|
| - // Keeping this change for a later CL.
|
| - result.checkNodeHasUnknownType('x');
|
| - result.checkNodeHasUnknownType('y');
|
| - result.checkNodeHasType('z', []);
|
| - result.checkNodeHasType('w', []);
|
| - });
|
| -}
|
| -
|
| -testBigTypesWidening1() {
|
| - final String source = r"""
|
| - small() => true ? 1 : 'abc';
|
| - big() => true ? 1 : (true ? 'abc' : false);
|
| - main () {
|
| - var x = small();
|
| - var y = big();
|
| - x; y;
|
| - }
|
| - """;
|
| - return analyze(source, maxConcreteTypeSize: 2).then((result) {
|
| - result.checkNodeHasType('x', [result.int, result.string]);
|
| - result.checkNodeHasUnknownType('y');
|
| - });
|
| -}
|
| -
|
| -testBigTypesWidening2() {
|
| - final String source = r"""
|
| - class A {
|
| - var x, y;
|
| - A(this.x, this.y);
|
| - }
|
| - main () {
|
| - var a = new A(1, 1);
|
| - a.x = 'abc';
|
| - a.y = 'abc';
|
| - a.y = true;
|
| - }
|
| - """;
|
| - return analyze(source, maxConcreteTypeSize: 2).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int, result.string]);
|
| - result.checkFieldHasUknownType('A', 'y');
|
| - });
|
| -}
|
| -
|
| -testDynamicIsAbsorbing() {
|
| - final String source = """
|
| - main () {
|
| - var x = 1;
|
| - if (true) {
|
| - x = $DYNAMIC;
|
| - } else {
|
| - x = 42;
|
| - }
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasUnknownType('x');
|
| - });
|
| -}
|
| -
|
| -testJsCall() {
|
| - final String source = r"""
|
| - import 'dart:_foreign_helper';
|
| - import 'dart:_interceptors';
|
| -
|
| - abstract class AbstractA {}
|
| - class A extends AbstractA {}
|
| - class B extends A {}
|
| - class BB extends B {}
|
| - class C extends A {}
|
| - class D implements A {}
|
| - class E extends A {}
|
| -
|
| - class X {}
|
| -
|
| - main () {
|
| - // we don't create any E on purpose
|
| - new B(); new BB(); new C(); new D();
|
| -
|
| - var a = JS('', '1');
|
| - var b = JS('Object', '1');
|
| - var c = JS('JSExtendableArray', '1');
|
| - var cNull = JS('JSExtendableArray|Null', '1');
|
| - var d = JS('String', '1');
|
| - var dNull = JS('String|Null', '1');
|
| - var e = JS('int', '1');
|
| - var eNull = JS('int|Null', '1');
|
| - var f = JS('double', '1');
|
| - var fNull = JS('double|Null', '1');
|
| - var g = JS('num', '1');
|
| - var gNull = JS('num|Null', '1');
|
| - var h = JS('bool', '1');
|
| - var hNull = JS('bool|Null', '1');
|
| - var i = JS('AbstractA', '1');
|
| - var iNull = JS('AbstractA|Null', '1');
|
| -
|
| - a; b; c; cNull; d; dNull; e; eNull; f; fNull; g; gNull; h; hNull; i;
|
| - iNull;
|
| - }
|
| - """;
|
| - return analyze(source, maxConcreteTypeSize: 6).then((result) {
|
| - List maybe(List types) => new List.from(types)..add(result.nullType);
|
| - // a and b have all the types seen by the resolver, which are more than 6
|
| - result.checkNodeHasUnknownType('a');
|
| - result.checkNodeHasUnknownType('b');
|
| - final expectedCType = [result.growableList];
|
| - result.checkNodeHasType('c', expectedCType);
|
| - result.checkNodeHasType('cNull', maybe(expectedCType));
|
| - final expectedDType = [result.string];
|
| - result.checkNodeHasType('d', expectedDType);
|
| - result.checkNodeHasType('dNull', maybe(expectedDType));
|
| - final expectedEType = [result.int];
|
| - result.checkNodeHasType('e', expectedEType);
|
| - result.checkNodeHasType('eNull', maybe(expectedEType));
|
| - final expectedFType = [result.num];
|
| - result.checkNodeHasType('f', expectedFType);
|
| - result.checkNodeHasType('fNull', maybe(expectedFType));
|
| - final expectedGType = [result.num];
|
| - result.checkNodeHasType('g', expectedGType);
|
| - result.checkNodeHasType('gNull', maybe(expectedGType));
|
| - final expectedType = [result.bool];
|
| - result.checkNodeHasType('h', expectedType);
|
| - result.checkNodeHasType('hNull', maybe(expectedType));
|
| - final expectedIType = [result.base('B'),
|
| - result.base('BB'),
|
| - result.base('C'),
|
| - result.base('D')];
|
| - result.checkNodeHasType('i', expectedIType);
|
| - result.checkNodeHasType('iNull', maybe(expectedIType));
|
| - });
|
| -}
|
| -
|
| -testJsCallAugmentsSeenClasses() {
|
| - final String source1 = """
|
| - main () {
|
| - var x = $DYNAMIC.truncate();
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source1).then((AnalysisResult result) {
|
| - result.checkNodeHasType('x', []);
|
| - }).whenComplete(() {
|
| -
|
| - final String source2 = """
|
| - import 'dart:_foreign_helper';
|
| -
|
| - main () {
|
| - var x = $DYNAMIC.truncate();
|
| - JS('double', 'foo');
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source2).then((AnalysisResult result) {
|
| - result.checkNodeHasType('x', [result.int]);
|
| - });
|
| - });
|
| -}
|
| -
|
| -testIsCheck() {
|
| - final String source = r"""
|
| - main () {
|
| - var x = (1 is String);
|
| - x;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.bool]);
|
| - });
|
| -}
|
| -
|
| -testSeenClasses() {
|
| - final String source = """
|
| - class A {
|
| - witness() => 42;
|
| - }
|
| - class B {
|
| - witness() => "string";
|
| - }
|
| - class AFactory {
|
| - onlyCalledInAFactory() => new A();
|
| - }
|
| - class BFactory {
|
| - onlyCalledInAFactory() => new B();
|
| - }
|
| -
|
| - main() {
|
| - new AFactory().onlyCalledInAFactory();
|
| - new BFactory();
|
| - // should be of type {int} and not {int, String} since B is unreachable
|
| - var foo = $DYNAMIC.witness();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testIntDoubleNum() {
|
| - final String source = r"""
|
| - main() {
|
| - var a = 1;
|
| - var b = 1.1;
|
| - var c = true ? 1 : 1.1;
|
| - a; b; c;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('a', [result.int]);
|
| - result.checkNodeHasType('b', [result.double]);
|
| - result.checkNodeHasType('c', [result.num]);
|
| - });
|
| -}
|
| -
|
| -testConcreteTypeToTypeMask() {
|
| - final String source = r"""
|
| - class A {}
|
| - class B extends A {}
|
| - class C extends A {}
|
| - class D implements A {}
|
| - main() {
|
| - new A();
|
| - new B();
|
| - new C();
|
| - new D();
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| -
|
| - convert(ConcreteType type) {
|
| - return result.compiler.typesTask.concreteTypesInferrer
|
| - .types.concreteTypeToTypeMask(type);
|
| - }
|
| -
|
| - final nullSingleton =
|
| - result.compiler.typesTask.concreteTypesInferrer.singletonConcreteType(
|
| - new NullBaseType());
|
| -
|
| - singleton(ClassElement element) {
|
| - return result.compiler.typesTask.concreteTypesInferrer
|
| - .singletonConcreteType(new ClassBaseType(element));
|
| - }
|
| -
|
| - var world = result.compiler.world;
|
| -
|
| - ClassElement a = findElement(result.compiler, 'A');
|
| - ClassElement b = findElement(result.compiler, 'B');
|
| - ClassElement c = findElement(result.compiler, 'C');
|
| - ClassElement d = findElement(result.compiler, 'D');
|
| -
|
| - for (ClassElement cls in [a, b, c, d]) {
|
| - Expect.equals(convert(singleton(cls)),
|
| - new TypeMask.nonNullExact(cls, world));
|
| - }
|
| -
|
| - for (ClassElement cls in [a, b, c, d]) {
|
| - Expect.equals(convert(singleton(cls).union(nullSingleton)),
|
| - new TypeMask.exact(cls, world));
|
| - }
|
| -
|
| - Expect.equals(convert(singleton(a).union(singleton(b))),
|
| - new TypeMask.nonNullSubclass(a, world));
|
| -
|
| - Expect.equals(
|
| - convert(singleton(a).union(singleton(b)).union(nullSingleton)),
|
| - new TypeMask.subclass(a, world));
|
| -
|
| - Expect.equals(
|
| - simplify(convert(singleton(b).union(singleton(d))), result.compiler),
|
| - new TypeMask.nonNullSubtype(a, world));
|
| - });
|
| -}
|
| -
|
| -testSelectors() {
|
| - final String source = r"""
|
| - // ABC <--- A
|
| - // `- BC <--- B
|
| - // `- C
|
| -
|
| - class ABC {}
|
| - class A extends ABC {}
|
| - class BC extends ABC {}
|
| - class B extends BC {}
|
| - class C extends BC {}
|
| -
|
| - class XY {}
|
| - class X extends XY { foo() => new B(); }
|
| - class Y extends XY { foo() => new C(); }
|
| - class Z { foo() => new A(); }
|
| -
|
| - main() {
|
| - new X().foo();
|
| - new Y().foo();
|
| - new Z().foo();
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| -
|
| - var world = result.compiler.world;
|
| -
|
| - ClassElement a = findElement(result.compiler, 'A');
|
| - ClassElement b = findElement(result.compiler, 'B');
|
| - ClassElement c = findElement(result.compiler, 'C');
|
| - ClassElement xy = findElement(result.compiler, 'XY');
|
| - ClassElement x = findElement(result.compiler, 'X');
|
| - ClassElement y = findElement(result.compiler, 'Y');
|
| - ClassElement z = findElement(result.compiler, 'Z');
|
| -
|
| - Selector foo =
|
| - new Selector.call(const PublicName("foo"), CallStructure.NO_ARGS);
|
| -
|
| - result.checkSelectorHasType(
|
| - foo,
|
| - null,
|
| - new TypeMask.unionOf([a, b, c]
|
| - .map((cls) => new TypeMask.nonNullExact(cls, world)),
|
| - result.compiler.world));
|
| - result.checkSelectorHasType(
|
| - foo,
|
| - new TypeMask.subclass(x, world),
|
| - new TypeMask.nonNullExact(b, world));
|
| - result.checkSelectorHasType(
|
| - foo,
|
| - new TypeMask.subclass(y, world),
|
| - new TypeMask.nonNullExact(c, world));
|
| - result.checkSelectorHasType(
|
| - foo,
|
| - new TypeMask.subclass(z, world),
|
| - new TypeMask.nonNullExact(a, world));
|
| - result.checkSelectorHasType(
|
| - foo,
|
| - new TypeMask.subclass(xy, world),
|
| - new TypeMask.unionOf([b, c].map((cls) =>
|
| - new TypeMask.nonNullExact(cls, world)), world));
|
| -
|
| - result.checkSelectorHasType(
|
| - new Selector.call(const PublicName("bar"), CallStructure.NO_ARGS),
|
| - null, null);
|
| - });
|
| -}
|
| -
|
| -testEqualsNullSelector() {
|
| - final String source = r"""
|
| - main() {
|
| - 1 == null;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - ClassElement bool = result.compiler.backend.boolImplementation;
|
| - result.checkSelectorHasType(new Selector.binaryOperator('=='),
|
| - null,
|
| - new TypeMask.nonNullExact(bool,
|
| - result.compiler.world));
|
| - });
|
| -}
|
| -
|
| -testMixins() {
|
| - final String source = r"""
|
| - class A {
|
| - foo() => "abc";
|
| - get x => 42;
|
| - }
|
| - class B extends Object with A {
|
| - bar() => foo();
|
| - baz() => x;
|
| - }
|
| - main() {
|
| - var b = new B();
|
| - var x = b.foo();
|
| - var y = b.bar();
|
| - var z = b.x;
|
| - var w = b.baz();
|
| - x; y; z; w;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('x', [result.string]);
|
| - result.checkNodeHasType('y', [result.string]);
|
| - result.checkNodeHasType('z', [result.int]);
|
| - result.checkNodeHasType('w', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures1() {
|
| - final String source = r"""
|
| - class A {
|
| - final foo = 42;
|
| - }
|
| - class B {
|
| - final foo = "abc";
|
| - }
|
| - class C {
|
| - final foo = true;
|
| - }
|
| - main() {
|
| - var a;
|
| - var f = (x) {
|
| - a = x.foo;
|
| - };
|
| - // We make sure that x doesn't have type dynamic by adding C to the
|
| - // set of seen classes and by checking that a's type doesn't contain
|
| - // bool.
|
| - new C();
|
| - f(new A());
|
| - f(new B());
|
| - a;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
|
| - });
|
| -}
|
| -
|
| -testClosures2() {
|
| - final String source = r"""
|
| - class A {
|
| - final foo = 42;
|
| - }
|
| - class B {
|
| - final foo = "abc";
|
| - }
|
| - class C {
|
| - final foo = true;
|
| - }
|
| - main() {
|
| - // We make sure that x doesn't have type dynamic by adding C to the
|
| - // set of seen classes and by checking that a's type doesn't contain
|
| - // bool.
|
| - new C();
|
| -
|
| - var a;
|
| - f(x) {
|
| - a = x.foo;
|
| - }
|
| - f(new A());
|
| - f(new B());
|
| - a; f;
|
| - }
|
| - """;
|
| - return analyze(source).then((AnalysisResult result) {
|
| - result.checkNodeHasType('a', [result.nullType, result.int, result.string]);
|
| - result.checkNodeHasType('f', [result.functionType]);
|
| - });
|
| -}
|
| -
|
| -testClosures3() {
|
| - final String source = r"""
|
| - class A {
|
| - var g;
|
| - A(this.g);
|
| - }
|
| - main() {
|
| - var foo = new A((x) => x).g(42);
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures4() {
|
| - final String source = """
|
| - class A {
|
| - var f = $DYNAMIC;
|
| - }
|
| - main() {
|
| - var f = (x) => x;
|
| - var g = (x) => "a";
|
| - var h = (x, y) => true;
|
| -
|
| - var foo = $DYNAMIC(42);
|
| - var bar = new A().f(1.2);
|
| - var baz = $DYNAMIC.f(null);
|
| -
|
| - foo; bar; baz;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int, result.string]);
|
| - result.checkNodeHasType('bar', [result.double, result.string]);
|
| - result.checkNodeHasType('baz', [result.nullType, result.string]);
|
| - });
|
| -}
|
| -
|
| -testClosures5() {
|
| - final String source = r"""
|
| - f(x) => x;
|
| - class A {
|
| - var g;
|
| - A(this.g);
|
| - }
|
| - main() {
|
| - var foo = new A(f).g(42);
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures6() {
|
| - final String source = r"""
|
| - class A {
|
| - var g;
|
| - A(this.g);
|
| - }
|
| - class B {
|
| - f(x) => x;
|
| - }
|
| - main() {
|
| - var foo = new A(new B().f).g(42);
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures7() {
|
| - final String source = r"""
|
| - class A {
|
| - final x = 42;
|
| - f() => () => x;
|
| - }
|
| - main() {
|
| - var foo = new A().f()();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures8() {
|
| - final String source = r"""
|
| - class A {
|
| - final x = 42;
|
| - f() => () => x;
|
| - }
|
| - class B extends A {
|
| - get x => "a";
|
| - }
|
| - main() {
|
| - var foo = new B().f()();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testClosures9() {
|
| - final String source = r"""
|
| - class A {
|
| - g() => 42;
|
| - f() => () => g();
|
| - }
|
| - class B extends A {
|
| - g() => "a";
|
| - }
|
| - main() {
|
| - var foo = new B().f()();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.string]);
|
| - });
|
| -}
|
| -
|
| -testClosures10() {
|
| - final String source = r"""
|
| - class A {
|
| - f() => 42;
|
| - }
|
| - main() {
|
| - var a = new A();
|
| - g() => a.f();
|
| - var foo = g();
|
| - foo; a;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures11() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - f() => x;
|
| - }
|
| - main() {
|
| - var a = new A();
|
| - f() => a.f();
|
| - a.x = 42;
|
| - var foo = f();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.nullType, result.int]);
|
| - });
|
| -}
|
| -
|
| -testClosures12() {
|
| - final String source = r"""
|
| - var f = (x) => x;
|
| - main() {
|
| - var foo = f(1);
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testRefinement() {
|
| - final String source = """
|
| - class A {
|
| - f() => null;
|
| - g() => 42;
|
| - }
|
| - class B {
|
| - g() => "aa";
|
| - }
|
| - main() {
|
| - var x = $DYNAMIC ? new A() : new B();
|
| - x.f();
|
| - var foo = x.g();
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testDefaultArguments() {
|
| - final String source = r"""
|
| - f1([x = 42]) => x;
|
| - g1([x]) => x;
|
| -
|
| - f2({x: 42}) => x;
|
| - g2({x}) => x;
|
| -
|
| - main() {
|
| - var xf1 = f1();
|
| - var xg1 = g1();
|
| - var xf2 = f2();
|
| - var xg2 = g2();
|
| - xf1; xg1; xf2; xg2;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkNodeHasType('xf1', [result.int]);
|
| - result.checkNodeHasType('xg1', [result.nullType]);
|
| - result.checkNodeHasType('xf2', [result.int]);
|
| - result.checkNodeHasType('xg2', [result.nullType]);
|
| - });
|
| -}
|
| -
|
| -testSuperConstructorCall() {
|
| - final String source = r"""
|
| - class A {
|
| - final x;
|
| - A(this.x);
|
| - }
|
| -
|
| - class B extends A {
|
| - B(x) : super(x);
|
| - }
|
| - main() {
|
| - var b = new B(42);
|
| - var foo = b.x;
|
| - foo;
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - result.checkNodeHasType('foo', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testSuperConstructorCall2() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - A() {
|
| - x = 42;
|
| - }
|
| - }
|
| - class B extends A {
|
| - }
|
| - main() {
|
| - new B();
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - });
|
| -}
|
| -
|
| -testSuperConstructorCall3() {
|
| - final String source = r"""
|
| - class A {
|
| - var x;
|
| - A() {
|
| - x = 42;
|
| - }
|
| - }
|
| - class B extends A {
|
| - B(unused) {}
|
| - }
|
| - main() {
|
| - new B("abc");
|
| - }
|
| - """;
|
| - return analyze(source).then((result) {
|
| - result.checkFieldHasType('A', 'x', [result.int]);
|
| - });
|
| -}
|
| -
|
| -void main() {
|
| - asyncTest(() => Future.forEach([
|
| - testDynamicBackDoor,
|
| - testVariableDeclaration,
|
| - testLiterals,
|
| - testRedefinition,
|
| - testIfThenElse,
|
| - testTernaryIf,
|
| - testWhile,
|
| - testDoWhile,
|
| - testFor1,
|
| - testFor2,
|
| - testFor3,
|
| - testForIn,
|
| - testToplevelVariable,
|
| - testToplevelVariable2,
|
| - testToplevelVariable3,
|
| - testNonRecusiveFunction,
|
| - testMultipleReturns,
|
| - testRecusiveFunction,
|
| - testMutuallyRecusiveFunction,
|
| - testSimpleSend,
|
| - testSendToThis1,
|
| - testSendToThis2,
|
| - testSendToThis3,
|
| - testSendToThis4,
|
| - testConstructor,
|
| - testGetters,
|
| - testToplevelGetters,
|
| - testDynamicGetters,
|
| - testSetters,
|
| - testToplevelSetters,
|
| - testOptionalNamedParameters,
|
| - testOptionalPositionalParameters,
|
| - testListLiterals,
|
| - testMapLiterals,
|
| - testReturn,
|
| - testNoReturn,
|
| - testArithmeticOperators,
|
| - testBooleanOperators,
|
| - testBooleanOperatorsShortCirtcuit,
|
| - testOperators,
|
| - testCompoundOperators1,
|
| - testCompoundOperators2,
|
| - testSetIndexOperator,
|
| - testInequality,
|
| - testFieldInitialization1,
|
| - testFieldInitialization2,
|
| - testFieldInitialization3,
|
| - testSendWithWrongArity,
|
| - testBigTypesWidening1,
|
| - testBigTypesWidening2,
|
| - testDynamicIsAbsorbing,
|
| - testLists,
|
| - testListWithCapacity,
|
| - testEmptyList,
|
| - testJsCall,
|
| - testJsCallAugmentsSeenClasses,
|
| - testIsCheck,
|
| - testSeenClasses,
|
| - testIntDoubleNum,
|
| - testConcreteTypeToTypeMask,
|
| - testSelectors,
|
| - // TODO(polux): this test is failing, see http://dartbug.com/16825.
|
| - //testEqualsNullSelector,
|
| - testMixins,
|
| - testClosures1,
|
| - testClosures2,
|
| - testClosures3,
|
| - testClosures4,
|
| - testClosures5,
|
| - testClosures6,
|
| - testClosures7,
|
| - testClosures8,
|
| - testClosures9,
|
| - testClosures10,
|
| - testClosures11,
|
| - testClosures12,
|
| - testRefinement,
|
| - testDefaultArguments,
|
| - testSuperConstructorCall,
|
| - testSuperConstructorCall2,
|
| - testSuperConstructorCall3,
|
| - ], (f) => f()));
|
| -}
|
|
|