Index: pkg/analyzer/lib/src/dart/constant/evaluation.dart |
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart |
index 57eee8973823954d54ef94305c1c0136612c826c..fcc14e114871f6141ba89614b895a02ca94c587a 100644 |
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart |
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart |
@@ -75,6 +75,9 @@ class ConstantEvaluationEngine { |
*/ |
final ConstantEvaluationValidator validator; |
+ /** Whether we are running in strong mode. */ |
+ final bool strongMode; |
+ |
/** |
* Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider] |
* is used to access known types. [_declaredVariables] is the set of |
@@ -82,9 +85,12 @@ class ConstantEvaluationEngine { |
* given, is used to verify correct dependency analysis when running unit |
* tests. |
*/ |
- ConstantEvaluationEngine(this.typeProvider, this._declaredVariables, |
+ ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables, |
{ConstantEvaluationValidator validator, TypeSystem typeSystem}) |
- : validator = |
+ : typeProvider = typeProvider, |
+ strongMode = |
+ typeProvider.objectType.element.context.analysisOptions.strongMode, |
+ validator = |
validator ?? new ConstantEvaluationValidator_ForProduction(), |
typeSystem = typeSystem ?? new TypeSystemImpl(); |
@@ -231,6 +237,7 @@ class ConstantEvaluationEngine { |
new ConstantVisitor(this, errorReporter); |
DartObjectImpl result = evaluateConstructorCall( |
constNode, |
+ [], |
constNode.arguments.arguments, |
element, |
constantVisitor, |
@@ -409,7 +416,8 @@ class ConstantEvaluationEngine { |
DartObjectImpl evaluateConstructorCall( |
AstNode node, |
- NodeList<Expression> arguments, |
+ List<DartType> typeArguments, |
+ List<Expression> arguments, |
ConstructorElement constructor, |
ConstantVisitor constantVisitor, |
ErrorReporter errorReporter) { |
@@ -515,25 +523,41 @@ class ConstantEvaluationEngine { |
// so consider it an unknown value to suppress further errors. |
return new DartObjectImpl.validWithUnknownValue(definingClass); |
} |
- HashMap<String, DartObjectImpl> fieldMap = |
- new HashMap<String, DartObjectImpl>(); |
+ var fieldMap = new HashMap<String, DartObjectImpl>(); |
+ var typeArgumentMap = new HashMap<String, DartObjectImpl>.fromIterables( |
+ (constructor.returnType as ParameterizedType) |
+ .typeParameters |
+ .map((t) => t.name), |
+ typeArguments.map((t) => |
+ new DartObjectImpl(typeProvider.typeType, new TypeState(t)))); |
+ |
+ var fieldInitVisitor = new ConstantVisitor(this, errorReporter, |
+ lexicalEnvironment: typeArgumentMap); |
// Start with final fields that are initialized at their declaration site. |
- for (FieldElement field in constructor.enclosingElement.fields) { |
+ List<FieldElement> fields = constructor.enclosingElement.fields; |
+ for (int i = 0; i < fields.length; i++) { |
+ FieldElement field = fields[i]; |
if ((field.isFinal || field.isConst) && |
!field.isStatic && |
field is ConstFieldElementImpl) { |
validator.beforeGetFieldEvaluationResult(field); |
- EvaluationResultImpl evaluationResult = field.evaluationResult; |
+ |
+ DartObjectImpl fieldValue; |
+ if (strongMode) { |
+ var fieldInit = constructorBase.fieldInitializers[i].initializer; |
+ fieldValue = fieldInit.accept(fieldInitVisitor); |
+ } else { |
+ fieldValue = field.evaluationResult?.value; |
+ } |
// It is possible that the evaluation result is null. |
// This happens for example when we have duplicate fields. |
// class Test {final x = 1; final x = 2; const Test();} |
- if (evaluationResult == null) { |
+ if (fieldValue == null) { |
continue; |
} |
// Match the value and the type. |
DartType fieldType = |
FieldMember.from(field, constructor.returnType).type; |
- DartObjectImpl fieldValue = evaluationResult.value; |
if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) { |
errorReporter.reportErrorForNode( |
CheckedModeCompileTimeErrorCode |
@@ -549,6 +573,14 @@ class ConstantEvaluationEngine { |
new HashMap<String, DartObjectImpl>(); |
List<ParameterElement> parameters = constructor.parameters; |
int parameterCount = parameters.length; |
+ |
+ HashMap<ParameterElement, DefaultFormalParameter> parameterDefaultMap; |
+ if (strongMode) { |
+ parameterDefaultMap = new HashMap.fromIterable( |
+ constructorBase.parameterInitializers, |
+ key: (p) => p.parameter.element); |
+ } |
+ |
for (int i = 0; i < parameterCount; i++) { |
ParameterElement parameter = parameters[i]; |
ParameterElement baseParameter = parameter; |
@@ -574,12 +606,22 @@ class ConstantEvaluationEngine { |
// The parameter is an optional positional parameter for which no value |
// was provided, so use the default value. |
validator.beforeGetParameterDefault(baseParameter); |
- EvaluationResultImpl evaluationResult = baseParameter.evaluationResult; |
- if (evaluationResult == null) { |
- // No default was provided, so the default value is null. |
- argumentValue = typeProvider.nullObject; |
- } else if (evaluationResult.value != null) { |
- argumentValue = evaluationResult.value; |
+ if (strongMode) { |
+ var defaultValue = parameterDefaultMap[parameter]?.defaultValue; |
+ if (defaultValue == null) { |
+ argumentValue = typeProvider.nullObject; |
+ } else { |
+ argumentValue = defaultValue.accept(fieldInitVisitor); |
+ } |
+ } else { |
+ EvaluationResultImpl evaluationResult = |
+ baseParameter.evaluationResult; |
+ if (evaluationResult == null) { |
+ // No default was provided, so the default value is null. |
+ argumentValue = typeProvider.nullObject; |
+ } else if (evaluationResult.value != null) { |
+ argumentValue = evaluationResult.value; |
+ } |
} |
} |
if (argumentValue != null) { |
@@ -661,6 +703,7 @@ class ConstantEvaluationEngine { |
if (constructor != null && constructor.isConst) { |
return evaluateConstructorCall( |
node, |
+ typeArguments, |
initializer.argumentList.arguments, |
constructor, |
initializerVisitor, |
@@ -677,8 +720,15 @@ class ConstantEvaluationEngine { |
if (superArguments == null) { |
superArguments = new NodeList<Expression>(null); |
} |
- evaluateSuperConstructorCall(node, fieldMap, superConstructor, |
- superArguments, initializerVisitor, errorReporter); |
+ |
+ evaluateSuperConstructorCall( |
+ node, |
+ fieldMap, |
+ superConstructor, |
+ superclass.typeArguments, |
+ superArguments, |
+ initializerVisitor, |
+ errorReporter); |
} |
} |
return new DartObjectImpl(definingClass, new GenericState(fieldMap)); |
@@ -688,12 +738,18 @@ class ConstantEvaluationEngine { |
AstNode node, |
HashMap<String, DartObjectImpl> fieldMap, |
ConstructorElement superConstructor, |
- NodeList<Expression> superArguments, |
+ List<DartType> superTypeArguments, |
+ List<Expression> superArguments, |
ConstantVisitor initializerVisitor, |
ErrorReporter errorReporter) { |
if (superConstructor != null && superConstructor.isConst) { |
- DartObjectImpl evaluationResult = evaluateConstructorCall(node, |
- superArguments, superConstructor, initializerVisitor, errorReporter); |
+ DartObjectImpl evaluationResult = evaluateConstructorCall( |
+ node, |
+ superTypeArguments, |
+ superArguments, |
+ superConstructor, |
+ initializerVisitor, |
+ errorReporter); |
if (evaluationResult != null) { |
fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult; |
} |
@@ -1231,8 +1287,25 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { |
// problem - the error has already been reported. |
return null; |
} |
- return evaluationEngine.evaluateConstructorCall( |
- node, node.argumentList.arguments, constructor, this, _errorReporter); |
+ |
+ var type = constructor.returnType as ParameterizedType; |
+ var typeArguments = type.typeArguments.map((t) { |
+ if (t is TypeParameterType && _lexicalEnvironment != null) { |
+ return _lexicalEnvironment[t.name]?.toTypeValue() ?? t; |
+ } |
+ return t; |
+ }).toList(); |
+ |
+ if (constructor is ConstructorMember) { |
+ constructor = (constructor as ConstructorMember).baseElement; |
+ } |
+ |
+ constructor = ConstructorMember.from( |
+ constructor, |
+ type.substitute2(typeArguments, type.typeArguments)); |
+ |
+ return evaluationEngine.evaluateConstructorCall(node, typeArguments, |
+ node.argumentList.arguments, constructor, this, _errorReporter); |
} |
@override |
@@ -1465,6 +1538,16 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { |
_typeProvider.symbolType, new SymbolState(buffer.toString())); |
} |
+ @override |
+ DartObjectImpl visitTypeName(TypeName node) { |
+ // TODO(jmesserly): what to do about type arguments? |
+ String name = node.name.name; |
+ if (_lexicalEnvironment != null && _lexicalEnvironment.containsKey(name)) { |
+ return _lexicalEnvironment[name]; |
+ } |
+ return new DartObjectImpl(_typeProvider.typeType, new TypeState(node.type)); |
+ } |
+ |
/** |
* Create an error associated with the given [node]. The error will have the |
* given error [code]. |
@@ -1497,10 +1580,9 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { |
} |
return new DartObjectImpl(functionType, new FunctionState(function)); |
} |
- } else if (variableElement is ClassElement || |
- variableElement is FunctionTypeAliasElement || |
- variableElement is DynamicElementImpl) { |
- return new DartObjectImpl(_typeProvider.typeType, new TypeState(element)); |
+ } else if (variableElement is TypeDefiningElement) { |
+ return new DartObjectImpl( |
+ _typeProvider.typeType, new TypeState(variableElement.type)); |
} |
// TODO(brianwilkerson) Figure out which error to report. |
_error(node, null); |