| 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);
|
|
|