diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index c63a5d5d411a..0a197f57d261 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -9613,12 +9613,13 @@ class PartialResolverVisitor extends ResolverVisitor { final bool strongMode; /** - * The static variables that have an initializer. These are the variables that - * need to be re-resolved after static variables have their types inferred. A - * subset of these variables are those whose types should be inferred. The - * list will be empty unless the resolver is being run in strong mode. + * The static variables and fields that have an initializer. These are the + * variables that need to be re-resolved after static variables have their + * types inferred. A subset of these variables are those whose types should + * be inferred. The list will be empty unless the resolver is being run in + * strong mode. */ - final List staticVariables = []; + final List variablesAndFields = []; /** * A flag indicating whether we should discard errors while resolving the @@ -9671,8 +9672,8 @@ class PartialResolverVisitor extends ResolverVisitor { @override Object visitFieldDeclaration(FieldDeclaration node) { - if (strongMode && node.isStatic) { - _addStaticVariables(node.fields.variables); + if (strongMode) { + _addVariables(node.fields.variables); bool wasDiscarding = discardErrorsInInitializer; discardErrorsInInitializer = true; try { @@ -9699,7 +9700,7 @@ class PartialResolverVisitor extends ResolverVisitor { @override Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { if (strongMode) { - _addStaticVariables(node.variables.variables); + _addVariables(node.variables.variables); bool wasDiscarding = discardErrorsInInitializer; discardErrorsInInitializer = true; try { @@ -9718,10 +9719,10 @@ class PartialResolverVisitor extends ResolverVisitor { * potentially need to be re-resolved after inference because they might * refer to a field whose type was inferred. */ - void _addStaticVariables(NodeList variables) { + void _addVariables(NodeList variables) { for (VariableDeclaration variable in variables) { if (variable.initializer != null) { - staticVariables.add(variable.element); + variablesAndFields.add(variable.element); } } } diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart index a21d94b70519..8ce90847ed50 100644 --- a/pkg/analyzer/lib/src/task/dart.dart +++ b/pkg/analyzer/lib/src/task/dart.dart @@ -2667,35 +2667,32 @@ class InferStaticVariableTypeTask extends InferStaticVariableTask { // have types inferred before inferring the type of this variable. // VariableElementImpl variable = target; + CompilationUnit unit = getRequiredInput(UNIT_INPUT); TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); RecordingErrorListener errorListener = new RecordingErrorListener(); - if (dependencyCycle == null) { - // - // Re-resolve the variable's initializer so that the inferred types of other - // variables will be propagated. - // - NodeLocator locator = new NodeLocator(variable.nameOffset); - AstNode node = locator.searchWithin(unit); - VariableDeclaration declaration = node - .getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); - if (declaration == null || declaration.name != node) { - throw new AnalysisException( - "NodeLocator failed to find a variable's declaration"); - } - Expression initializer = declaration.initializer; - ResolutionEraser.erase(initializer, eraseDeclarations: false); - ResolutionContext resolutionContext = - ResolutionContextBuilder.contextFor(initializer, errorListener); - ResolverVisitor visitor = new ResolverVisitor( - variable.library, variable.source, typeProvider, errorListener, - nameScope: resolutionContext.scope); - if (resolutionContext.enclosingClassDeclaration != null) { - visitor.prepareToResolveMembersInClass( - resolutionContext.enclosingClassDeclaration); - } - visitor.initForIncrementalResolution(); - initializer.accept(visitor); + VariableDeclaration declaration = getDeclaration(unit); + // + // Re-resolve the variable's initializer so that the inferred types of other + // variables will be propagated. + // + Expression initializer = declaration.initializer; + ResolutionEraser.erase(initializer, eraseDeclarations: false); + ResolutionContext resolutionContext = + ResolutionContextBuilder.contextFor(initializer, errorListener); + ResolverVisitor visitor = new ResolverVisitor( + variable.library, variable.source, typeProvider, errorListener, + nameScope: resolutionContext.scope); + if (resolutionContext.enclosingClassDeclaration != null) { + visitor.prepareToResolveMembersInClass( + resolutionContext.enclosingClassDeclaration); + } + visitor.initForIncrementalResolution(); + initializer.accept(visitor); + + // If we're not in a dependency cycle, and we have no type annotation, + // do inference. + if (dependencyCycle == null && variable.hasImplicitType) { // // Record the type of the variable. // @@ -3159,7 +3156,7 @@ class PartiallyResolveUnitReferencesTask extends SourceBasedAnalysisTask { // // Record outputs. // - outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.staticVariables; + outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.variablesAndFields; outputs[PARTIALLY_RESOLVE_REFERENCES_ERRORS] = removeDuplicateErrors(errorListener.errors); outputs[RESOLVED_UNIT5] = unit; diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart index 366703821dc4..51a86fb9b306 100644 --- a/pkg/analyzer/test/src/task/dart_test.dart +++ b/pkg/analyzer/test/src/task/dart_test.dart @@ -60,6 +60,7 @@ main() { runReflectiveTests(ResolveUnitTypeNamesTaskTest); runReflectiveTests(ResolveVariableReferencesTaskTest); runReflectiveTests(ScanDartTaskTest); + runReflectiveTests(StrongModeInferenceTest); runReflectiveTests(VerifyUnitTaskTest); } @@ -1906,6 +1907,68 @@ class Z {} expect(method.element.returnType, typeY); expect(method.element.parameters[0].type, typeZ); } + + void test_perform_cross_library_const() { + enableStrongMode(); + AnalysisTarget firstSource = newSource( + '/first.dart', + ''' +library first; + +const a = 'hello'; +'''); + AnalysisTarget secondSource = newSource( + '/second.dart', + ''' +import 'first.dart'; + +const b = a; +class M { + String c = a; +} +'''); + computeResult( + new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT7, + matcher: isInferInstanceMembersInUnitTask); + CompilationUnit firstUnit = outputs[RESOLVED_UNIT7]; + computeResult( + new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT7); + CompilationUnit secondUnit = outputs[RESOLVED_UNIT7]; + + VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a'); + VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b'); + VariableDeclaration variableC = getFieldInClass(secondUnit, 'M', 'c'); + InterfaceType stringType = context.typeProvider.stringType; + + expect(variableA.element.type, stringType); + expect(variableB.element.type, stringType); + expect(variableB.initializer.staticType, stringType); + expect(variableC.element.type, stringType); + expect(variableC.initializer.staticType, stringType); + } + + void test_perform_reresolution() { + enableStrongMode(); + AnalysisTarget source = newSource( + '/test.dart', + ''' +const topLevel = ''; +class C { + String field = topLevel; +} +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7); + CompilationUnit unit = outputs[RESOLVED_UNIT7]; + VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel'); + VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field'); + VariableElement topLevel = topLevelDecl.name.staticElement; + VariableElement field = fieldDecl.name.staticElement; + + InterfaceType stringType = context.typeProvider.stringType; + expect(topLevel.type, stringType); + expect(field.type, stringType); + expect(fieldDecl.initializer.staticType, stringType); + } } @reflectiveTest @@ -1987,6 +2050,23 @@ var Y = () { InterfaceType intType = context.typeProvider.intType; expect(expression.staticType, intType); } + + void test_perform_const_field() { + enableStrongMode(); + AnalysisTarget source = newSource( + '/test.dart', + ''' +class M { + static const X = ""; +} +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6, + matcher: isInferStaticVariableTypesInUnitTask); + CompilationUnit unit = outputs[RESOLVED_UNIT6]; + VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X'); + InterfaceType stringType = context.typeProvider.stringType; + expect(declaration.element.type, stringType); + } } @reflectiveTest @@ -2024,10 +2104,60 @@ var topLevel = ''; } void test_perform() { + AnalysisTarget source = newSource( + '/test3.dart', + ''' +var topLevel3 = ''; +class C { + var field3 = topLevel3; +} +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); + CompilationUnit unit = outputs[RESOLVED_UNIT5]; + VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel3'); + VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field3'); + VariableElement topLevel = topLevelDecl.name.staticElement; + VariableElement field = fieldDecl.name.staticElement; + + computeResult(field, INFERRED_STATIC_VARIABLE, + matcher: isInferStaticVariableTypeTask); + InterfaceType stringType = context.typeProvider.stringType; + expect(topLevel.type, stringType); + expect(field.type, stringType); + expect(fieldDecl.initializer.staticType, stringType); + expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0)); + } + + void test_perform_reresolution() { AnalysisTarget source = newSource( '/test.dart', ''' -var topLevel = ''; +const topLevel = ''; +class C { + String field = topLevel; +} +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); + CompilationUnit unit = outputs[RESOLVED_UNIT5]; + VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel'); + VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field'); + VariableElement topLevel = topLevelDecl.name.staticElement; + VariableElement field = fieldDecl.name.staticElement; + + computeResult(field, INFERRED_STATIC_VARIABLE, + matcher: isInferStaticVariableTypeTask); + InterfaceType stringType = context.typeProvider.stringType; + expect(topLevel.type, stringType); + expect(field.type, stringType); + expect(fieldDecl.initializer.staticType, stringType); + expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0)); + } + + void test_perform_const() { + AnalysisTarget source = newSource( + '/test.dart', + ''' +const topLevel = "hello"; class C { var field = topLevel; } @@ -2307,7 +2437,7 @@ class C { computeResult(target, RESOLVED_UNIT5, matcher: isPartiallyResolveUnitReferencesTask); // Test the outputs - expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(4)); + expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(5)); CompilationUnit unit = outputs[RESOLVED_UNIT5]; expect(unit, same(outputs[RESOLVED_UNIT5])); // Test the state of the AST @@ -2463,6 +2593,472 @@ class C { } } +@reflectiveTest +class StrongModeInferenceTest extends _AbstractDartTaskTest { + + @override + void setUp() { + super.setUp(); + enableStrongMode(); + } + + // Check that even within a static variable cycle, inferred + // types get propagated to the members of the cycle. + void test_perform_cycle() { + AnalysisTarget source = newSource( + '/test.dart', + ''' +var piFirst = true; +var pi = piFirst ? 3.14 : tau / 2; +var tau = piFirst ? pi * 2 : 6.28; +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + VariableElement piFirst = + getTopLevelVariable(unit, 'piFirst').name.staticElement; + VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement; + VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement; + Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer + as ConditionalExpression).condition; + + expect(piFirstUse.staticType, context.typeProvider.boolType); + expect(piFirst.type, context.typeProvider.boolType); + expect(pi.type.isDynamic, isTrue); + expect(tau.type.isDynamic, isTrue); + } + + void test_perform_local_explicit_disabled() { + AnalysisTarget source = newSource( + '/test.dart', + ''' + test() { + int x = 3; + x = "hi"; + } +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + + List statements = getStatementsInTopLevelFunction(unit, "test"); + VariableDeclaration decl = + (statements[0] as VariableDeclarationStatement).variables.variables[0]; + expect(decl.element.type, intType); + expect(decl.initializer.staticType, intType); + + ExpressionStatement statement = statements[1]; + AssignmentExpression assgn = statement.expression; + expect(assgn.leftHandSide.staticType, intType); + expect(assgn.rightHandSide.staticType, stringType); + } + + void assertVariableDeclarationTypes( + VariableDeclaration decl, DartType varType, DartType initializerType) { + expect(decl.element.type, varType); + expect(decl.initializer.staticType, initializerType); + } + + void assertVariableDeclarationStatementTypes( + Statement stmt, DartType varType, DartType initializerType) { + VariableDeclaration decl = + (stmt as VariableDeclarationStatement).variables.variables[0]; + assertVariableDeclarationTypes(decl, varType, initializerType); + } + + void assertAssignmentStatementTypes( + Statement stmt, DartType leftType, DartType rightType) { + AssignmentExpression assgn = (stmt as ExpressionStatement).expression; + expect(assgn.leftHandSide.staticType, leftType); + expect(assgn.rightHandSide.staticType, rightType); + } + + // Test that local variables in method bodies are inferred appropriately + void test_perform_inference_local_variables() { + AnalysisTarget source = newSource( + '/test.dart', + ''' + test() { + int x = 3; + x = "hi"; + var y = 3; + y = "hi"; + } +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + + List statements = getStatementsInTopLevelFunction(unit, "test"); + + assertVariableDeclarationStatementTypes(statements[0], intType, intType); + assertAssignmentStatementTypes(statements[1], intType, stringType); + assertVariableDeclarationStatementTypes(statements[2], intType, intType); + assertAssignmentStatementTypes(statements[3], intType, stringType); + } + + // Test inference interactions between local variables and fields + void test_perform_inference_local_variables_fields() { + AnalysisTarget source = newSource( + '/test.dart', + ''' + class A { + int x = 0; + + test1() { + var a = x; + a = "hi"; + a = 3; + var b = y; + b = "hi"; + b = 4; + var c = z; + c = "hi"; + c = 4; + } + + int y; // field def after use + final z = 42; // should infer `int` + } +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + + List statements = getStatementsInMethod(unit, "A", "test1"); + + assertVariableDeclarationStatementTypes(statements[0], intType, intType); + assertAssignmentStatementTypes(statements[1], intType, stringType); + assertAssignmentStatementTypes(statements[2], intType, intType); + + assertVariableDeclarationStatementTypes(statements[3], intType, intType); + assertAssignmentStatementTypes(statements[4], intType, stringType); + assertAssignmentStatementTypes(statements[5], intType, intType); + + assertVariableDeclarationStatementTypes(statements[6], intType, intType); + assertAssignmentStatementTypes(statements[7], intType, stringType); + assertAssignmentStatementTypes(statements[8], intType, intType); + + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "x"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "z"), intType, intType); + } + + // Test inference interactions between local variables and top level + // variables + void test_perform_inference_local_variables_topLevel() { + AnalysisTarget source = newSource( + '/test.dart', + ''' + int x = 0; + + test1() { + var a = x; + a = /*severe:StaticTypeError*/"hi"; + a = 3; + var b = y; + b = /*severe:StaticTypeError*/"hi"; + b = 4; + var c = z; + c = /*severe:StaticTypeError*/"hi"; + c = 4; + } + + int y = 0; // field def after use + final z = 42; // should infer `int` +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + + List statements = getStatementsInTopLevelFunction(unit, "test1"); + + assertVariableDeclarationStatementTypes(statements[0], intType, intType); + assertAssignmentStatementTypes(statements[1], intType, stringType); + assertAssignmentStatementTypes(statements[2], intType, intType); + + assertVariableDeclarationStatementTypes(statements[3], intType, intType); + assertAssignmentStatementTypes(statements[4], intType, stringType); + assertAssignmentStatementTypes(statements[5], intType, intType); + + assertVariableDeclarationStatementTypes(statements[6], intType, intType); + assertAssignmentStatementTypes(statements[7], intType, stringType); + assertAssignmentStatementTypes(statements[8], intType, intType); + + assertVariableDeclarationTypes( + getTopLevelVariable(unit, "x"), intType, intType); + assertVariableDeclarationTypes( + getTopLevelVariable(unit, "y"), intType, intType); + assertVariableDeclarationTypes( + getTopLevelVariable(unit, "z"), intType, intType); + } + + // Test that inference does not propagate from null + void test_perform_inference_null() { + AnalysisTarget source = newSource( + '/test.dart', + ''' + var x = null; + var y = 3; + class A { + static var x = null; + static var y = 3; + + var x2 = null; + var y2 = 3; + } + + test() { + x = "hi"; + y = /*severe:StaticTypeError*/"hi"; + A.x = "hi"; + A.y = /*severe:StaticTypeError*/"hi"; + new A().x2 = "hi"; + new A().y2 = /*severe:StaticTypeError*/"hi"; + } +'''); + computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); + CompilationUnit unit = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + DartType bottomType = context.typeProvider.bottomType; + DartType dynamicType = context.typeProvider.dynamicType; + + assertVariableDeclarationTypes( + getTopLevelVariable(unit, "x"), dynamicType, bottomType); + assertVariableDeclarationTypes( + getTopLevelVariable(unit, "y"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "x"), dynamicType, bottomType); + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "y"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "x2"), dynamicType, bottomType); + assertVariableDeclarationTypes( + getFieldInClass(unit, "A", "y2"), intType, intType); + + List statements = getStatementsInTopLevelFunction(unit, "test"); + + assertAssignmentStatementTypes(statements[0], dynamicType, stringType); + assertAssignmentStatementTypes(statements[1], intType, stringType); + assertAssignmentStatementTypes(statements[2], dynamicType, stringType); + assertAssignmentStatementTypes(statements[3], intType, stringType); + assertAssignmentStatementTypes(statements[4], dynamicType, stringType); + assertAssignmentStatementTypes(statements[5], intType, stringType); + } + + // Test inference across units (non-cyclic) + void test_perform_inference_cross_unit_non_cyclic() { + AnalysisTarget firstSource = newSource( + '/a.dart', + ''' + var x = 2; + class A { static var x = 2; } +'''); + AnalysisTarget secondSource = newSource( + '/test.dart', + ''' + import 'a.dart'; + var y = x; + class B { static var y = A.x; } + + test1() { + x = /*severe:StaticTypeError*/"hi"; + y = /*severe:StaticTypeError*/"hi"; + A.x = /*severe:StaticTypeError*/"hi"; + B.y = /*severe:StaticTypeError*/"hi"; + } +'''); + computeResult( + new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8); + CompilationUnit unit1 = outputs[RESOLVED_UNIT8]; + computeResult( + new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8); + CompilationUnit unit2 = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + DartType dynamicType = context.typeProvider.dynamicType; + + assertVariableDeclarationTypes( + getTopLevelVariable(unit1, "x"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit1, "A", "x"), intType, intType); + + assertVariableDeclarationTypes( + getTopLevelVariable(unit2, "y"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit2, "B", "y"), intType, intType); + + List statements = + getStatementsInTopLevelFunction(unit2, "test1"); + + assertAssignmentStatementTypes(statements[0], intType, stringType); + assertAssignmentStatementTypes(statements[1], intType, stringType); + } + + // Test inference across units (cyclic) + void test_perform_inference_cross_unit_cyclic() { + AnalysisTarget firstSource = newSource( + '/a.dart', + ''' + import 'test.dart'; + var x = 2; + class A { static var x = 2; } +'''); + AnalysisTarget secondSource = newSource( + '/test.dart', + ''' + import 'a.dart'; + var y = x; + class B { static var y = A.x; } + + test1() { + int t = 3; + t = x; + t = y; + t = A.x; + t = B.y; + } +'''); + computeResult( + new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8); + CompilationUnit unit1 = outputs[RESOLVED_UNIT8]; + computeResult( + new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8); + CompilationUnit unit2 = outputs[RESOLVED_UNIT8]; + + InterfaceType intType = context.typeProvider.intType; + InterfaceType stringType = context.typeProvider.stringType; + + assertVariableDeclarationTypes( + getTopLevelVariable(unit1, "x"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit1, "A", "x"), intType, intType); + + assertVariableDeclarationTypes( + getTopLevelVariable(unit2, "y"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit2, "B", "y"), intType, intType); + + List statements = + getStatementsInTopLevelFunction(unit2, "test1"); + + assertAssignmentStatementTypes(statements[1], intType, intType); + assertAssignmentStatementTypes(statements[2], intType, intType); + assertAssignmentStatementTypes(statements[3], intType, intType); + assertAssignmentStatementTypes(statements[4], intType, intType); + } + + // Test inference of instance fields across units + // TODO(leafp): Fix this + // https://github.com/dart-lang/dev_compiler/issues/354 + void fail_perform_inference_cross_unit_instance() { + List sources = newSources({ + '/a7.dart': ''' + import 'b7.dart'; + class A { + final a2 = new B().b2; + } + ''', + '/b7.dart': ''' + class B { + final b2 = 1; + } + ''', + '/main7.dart': ''' + import "a7.dart"; + + test1() { + int x = 0; + x = new A().a2; + } + ''' + }); + List units = + computeLibraryResults(sources, RESOLVED_UNIT8).toList(); + CompilationUnit unit0 = units[0]; + CompilationUnit unit1 = units[1]; + CompilationUnit unit2 = units[2]; + + InterfaceType intType = context.typeProvider.intType; + + assertVariableDeclarationTypes( + getFieldInClass(unit0, "A", "a2"), intType, intType); + + assertVariableDeclarationTypes( + getFieldInClass(unit1, "B", "b2"), intType, intType); + + List statements = + getStatementsInTopLevelFunction(unit2, "test1"); + + assertAssignmentStatementTypes(statements[1], intType, intType); + } + + // Test inference between static and instance fields + // TODO(leafp): Fix this + // https://github.com/dart-lang/dev_compiler/issues/354 + void fail_perform_inference_cross_unit_static_instance() { + List sources = newSources({ + '/a.dart': ''' + import 'b.dart'; + class A { + static final a1 = B.b1; + final a2 = new B().b2; + } + ''', + '/b.dart': ''' + class B { + static final b1 = 1; + final b2 = 1; + } + ''', + '/main.dart': ''' + import "a.dart"; + + test1() { + int x = 0; + // inference in A now works. + x = A.a1; + x = new A().a2; + } + ''' + }); + List units = + computeLibraryResults(sources, RESOLVED_UNIT8).toList(); + CompilationUnit unit0 = units[0]; + CompilationUnit unit1 = units[1]; + CompilationUnit unit2 = units[2]; + + InterfaceType intType = context.typeProvider.intType; + + assertVariableDeclarationTypes( + getFieldInClass(unit0, "A", "a1"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit0, "A", "a2"), intType, intType); + + assertVariableDeclarationTypes( + getFieldInClass(unit1, "B", "b1"), intType, intType); + assertVariableDeclarationTypes( + getFieldInClass(unit1, "B", "b2"), intType, intType); + + List statements = + getStatementsInTopLevelFunction(unit2, "test1"); + + assertAssignmentStatementTypes(statements[1], intType, intType); + assertAssignmentStatementTypes(statements[2], intType, intType); + } +} + @reflectiveTest class ResolveLibraryTypeNamesTaskTest extends _AbstractDartTaskTest { test_perform() { @@ -2791,6 +3387,23 @@ main() { errorListener.assertErrorsWithCodes( [StaticTypeWarningCode.NON_BOOL_CONDITION]); } + + void test_perform_reresolution() { + enableStrongMode(); + AnalysisTarget source = newSource( + '/test.dart', + ''' +const topLevel = 3; +class C { + String field = topLevel; +} +'''); + computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS); + // validate + _fillErrorListener(VERIFY_ERRORS); + errorListener.assertErrorsWithCodes( + [StaticTypeWarningCode.INVALID_ASSIGNMENT]); + } } class _AbstractDartTaskTest extends AbstractContextTest { @@ -2816,6 +3429,17 @@ class _AbstractDartTaskTest extends AbstractContextTest { }); } + List computeLibraryResults( + List sources, ResultDescriptor result, + {isInstanceOf matcher: null}) { + dynamic compute(Source source) { + computeResult(new LibrarySpecificUnit(source, source), result, + matcher: matcher); + return outputs[result]; + } + return sources.map(compute).toList(); + } + /** * Create a script object with a single fragment containing the given * [scriptContent]. @@ -2901,6 +3525,20 @@ class _AbstractDartTaskTest extends AbstractContextTest { return null; } + List getStatementsInMethod( + CompilationUnit unit, String className, String methodName) { + MethodDeclaration method = getMethodInClass(unit, className, methodName); + BlockFunctionBody body = method.body; + return body.block.statements; + } + + List getStatementsInTopLevelFunction( + CompilationUnit unit, String functionName) { + FunctionDeclaration function = getTopLevelFunction(unit, functionName); + BlockFunctionBody body = function.functionExpression.body; + return body.block.statements; + } + /** * Return the declaration of the top-level variable with the given * [variableName] in the given compilation [unit]. @@ -2922,6 +3560,23 @@ class _AbstractDartTaskTest extends AbstractContextTest { return null; } + /** + * Return the declaration of the top-level function with the given + * [functionName] in the given compilation [unit]. + */ + FunctionDeclaration getTopLevelFunction( + CompilationUnit unit, String functionName) { + NodeList unitMembers = unit.declarations; + for (CompilationUnitMember unitMember in unitMembers) { + if (unitMember is FunctionDeclaration) { + if (unitMember.name.name == functionName) { + return unitMember; + } + } + } + return null; + } + void setUp() { super.setUp(); emptySource = newSource('/test.dart');