diff --git a/compiler/java/com/google/dart/compiler/resolver/Resolver.java b/compiler/java/com/google/dart/compiler/resolver/Resolver.java index 0d8dfd7a62a..15737738f0e 100644 --- a/compiler/java/com/google/dart/compiler/resolver/Resolver.java +++ b/compiler/java/com/google/dart/compiler/resolver/Resolver.java @@ -678,7 +678,7 @@ public class Resolver { // Now, this constant has a type. Save it for future reference. Element element = node.getElement(); Type expressionType = expression.getType(); - if (expressionType != null && TypeKind.of(element.getType()) == TypeKind.DYNAMIC) { + if (isFinal && expressionType != null && TypeKind.of(element.getType()) == TypeKind.DYNAMIC) { Type fieldType = Types.makeInferred(expressionType); Elements.setType(element, fieldType); } diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java index 70d4b7d802a..a6f774551e6 100644 --- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java +++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java @@ -576,11 +576,12 @@ public class TypeAnalyzer implements DartCompilationPhase { * assigned value type is compatible with this propagated type. */ private void checkPropagatedTypeCompatible(DartExpression lhsNode, Type rhs) { - if (lhsNode.getElement() instanceof VariableElement) { - VariableElement variableElement = (VariableElement) lhsNode.getElement(); - Type variableType = variableElement.getType(); + Element element = lhsNode.getElement(); + if (ElementKind.of(element) == ElementKind.VARIABLE + || ElementKind.of(element) == ElementKind.FIELD) { + Type variableType = element.getType(); if (variableType.isInferred() && !types.isAssignable(variableType, rhs)) { - Elements.setType(variableElement, dynamicType); + Elements.setType(element, dynamicType); } } } @@ -2521,8 +2522,10 @@ public class TypeAnalyzer implements DartCompilationPhase { return typeOf(accessor); } else { Type result = checkInitializedDeclaration(node, node.getValue()); - // if no type declared for variables, try to use type of value - { + // if no type declared for field, try to use type of value + // only final fields, because only in this case we can be sure that field is not assigned + // somewhere, may be even not in this unit + if (node.getModifiers().isFinal()) { DartExpression value = node.getValue(); if (value != null) { Type valueType = value.getType(); diff --git a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java index 88595fa9de6..4dba9fb9396 100644 --- a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java +++ b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java @@ -2210,13 +2210,13 @@ public class TypeAnalyzerCompilerTest extends CompilerTestCase { assertInferredElementTypeString(testUnit, "v1", "String"); } - public void test_typesPropagation_field_inClass() throws Exception { + public void test_typesPropagation_field_inClass_final() throws Exception { analyzeLibrary( "// filler filler filler filler filler filler filler filler filler filler", "class A {", - " var v1 = 123;", - " var v2 = Math.random();", - " var v3 = 1 + 2.0;", + " final v1 = 123;", + " final v2 = Math.random();", + " final v3 = 1 + 2.0;", "}", ""); assertInferredElementTypeString(testUnit, "v1", "int"); @@ -2224,18 +2224,66 @@ public class TypeAnalyzerCompilerTest extends CompilerTestCase { assertInferredElementTypeString(testUnit, "v3", "double"); } - public void test_typesPropagation_field_topLevel() throws Exception { + public void test_typesPropagation_field_inClass_const() throws Exception { analyzeLibrary( "// filler filler filler filler filler filler filler filler filler filler", - "var v1 = 123;", - "var v2 = Math.random();", - "var v3 = 1 + 2.0;", + "class A {", + " const v1 = 123;", + " final v2 = 1 + 2.0;", + "}", + ""); + assertInferredElementTypeString(testUnit, "v1", "int"); + assertInferredElementTypeString(testUnit, "v2", "double"); + } + + /** + * If field is not final, we don't know if is will be assigned somewhere else, may be even not in + * there same unit, so we cannot be sure about its type. + */ + public void test_typesPropagation_field_inClass_notFinal() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "class A {", + " var v1 = 123;", + "}", + ""); + assertInferredElementTypeString(testUnit, "v1", ""); + } + + public void test_typesPropagation_field_topLevel_final() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "final v1 = 123;", + "final v2 = Math.random();", + "final v3 = 1 + 2.0;", ""); assertInferredElementTypeString(testUnit, "v1", "int"); assertInferredElementTypeString(testUnit, "v2", "double"); assertInferredElementTypeString(testUnit, "v3", "double"); } + public void test_typesPropagation_field_topLevel_const() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "const v1 = 123;", + "const v2 = 1 + 2.0;", + ""); + assertInferredElementTypeString(testUnit, "v1", "int"); + assertInferredElementTypeString(testUnit, "v2", "double"); + } + + /** + * If field is not final, we don't know if is will be assigned somewhere else, may be even not in + * there same unit, so we cannot be sure about its type. + */ + public void test_typesPropagation_field_topLevel_notFinal() throws Exception { + analyzeLibrary( + "// filler filler filler filler filler filler filler filler filler filler", + "var v1 = 123;", + ""); + assertInferredElementTypeString(testUnit, "v1", ""); + } + public void test_typesPropagation_FunctionAliasType() throws Exception { analyzeLibrary( "// filler filler filler filler filler filler filler filler filler filler",