Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Unified Diff: pkg/analyzer/test/generated/strong_mode_test.dart

Issue 1782463002: Split resolver_test.dart into smaller files. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/test/generated/strong_mode_test.dart
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..115d966e9d0df2027ea44e2cb7492c25862adb7b
--- /dev/null
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -0,0 +1,2280 @@
+// Copyright (c) 2016, 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.
+
+library analyzer.test.generated.strong_mode_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+import '../utils.dart';
+import 'resolver_test_case.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(StrongModeDownwardsInferenceTest);
+ runReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
+ runReflectiveTests(StrongModeTypePropagationTest);
+}
+
+/**
+ * Strong mode static analyzer downwards inference tests
+ */
+@reflectiveTest
+class StrongModeDownwardsInferenceTest extends ResolverTestCase {
+ TypeAssertions _assertions;
+
+ Asserter<DartType> _isDynamic;
+ Asserter<InterfaceType> _isFutureOfDynamic;
+ Asserter<InterfaceType> _isFutureOfInt;
+ Asserter<DartType> _isInt;
+ Asserter<DartType> _isNum;
+ Asserter<DartType> _isString;
+
+ AsserterBuilder2<Asserter<DartType>, Asserter<DartType>, DartType>
+ _isFunction2Of;
+ AsserterBuilder<List<Asserter<DartType>>, InterfaceType> _isFutureOf;
+ AsserterBuilderBuilder<Asserter<DartType>, List<Asserter<DartType>>, DartType>
+ _isInstantiationOf;
+ AsserterBuilder<Asserter<DartType>, InterfaceType> _isListOf;
+ AsserterBuilder2<Asserter<DartType>, Asserter<DartType>, InterfaceType>
+ _isMapOf;
+ AsserterBuilder<List<Asserter<DartType>>, InterfaceType> _isStreamOf;
+ AsserterBuilder<DartType, DartType> _isType;
+
+ AsserterBuilder<Element, DartType> _hasElement;
+ AsserterBuilder<DartType, DartType> _sameElement;
+
+ @override
+ void setUp() {
+ super.setUp();
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ _assertions = new TypeAssertions(typeProvider);
+ _isType = _assertions.isType;
+ _hasElement = _assertions.hasElement;
+ _isInstantiationOf = _assertions.isInstantiationOf;
+ _isInt = _assertions.isInt;
+ _isNum = _assertions.isNum;
+ _isString = _assertions.isString;
+ _isDynamic = _assertions.isDynamic;
+ _isListOf = _assertions.isListOf;
+ _isMapOf = _assertions.isMapOf;
+ _isFunction2Of = _assertions.isFunction2Of;
+ _sameElement = _assertions.sameElement;
+ _isFutureOf = _isInstantiationOf(_sameElement(typeProvider.futureType));
+ _isFutureOfDynamic = _isFutureOf([_isDynamic]);
+ _isFutureOfInt = _isFutureOf([_isInt]);
+ _isStreamOf = _isInstantiationOf(_sameElement(typeProvider.streamType));
+ }
+
+ void test_async_method_propagation() {
+ String code = r'''
+ import "dart:async";
+ class A {
+ Future f0() => new Future.value(3);
+ Future f1() async => new Future.value(3);
+ Future f2() async => await new Future.value(3);
+
+ Future<int> f3() => new Future.value(3);
+ Future<int> f4() async => new Future.value(3);
+ Future<int> f5() async => await new Future.value(3);
+
+ Future g0() { return new Future.value(3); }
+ Future g1() async { return new Future.value(3); }
+ Future g2() async { return await new Future.value(3); }
+
+ Future<int> g3() { return new Future.value(3); }
+ Future<int> g4() async { return new Future.value(3); }
+ Future<int> g5() async { return await new Future.value(3); }
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ MethodDeclaration test = AstFinder.getMethodInClass(unit, "A", name);
+ FunctionBody body = test.body;
+ Expression returnExp;
+ if (body is ExpressionFunctionBody) {
+ returnExp = body.expression;
+ } else {
+ ReturnStatement stmt = (body as BlockFunctionBody).block.statements[0];
+ returnExp = stmt.expression;
+ }
+ DartType type = returnExp.staticType;
+ if (returnExp is AwaitExpression) {
+ type = returnExp.expression.staticType;
+ }
+ typeTest(type);
+ }
+
+ check("f0", _isFutureOfDynamic);
+ check("f1", _isFutureOfDynamic);
+ check("f2", _isFutureOfDynamic);
+
+ check("f3", _isFutureOfInt);
+ // This should be int when we handle the implicit Future<T> | T union
+ // https://github.com/dart-lang/sdk/issues/25322
+ check("f4", _isFutureOfDynamic);
+ check("f5", _isFutureOfInt);
+
+ check("g0", _isFutureOfDynamic);
+ check("g1", _isFutureOfDynamic);
+ check("g2", _isFutureOfDynamic);
+
+ check("g3", _isFutureOfInt);
+ // This should be int when we handle the implicit Future<T> | T union
+ // https://github.com/dart-lang/sdk/issues/25322
+ check("g4", _isFutureOfDynamic);
+ check("g5", _isFutureOfInt);
+ }
+
+ void test_async_propagation() {
+ String code = r'''
+ import "dart:async";
+
+ Future f0() => new Future.value(3);
+ Future f1() async => new Future.value(3);
+ Future f2() async => await new Future.value(3);
+
+ Future<int> f3() => new Future.value(3);
+ Future<int> f4() async => new Future.value(3);
+ Future<int> f5() async => await new Future.value(3);
+
+ Future g0() { return new Future.value(3); }
+ Future g1() async { return new Future.value(3); }
+ Future g2() async { return await new Future.value(3); }
+
+ Future<int> g3() { return new Future.value(3); }
+ Future<int> g4() async { return new Future.value(3); }
+ Future<int> g5() async { return await new Future.value(3); }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ FunctionDeclaration test = AstFinder.getTopLevelFunction(unit, name);
+ FunctionBody body = test.functionExpression.body;
+ Expression returnExp;
+ if (body is ExpressionFunctionBody) {
+ returnExp = body.expression;
+ } else {
+ ReturnStatement stmt = (body as BlockFunctionBody).block.statements[0];
+ returnExp = stmt.expression;
+ }
+ DartType type = returnExp.staticType;
+ if (returnExp is AwaitExpression) {
+ type = returnExp.expression.staticType;
+ }
+ typeTest(type);
+ }
+
+ check("f0", _isFutureOfDynamic);
+ check("f1", _isFutureOfDynamic);
+ check("f2", _isFutureOfDynamic);
+
+ check("f3", _isFutureOfInt);
+ // This should be int when we handle the implicit Future<T> | T union
+ // https://github.com/dart-lang/sdk/issues/25322
+ check("f4", _isFutureOfDynamic);
+ check("f5", _isFutureOfInt);
+
+ check("g0", _isFutureOfDynamic);
+ check("g1", _isFutureOfDynamic);
+ check("g2", _isFutureOfDynamic);
+
+ check("g3", _isFutureOfInt);
+ // This should be int when we handle the implicit Future<T> | T union
+ // https://github.com/dart-lang/sdk/issues/25322
+ check("g4", _isFutureOfDynamic);
+ check("g5", _isFutureOfInt);
+ }
+
+ void test_async_star_method_propagation() {
+ String code = r'''
+ import "dart:async";
+ class A {
+ Stream g0() async* { yield []; }
+ Stream g1() async* { yield* new Stream(); }
+
+ Stream<List<int>> g2() async* { yield []; }
+ Stream<List<int>> g3() async* { yield* new Stream(); }
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ MethodDeclaration test = AstFinder.getMethodInClass(unit, "A", name);
+ BlockFunctionBody body = test.body;
+ YieldStatement stmt = body.block.statements[0];
+ Expression exp = stmt.expression;
+ typeTest(exp.staticType);
+ }
+
+ check("g0", _isListOf(_isDynamic));
+ check("g1", _isStreamOf([_isDynamic]));
+
+ check("g2", _isListOf(_isInt));
+ check("g3", _isStreamOf([_isListOf(_isInt)]));
+ }
+
+ void test_async_star_propagation() {
+ String code = r'''
+ import "dart:async";
+
+ Stream g0() async* { yield []; }
+ Stream g1() async* { yield* new Stream(); }
+
+ Stream<List<int>> g2() async* { yield []; }
+ Stream<List<int>> g3() async* { yield* new Stream(); }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ FunctionDeclaration test = AstFinder.getTopLevelFunction(unit, name);
+ BlockFunctionBody body = test.functionExpression.body;
+ YieldStatement stmt = body.block.statements[0];
+ Expression exp = stmt.expression;
+ typeTest(exp.staticType);
+ }
+
+ check("g0", _isListOf(_isDynamic));
+ check("g1", _isStreamOf([_isDynamic]));
+
+ check("g2", _isListOf(_isInt));
+ check("g3", _isStreamOf([_isListOf(_isInt)]));
+ }
+
+ void test_cascadeExpression() {
+ String code = r'''
+ class A<T> {
+ List<T> map(T a, List<T> mapper(T x)) => mapper(a);
+ }
+
+ void main () {
+ A<int> a = new A()..map(0, (x) => [x]);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ CascadeExpression fetch(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ CascadeExpression exp = decl.initializer;
+ return exp;
+ }
+ Element elementA = AstFinder.getClass(unit, "A").element;
+
+ CascadeExpression cascade = fetch(0);
+ _isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.staticType);
+ MethodInvocation invoke = cascade.cascadeSections[0];
+ FunctionExpression function = invoke.argumentList.arguments[1];
+ ExecutableElement f0 = function.element;
+ _isListOf(_isInt)(f0.type.returnType);
+ expect(f0.type.normalParameterTypes[0], typeProvider.intType);
+ }
+
+ void test_constructorInitializer_propagation() {
+ String code = r'''
+ class A {
+ List<String> x;
+ A() : this.x = [];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ ConstructorFieldInitializer assignment = constructor.initializers[0];
+ Expression exp = assignment.expression;
+ _isListOf(_isString)(exp.staticType);
+ }
+
+ void test_factoryConstructor_propagation() {
+ String code = r'''
+ class A<T> {
+ factory A() { return new B(); }
+ }
+ class B<S> extends A<S> {}
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ BlockFunctionBody body = constructor.body;
+ ReturnStatement stmt = body.block.statements[0];
+ InstanceCreationExpression exp = stmt.expression;
+ ClassElement elementB = AstFinder.getClass(unit, "B").element;
+ ClassElement elementA = AstFinder.getClass(unit, "A").element;
+ expect(exp.constructorName.type.type.element, elementB);
+ _isInstantiationOf(_hasElement(elementB))(
+ [_isType(elementA.typeParameters[0].type)])(exp.staticType);
+ }
+
+ void test_fieldDeclaration_propagation() {
+ String code = r'''
+ class A {
+ List<String> f0 = ["hello"];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ VariableDeclaration field = AstFinder.getFieldInClass(unit, "A", "f0");
+
+ _isListOf(_isString)(field.initializer.staticType);
+ }
+
+ void test_functionDeclaration_body_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ List<int> test1() => [];
+
+ Function2<int, int> test2 (int x) {
+ Function2<String, int> inner() {
+ return (x) => x.length;
+ }
+ return (x) => x;
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ FunctionDeclaration test1 = AstFinder.getTopLevelFunction(unit, "test1");
+ ExpressionFunctionBody body = test1.functionExpression.body;
+ assertListOfInt(body.expression.staticType);
+
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+
+ FunctionDeclaration inner =
+ (statements[0] as FunctionDeclarationStatement).functionDeclaration;
+ BlockFunctionBody body0 = inner.functionExpression.body;
+ ReturnStatement return0 = body0.block.statements[0];
+ Expression anon0 = return0.expression;
+ FunctionType type0 = anon0.staticType;
+ expect(type0.returnType, typeProvider.intType);
+ expect(type0.normalParameterTypes[0], typeProvider.stringType);
+
+ FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
+ FunctionType type1 = anon1.element.type;
+ expect(type1.returnType, typeProvider.intType);
+ expect(type1.normalParameterTypes[0], typeProvider.intType);
+ }
+
+ void test_functionLiteral_assignment_typedArguments() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, String> l0 = (int x) => null;
+ Function2<int, String> l1 = (int x) => "hello";
+ Function2<int, String> l2 = (String x) => "hello";
+ Function2<int, String> l3 = (int x) => 3;
+ Function2<int, String> l4 = (int x) {return 3;};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_assignment_unTypedArguments() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, String> l0 = (x) => null;
+ Function2<int, String> l1 = (x) => "hello";
+ Function2<int, String> l2 = (x) => "hello";
+ Function2<int, String> l3 = (x) => 3;
+ Function2<int, String> l4 = (x) {return 3;};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_body_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, List<String>> l0 = (int x) => ["hello"];
+ Function2<int, List<String>> l1 = (String x) => ["hello"];
+ Function2<int, List<String>> l2 = (int x) => [3];
+ Function2<int, List<String>> l3 = (int x) {return [3];};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ Expression functionReturnValue(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ FunctionBody body = exp.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ assertListOfString(functionReturnValue(0).staticType);
+ assertListOfString(functionReturnValue(1).staticType);
+ assertListOfString(functionReturnValue(2).staticType);
+ assertListOfString(functionReturnValue(3).staticType);
+ }
+
+ void test_functionLiteral_functionExpressionInvocation_typedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ (new Mapper<int, String>().map)((int x) => null);
+ (new Mapper<int, String>().map)((int x) => "hello");
+ (new Mapper<int, String>().map)((String x) => "hello");
+ (new Mapper<int, String>().map)((int x) => 3);
+ (new Mapper<int, String>().map)((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ FunctionExpressionInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionExpressionInvocation_unTypedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ (new Mapper<int, String>().map)((x) => null);
+ (new Mapper<int, String>().map)((x) => "hello");
+ (new Mapper<int, String>().map)((x) => "hello");
+ (new Mapper<int, String>().map)((x) => 3);
+ (new Mapper<int, String>().map)((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ FunctionExpressionInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionInvocation_typedArguments() {
+ String code = r'''
+ String map(String mapper(int x)) => mapper(null);
+
+ void main () {
+ map((int x) => null);
+ map((int x) => "hello");
+ map((String x) => "hello");
+ map((int x) => 3);
+ map((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionInvocation_unTypedArguments() {
+ String code = r'''
+ String map(String mapper(int x)) => mapper(null);
+
+ void main () {
+ map((x) => null);
+ map((x) => "hello");
+ map((x) => "hello");
+ map((x) => 3);
+ map((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_methodInvocation_typedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ new Mapper<int, String>().map((int x) => null);
+ new Mapper<int, String>().map((int x) => "hello");
+ new Mapper<int, String>().map((String x) => "hello");
+ new Mapper<int, String>().map((int x) => 3);
+ new Mapper<int, String>().map((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_methodInvocation_unTypedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ new Mapper<int, String>().map((x) => null);
+ new Mapper<int, String>().map((x) => "hello");
+ new Mapper<int, String>().map((x) => "hello");
+ new Mapper<int, String>().map((x) => 3);
+ new Mapper<int, String>().map((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_unTypedArgument_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, int> l0 = (x) => x;
+ Function2<int, int> l1 = (x) => x+1;
+ Function2<int, String> l2 = (x) => x;
+ Function2<int, String> l3 = (x) => x.toLowerCase();
+ Function2<String, String> l4 = (x) => x.toLowerCase();
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ Expression functionReturnValue(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ FunctionBody body = exp.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ expect(functionReturnValue(0).staticType, typeProvider.intType);
+ expect(functionReturnValue(1).staticType, typeProvider.intType);
+ expect(functionReturnValue(2).staticType, typeProvider.intType);
+ expect(functionReturnValue(3).staticType, typeProvider.dynamicType);
+ expect(functionReturnValue(4).staticType, typeProvider.stringType);
+ }
+
+ void test_inference_hints() {
+ Source source = addSource(r'''
+ void main () {
+ var x = 3;
+ List<int> l0 = [];
+ }
+ ''');
+ resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_instanceCreation() {
+ String code = r'''
+ class A<S, T> {
+ S x;
+ T y;
+ A(this.x, this.y);
+ A.named(this.x, this.y);
+ }
+
+ class B<S, T> extends A<T, S> {
+ B(S y, T x) : super(x, y);
+ B.named(S y, T x) : super.named(x, y);
+ }
+
+ class C<S> extends B<S, S> {
+ C(S a) : super(a, a);
+ C.named(S a) : super.named(a, a);
+ }
+
+ class D<S, T> extends B<T, int> {
+ D(T a) : super(a, 3);
+ D.named(T a) : super.named(a, 3);
+ }
+
+ class E<S, T> extends A<C<S>, T> {
+ E(T a) : super(null, a);
+ }
+
+ class F<S, T> extends A<S, T> {
+ F(S x, T y, {List<S> a, List<T> b}) : super(x, y);
+ F.named(S x, T y, [S a, T b]) : super(a, b);
+ }
+
+ void test0() {
+ A<int, String> a0 = new A(3, "hello");
+ A<int, String> a1 = new A.named(3, "hello");
+ A<int, String> a2 = new A<int, String>(3, "hello");
+ A<int, String> a3 = new A<int, String>.named(3, "hello");
+ A<int, String> a4 = new A<int, dynamic>(3, "hello");
+ A<int, String> a5 = new A<dynamic, dynamic>.named(3, "hello");
+ }
+ void test1() {
+ A<int, String> a0 = new A("hello", 3);
+ A<int, String> a1 = new A.named("hello", 3);
+ }
+ void test2() {
+ A<int, String> a0 = new B("hello", 3);
+ A<int, String> a1 = new B.named("hello", 3);
+ A<int, String> a2 = new B<String, int>("hello", 3);
+ A<int, String> a3 = new B<String, int>.named("hello", 3);
+ A<int, String> a4 = new B<String, dynamic>("hello", 3);
+ A<int, String> a5 = new B<dynamic, dynamic>.named("hello", 3);
+ }
+ void test3() {
+ A<int, String> a0 = new B(3, "hello");
+ A<int, String> a1 = new B.named(3, "hello");
+ }
+ void test4() {
+ A<int, int> a0 = new C(3);
+ A<int, int> a1 = new C.named(3);
+ A<int, int> a2 = new C<int>(3);
+ A<int, int> a3 = new C<int>.named(3);
+ A<int, int> a4 = new C<dynamic>(3);
+ A<int, int> a5 = new C<dynamic>.named(3);
+ }
+ void test5() {
+ A<int, int> a0 = new C("hello");
+ A<int, int> a1 = new C.named("hello");
+ }
+ void test6() {
+ A<int, String> a0 = new D("hello");
+ A<int, String> a1 = new D.named("hello");
+ A<int, String> a2 = new D<int, String>("hello");
+ A<int, String> a3 = new D<String, String>.named("hello");
+ A<int, String> a4 = new D<num, dynamic>("hello");
+ A<int, String> a5 = new D<dynamic, dynamic>.named("hello");
+ }
+ void test7() {
+ A<int, String> a0 = new D(3);
+ A<int, String> a1 = new D.named(3);
+ }
+ void test8() {
+ // Currently we only allow variable constraints. Test that we reject.
+ A<C<int>, String> a0 = new E("hello");
+ }
+ void test9() { // Check named and optional arguments
+ A<int, String> a0 = new F(3, "hello", a: [3], b: ["hello"]);
+ A<int, String> a1 = new F(3, "hello", a: ["hello"], b:[3]);
+ A<int, String> a2 = new F.named(3, "hello", 3, "hello");
+ A<int, String> a3 = new F.named(3, "hello");
+ A<int, String> a4 = new F.named(3, "hello", "hello", 3);
+ A<int, String> a5 = new F.named(3, "hello", "hello");
+ }
+ }''';
+ CompilationUnit unit = resolveSource(code);
+
+ Expression rhs(VariableDeclarationStatement stmt) {
+ VariableDeclaration decl = stmt.variables.variables[0];
+ Expression exp = decl.initializer;
+ return exp;
+ }
+
+ void hasType(Asserter<DartType> assertion, Expression exp) =>
+ assertion(exp.staticType);
+
+ Element elementA = AstFinder.getClass(unit, "A").element;
+ Element elementB = AstFinder.getClass(unit, "B").element;
+ Element elementC = AstFinder.getClass(unit, "C").element;
+ Element elementD = AstFinder.getClass(unit, "D").element;
+ Element elementE = AstFinder.getClass(unit, "E").element;
+ Element elementF = AstFinder.getClass(unit, "F").element;
+
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf =
+ _isInstantiationOf(_hasElement(elementA));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf =
+ _isInstantiationOf(_hasElement(elementB));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertCOf =
+ _isInstantiationOf(_hasElement(elementC));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertDOf =
+ _isInstantiationOf(_hasElement(elementD));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertEOf =
+ _isInstantiationOf(_hasElement(elementE));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertFOf =
+ _isInstantiationOf(_hasElement(elementF));
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test0");
+
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[3]));
+ hasType(assertAOf([_isInt, _isDynamic]), rhs(statements[4]));
+ hasType(assertAOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test1");
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[2]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[3]));
+ hasType(assertBOf([_isString, _isDynamic]), rhs(statements[4]));
+ hasType(assertBOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test3");
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test4");
+ hasType(assertCOf([_isInt]), rhs(statements[0]));
+ hasType(assertCOf([_isInt]), rhs(statements[1]));
+ hasType(assertCOf([_isInt]), rhs(statements[2]));
+ hasType(assertCOf([_isInt]), rhs(statements[3]));
+ hasType(assertCOf([_isDynamic]), rhs(statements[4]));
+ hasType(assertCOf([_isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test5");
+ hasType(assertCOf([_isInt]), rhs(statements[0]));
+ hasType(assertCOf([_isInt]), rhs(statements[1]));
+ }
+
+ {
+ // The first type parameter is not constrained by the
+ // context. We could choose a tighter type, but currently
+ // we just use dynamic.
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test6");
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+ hasType(assertDOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertDOf([_isString, _isString]), rhs(statements[3]));
+ hasType(assertDOf([_isNum, _isDynamic]), rhs(statements[4]));
+ hasType(assertDOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test7");
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test8");
+ hasType(assertEOf([_isDynamic, _isDynamic]), rhs(statements[0]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test9");
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[1]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[3]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[4]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[5]));
+ }
+ }
+
+ void test_listLiteral_nested() {
+ String code = r'''
+ void main () {
+ List<List<int>> l0 = [[]];
+ Iterable<List<int>> l1 = [[3]];
+ Iterable<List<int>> l2 = [[3], [4]];
+ List<List<int>> l3 = [["hello", 3], []];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ ListLiteral literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+ Asserter<InterfaceType> assertListOfListOfInt = _isListOf(assertListOfInt);
+
+ assertListOfListOfInt(literal(0).staticType);
+ assertListOfListOfInt(literal(1).staticType);
+ assertListOfListOfInt(literal(2).staticType);
+ assertListOfListOfInt(literal(3).staticType);
+
+ assertListOfInt(literal(1).elements[0].staticType);
+ assertListOfInt(literal(2).elements[0].staticType);
+ assertListOfInt(literal(3).elements[0].staticType);
+ }
+
+ void test_listLiteral_simple() {
+ String code = r'''
+ void main () {
+ List<int> l0 = [];
+ List<int> l1 = [3];
+ List<int> l2 = ["hello"];
+ List<int> l3 = ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_listLiteral_simple_const() {
+ String code = r'''
+ void main () {
+ const List<int> c0 = const [];
+ const List<int> c1 = const [3];
+ const List<int> c2 = const ["hello"];
+ const List<int> c3 = const ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_listLiteral_simple_disabled() {
+ String code = r'''
+ void main () {
+ List<int> l0 = <num>[];
+ List<int> l1 = <num>[3];
+ List<int> l2 = <String>["hello"];
+ List<int> l3 = <dynamic>["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ _isListOf(_isNum)(literal(0));
+ _isListOf(_isNum)(literal(1));
+ _isListOf(_isString)(literal(2));
+ _isListOf(_isDynamic)(literal(3));
+ }
+
+ void test_listLiteral_simple_subtype() {
+ String code = r'''
+ void main () {
+ Iterable<int> l0 = [];
+ Iterable<int> l1 = [3];
+ Iterable<int> l2 = ["hello"];
+ Iterable<int> l3 = ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_mapLiteral_nested() {
+ String code = r'''
+ void main () {
+ Map<int, List<String>> l0 = {};
+ Map<int, List<String>> l1 = {3: ["hello"]};
+ Map<int, List<String>> l2 = {"hello": ["hello"]};
+ Map<int, List<String>> l3 = {3: [3]};
+ Map<int, List<String>> l4 = {3:["hello"], "hello": [3]};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ MapLiteral literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp;
+ }
+
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ Asserter<InterfaceType> assertMapOfIntToListOfString =
+ _isMapOf(_isInt, assertListOfString);
+
+ assertMapOfIntToListOfString(literal(0).staticType);
+ assertMapOfIntToListOfString(literal(1).staticType);
+ assertMapOfIntToListOfString(literal(2).staticType);
+ assertMapOfIntToListOfString(literal(3).staticType);
+ assertMapOfIntToListOfString(literal(4).staticType);
+
+ assertListOfString(literal(1).entries[0].value.staticType);
+ assertListOfString(literal(2).entries[0].value.staticType);
+ assertListOfString(literal(3).entries[0].value.staticType);
+ assertListOfString(literal(4).entries[0].value.staticType);
+ }
+
+ void test_mapLiteral_simple() {
+ String code = r'''
+ void main () {
+ Map<int, String> l0 = {};
+ Map<int, String> l1 = {3: "hello"};
+ Map<int, String> l2 = {"hello": "hello"};
+ Map<int, String> l3 = {3: 3};
+ Map<int, String> l4 = {3:"hello", "hello": 3};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertMapOfIntToString =
+ _isMapOf(_isInt, _isString);
+
+ assertMapOfIntToString(literal(0));
+ assertMapOfIntToString(literal(1));
+ assertMapOfIntToString(literal(2));
+ assertMapOfIntToString(literal(3));
+ }
+
+ void test_mapLiteral_simple_disabled() {
+ String code = r'''
+ void main () {
+ Map<int, String> l0 = <int, dynamic>{};
+ Map<int, String> l1 = <int, dynamic>{3: "hello"};
+ Map<int, String> l2 = <int, dynamic>{"hello": "hello"};
+ Map<int, String> l3 = <int, dynamic>{3: 3};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertMapOfIntToDynamic =
+ _isMapOf(_isInt, _isDynamic);
+
+ assertMapOfIntToDynamic(literal(0));
+ assertMapOfIntToDynamic(literal(1));
+ assertMapOfIntToDynamic(literal(2));
+ assertMapOfIntToDynamic(literal(3));
+ }
+
+ void test_methodDeclaration_body_propagation() {
+ String code = r'''
+ class A {
+ List<String> m0(int x) => ["hello"];
+ List<String> m1(int x) {return [3];};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ Expression methodReturnValue(String methodName) {
+ MethodDeclaration method =
+ AstFinder.getMethodInClass(unit, "A", methodName);
+ FunctionBody body = method.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ assertListOfString(methodReturnValue("m0").staticType);
+ assertListOfString(methodReturnValue("m1").staticType);
+ }
+
+ void test_redirectingConstructor_propagation() {
+ String code = r'''
+ class A {
+ A() : this.named([]);
+ A.named(List<String> x);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ RedirectingConstructorInvocation invocation = constructor.initializers[0];
+ Expression exp = invocation.argumentList.arguments[0];
+ _isListOf(_isString)(exp.staticType);
+ }
+
+ void test_superConstructorInvocation_propagation() {
+ String code = r'''
+ class B {
+ B(List<String>);
+ }
+ class A extends B {
+ A() : super([]);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ SuperConstructorInvocation invocation = constructor.initializers[0];
+ Expression exp = invocation.argumentList.arguments[0];
+ _isListOf(_isString)(exp.staticType);
+ }
+
+ void test_sync_star_method_propagation() {
+ String code = r'''
+ import "dart:async";
+ class A {
+ Iterable f0() sync* { yield []; }
+ Iterable f1() sync* { yield* new List(); }
+
+ Iterable<List<int>> f2() sync* { yield []; }
+ Iterable<List<int>> f3() sync* { yield* new List(); }
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ MethodDeclaration test = AstFinder.getMethodInClass(unit, "A", name);
+ BlockFunctionBody body = test.body;
+ YieldStatement stmt = body.block.statements[0];
+ Expression exp = stmt.expression;
+ typeTest(exp.staticType);
+ }
+
+ check("f0", _isListOf(_isDynamic));
+ check("f1", _isListOf(_isDynamic));
+
+ check("f2", _isListOf(_isInt));
+ check("f3", _isListOf(_isListOf(_isInt)));
+ }
+
+ void test_sync_star_propagation() {
+ String code = r'''
+ import "dart:async";
+
+ Iterable f0() sync* { yield []; }
+ Iterable f1() sync* { yield* new List(); }
+
+ Iterable<List<int>> f2() sync* { yield []; }
+ Iterable<List<int>> f3() sync* { yield* new List(); }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ void check(String name, Asserter<InterfaceType> typeTest) {
+ FunctionDeclaration test = AstFinder.getTopLevelFunction(unit, name);
+ BlockFunctionBody body = test.functionExpression.body;
+ YieldStatement stmt = body.block.statements[0];
+ Expression exp = stmt.expression;
+ typeTest(exp.staticType);
+ }
+
+ check("f0", _isListOf(_isDynamic));
+ check("f1", _isListOf(_isDynamic));
+
+ check("f2", _isListOf(_isInt));
+ check("f3", _isListOf(_isListOf(_isInt)));
+ }
+}
+
+/**
+ * Strong mode static analyzer end to end tests
+ */
+@reflectiveTest
+class StrongModeStaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared {
+ void fail_genericMethod_tearoff_instantiated() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(E e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+ var methodTearOffInst = c.f/*<int>*/;
+ var staticTearOffInst = C.g/*<int>*/;
+ var staticFieldTearOffInst = C.h/*<int>*/;
+ var topFunTearOffInst = topF/*<int>*/;
+ var topFieldTearOffInst = topG/*<int>*/;
+ var localTearOffInst = lf/*<int>*/;
+ var paramTearOffInst = pf/*<int>*/;
+}
+''');
+ expectIdentifierType('methodTearOffInst', "(int) → int");
+ expectIdentifierType('staticTearOffInst', "(int) → int");
+ expectIdentifierType('staticFieldTearOffInst', "(int) → int");
+ expectIdentifierType('topFunTearOffInst', "(int) → int");
+ expectIdentifierType('topFieldTearOffInst', "(int) → int");
+ expectIdentifierType('localTearOffInst', "(int) → int");
+ expectIdentifierType('paramTearOffInst', "(int) → int");
+ }
+
+ void setUp() {
+ super.setUp();
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ }
+
+ void test_dynamicObjectGetter_hashCode() {
+ String code = r'''
+main() {
+ dynamic a = null;
+ var foo = a.hashCode;
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'int', isNull);
+ }
+
+ void test_dynamicObjectMethod_toString() {
+ String code = r'''
+main() {
+ dynamic a = null;
+ var foo = a.toString();
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'String', isNull);
+ }
+
+ void test_genericFunction() {
+ resolveTestUnit(r'/*=T*/ f/*<T>*/(/*=T*/ x) => null;');
+ expectFunctionType('f', '<T>(T) → T',
+ elementTypeParams: '[T]', typeFormals: '[T]');
+ SimpleIdentifier f = findIdentifier('f');
+ FunctionElementImpl e = f.staticElement;
+ FunctionType ft = e.type.instantiate([typeProvider.stringType]);
+ expect(ft.toString(), '(String) → String');
+ }
+
+ void test_genericFunction_bounds() {
+ resolveTestUnit(r'/*=T*/ f/*<T extends num>*/(/*=T*/ x) => null;');
+ expectFunctionType('f', '<T extends num>(T) → T',
+ elementTypeParams: '[T extends num]', typeFormals: '[T extends num]');
+ }
+
+ void test_genericFunction_parameter() {
+ resolveTestUnit(r'''
+void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}
+''');
+ expectFunctionType('f', '<T>(T) → T',
+ elementTypeParams: '[T]', typeFormals: '[T]');
+ SimpleIdentifier f = findIdentifier('f');
+ ParameterElementImpl e = f.staticElement;
+ FunctionType type = e.type;
+ FunctionType ft = type.instantiate([typeProvider.stringType]);
+ expect(ft.toString(), '(String) → String');
+ }
+
+ void test_genericFunction_static() {
+ resolveTestUnit(r'''
+class C<E> {
+ static /*=T*/ f/*<T>*/(/*=T*/ x) => null;
+}
+''');
+ expectFunctionType('f', '<T>(T) → T',
+ elementTypeParams: '[T]', typeFormals: '[T]');
+ SimpleIdentifier f = findIdentifier('f');
+ MethodElementImpl e = f.staticElement;
+ FunctionType ft = e.type.instantiate([typeProvider.stringType]);
+ expect(ft.toString(), '(String) → String');
+ }
+
+ void test_genericFunction_typedef() {
+ String code = r'''
+typedef T F<T>(T x);
+F f0;
+
+class C {
+ static F f1;
+ F f2;
+ void g(F f3) {
+ F f4;
+ f0(3);
+ f1(3);
+ f2(3);
+ f3(3);
+ f4(3);
+ }
+}
+
+class D<S> {
+ static F f1;
+ F f2;
+ void g(F f3) {
+ F f4;
+ f0(3);
+ f1(3);
+ f2(3);
+ f3(3);
+ f4(3);
+ }
+}
+''';
+ resolveTestUnit(code);
+
+ checkBody(String className) {
+ List<Statement> statements =
+ AstFinder.getStatementsInMethod(testUnit, className, "g");
+
+ for (int i = 1; i <= 5; i++) {
+ Expression exp = (statements[i] as ExpressionStatement).expression;
+ expect(exp.staticType, typeProvider.dynamicType);
+ }
+ }
+
+ checkBody("C");
+ checkBody("D");
+ }
+
+ void test_genericMethod() {
+ resolveTestUnit(r'''
+class C<E> {
+ List/*<T>*/ f/*<T>*/(E e) => null;
+}
+main() {
+ C<String> cOfString;
+}
+''');
+ expectFunctionType('f', '<T>(E) → List<T>',
+ elementTypeParams: '[T]',
+ typeParams: '[E]',
+ typeArgs: '[E]',
+ typeFormals: '[T]');
+ SimpleIdentifier c = findIdentifier('cOfString');
+ FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
+ expect(ft.toString(), '<T>(String) → List<T>');
+ ft = ft.instantiate([typeProvider.intType]);
+ expect(ft.toString(), '(String) → List<int>');
+ expect('${ft.typeArguments}/${ft.typeParameters}', '[String, int]/[E, T]');
+ }
+
+ void test_genericMethod_explicitTypeParams() {
+ resolveTestUnit(r'''
+class C<E> {
+ List/*<T>*/ f/*<T>*/(E e) => null;
+}
+main() {
+ C<String> cOfString;
+ var x = cOfString.f/*<int>*/('hi');
+}
+''');
+ MethodInvocation f = findIdentifier('f/*<int>*/').parent;
+ FunctionType ft = f.staticInvokeType;
+ expect(ft.toString(), '(String) → List<int>');
+ expect('${ft.typeArguments}/${ft.typeParameters}', '[String, int]/[E, T]');
+
+ SimpleIdentifier x = findIdentifier('x');
+ expect(x.staticType,
+ typeProvider.listType.instantiate([typeProvider.intType]));
+ }
+
+ void test_genericMethod_functionExpressionInvocation_explicit() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+ var lambdaCall = (/*<E>*/(/*=E*/ e) => e)/*<int>*/(3);
+ var methodCall = (c.f)/*<int>*/(3);
+ var staticCall = (C.g)/*<int>*/(3);
+ var staticFieldCall = (C.h)/*<int>*/(3);
+ var topFunCall = (topF)/*<int>*/(3);
+ var topFieldCall = (topG)/*<int>*/(3);
+ var localCall = (lf)/*<int>*/(3);
+ var paramCall = (pf)/*<int>*/(3);
+}
+''');
+ expectIdentifierType('methodCall', "int");
+ expectIdentifierType('staticCall', "int");
+ expectIdentifierType('staticFieldCall', "int");
+ expectIdentifierType('topFunCall', "int");
+ expectIdentifierType('topFieldCall', "int");
+ expectIdentifierType('localCall', "int");
+ expectIdentifierType('paramCall', "int");
+ expectIdentifierType('lambdaCall', "int");
+ }
+
+ void test_genericMethod_functionExpressionInvocation_inferred() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+ var lambdaCall = (/*<E>*/(/*=E*/ e) => e)(3);
+ var methodCall = (c.f)(3);
+ var staticCall = (C.g)(3);
+ var staticFieldCall = (C.h)(3);
+ var topFunCall = (topF)(3);
+ var topFieldCall = (topG)(3);
+ var localCall = (lf)(3);
+ var paramCall = (pf)(3);
+}
+''');
+ expectIdentifierType('methodCall', "int");
+ expectIdentifierType('staticCall', "int");
+ expectIdentifierType('staticFieldCall', "int");
+ expectIdentifierType('topFunCall', "int");
+ expectIdentifierType('topFieldCall', "int");
+ expectIdentifierType('localCall', "int");
+ expectIdentifierType('paramCall', "int");
+ expectIdentifierType('lambdaCall', "int");
+ }
+
+ void test_genericMethod_functionInvocation_explicit() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+ var methodCall = c.f/*<int>*/(3);
+ var staticCall = C.g/*<int>*/(3);
+ var staticFieldCall = C.h/*<int>*/(3);
+ var topFunCall = topF/*<int>*/(3);
+ var topFieldCall = topG/*<int>*/(3);
+ var localCall = lf/*<int>*/(3);
+ var paramCall = pf/*<int>*/(3);
+}
+''');
+ expectIdentifierType('methodCall', "int");
+ expectIdentifierType('staticCall', "int");
+ expectIdentifierType('staticFieldCall', "int");
+ expectIdentifierType('topFunCall', "int");
+ expectIdentifierType('topFieldCall', "int");
+ expectIdentifierType('localCall', "int");
+ expectIdentifierType('paramCall', "int");
+ }
+
+ void test_genericMethod_functionInvocation_inferred() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+ var methodCall = c.f(3);
+ var staticCall = C.g(3);
+ var staticFieldCall = C.h(3);
+ var topFunCall = topF(3);
+ var topFieldCall = topG(3);
+ var localCall = lf(3);
+ var paramCall = pf(3);
+}
+''');
+ expectIdentifierType('methodCall', "int");
+ expectIdentifierType('staticCall', "int");
+ expectIdentifierType('staticFieldCall', "int");
+ expectIdentifierType('topFunCall', "int");
+ expectIdentifierType('topFieldCall', "int");
+ expectIdentifierType('localCall', "int");
+ expectIdentifierType('paramCall', "int");
+ }
+
+ void test_genericMethod_functionTypedParameter() {
+ resolveTestUnit(r'''
+class C<E> {
+ List/*<T>*/ f/*<T>*/(/*=T*/ f(E e)) => null;
+}
+main() {
+ C<String> cOfString;
+}
+''');
+ expectFunctionType('f', '<T>((E) → T) → List<T>',
+ elementTypeParams: '[T]',
+ typeParams: '[E]',
+ typeArgs: '[E]',
+ typeFormals: '[T]');
+
+ SimpleIdentifier c = findIdentifier('cOfString');
+ FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
+ expect(ft.toString(), '<T>((String) → T) → List<T>');
+ ft = ft.instantiate([typeProvider.intType]);
+ expect(ft.toString(), '((String) → int) → List<int>');
+ }
+
+ void test_genericMethod_implicitDynamic() {
+ // Regression test for:
+ // https://github.com/dart-lang/sdk/issues/25100#issuecomment-162047588
+ // These should not cause any hints or warnings.
+ resolveTestUnit(r'''
+class List<E> {
+ /*=T*/ map/*<T>*/(/*=T*/ f(E e)) => null;
+}
+void foo() {
+ List list = null;
+ list.map((e) => e);
+ list.map((e) => 3);
+}''');
+ expectIdentifierType('map((e) => e);', '<T>((dynamic) → T) → T', isNull);
+ expectIdentifierType('map((e) => 3);', '<T>((dynamic) → T) → T', isNull);
+
+ MethodInvocation m1 = findIdentifier('map((e) => e);').parent;
+ expect(m1.staticInvokeType.toString(), '((dynamic) → dynamic) → dynamic');
+ MethodInvocation m2 = findIdentifier('map((e) => 3);').parent;
+ expect(m2.staticInvokeType.toString(), '((dynamic) → int) → int');
+ }
+
+ void test_genericMethod_max_doubleDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2.0);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'double', isNull);
+ }
+
+ void test_genericMethod_max_doubleDouble_prefixed() {
+ String code = r'''
+import 'dart:math' as math;
+main() {
+ var foo = math.max(1.0, 2.0);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'double', isNull);
+ }
+
+ void test_genericMethod_max_doubleInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'num', isNull);
+ }
+
+ void test_genericMethod_max_intDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2.0);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'num', isNull);
+ }
+
+ void test_genericMethod_max_intInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'int', isNull);
+ }
+
+ void test_genericMethod_nestedBound() {
+ String code = r'''
+class Foo<T extends num> {
+ void method/*<U extends T>*/(dynamic/*=U*/ u) {
+ u.abs();
+ }
+}
+''';
+ // Just validate that there is no warning on the call to `.abs()`.
+ resolveTestUnit(code);
+ }
+
+ void test_genericMethod_nestedCapture() {
+ resolveTestUnit(r'''
+class C<T> {
+ /*=T*/ f/*<S>*/(/*=S*/ x) {
+ new C<S>().f/*<int>*/(3);
+ new C<S>().f; // tear-off
+ return null;
+ }
+}
+''');
+ MethodInvocation f = findIdentifier('f/*<int>*/(3);').parent;
+ expect(f.staticInvokeType.toString(), '(int) → S');
+ FunctionType ft = f.staticInvokeType;
+ expect('${ft.typeArguments}/${ft.typeParameters}', '[S, int]/[T, S]');
+
+ expectIdentifierType('f;', '<S₀>(S₀) → S');
+ }
+
+ void test_genericMethod_nestedFunctions() {
+ resolveTestUnit(r'''
+/*=S*/ f/*<S>*/(/*=S*/ x) {
+ g/*<S>*/(/*=S*/ x) => f;
+ return null;
+}
+''');
+ expectIdentifierType('f', '<S>(S) → S');
+ expectIdentifierType('g', '<S>(S) → dynamic');
+ }
+
+ void test_genericMethod_override() {
+ resolveTestUnit(r'''
+class C {
+ /*=T*/ f/*<T>*/(/*=T*/ x) => null;
+}
+class D extends C {
+ /*=T*/ f/*<T>*/(/*=T*/ x) => null; // from D
+}
+''');
+ expectFunctionType('f/*<T>*/(/*=T*/ x) => null; // from D', '<T>(T) → T',
+ elementTypeParams: '[T]', typeFormals: '[T]');
+ SimpleIdentifier f =
+ findIdentifier('f/*<T>*/(/*=T*/ x) => null; // from D');
+ MethodElementImpl e = f.staticElement;
+ FunctionType ft = e.type.instantiate([typeProvider.stringType]);
+ expect(ft.toString(), '(String) → String');
+ }
+
+ void test_genericMethod_override_bounds() {
+ resolveTestUnit(r'''
+class A {}
+class B extends A {}
+class C {
+ /*=T*/ f/*<T extends B>*/(/*=T*/ x) => null;
+}
+class D extends C {
+ /*=T*/ f/*<T extends A>*/(/*=T*/ x) => null;
+}
+''');
+ }
+
+ void test_genericMethod_override_invalidReturnType() {
+ Source source = addSource(r'''
+class C {
+ Iterable/*<T>*/ f/*<T>*/(/*=T*/ x) => null;
+}
+class D extends C {
+ String f/*<S>*/(/*=S*/ x) => null;
+}''');
+ // TODO(jmesserly): we can't use assertErrors because STRONG_MODE_* errors
+ // from CodeChecker don't have working equality.
+ List<AnalysisError> errors = analysisContext2.computeErrors(source);
+
+ // Sort errors by name.
+ errors.sort((AnalysisError e1, AnalysisError e2) =>
+ e1.errorCode.name.compareTo(e2.errorCode.name));
+
+ expect(errors.map((e) => e.errorCode.name), [
+ 'INVALID_METHOD_OVERRIDE_RETURN_TYPE',
+ 'STRONG_MODE_INVALID_METHOD_OVERRIDE'
+ ]);
+ expect(errors[0].message, contains('Iterable<S>'),
+ reason: 'errors should be in terms of the type parameters '
+ 'at the error location');
+ verify([source]);
+ }
+
+ void test_genericMethod_override_invalidTypeParamBounds() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {}
+class C {
+ /*=T*/ f/*<T extends A>*/(/*=T*/ x) => null;
+}
+class D extends C {
+ /*=T*/ f/*<T extends B>*/(/*=T*/ x) => null;
+}''');
+ // TODO(jmesserly): this is modified code from assertErrors, which we can't
+ // use directly because STRONG_MODE_* errors don't have working equality.
+ List<AnalysisError> errors = analysisContext2.computeErrors(source);
+ List errorNames = errors.map((e) => e.errorCode.name).toList();
+ expect(errorNames, hasLength(2));
+ expect(errorNames, contains('STRONG_MODE_INVALID_METHOD_OVERRIDE'));
+ expect(
+ errorNames, contains('INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND'));
+ verify([source]);
+ }
+
+ void test_genericMethod_override_invalidTypeParamCount() {
+ Source source = addSource(r'''
+class C {
+ /*=T*/ f/*<T>*/(/*=T*/ x) => null;
+}
+class D extends C {
+ /*=S*/ f/*<T, S>*/(/*=T*/ x) => null;
+}''');
+ // TODO(jmesserly): we can't use assertErrors because STRONG_MODE_* errors
+ // from CodeChecker don't have working equality.
+ List<AnalysisError> errors = analysisContext2.computeErrors(source);
+ expect(errors.map((e) => e.errorCode.name), [
+ 'STRONG_MODE_INVALID_METHOD_OVERRIDE',
+ 'INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS'
+ ]);
+ verify([source]);
+ }
+
+ void test_genericMethod_propagatedType_promotion() {
+ // Regression test for:
+ // https://github.com/dart-lang/sdk/issues/25340
+
+ // Note, after https://github.com/dart-lang/sdk/issues/25486 the original
+ // example won't work, as we now compute a static type and therefore discard
+ // the propagated type. So a new test was created that doesn't run under
+ // strong mode.
+ resolveTestUnit(r'''
+abstract class Iter {
+ List/*<S>*/ map/*<S>*/(/*=S*/ f(x));
+}
+class C {}
+C toSpan(dynamic element) {
+ if (element is Iter) {
+ var y = element.map(toSpan);
+ }
+ return null;
+}''');
+ expectIdentifierType('y = ', 'List<C>', isNull);
+ }
+
+ void test_genericMethod_tearoff() {
+ resolveTestUnit(r'''
+class C<E> {
+ /*=T*/ f/*<T>*/(E e) => null;
+ static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+ static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+ var c = new C<int>();
+ /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+ var methodTearOff = c.f;
+ var staticTearOff = C.g;
+ var staticFieldTearOff = C.h;
+ var topFunTearOff = topF;
+ var topFieldTearOff = topG;
+ var localTearOff = lf;
+ var paramTearOff = pf;
+}
+''');
+ expectIdentifierType('methodTearOff', "<T>(int) → T");
+ expectIdentifierType('staticTearOff', "<T>(T) → T");
+ expectIdentifierType('staticFieldTearOff', "<T>(T) → T");
+ expectIdentifierType('topFunTearOff', "<T>(T) → T");
+ expectIdentifierType('topFieldTearOff', "<T>(T) → T");
+ expectIdentifierType('localTearOff', "<T>(T) → T");
+ expectIdentifierType('paramTearOff', "<T>(T) → T");
+ }
+
+ void test_genericMethod_then() {
+ String code = r'''
+import 'dart:async';
+String toString(int x) => x.toString();
+main() {
+ Future<int> bar = null;
+ var foo = bar.then(toString);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'Future<String>', isNull);
+ }
+
+ void test_genericMethod_then_prefixed() {
+ String code = r'''
+import 'dart:async' as async;
+String toString(int x) => x.toString();
+main() {
+ async.Future<int> bar = null;
+ var foo = bar.then(toString);
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'Future<String>', isNull);
+ }
+
+ void test_genericMethod_then_propagatedType() {
+ // Regression test for https://github.com/dart-lang/sdk/issues/25482.
+ String code = r'''
+import 'dart:async';
+void main() {
+ Future<String> p;
+ var foo = p.then((r) => new Future<String>.value(3));
+}
+''';
+ // This should produce no hints or warnings.
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'Future<String>', isNull);
+ }
+
+ void test_implicitBounds() {
+ String code = r'''
+class A<T> {}
+
+class B<T extends num> {}
+
+class C<S extends int, T extends B<S>, U extends B> {}
+
+void test() {
+//
+ A ai;
+ B bi;
+ C ci;
+ var aa = new A();
+ var bb = new B();
+ var cc = new C();
+}
+''';
+ resolveTestUnit(code);
+ expectIdentifierType('ai', "A<dynamic>");
+ expectIdentifierType('bi', "B<num>");
+ expectIdentifierType('ci', "C<int, B<int>, B<num>>");
+ expectIdentifierType('aa', "A<dynamic>");
+ expectIdentifierType('bb', "B<num>");
+ expectIdentifierType('cc', "C<int, B<int>, B<num>>");
+ }
+
+ void test_setterWithDynamicTypeIsError() {
+ Source source = addSource(r'''
+class A {
+ dynamic set f(String s) => null;
+}
+dynamic set g(int x) => null;
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ StaticWarningCode.NON_VOID_RETURN_FOR_SETTER,
+ StaticWarningCode.NON_VOID_RETURN_FOR_SETTER
+ ]);
+ verify([source]);
+ }
+
+ void test_setterWithExplicitVoidType_returningVoid() {
+ Source source = addSource(r'''
+void returnsVoid() {}
+class A {
+ void set f(String s) => returnsVoid();
+}
+void set g(int x) => returnsVoid();
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_setterWithNoVoidType() {
+ Source source = addSource(r'''
+class A {
+ set f(String s) {
+ return '42';
+ }
+}
+set g(int x) => 42;
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
+ StaticTypeWarningCode.RETURN_OF_INVALID_TYPE
+ ]);
+ verify([source]);
+ }
+
+ void test_setterWithNoVoidType_returningVoid() {
+ Source source = addSource(r'''
+void returnsVoid() {}
+class A {
+ set f(String s) => returnsVoid();
+}
+set g(int x) => returnsVoid();
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_setterWithOtherTypeIsError() {
+ Source source = addSource(r'''
+class A {
+ String set f(String s) => null;
+}
+Object set g(x) => null;
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ StaticWarningCode.NON_VOID_RETURN_FOR_SETTER,
+ StaticWarningCode.NON_VOID_RETURN_FOR_SETTER
+ ]);
+ verify([source]);
+ }
+
+ void test_ternaryOperator_null_left() {
+ String code = r'''
+main() {
+ var foo = (true) ? null : 3;
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'int', isNull);
+ }
+
+ void test_ternaryOperator_null_right() {
+ String code = r'''
+main() {
+ var foo = (true) ? 3 : null;
+}
+''';
+ resolveTestUnit(code);
+ expectInitializerType('foo', 'int', isNull);
+ }
+}
+
+@reflectiveTest
+class StrongModeTypePropagationTest extends ResolverTestCase {
+ @override
+ void setUp() {
+ super.setUp();
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ }
+
+ void test_foreachInference_dynamic_disabled() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ for (dynamic v in list) {
+ v; // marker
+ }
+}''';
+ assertPropagatedIterationType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_foreachInference_reusedVar_disabled() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ var v;
+ for (v in list) {
+ v; // marker
+ }
+}''';
+ assertPropagatedIterationType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_foreachInference_var() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ for (var v in list) {
+ v; // marker
+ }
+}''';
+ assertPropagatedIterationType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_foreachInference_var_iterable() {
+ String code = r'''
+main() {
+ Iterable<int> list = <int>[];
+ for (var v in list) {
+ v; // marker
+ }
+}''';
+ assertPropagatedIterationType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_foreachInference_var_stream() {
+ String code = r'''
+import 'dart:async';
+main() async {
+ Stream<int> stream = null;
+ await for (var v in stream) {
+ v; // marker
+ }
+}''';
+ assertPropagatedIterationType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_bottom_disabled() {
+ String code = r'''
+main() {
+ var v = null;
+ v; // marker
+}''';
+ assertPropagatedAssignedType(code, typeProvider.dynamicType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.dynamicType, null);
+ }
+
+ void test_localVariableInference_constant() {
+ String code = r'''
+main() {
+ var v = 3;
+ v; // marker
+}''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_declaredType_disabled() {
+ String code = r'''
+main() {
+ dynamic v = 3;
+ v; // marker
+}''';
+ assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_localVariableInference_noInitializer_disabled() {
+ String code = r'''
+main() {
+ var v;
+ v = 3;
+ v; // marker
+}''';
+ assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_localVariableInference_transitive_field_inferred_lexical() {
+ String code = r'''
+class A {
+ final x = 3;
+ f() {
+ var v = x;
+ return v; // marker
+ }
+}
+main() {
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_inferred_reversed() {
+ String code = r'''
+class A {
+ f() {
+ var v = x;
+ return v; // marker
+ }
+ final x = 3;
+}
+main() {
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_lexical() {
+ String code = r'''
+class A {
+ int x = 3;
+ f() {
+ var v = x;
+ return v; // marker
+ }
+}
+main() {
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_reversed() {
+ String code = r'''
+class A {
+ f() {
+ var v = x;
+ return v; // marker
+ }
+ int x = 3;
+}
+main() {
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_list_local() {
+ String code = r'''
+main() {
+ var x = <int>[3];
+ var v = x[0];
+ v; // marker
+}''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_local() {
+ String code = r'''
+main() {
+ var x = 3;
+ var v = x;
+ v; // marker
+}''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_inferred_lexical() {
+ String code = r'''
+final x = 3;
+main() {
+ var v = x;
+ v; // marker
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_inferred_reversed() {
+ String code = r'''
+main() {
+ var v = x;
+ v; // marker
+}
+final x = 3;
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_lexical() {
+ String code = r'''
+int x = 3;
+main() {
+ var v = x;
+ v; // marker
+}
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_reversed() {
+ String code = r'''
+main() {
+ var v = x;
+ v; // marker
+}
+int x = 3;
+''';
+ assertPropagatedAssignedType(code, typeProvider.intType, null);
+ assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698