|  | // Copyright (c) 2014, 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. | 
|  |  | 
|  | import 'dart:collection'; | 
|  |  | 
|  | import 'package:analyzer/dart/analysis/features.dart'; | 
|  | import 'package:analyzer/dart/ast/syntactic_entity.dart'; | 
|  | import 'package:analyzer/dart/ast/token.dart'; | 
|  | import 'package:analyzer/dart/ast/visitor.dart'; | 
|  | import 'package:analyzer/dart/element/element.dart'; | 
|  | import 'package:analyzer/dart/element/nullability_suffix.dart'; | 
|  | import 'package:analyzer/dart/element/type.dart'; | 
|  | import 'package:analyzer/dart/element/type_provider.dart'; | 
|  | import 'package:analyzer/error/error.dart'; | 
|  | import 'package:analyzer/error/listener.dart'; | 
|  | import 'package:analyzer/src/dart/ast/ast.dart'; | 
|  | import 'package:analyzer/src/dart/ast/extensions.dart'; | 
|  | import 'package:analyzer/src/dart/ast/token.dart'; | 
|  | import 'package:analyzer/src/dart/constant/from_environment_evaluator.dart'; | 
|  | import 'package:analyzer/src/dart/constant/has_type_parameter_reference.dart'; | 
|  | import 'package:analyzer/src/dart/constant/potentially_constant.dart'; | 
|  | import 'package:analyzer/src/dart/element/element.dart'; | 
|  | import 'package:analyzer/src/dart/element/member.dart'; | 
|  | import 'package:analyzer/src/dart/element/type_algebra.dart'; | 
|  | import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl; | 
|  | import 'package:analyzer/src/error/codes.dart'; | 
|  | import 'package:analyzer/src/generated/constant.dart'; | 
|  | import 'package:analyzer/src/generated/engine.dart'; | 
|  | import 'package:analyzer/src/task/api/model.dart'; | 
|  | import 'package:analyzer/src/utilities/extensions/collection.dart'; | 
|  | import 'package:analyzer/src/utilities/extensions/object.dart'; | 
|  |  | 
|  | class ConstantEvaluationConfiguration { | 
|  | final Map<AstNode, AstNode> _errorNodes = {}; | 
|  |  | 
|  | /// We evaluate constant values using expressions stored in elements. | 
|  | /// But these expressions don't have offsets set. | 
|  | /// This includes elements and expressions of the file being resolved. | 
|  | /// So, to make sure that we report errors at right offsets, we "replace" | 
|  | /// these constant expressions. | 
|  | /// | 
|  | /// A similar issue happens for enum values, which are desugared into | 
|  | /// synthetic [InstanceCreationExpression], which never had any offsets. | 
|  | /// So, we remember that any errors should be reported at the corresponding | 
|  | /// [EnumConstantDeclaration]s. | 
|  | void addErrorNode({ | 
|  | required AstNode? fromElement, | 
|  | required AstNode? fromAst, | 
|  | }) { | 
|  | if (fromElement != null && fromAst != null) { | 
|  | _errorNodes[fromElement] = fromAst; | 
|  | } | 
|  | } | 
|  |  | 
|  | AstNode errorNode(AstNode node) { | 
|  | return _errorNodes[node] ?? node; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Helper class encapsulating the methods for evaluating constants and | 
|  | /// constant instance creation expressions. | 
|  | class ConstantEvaluationEngine { | 
|  | /// The set of variables declared on the command line using '-D'. | 
|  | final DeclaredVariables _declaredVariables; | 
|  |  | 
|  | /// Whether the `non-nullable` feature is enabled. | 
|  | final bool _isNonNullableByDefault; | 
|  |  | 
|  | final ConstantEvaluationConfiguration configuration; | 
|  |  | 
|  | /// Initialize a newly created [ConstantEvaluationEngine]. | 
|  | /// | 
|  | /// [declaredVariables] is the set of variables declared on the command | 
|  | /// line using '-D'. | 
|  | ConstantEvaluationEngine({ | 
|  | required DeclaredVariables declaredVariables, | 
|  | required bool isNonNullableByDefault, | 
|  | required this.configuration, | 
|  | })  : _declaredVariables = declaredVariables, | 
|  | _isNonNullableByDefault = isNonNullableByDefault; | 
|  |  | 
|  | /// Compute the constant value associated with the given [constant]. | 
|  | void computeConstantValue(ConstantEvaluationTarget constant) { | 
|  | if (constant is Element) { | 
|  | var element = constant as Element; | 
|  | constant = element.declaration as ConstantEvaluationTarget; | 
|  | } | 
|  |  | 
|  | var library = constant.library as LibraryElementImpl; | 
|  | if (constant is ParameterElementImpl) { | 
|  | if (constant is ConstVariableElement) { | 
|  | var defaultValue = constant.constantInitializer; | 
|  | if (defaultValue != null) { | 
|  | RecordingErrorListener errorListener = RecordingErrorListener(); | 
|  | ErrorReporter errorReporter = ErrorReporter( | 
|  | errorListener, | 
|  | constant.source!, | 
|  | isNonNullableByDefault: library.isNonNullableByDefault, | 
|  | ); | 
|  | // TODO(kallentu): Remove unwrapping of Constant. | 
|  | var dartConstant = defaultValue | 
|  | .accept(ConstantVisitor(this, library, errorReporter)); | 
|  | var dartObject = dartConstant is DartObjectImpl ? dartConstant : null; | 
|  | constant.evaluationResult = | 
|  | EvaluationResultImpl(dartObject, errorListener.errors); | 
|  | } else { | 
|  | constant.evaluationResult = EvaluationResultImpl( | 
|  | _nullObject(library), | 
|  | ); | 
|  | } | 
|  | } | 
|  | } else if (constant is VariableElementImpl) { | 
|  | var constantInitializer = constant.constantInitializer; | 
|  | if (constantInitializer != null) { | 
|  | RecordingErrorListener errorListener = RecordingErrorListener(); | 
|  | ErrorReporter errorReporter = ErrorReporter( | 
|  | errorListener, | 
|  | constant.source!, | 
|  | isNonNullableByDefault: library.isNonNullableByDefault, | 
|  | ); | 
|  | // TODO(kallentu): Remove unwrapping of Constant. | 
|  | var dartConstant = constantInitializer | 
|  | .accept(ConstantVisitor(this, library, errorReporter)); | 
|  | var dartObject = dartConstant is DartObjectImpl ? dartConstant : null; | 
|  | // Only check the type for truly const declarations (don't check final | 
|  | // fields with initializers, since their types may be generic.  The type | 
|  | // of the final field will be checked later, when the constructor is | 
|  | // invoked). | 
|  | if (dartObject != null && constant.isConst) { | 
|  | if (!library.typeSystem.runtimeTypeMatch(dartObject, constant.type)) { | 
|  | // If the static types are mismatched, an error would have already | 
|  | // been reported. | 
|  | if (library.typeSystem.isAssignableTo( | 
|  | constantInitializer.typeOrThrow, constant.type)) { | 
|  | errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, | 
|  | constantInitializer, | 
|  | [dartObject.type, constant.type]); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Associate with the variable. | 
|  | dartObject = DartObjectImpl.forVariable(dartObject, constant); | 
|  | } | 
|  |  | 
|  | if (dartObject != null) { | 
|  | var enumConstant = _enumConstant(constant); | 
|  | if (enumConstant != null) { | 
|  | dartObject.updateEnumConstant( | 
|  | index: enumConstant.index, | 
|  | name: enumConstant.name, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | constant.evaluationResult = | 
|  | EvaluationResultImpl(dartObject, errorListener.errors); | 
|  | } | 
|  | } else if (constant is ConstructorElementImpl) { | 
|  | if (constant.isConst) { | 
|  | // No evaluation needs to be done; constructor declarations are only in | 
|  | // the dependency graph to ensure that any constants referred to in | 
|  | // initializer lists and parameter defaults are evaluated before | 
|  | // invocations of the constructor. | 
|  | constant.isConstantEvaluated = true; | 
|  | } | 
|  | } else if (constant is ElementAnnotationImpl) { | 
|  | var constNode = constant.annotationAst; | 
|  | var element = constant.element; | 
|  | if (element is PropertyAccessorElement) { | 
|  | // The annotation is a reference to a compile-time constant variable. | 
|  | // Just copy the evaluation result. | 
|  | VariableElementImpl variableElement = | 
|  | element.variable.declaration as VariableElementImpl; | 
|  | if (variableElement.evaluationResult != null) { | 
|  | constant.evaluationResult = variableElement.evaluationResult; | 
|  | } else { | 
|  | // This could happen in the event that the annotation refers to a | 
|  | // non-constant.  The error is detected elsewhere, so just silently | 
|  | // ignore it here. | 
|  | constant.evaluationResult = EvaluationResultImpl(null); | 
|  | } | 
|  | } else if (element is ConstructorElement && | 
|  | element.isConst && | 
|  | constNode.arguments != null) { | 
|  | RecordingErrorListener errorListener = RecordingErrorListener(); | 
|  | ErrorReporter errorReporter = ErrorReporter( | 
|  | errorListener, | 
|  | constant.source, | 
|  | isNonNullableByDefault: library.isNonNullableByDefault, | 
|  | ); | 
|  | ConstantVisitor constantVisitor = | 
|  | ConstantVisitor(this, library, errorReporter); | 
|  | var result = evaluateConstructorCall( | 
|  | library, | 
|  | constNode, | 
|  | element.returnType2.typeArguments, | 
|  | constNode.arguments!.arguments, | 
|  | element, | 
|  | constantVisitor, | 
|  | errorReporter); | 
|  | constant.evaluationResult = | 
|  | EvaluationResultImpl(result, errorListener.errors); | 
|  | } else { | 
|  | // This may happen for invalid code (e.g. failing to pass arguments | 
|  | // to an annotation which references a const constructor).  The error | 
|  | // is detected elsewhere, so just silently ignore it here. | 
|  | constant.evaluationResult = EvaluationResultImpl(null); | 
|  | } | 
|  | } else if (constant is VariableElement) { | 
|  | // constant is a VariableElement but not a VariableElementImpl.  This can | 
|  | // happen sometimes in the case of invalid user code (for example, a | 
|  | // constant expression that refers to a non-static field inside a generic | 
|  | // class will wind up referring to a FieldMember).  The error is detected | 
|  | // elsewhere, so just silently ignore it here. | 
|  | } else { | 
|  | // Should not happen. | 
|  | assert(false); | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logError("Constant value computer trying to compute " | 
|  | "the value of a node of type ${constant.runtimeType}"); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Determine which constant elements need to have their values computed | 
|  | /// prior to computing the value of [constant], and report them using | 
|  | /// [callback]. | 
|  | void computeDependencies( | 
|  | ConstantEvaluationTarget constant, ReferenceFinderCallback callback) { | 
|  | if (constant is ConstFieldElementImpl && constant.isEnumConstant) { | 
|  | var enclosing = constant.enclosingElement2; | 
|  | if (enclosing is EnumElementImpl) { | 
|  | if (enclosing.name == 'values') { | 
|  | return; | 
|  | } | 
|  | if (constant.name == enclosing.name) { | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ReferenceFinder referenceFinder = ReferenceFinder(callback); | 
|  | if (constant is ConstructorElement) { | 
|  | constant = constant.declaration; | 
|  | } | 
|  | if (constant is VariableElement) { | 
|  | var declaration = constant.declaration as VariableElementImpl; | 
|  | var initializer = declaration.constantInitializer; | 
|  | if (initializer != null) { | 
|  | initializer.accept(referenceFinder); | 
|  | } | 
|  | } else if (constant is ConstructorElementImpl) { | 
|  | if (constant.isConst) { | 
|  | var redirectedConstructor = getConstRedirectedConstructor(constant); | 
|  | if (redirectedConstructor != null) { | 
|  | var redirectedConstructorBase = redirectedConstructor.declaration; | 
|  | callback(redirectedConstructorBase); | 
|  | return; | 
|  | } else if (constant.isFactory) { | 
|  | // Factory constructor, but getConstRedirectedConstructor returned | 
|  | // null.  This can happen if we're visiting one of the special | 
|  | // external const factory constructors in the SDK, or if the code | 
|  | // contains errors (such as delegating to a non-const constructor, or | 
|  | // delegating to a constructor that can't be resolved).  In any of | 
|  | // these cases, we'll evaluate calls to this constructor without | 
|  | // having to refer to any other constants.  So we don't need to report | 
|  | // any dependencies. | 
|  | return; | 
|  | } | 
|  | final returnType = constant.returnType2; | 
|  | if (returnType is InterfaceType) { | 
|  | bool defaultSuperInvocationNeeded = true; | 
|  | var initializers = constant.constantInitializers; | 
|  | for (ConstructorInitializer initializer in initializers) { | 
|  | if (initializer is SuperConstructorInvocation || | 
|  | initializer is RedirectingConstructorInvocation) { | 
|  | defaultSuperInvocationNeeded = false; | 
|  | } | 
|  | initializer.accept(referenceFinder); | 
|  | } | 
|  | if (defaultSuperInvocationNeeded) { | 
|  | // No explicit superconstructor invocation found, so we need to | 
|  | // manually insert a reference to the implicit superconstructor. | 
|  | var superclass = returnType.superclass; | 
|  | if (superclass != null && !superclass.isDartCoreObject) { | 
|  | var unnamedConstructor = | 
|  | superclass.element.unnamedConstructor?.declaration; | 
|  | if (unnamedConstructor != null && unnamedConstructor.isConst) { | 
|  | callback(unnamedConstructor); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | for (FieldElement field in constant.enclosingElement2.fields) { | 
|  | // Note: non-static const isn't allowed but we handle it anyway so | 
|  | // that we won't be confused by incorrect code. | 
|  | if ((field.isFinal || field.isConst) && | 
|  | !field.isStatic && | 
|  | field.hasInitializer) { | 
|  | callback(field); | 
|  | } | 
|  | } | 
|  | for (ParameterElement parameterElement in constant.parameters) { | 
|  | callback(parameterElement); | 
|  | } | 
|  | } | 
|  | } else if (constant is ElementAnnotationImpl) { | 
|  | Annotation constNode = constant.annotationAst; | 
|  | var element = constant.element; | 
|  | if (element is PropertyAccessorElement) { | 
|  | // The annotation is a reference to a compile-time constant variable, | 
|  | // so it depends on the variable. | 
|  | callback(element.variable.declaration); | 
|  | } else if (element is ConstructorElement) { | 
|  | // The annotation is a constructor invocation, so it depends on the | 
|  | // constructor. | 
|  | callback(element.declaration); | 
|  | } else { | 
|  | // This could happen in the event of invalid code.  The error will be | 
|  | // reported at constant evaluation time. | 
|  | } | 
|  | if (constNode.arguments != null) { | 
|  | constNode.arguments!.accept(referenceFinder); | 
|  | } | 
|  | } else if (constant is VariableElement) { | 
|  | // constant is a VariableElement but not a VariableElementImpl.  This can | 
|  | // happen sometimes in the case of invalid user code (for example, a | 
|  | // constant expression that refers to a non-static field inside a generic | 
|  | // class will wind up referring to a FieldMember).  So just don't bother | 
|  | // computing any dependencies. | 
|  | } else { | 
|  | // Should not happen. | 
|  | assert(false); | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logError("Constant value computer trying to compute " | 
|  | "the value of a node of type ${constant.runtimeType}"); | 
|  | } | 
|  | } | 
|  |  | 
|  | DartObjectImpl? evaluateConstructorCall( | 
|  | LibraryElementImpl library, | 
|  | AstNode node, | 
|  | List<DartType>? typeArguments, | 
|  | List<Expression> arguments, | 
|  | ConstructorElement constructor, | 
|  | ConstantVisitor constantVisitor, | 
|  | ErrorReporter errorReporter, { | 
|  | ConstructorInvocation? invocation, | 
|  | }) { | 
|  | return _InstanceCreationEvaluator.evaluate( | 
|  | this, | 
|  | _declaredVariables, | 
|  | errorReporter, | 
|  | library, | 
|  | node, | 
|  | constructor, | 
|  | typeArguments, | 
|  | arguments, | 
|  | constantVisitor, | 
|  | isNullSafe: _isNonNullableByDefault, | 
|  | invocation: invocation, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// Generate an error indicating that the given [constant] is not a valid | 
|  | /// compile-time constant because it references at least one of the constants | 
|  | /// in the given [cycle], each of which directly or indirectly references the | 
|  | /// constant. | 
|  | void generateCycleError( | 
|  | Iterable<ConstantEvaluationTarget> cycle, | 
|  | ConstantEvaluationTarget constant, | 
|  | ) { | 
|  | if (constant is VariableElement) { | 
|  | RecordingErrorListener errorListener = RecordingErrorListener(); | 
|  | ErrorReporter errorReporter = ErrorReporter( | 
|  | errorListener, | 
|  | constant.source!, | 
|  | isNonNullableByDefault: constant.library!.isNonNullableByDefault, | 
|  | ); | 
|  | // TODO(paulberry): It would be really nice if we could extract enough | 
|  | // information from the 'cycle' argument to provide the user with a | 
|  | // description of the cycle. | 
|  | errorReporter.reportErrorForElement( | 
|  | CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, constant, []); | 
|  | (constant as VariableElementImpl).evaluationResult = | 
|  | EvaluationResultImpl(null, errorListener.errors); | 
|  | } else if (constant is ConstructorElement) { | 
|  | // We don't report cycle errors on constructor declarations since there | 
|  | // is nowhere to put the error information. | 
|  | } else { | 
|  | // Should not happen.  Formal parameter defaults and annotations should | 
|  | // never appear as part of a cycle because they can't be referred to. | 
|  | assert(false); | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logError("Constant value computer trying to report a cycle error " | 
|  | "for a node of type ${constant.runtimeType}"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// If [constructor] redirects to another const constructor, return the | 
|  | /// const constructor it redirects to.  Otherwise return `null`. | 
|  | static ConstructorElement? getConstRedirectedConstructor( | 
|  | ConstructorElement constructor) { | 
|  | if (!constructor.isFactory) { | 
|  | return null; | 
|  | } | 
|  | var typeProvider = constructor.library.typeProvider; | 
|  | if (constructor.enclosingElement2 == typeProvider.symbolElement) { | 
|  | // The dart:core.Symbol has a const factory constructor that redirects | 
|  | // to dart:_internal.Symbol.  That in turn redirects to an external | 
|  | // const constructor, which we won't be able to evaluate. | 
|  | // So stop following the chain of redirections at dart:core.Symbol, and | 
|  | // let [evaluateInstanceCreationExpression] handle it specially. | 
|  | return null; | 
|  | } | 
|  | var redirectedConstructor = constructor.redirectedConstructor; | 
|  | if (redirectedConstructor == null) { | 
|  | // This can happen if constructor is an external factory constructor. | 
|  | return null; | 
|  | } | 
|  | if (!redirectedConstructor.isConst) { | 
|  | // Delegating to a non-const constructor--this is not allowed (and | 
|  | // is checked elsewhere--see | 
|  | // [ErrorVerifier.checkForRedirectToNonConstConstructor()]). | 
|  | return null; | 
|  | } | 
|  | return redirectedConstructor; | 
|  | } | 
|  |  | 
|  | static _EnumConstant? _enumConstant(VariableElementImpl element) { | 
|  | if (element is ConstFieldElementImpl && element.isEnumConstant) { | 
|  | var enum_ = element.enclosingElement2; | 
|  | if (enum_ is EnumElementImpl) { | 
|  | var index = enum_.constants.indexOf(element); | 
|  | assert(index >= 0); | 
|  | return _EnumConstant( | 
|  | index: index, | 
|  | name: element.name, | 
|  | ); | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | static DartObjectImpl _nullObject(LibraryElementImpl library) { | 
|  | return DartObjectImpl( | 
|  | library.typeSystem, | 
|  | library.typeProvider.nullType, | 
|  | NullState.NULL_STATE, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Interface for [AnalysisTarget]s for which constant evaluation can be | 
|  | /// performed. | 
|  | abstract class ConstantEvaluationTarget extends AnalysisTarget { | 
|  | /// Return the [AnalysisContext] which should be used to evaluate this | 
|  | /// constant. | 
|  | AnalysisContext get context; | 
|  |  | 
|  | /// Return whether this constant is evaluated. | 
|  | bool get isConstantEvaluated; | 
|  |  | 
|  | /// The library with this constant. | 
|  | LibraryElement? get library; | 
|  | } | 
|  |  | 
|  | /// Interface used by unit tests to verify correct dependency analysis during | 
|  | /// constant evaluation. | 
|  | abstract class ConstantEvaluationValidator { | 
|  | /// This method is called just before computing the constant value associated | 
|  | /// with [constant]. Unit tests will override this method to introduce | 
|  | /// additional error checking. | 
|  | void beforeComputeValue(ConstantEvaluationTarget constant); | 
|  |  | 
|  | /// This method is called just before getting the constant initializers | 
|  | /// associated with the [constructor]. Unit tests will override this method to | 
|  | /// introduce additional error checking. | 
|  | void beforeGetConstantInitializers(ConstructorElement constructor); | 
|  |  | 
|  | /// This method is called just before retrieving an evaluation result from an | 
|  | /// element. Unit tests will override it to introduce additional error | 
|  | /// checking. | 
|  | void beforeGetEvaluationResult(ConstantEvaluationTarget constant); | 
|  |  | 
|  | /// This method is called just before getting the constant value of a field | 
|  | /// with an initializer.  Unit tests will override this method to introduce | 
|  | /// additional error checking. | 
|  | void beforeGetFieldEvaluationResult(FieldElementImpl field); | 
|  |  | 
|  | /// This method is called just before getting a parameter's default value. | 
|  | /// Unit tests will override this method to introduce additional error | 
|  | /// checking. | 
|  | void beforeGetParameterDefault(ParameterElement parameter); | 
|  | } | 
|  |  | 
|  | /// Implementation of [ConstantEvaluationValidator] used in production; does no | 
|  | /// validation. | 
|  | class ConstantEvaluationValidator_ForProduction | 
|  | implements ConstantEvaluationValidator { | 
|  | @override | 
|  | void beforeComputeValue(ConstantEvaluationTarget constant) {} | 
|  |  | 
|  | @override | 
|  | void beforeGetConstantInitializers(ConstructorElement constructor) {} | 
|  |  | 
|  | @override | 
|  | void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {} | 
|  |  | 
|  | @override | 
|  | void beforeGetFieldEvaluationResult(FieldElementImpl field) {} | 
|  |  | 
|  | @override | 
|  | void beforeGetParameterDefault(ParameterElement parameter) {} | 
|  | } | 
|  |  | 
|  | /// A visitor used to evaluate constant expressions to produce their | 
|  | /// compile-time value. | 
|  | class ConstantVisitor extends UnifyingAstVisitor<Constant> { | 
|  | /// The evaluation engine used to access the feature set, type system, and | 
|  | /// type provider. | 
|  | final ConstantEvaluationEngine evaluationEngine; | 
|  |  | 
|  | /// The library that contains the constant expression being evaluated. | 
|  | final LibraryElementImpl _library; | 
|  |  | 
|  | /// A mapping of variable names to runtime values. | 
|  | final Map<String, DartObjectImpl>? _lexicalEnvironment; | 
|  |  | 
|  | /// A mapping of type parameter names to runtime values (types). | 
|  | final Map<TypeParameterElement, DartType>? _lexicalTypeEnvironment; | 
|  |  | 
|  | final Substitution? _substitution; | 
|  |  | 
|  | /// Error reporter that we use to report errors accumulated while computing | 
|  | /// the constant. | 
|  | final ErrorReporter _errorReporter; | 
|  |  | 
|  | /// Helper class used to compute constant values. | 
|  | late final DartObjectComputer _dartObjectComputer; | 
|  |  | 
|  | /// Initialize a newly created constant visitor. The [evaluationEngine] is | 
|  | /// used to evaluate instance creation expressions. The [lexicalEnvironment] | 
|  | /// is a map containing values which should override identifiers, or `null` if | 
|  | /// no overriding is necessary. The [_errorReporter] is used to report errors | 
|  | /// found during evaluation.  The [validator] is used by unit tests to verify | 
|  | /// correct dependency analysis. | 
|  | /// | 
|  | /// The [substitution] is specified for instance creations. | 
|  | ConstantVisitor( | 
|  | this.evaluationEngine, | 
|  | this._library, | 
|  | this._errorReporter, { | 
|  | Map<String, DartObjectImpl>? lexicalEnvironment, | 
|  | Map<TypeParameterElement, DartType>? lexicalTypeEnvironment, | 
|  | Substitution? substitution, | 
|  | })  : _lexicalEnvironment = lexicalEnvironment, | 
|  | _lexicalTypeEnvironment = lexicalTypeEnvironment, | 
|  | _substitution = substitution { | 
|  | _dartObjectComputer = DartObjectComputer( | 
|  | typeSystem, | 
|  | _library.featureSet, | 
|  | _errorReporter, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// Convenience getter to gain access to the [evaluationEngine]'s type system. | 
|  | TypeSystemImpl get typeSystem => _library.typeSystem; | 
|  |  | 
|  | bool get _isNonNullableByDefault => typeSystem.isNonNullableByDefault; | 
|  |  | 
|  | /// Convenience getter to gain access to the [evaluationEngine]'s type | 
|  | /// provider. | 
|  | TypeProvider get _typeProvider => _library.typeProvider; | 
|  |  | 
|  | @override | 
|  | Constant visitAdjacentStrings(AdjacentStrings node) { | 
|  | return _concatenateNodes(node, node.strings); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitAsExpression(AsExpression node) { | 
|  | var expression = _getConstant(node.expression); | 
|  | if (expression is! DartObjectImpl) { | 
|  | return expression; | 
|  | } | 
|  | var type = _getConstant(node.type); | 
|  | if (type is! DartObjectImpl) { | 
|  | return type; | 
|  | } | 
|  | return _dartObjectComputer.castToType(node, expression, type); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitBinaryExpression(BinaryExpression node) { | 
|  | if (node.staticElement?.enclosingElement2 is ExtensionElement) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD); | 
|  | } | 
|  |  | 
|  | TokenType operatorType = node.operator.type; | 
|  | var leftResult = _getConstant(node.leftOperand); | 
|  | if (leftResult is! DartObjectImpl) { | 
|  | return leftResult; | 
|  | } | 
|  |  | 
|  | // Used for the [DartObjectComputer], which will handle any exceptions. | 
|  | DartObjectImpl rightOperandComputer() { | 
|  | var constant = _getConstant(node.rightOperand); | 
|  | switch (constant) { | 
|  | case DartObjectImpl(): | 
|  | return constant; | 
|  | case InvalidConstant(): | 
|  | throw EvaluationException(constant.errorCode); | 
|  | default: | 
|  | throw EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Evaluate lazy operators. | 
|  | if (operatorType == TokenType.AMPERSAND_AMPERSAND) { | 
|  | if (leftResult.toBoolValue() == false) { | 
|  | var error = _reportNotPotentialConstants(node.rightOperand); | 
|  | if (error is InvalidConstant) { | 
|  | return error; | 
|  | } | 
|  | } | 
|  | return _dartObjectComputer.lazyAnd( | 
|  | node, leftResult, rightOperandComputer); | 
|  | } else if (operatorType == TokenType.BAR_BAR) { | 
|  | if (leftResult.toBoolValue() == true) { | 
|  | var error = _reportNotPotentialConstants(node.rightOperand); | 
|  | if (error is InvalidConstant) { | 
|  | return error; | 
|  | } | 
|  | } | 
|  | return _dartObjectComputer.lazyOr(node, leftResult, rightOperandComputer); | 
|  | } else if (operatorType == TokenType.QUESTION_QUESTION) { | 
|  | if (leftResult.isNull != true) { | 
|  | var error = _reportNotPotentialConstants(node.rightOperand); | 
|  | if (error is InvalidConstant) { | 
|  | return error; | 
|  | } | 
|  | } | 
|  | return _dartObjectComputer.lazyQuestionQuestion( | 
|  | node, leftResult, () => _getConstant(node.rightOperand)); | 
|  | } | 
|  |  | 
|  | // Evaluate eager operators. | 
|  | var rightResult = _getConstant(node.rightOperand); | 
|  | if (rightResult is! DartObjectImpl) { | 
|  | return rightResult; | 
|  | } | 
|  | if (operatorType == TokenType.AMPERSAND) { | 
|  | return _dartObjectComputer.eagerAnd(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.BANG_EQ) { | 
|  | return _dartObjectComputer.notEqual(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.BAR) { | 
|  | return _dartObjectComputer.eagerOr(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.CARET) { | 
|  | return _dartObjectComputer.eagerXor(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.EQ_EQ) { | 
|  | return _dartObjectComputer.equalEqual(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.GT) { | 
|  | return _dartObjectComputer.greaterThan(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.GT_EQ) { | 
|  | return _dartObjectComputer.greaterThanOrEqual( | 
|  | node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.GT_GT) { | 
|  | return _dartObjectComputer.shiftRight(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.GT_GT_GT) { | 
|  | return _dartObjectComputer.logicalShiftRight( | 
|  | node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.LT) { | 
|  | return _dartObjectComputer.lessThan(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.LT_EQ) { | 
|  | return _dartObjectComputer.lessThanOrEqual(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.LT_LT) { | 
|  | return _dartObjectComputer.shiftLeft(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.MINUS) { | 
|  | return _dartObjectComputer.minus(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.PERCENT) { | 
|  | return _dartObjectComputer.remainder(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.PLUS) { | 
|  | return _dartObjectComputer.add(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.STAR) { | 
|  | return _dartObjectComputer.times(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.SLASH) { | 
|  | return _dartObjectComputer.divide(node, leftResult, rightResult); | 
|  | } else if (operatorType == TokenType.TILDE_SLASH) { | 
|  | return _dartObjectComputer.integerDivide(node, leftResult, rightResult); | 
|  | } else { | 
|  | // TODO(https://github.com/dart-lang/sdk/issues/47061): Use a specific | 
|  | // error code. | 
|  | _error(node, null); | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitBooleanLiteral(BooleanLiteral node) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.boolType, | 
|  | BoolState.from(node.value), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitConditionalExpression(ConditionalExpression node) { | 
|  | var condition = node.condition; | 
|  | var conditionConstant = _getConstant(condition); | 
|  | if (conditionConstant is! DartObjectImpl) { | 
|  | return conditionConstant; | 
|  | } | 
|  |  | 
|  | if (!conditionConstant.isBool) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition); | 
|  | return InvalidConstant( | 
|  | condition, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); | 
|  | } | 
|  | conditionConstant = _dartObjectComputer.applyBooleanConversion( | 
|  | condition, conditionConstant); | 
|  | if (conditionConstant is! DartObjectImpl) { | 
|  | return conditionConstant; | 
|  | } | 
|  |  | 
|  | var conditionResultBool = conditionConstant.toBoolValue(); | 
|  | if (conditionResultBool == true) { | 
|  | var error = _reportNotPotentialConstants(node.elseExpression); | 
|  | if (error is InvalidConstant) { | 
|  | return error; | 
|  | } | 
|  | return _getConstant(node.thenExpression); | 
|  | } else if (conditionResultBool == false) { | 
|  | var error = _reportNotPotentialConstants(node.thenExpression); | 
|  | if (error is InvalidConstant) { | 
|  | return error; | 
|  | } | 
|  | return _getConstant(node.elseExpression); | 
|  | } else { | 
|  | var thenConstant = _getConstant(node.thenExpression); | 
|  | if (thenConstant is InvalidConstant) { | 
|  | return thenConstant; | 
|  | } | 
|  | var elseConstant = _getConstant(node.elseExpression); | 
|  | if (elseConstant is InvalidConstant) { | 
|  | return elseConstant; | 
|  | } | 
|  | return DartObjectImpl.validWithUnknownValue( | 
|  | typeSystem, | 
|  | node.typeOrThrow, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitConstructorReference(ConstructorReference node) { | 
|  | var constructorFunctionType = node.typeOrThrow; | 
|  | if (constructorFunctionType is! FunctionType) { | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | var classType = constructorFunctionType.returnType as InterfaceType; | 
|  | var typeArguments = classType.typeArguments; | 
|  | // The result is already instantiated during resolution; | 
|  | // [_dartObjectComputer.typeInstantiate] is unnecessary. | 
|  | var typeElement = node.constructorName.type.element as TypeDefiningElement; | 
|  |  | 
|  | TypeAliasElement? viaTypeAlias; | 
|  | if (typeElement is TypeAliasElementImpl) { | 
|  | if (constructorFunctionType.typeFormals.isNotEmpty && | 
|  | !typeElement.isProperRename) { | 
|  | // The type alias is not a proper rename of the aliased class, so | 
|  | // the constructor tear-off is distinct from the associated | 
|  | // constructor function of the aliased class. | 
|  | viaTypeAlias = typeElement; | 
|  | } | 
|  | } | 
|  |  | 
|  | final constructorElement = node.constructorName.staticElement?.declaration | 
|  | .ifTypeOrNull<ConstructorElementImpl>(); | 
|  | if (constructorElement == null) { | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  |  | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | node.typeOrThrow, | 
|  | FunctionState(constructorElement, | 
|  | typeArguments: typeArguments, viaTypeAlias: viaTypeAlias), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitDoubleLiteral(DoubleLiteral node) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.doubleType, | 
|  | DoubleState(node.value), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitFunctionReference(FunctionReference node) { | 
|  | var functionResult = _getConstant(node.function); | 
|  | if (functionResult is! DartObjectImpl) { | 
|  | return functionResult; | 
|  | } | 
|  |  | 
|  | // Report an error if any of the _inferred_ type argument types refer to a | 
|  | // type parameter. If, however, `node.typeArguments` is not `null`, then | 
|  | // any type parameters contained therein are reported as non-constant in | 
|  | // [ConstantVerifier]. | 
|  | if (node.typeArguments == null) { | 
|  | var typeArgumentTypes = node.typeArgumentTypes; | 
|  | if (typeArgumentTypes != null) { | 
|  | var instantiatedTypeArgumentTypes = typeArgumentTypes.map((type) { | 
|  | if (type is TypeParameterType) { | 
|  | return _lexicalTypeEnvironment?[type.element] ?? type; | 
|  | } else { | 
|  | return type; | 
|  | } | 
|  | }); | 
|  | if (instantiatedTypeArgumentTypes.any(hasTypeParameterReference)) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF, | 
|  | node); | 
|  | return InvalidConstant(node, | 
|  | CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | var typeArgumentList = node.typeArguments; | 
|  | if (typeArgumentList == null) { | 
|  | return _instantiateFunctionType(node, functionResult); | 
|  | } | 
|  |  | 
|  | var typeArguments = <DartType>[]; | 
|  | for (var typeArgument in typeArgumentList.arguments) { | 
|  | var object = _getConstant(typeArgument); | 
|  | if (object is! DartObjectImpl) { | 
|  | return object; | 
|  | } | 
|  | var typeArgumentType = object.toTypeValue(); | 
|  | if (typeArgumentType == null) { | 
|  | return InvalidConstant( | 
|  | typeArgument, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | // TODO(srawlins): Test type alias types (`typedef i = int`) used as | 
|  | // type arguments. Possibly change implementation based on | 
|  | // canonicalization rules. | 
|  | typeArguments.add(typeArgumentType); | 
|  | } | 
|  | return _dartObjectComputer.typeInstantiate( | 
|  | functionResult, typeArguments, node.function); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitGenericFunctionType(GenericFunctionType node) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(node.type), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant? visitInstanceCreationExpression(InstanceCreationExpression node) { | 
|  | if (!node.isConst) { | 
|  | // TODO(https://github.com/dart-lang/sdk/issues/47061): Use a specific | 
|  | // error code. | 
|  | _error(node, null); | 
|  | return null; | 
|  | } | 
|  | var constructor = node.constructorName.staticElement; | 
|  | if (constructor == null) { | 
|  | // Couldn't resolve the constructor so we can't compute a value.  No | 
|  | // problem - the error has already been reported. | 
|  | return null; | 
|  | } | 
|  |  | 
|  | return evaluationEngine.evaluateConstructorCall( | 
|  | _library, | 
|  | node, | 
|  | constructor.returnType2.typeArguments, | 
|  | node.argumentList.arguments, | 
|  | constructor, | 
|  | this, | 
|  | _errorReporter, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitIntegerLiteral(IntegerLiteral node) { | 
|  | if (node.staticType == _typeProvider.doubleType) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.doubleType, | 
|  | DoubleState(node.value?.toDouble()), | 
|  | ); | 
|  | } | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.intType, | 
|  | IntState(node.value), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitInterpolationExpression(InterpolationExpression node) { | 
|  | var result = _getConstant(node.expression); | 
|  | if (result is! DartObjectImpl) { | 
|  | return result; | 
|  | } | 
|  |  | 
|  | if (!result.isBoolNumStringOrNull) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); | 
|  | } | 
|  | return _dartObjectComputer.performToString(node, result); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitInterpolationString(InterpolationString node) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.stringType, | 
|  | StringState(node.value), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitIsExpression(IsExpression node) { | 
|  | var expression = _getConstant(node.expression); | 
|  | if (expression is! DartObjectImpl) { | 
|  | return expression; | 
|  | } | 
|  | var type = _getConstant(node.type); | 
|  | if (type is! DartObjectImpl) { | 
|  | return type; | 
|  | } | 
|  | return _dartObjectComputer.typeTest(node, expression, type); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitListLiteral(ListLiteral node) { | 
|  | if (!node.isConst) { | 
|  | // TODO(kallentu): Don't report the error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL); | 
|  | } | 
|  | final elements = <DartObjectImpl>[]; | 
|  | for (CollectionElement element in node.elements) { | 
|  | var result = _addElementsToList(elements, element); | 
|  | if (result is InvalidConstant) { | 
|  | return result; | 
|  | } | 
|  | } | 
|  | var nodeType = node.staticType; | 
|  | DartType elementType = | 
|  | nodeType is InterfaceType && nodeType.typeArguments.isNotEmpty | 
|  | ? nodeType.typeArguments[0] | 
|  | : _typeProvider.dynamicType; | 
|  | InterfaceType listType = _typeProvider.listType(elementType); | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | listType, | 
|  | ListState( | 
|  | elementType: elementType, | 
|  | elements: elements, | 
|  | ), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitMethodInvocation(MethodInvocation node) { | 
|  | var element = node.methodName.staticElement; | 
|  | if (element is FunctionElement) { | 
|  | if (element.name == "identical") { | 
|  | NodeList<Expression> arguments = node.argumentList.arguments; | 
|  | if (arguments.length == 2) { | 
|  | var enclosingElement = element.enclosingElement2; | 
|  | if (enclosingElement is CompilationUnitElement) { | 
|  | LibraryElement library = enclosingElement.library; | 
|  | if (library.isDartCore) { | 
|  | var leftArgument = _getConstant(arguments[0]); | 
|  | if (leftArgument is! DartObjectImpl) { | 
|  | return leftArgument; | 
|  | } | 
|  | var rightArgument = _getConstant(arguments[1]); | 
|  | if (rightArgument is! DartObjectImpl) { | 
|  | return rightArgument; | 
|  | } | 
|  | return _dartObjectComputer.isIdentical( | 
|  | node, leftArgument, rightArgument); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitNamedExpression(NamedExpression node) => | 
|  | _getConstant(node.expression); | 
|  |  | 
|  | @override | 
|  | Constant visitNamedType(NamedType node) { | 
|  | var type = node.typeOrThrow; | 
|  |  | 
|  | if ((!_isNonNullableByDefault || node.isTypeLiteralInConstantPattern) && | 
|  | hasTypeParameterReference(type)) { | 
|  | // TODO(kallentu): Don't report error here and report a more specific | 
|  | // diagnostic | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.INVALID_CONSTANT, node); | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } else if (node.isDeferred) { | 
|  | return _getDeferredLibraryError(node, node.name2) ?? | 
|  | InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  |  | 
|  | if (_substitution != null) { | 
|  | type = _substitution!.substituteType(type); | 
|  | } | 
|  |  | 
|  | return _getConstantValue( | 
|  | errorNode: node, | 
|  | expression: null, | 
|  | identifier: null, | 
|  | element: node.element, | 
|  | givenType: type, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant? visitNode(AstNode node) { | 
|  | // TODO(https://github.com/dart-lang/sdk/issues/47061): Use a specific | 
|  | // error code. | 
|  | _error(node, null); | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitNullLiteral(NullLiteral node) { | 
|  | return ConstantEvaluationEngine._nullObject(_library); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitParenthesizedExpression(ParenthesizedExpression node) => | 
|  | _getConstant(node.expression); | 
|  |  | 
|  | @override | 
|  | Constant visitPrefixedIdentifier(PrefixedIdentifier node) { | 
|  | SimpleIdentifier prefixNode = node.prefix; | 
|  | var prefixElement = prefixNode.staticElement; | 
|  |  | 
|  | // importPrefix.CONST | 
|  | if (prefixElement is PrefixElement) { | 
|  | if (node.isDeferred) { | 
|  | return _getDeferredLibraryError(node, node.identifier) ?? | 
|  | InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | } else if (prefixElement is! ExtensionElement) { | 
|  | var prefixResult = _getConstant(prefixNode); | 
|  | if (prefixResult is! DartObjectImpl) { | 
|  | return prefixResult; | 
|  | } | 
|  |  | 
|  | // String.length | 
|  | if (prefixElement is! InterfaceElement) { | 
|  | if (_isStringLength(prefixResult, node.identifier)) { | 
|  | return prefixResult.stringLength(typeSystem); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Validate prefixed identifier. | 
|  | return _getConstantValue( | 
|  | errorNode: node, | 
|  | expression: node, | 
|  | identifier: node.identifier, | 
|  | element: node.identifier.staticElement, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitPrefixExpression(PrefixExpression node) { | 
|  | var operand = _getConstant(node.operand); | 
|  | if (operand is! DartObjectImpl) { | 
|  | return operand; | 
|  | } | 
|  | if (node.staticElement?.enclosingElement2 is ExtensionElement) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD); | 
|  | } | 
|  | if (node.operator.type == TokenType.BANG) { | 
|  | return _dartObjectComputer.logicalNot(node, operand); | 
|  | } else if (node.operator.type == TokenType.TILDE) { | 
|  | return _dartObjectComputer.bitNot(node, operand); | 
|  | } else if (node.operator.type == TokenType.MINUS) { | 
|  | return _dartObjectComputer.negated(node, operand); | 
|  | } else { | 
|  | // TODO(https://github.com/dart-lang/sdk/issues/47061): Use a specific | 
|  | // error code. | 
|  | _error(node, null); | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitPropertyAccess(PropertyAccess node) { | 
|  | var target = node.target; | 
|  | if (target != null) { | 
|  | var prefixResult = _getConstant(target); | 
|  | if (prefixResult is! DartObjectImpl) { | 
|  | return prefixResult; | 
|  | } | 
|  | if (_isStringLength(prefixResult, node.propertyName)) { | 
|  | return prefixResult.stringLength(typeSystem); | 
|  | } | 
|  | } | 
|  | return _getConstantValue( | 
|  | errorNode: node, | 
|  | expression: node, | 
|  | identifier: node.propertyName, | 
|  | element: node.propertyName.staticElement, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitRecordLiteral(RecordLiteral node) { | 
|  | var positionalFields = <DartObjectImpl>[]; | 
|  | var namedFields = <String, DartObjectImpl>{}; | 
|  | for (var field in node.fields) { | 
|  | if (field is NamedExpression) { | 
|  | var name = field.name.label.name; | 
|  | var value = _getConstant(field.expression); | 
|  | if (value is! DartObjectImpl) { | 
|  | return value; | 
|  | } | 
|  | namedFields[name] = value; | 
|  | } else { | 
|  | var value = _getConstant(field); | 
|  | if (value is! DartObjectImpl) { | 
|  | return value; | 
|  | } | 
|  | positionalFields.add(value); | 
|  | } | 
|  | } | 
|  |  | 
|  | final nodeType = RecordType( | 
|  | positional: positionalFields.map((e) => e.type).toList(), | 
|  | named: namedFields.map((name, value) => MapEntry(name, value.type)), | 
|  | nullabilitySuffix: NullabilitySuffix.none, | 
|  | ); | 
|  |  | 
|  | return DartObjectImpl( | 
|  | typeSystem, nodeType, RecordState(positionalFields, namedFields)); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitSetOrMapLiteral(SetOrMapLiteral node) { | 
|  | // Note: due to dartbug.com/33441, it's possible that a set/map literal | 
|  | // resynthesized from a summary will have neither its `isSet` or `isMap` | 
|  | // boolean set to `true`.  We work around the problem by assuming such | 
|  | // literals are maps. | 
|  | // TODO(paulberry): when dartbug.com/33441 is fixed, add an assertion here | 
|  | // to verify that `node.isSet == !node.isMap`. | 
|  | bool isMap = !node.isSet; | 
|  | if (isMap) { | 
|  | if (!node.isConst) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL); | 
|  | } | 
|  | Map<DartObjectImpl, DartObjectImpl> map = {}; | 
|  | for (CollectionElement element in node.elements) { | 
|  | var result = _addElementsToMap(map, element); | 
|  | if (result is InvalidConstant) { | 
|  | return result; | 
|  | } | 
|  | } | 
|  | DartType keyType = _typeProvider.dynamicType; | 
|  | DartType valueType = _typeProvider.dynamicType; | 
|  | var nodeType = node.staticType; | 
|  | if (nodeType is InterfaceType) { | 
|  | var typeArguments = nodeType.typeArguments; | 
|  | if (typeArguments.length >= 2) { | 
|  | keyType = typeArguments[0]; | 
|  | valueType = typeArguments[1]; | 
|  | } | 
|  | } | 
|  | InterfaceType mapType = _typeProvider.mapType(keyType, valueType); | 
|  | return DartObjectImpl(typeSystem, mapType, MapState(map)); | 
|  | } else { | 
|  | if (!node.isConst) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL, node); | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL); | 
|  | } | 
|  | Set<DartObjectImpl> set = <DartObjectImpl>{}; | 
|  | for (CollectionElement element in node.elements) { | 
|  | var result = _addElementsToSet(set, element); | 
|  | if (result is InvalidConstant) { | 
|  | return result; | 
|  | } | 
|  | } | 
|  | var nodeType = node.staticType; | 
|  | DartType elementType = | 
|  | nodeType is InterfaceType && nodeType.typeArguments.isNotEmpty | 
|  | ? nodeType.typeArguments[0] | 
|  | : _typeProvider.dynamicType; | 
|  | InterfaceType setType = _typeProvider.setType(elementType); | 
|  | return DartObjectImpl(typeSystem, setType, SetState(set)); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitSimpleIdentifier(SimpleIdentifier node) { | 
|  | var value = _lexicalEnvironment?[node.name]; | 
|  | if (value != null) { | 
|  | return _instantiateFunctionTypeForSimpleIdentifier(node, value); | 
|  | } | 
|  |  | 
|  | return _getConstantValue( | 
|  | errorNode: node, | 
|  | expression: node, | 
|  | identifier: node, | 
|  | element: node.staticElement, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitSimpleStringLiteral(SimpleStringLiteral node) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.stringType, | 
|  | StringState(node.value), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitStringInterpolation(StringInterpolation node) { | 
|  | return _concatenateNodes(node, node.elements); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitSymbolLiteral(SymbolLiteral node) { | 
|  | StringBuffer buffer = StringBuffer(); | 
|  | List<Token> components = node.components; | 
|  | for (int i = 0; i < components.length; i++) { | 
|  | if (i > 0) { | 
|  | buffer.writeCharCode(0x2E); | 
|  | } | 
|  | buffer.write(components[i].lexeme); | 
|  | } | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.symbolType, | 
|  | SymbolState(buffer.toString()), | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Constant visitTypeLiteral(TypeLiteral node) => _getConstant(node.type); | 
|  |  | 
|  | /// Add the entries produced by evaluating the given collection [element] to | 
|  | /// the given [list]. Return an [InvalidConstant] if the evaluation of one or | 
|  | /// more of the elements failed. | 
|  | InvalidConstant? _addElementsToList( | 
|  | List<DartObject> list, CollectionElement element) { | 
|  | switch (element) { | 
|  | case Expression(): | 
|  | var expression = _getConstant(element); | 
|  | switch (expression) { | 
|  | case InvalidConstant(): | 
|  | return expression; | 
|  | case DartObjectImpl(): | 
|  | list.add(expression); | 
|  | return null; | 
|  | } | 
|  | case ForElement(): | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT, element); | 
|  | return InvalidConstant( | 
|  | element, CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT); | 
|  | case IfElement(): | 
|  | var condition = _getConstant(element.expression); | 
|  | switch (condition) { | 
|  | case InvalidConstant(): | 
|  | return condition; | 
|  | case DartObjectImpl(): | 
|  | var conditionValue = condition.toBoolValue(); | 
|  | if (conditionValue == null) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.NON_BOOL_CONDITION, element.expression); | 
|  | return InvalidConstant( | 
|  | element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION); | 
|  | } else if (conditionValue) { | 
|  | return _addElementsToList(list, element.thenElement); | 
|  | } else if (element.elseElement != null) { | 
|  | return _addElementsToList(list, element.elseElement!); | 
|  | } | 
|  | // There's no else element, but the condition value is false. | 
|  | return null; | 
|  | } | 
|  | case MapLiteralEntry(): | 
|  | return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | case SpreadElement(): | 
|  | var spread = _getConstant(element.expression); | 
|  | switch (spread) { | 
|  | case InvalidConstant(): | 
|  | return spread; | 
|  | case DartObjectImpl(): | 
|  | var listValue = spread.toListValue(); | 
|  | if (listValue == null) { | 
|  | return InvalidConstant(element.expression, | 
|  | CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET); | 
|  | } | 
|  | list.addAll(listValue); | 
|  | return null; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Add the entries produced by evaluating the given map [element] to the | 
|  | /// given [map]. Return an [InvalidConstant] if the evaluation of one or | 
|  | /// more of the elements failed. | 
|  | InvalidConstant? _addElementsToMap( | 
|  | Map<DartObjectImpl, DartObjectImpl> map, CollectionElement element) { | 
|  | switch (element) { | 
|  | case Expression(): | 
|  | return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | case ForElement(): | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT, element); | 
|  | return InvalidConstant( | 
|  | element, CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT); | 
|  | case IfElement(): | 
|  | var condition = _getConstant(element.expression); | 
|  | switch (condition) { | 
|  | case InvalidConstant(): | 
|  | return condition; | 
|  | case DartObjectImpl(): | 
|  | var conditionValue = condition.toBoolValue(); | 
|  | if (conditionValue == null) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.NON_BOOL_CONDITION, element.expression); | 
|  | return InvalidConstant( | 
|  | element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION); | 
|  | } else if (conditionValue) { | 
|  | return _addElementsToMap(map, element.thenElement); | 
|  | } else if (element.elseElement != null) { | 
|  | return _addElementsToMap(map, element.elseElement!); | 
|  | } | 
|  | // There's no else element, but the condition value is false. | 
|  | return null; | 
|  | } | 
|  | case MapLiteralEntry(): | 
|  | var keyResult = _getConstant(element.key); | 
|  | var valueResult = _getConstant(element.value); | 
|  | switch (keyResult) { | 
|  | case InvalidConstant(): | 
|  | return keyResult; | 
|  | case DartObjectImpl(): | 
|  | switch (valueResult) { | 
|  | case InvalidConstant(): | 
|  | return valueResult; | 
|  | case DartObjectImpl(): | 
|  | map[keyResult] = valueResult; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | case SpreadElement(): | 
|  | var spread = _getConstant(element.expression); | 
|  | switch (spread) { | 
|  | case InvalidConstant(): | 
|  | return spread; | 
|  | case DartObjectImpl(): | 
|  | var mapValue = spread.toMapValue(); | 
|  | if (mapValue == null) { | 
|  | return InvalidConstant(element.expression, | 
|  | CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP); | 
|  | } | 
|  | map.addAll(mapValue); | 
|  | return null; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Add the entries produced by evaluating the given collection [element] to | 
|  | /// the given [set]. Return an [InvalidConstant] if the evaluation of one or | 
|  | /// more of the elements failed. | 
|  | InvalidConstant? _addElementsToSet( | 
|  | Set<DartObject> set, CollectionElement element) { | 
|  | switch (element) { | 
|  | case Expression(): | 
|  | var expression = _getConstant(element); | 
|  | switch (expression) { | 
|  | case InvalidConstant(): | 
|  | return expression; | 
|  | case DartObjectImpl(): | 
|  | set.add(expression); | 
|  | return null; | 
|  | } | 
|  | case ForElement(): | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT, element); | 
|  | return InvalidConstant( | 
|  | element, CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT); | 
|  | case IfElement(): | 
|  | var condition = _getConstant(element.expression); | 
|  | switch (condition) { | 
|  | case InvalidConstant(): | 
|  | return condition; | 
|  | case DartObjectImpl(): | 
|  | var conditionValue = condition.toBoolValue(); | 
|  | if (conditionValue == null) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.NON_BOOL_CONDITION, element.expression); | 
|  | return InvalidConstant( | 
|  | element.expression, CompileTimeErrorCode.NON_BOOL_CONDITION); | 
|  | } else if (conditionValue) { | 
|  | return _addElementsToSet(set, element.thenElement); | 
|  | } else if (element.elseElement != null) { | 
|  | return _addElementsToSet(set, element.elseElement!); | 
|  | } | 
|  | // There's no else element, but the condition value is false. | 
|  | return null; | 
|  | } | 
|  | case MapLiteralEntry(): | 
|  | return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | case SpreadElement(): | 
|  | var spread = _getConstant(element.expression); | 
|  | switch (spread) { | 
|  | case InvalidConstant(): | 
|  | return spread; | 
|  | case DartObjectImpl(): | 
|  | var setValue = spread.toSetValue(); | 
|  | if (setValue == null) { | 
|  | return InvalidConstant(element.expression, | 
|  | CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET); | 
|  | } | 
|  | set.addAll(setValue); | 
|  | return null; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Returns the result of concatenating [astNodes]. | 
|  | /// | 
|  | /// If there's an [InvalidConstant] found, it will return early. | 
|  | Constant _concatenateNodes(Expression node, List<AstNode> astNodes) { | 
|  | Constant? result; | 
|  | for (AstNode astNode in astNodes) { | 
|  | var constant = _getConstant(astNode); | 
|  | if (constant is! DartObjectImpl) { | 
|  | return constant; | 
|  | } | 
|  |  | 
|  | if (result == null) { | 
|  | result = constant; | 
|  | } else if (result is DartObjectImpl) { | 
|  | result = _dartObjectComputer.concatenate(node, result, constant); | 
|  | if (result is InvalidConstant) { | 
|  | return result; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (result == null) { | 
|  | // No errors have been detected, but we did not concatenate any nodes. | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.stringType, | 
|  | StringState.UNKNOWN_VALUE, | 
|  | ); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /// Create an error associated with the given [node]. The error will have the | 
|  | /// given error [code]. | 
|  | void _error(AstNode node, ErrorCode? code) { | 
|  | if (code == null) { | 
|  | var parent = node.parent; | 
|  | var parent2 = parent?.parent; | 
|  | if (parent is ArgumentList && | 
|  | parent2 is InstanceCreationExpression && | 
|  | parent2.isConst) { | 
|  | code = CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT; | 
|  | } else { | 
|  | code = CompileTimeErrorCode.INVALID_CONSTANT; | 
|  | } | 
|  | } | 
|  | _errorReporter.reportErrorForNode(code, node); | 
|  | } | 
|  |  | 
|  | /// Return a [Constant], evaluated by the [ConstantVisitor]. | 
|  | /// | 
|  | /// The [ConstantVisitor] shouldn't return any `null` values even though | 
|  | /// [UnifyingAstVisitor] allows it. If we encounter an unexpected `null` | 
|  | /// value, we will return an [InvalidConstant] instead. | 
|  | Constant _getConstant(AstNode node) { | 
|  | var result = node.accept(this); | 
|  | if (result == null) { | 
|  | // Should never reach this. | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /// Returns a [Constant] based on the [element] provided. | 
|  | /// | 
|  | /// The [errorNode] is the node to be used if an error needs to be reported, | 
|  | /// the [expression] is used to identify type parameter errors, and | 
|  | /// [identifier] to determine the constant of any [ExecutableElement]s. | 
|  | /// | 
|  | /// TODO(kallentu): Revisit this method and clean it up a bit. | 
|  | Constant _getConstantValue({ | 
|  | required AstNode errorNode, | 
|  | required Expression? expression, | 
|  | required SimpleIdentifier? identifier, | 
|  | required Element? element, | 
|  | DartType? givenType, | 
|  | }) { | 
|  | element = element?.declaration; | 
|  | var variableElement = | 
|  | element is PropertyAccessorElement ? element.variable : element; | 
|  |  | 
|  | // TODO(srawlins): Remove this check when [FunctionReference]s are inserted | 
|  | // for generic function instantiation for pre-constructor-references code. | 
|  | if (expression is SimpleIdentifier && | 
|  | (expression.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ?? | 
|  | false)) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _error(expression, null); | 
|  | return InvalidConstant(expression, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  |  | 
|  | if (variableElement is VariableElementImpl) { | 
|  | // We access values of constant variables here in two cases: when we | 
|  | // compute values of other constant variables, or when we compute values | 
|  | // and errors for other constant expressions. In either case we have | 
|  | // already computed values of all dependencies first (or detect a cycle), | 
|  | // so the value has already been computed and we can just return it. | 
|  | var result = variableElement.evaluationResult; | 
|  | if (variableElement.isConst && result != null) { | 
|  | var value = result.value; | 
|  | if (value == null || identifier == null) { | 
|  | return InvalidConstant( | 
|  | errorNode, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | return _instantiateFunctionTypeForSimpleIdentifier(identifier, value); | 
|  | } | 
|  | } else if (variableElement is ConstructorElementImpl && | 
|  | expression != null) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | expression.typeOrThrow, | 
|  | FunctionState(variableElement), | 
|  | ); | 
|  | } else if (variableElement is ExecutableElementImpl) { | 
|  | if (variableElement.isStatic) { | 
|  | var rawType = DartObjectImpl( | 
|  | typeSystem, | 
|  | variableElement.type, | 
|  | FunctionState(variableElement), | 
|  | ); | 
|  | if (identifier == null) { | 
|  | return InvalidConstant( | 
|  | errorNode, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | return _instantiateFunctionTypeForSimpleIdentifier(identifier, rawType); | 
|  | } | 
|  | } else if (variableElement is InterfaceElement) { | 
|  | var type = givenType ?? | 
|  | variableElement.instantiate( | 
|  | typeArguments: variableElement.typeParameters | 
|  | .map((t) => _typeProvider.dynamicType) | 
|  | .toFixedList(), | 
|  | nullabilitySuffix: NullabilitySuffix.star, | 
|  | ); | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(type), | 
|  | ); | 
|  | } else if (variableElement is DynamicElementImpl) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(_typeProvider.dynamicType), | 
|  | ); | 
|  | } else if (variableElement is TypeAliasElement) { | 
|  | var type = givenType ?? | 
|  | variableElement.instantiate( | 
|  | typeArguments: variableElement.typeParameters | 
|  | .map((t) => t.bound ?? _typeProvider.dynamicType) | 
|  | .toList(), | 
|  | nullabilitySuffix: NullabilitySuffix.star, | 
|  | ); | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(type), | 
|  | ); | 
|  | } else if (variableElement is NeverElementImpl) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(_typeProvider.neverType), | 
|  | ); | 
|  | } else if (variableElement is TypeParameterElement) { | 
|  | // Constants may refer to type parameters only if the constructor-tearoffs | 
|  | // feature is enabled. | 
|  | if (_library.featureSet.isEnabled(Feature.constructor_tearoffs)) { | 
|  | var typeArgument = _lexicalTypeEnvironment?[variableElement]; | 
|  | if (typeArgument != null) { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | _typeProvider.typeType, | 
|  | TypeState(typeArgument), | 
|  | ); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO(https://github.com/dart-lang/sdk/issues/47061): Use a specific | 
|  | // error code. | 
|  | final errorNode2 = evaluationEngine.configuration.errorNode(errorNode); | 
|  | _error(errorNode2, null); | 
|  | return InvalidConstant(errorNode2, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  |  | 
|  | InvalidConstant? _getDeferredLibraryError( | 
|  | AstNode node, SyntacticEntity errorTarget) { | 
|  | var errorCode = () { | 
|  | AstNode? previous; | 
|  | for (AstNode? current = node; current != null;) { | 
|  | if (current is Annotation) { | 
|  | return CompileTimeErrorCode | 
|  | .INVALID_ANNOTATION_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is ConstantContextForExpressionImpl) { | 
|  | return CompileTimeErrorCode | 
|  | .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is DefaultFormalParameter) { | 
|  | return CompileTimeErrorCode | 
|  | .NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is IfElement && current.expression == node) { | 
|  | return CompileTimeErrorCode | 
|  | .IF_ELEMENT_CONDITION_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is ListLiteral) { | 
|  | return CompileTimeErrorCode | 
|  | .NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is MapLiteralEntry) { | 
|  | if (previous == current.key) { | 
|  | return CompileTimeErrorCode | 
|  | .NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY; | 
|  | } else { | 
|  | return CompileTimeErrorCode | 
|  | .NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY; | 
|  | } | 
|  | } else if (current is SetOrMapLiteral) { | 
|  | return CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is SpreadElement) { | 
|  | return CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is SwitchCase) { | 
|  | return CompileTimeErrorCode | 
|  | .NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is SwitchPatternCase) { | 
|  | return CompileTimeErrorCode.PATTERN_CONSTANT_FROM_DEFERRED_LIBRARY; | 
|  | } else if (current is VariableDeclaration) { | 
|  | return CompileTimeErrorCode | 
|  | .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY; | 
|  | } | 
|  | previous = current; | 
|  | current = current.parent; | 
|  | } | 
|  | }(); | 
|  | if (errorCode != null) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForOffset( | 
|  | errorCode, | 
|  | errorTarget.offset, | 
|  | errorTarget.length, | 
|  | ); | 
|  | return InvalidConstant(node, errorCode); | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | /// If the type of [value] is a generic [FunctionType], and [node] has type | 
|  | /// argument types, returns [value] type-instantiated with those [node]'s | 
|  | /// type argument types, otherwise returns [value]. | 
|  | DartObjectImpl _instantiateFunctionType( | 
|  | FunctionReference node, DartObjectImpl value) { | 
|  | var functionElement = value.toFunctionValue(); | 
|  | if (functionElement is! ExecutableElement) { | 
|  | return value; | 
|  | } | 
|  | var valueType = functionElement.type; | 
|  | if (valueType.typeFormals.isNotEmpty) { | 
|  | var typeArgumentTypes = node.typeArgumentTypes; | 
|  | if (typeArgumentTypes != null && typeArgumentTypes.isNotEmpty) { | 
|  | var instantiatedType = | 
|  | functionElement.type.instantiate(typeArgumentTypes); | 
|  | var substitution = _substitution; | 
|  | if (substitution != null) { | 
|  | instantiatedType = | 
|  | substitution.substituteType(instantiatedType) as FunctionType; | 
|  | } | 
|  | return value.typeInstantiate( | 
|  | typeSystem, instantiatedType, typeArgumentTypes); | 
|  | } | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /// If the type of [value] is a generic [FunctionType], and [node] is a | 
|  | /// [SimpleIdentifier] with tear-off type argument types, returns [value] | 
|  | /// type-instantiated with those [node]'s tear-off type argument types, | 
|  | /// otherwise returns [value]. | 
|  | Constant _instantiateFunctionTypeForSimpleIdentifier( | 
|  | SimpleIdentifier node, DartObjectImpl value) { | 
|  | // TODO(srawlins): When all code uses [FunctionReference]s generated via | 
|  | // generic function instantiation, remove this method and all call sites. | 
|  | var functionElement = value.toFunctionValue(); | 
|  | if (functionElement is! ExecutableElement) { | 
|  | return value; | 
|  | } | 
|  | var valueType = functionElement.type; | 
|  | if (valueType.typeFormals.isNotEmpty) { | 
|  | var tearOffTypeArgumentTypes = node.tearOffTypeArgumentTypes; | 
|  | if (tearOffTypeArgumentTypes != null && | 
|  | tearOffTypeArgumentTypes.isNotEmpty) { | 
|  | var instantiatedType = | 
|  | functionElement.type.instantiate(tearOffTypeArgumentTypes); | 
|  | return value.typeInstantiate( | 
|  | typeSystem, instantiatedType, tearOffTypeArgumentTypes); | 
|  | } | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /// Return `true` if the given [targetResult] represents a string and the | 
|  | /// [identifier] is "length". | 
|  | bool _isStringLength( | 
|  | DartObjectImpl targetResult, SimpleIdentifier identifier) { | 
|  | final targetType = targetResult.type; | 
|  | if (!(targetType is InterfaceType && | 
|  | targetType.element == _typeProvider.stringElement)) { | 
|  | return false; | 
|  | } | 
|  | return identifier.name == 'length' && | 
|  | identifier.staticElement?.enclosingElement2 is! ExtensionElement; | 
|  | } | 
|  |  | 
|  | /// Returns the first not-potentially constant error found with [node] or | 
|  | /// `null` if there are none. | 
|  | InvalidConstant? _reportNotPotentialConstants(AstNode node) { | 
|  | var notPotentiallyConstants = getNotPotentiallyConstants( | 
|  | node, | 
|  | featureSet: _library.featureSet, | 
|  | ); | 
|  | if (notPotentiallyConstants.isEmpty) return null; | 
|  |  | 
|  | // TODO(kallentu): Don't report error here. | 
|  | // Only report the first invalid constant we see. | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.INVALID_CONSTANT, | 
|  | notPotentiallyConstants.first, | 
|  | ); | 
|  | return InvalidConstant( | 
|  | notPotentiallyConstants.first, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  |  | 
|  | /// Return the value of the given [expression], or a representation of 'null' | 
|  | /// if the expression cannot be evaluated. | 
|  | DartObjectImpl _valueOf(Expression expression) { | 
|  | var expressionValue = expression.accept(this); | 
|  | if (expressionValue is DartObjectImpl) { | 
|  | return expressionValue; | 
|  | } | 
|  | return ConstantEvaluationEngine._nullObject(_library); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A utility class that contains methods for manipulating instances of a Dart | 
|  | /// class and for collecting errors during evaluation. | 
|  | class DartObjectComputer { | 
|  | final TypeSystemImpl _typeSystem; | 
|  | final FeatureSet _featureSet; | 
|  |  | 
|  | /// The error reporter that we are using to collect errors. | 
|  | final ErrorReporter _errorReporter; | 
|  |  | 
|  | DartObjectComputer(this._typeSystem, this._featureSet, this._errorReporter); | 
|  |  | 
|  | Constant add(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.add(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return the result of applying boolean conversion to the | 
|  | /// [evaluationResult]. The [node] is the node against which errors should be | 
|  | /// reported. | 
|  | Constant applyBooleanConversion( | 
|  | AstNode node, DartObjectImpl evaluationResult) { | 
|  | try { | 
|  | return evaluationResult.convertToBool(_typeSystem); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant bitNot(Expression node, DartObjectImpl evaluationResult) { | 
|  | try { | 
|  | return evaluationResult.bitNot(_typeSystem); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant castToType( | 
|  | AsExpression node, DartObjectImpl expression, DartObjectImpl type) { | 
|  | try { | 
|  | return expression.castToType(_typeSystem, type); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant concatenate(Expression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.concatenate(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant divide(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.divide(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant eagerAnd(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.eagerAnd(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant eagerOr(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.eagerOr(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | DartObjectImpl? eagerQuestionQuestion(Expression node, | 
|  | DartObjectImpl? leftOperand, DartObjectImpl? rightOperand) { | 
|  | if (leftOperand != null && rightOperand != null) { | 
|  | if (leftOperand.isNull) { | 
|  | return rightOperand; | 
|  | } | 
|  | return leftOperand; | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | Constant eagerXor(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.eagerXor(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant equalEqual(Expression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.equalEqual(_typeSystem, _featureSet, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant greaterThan(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.greaterThan(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant greaterThanOrEqual(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.greaterThanOrEqual(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant integerDivide(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.integerDivide(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant isIdentical(Expression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.isIdentical2(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant lazyAnd(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl Function() rightOperandComputer) { | 
|  | try { | 
|  | return leftOperand.lazyAnd(_typeSystem, rightOperandComputer); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant lazyOr(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl Function() rightOperandComputer) { | 
|  | try { | 
|  | return leftOperand.lazyOr(_typeSystem, rightOperandComputer); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant lazyQuestionQuestion(Expression node, DartObjectImpl leftOperand, | 
|  | Constant Function() rightOperandComputer) { | 
|  | if (leftOperand.isNull) { | 
|  | return rightOperandComputer(); | 
|  | } | 
|  | return leftOperand; | 
|  | } | 
|  |  | 
|  | Constant lessThan(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.lessThan(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant lessThanOrEqual(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.lessThanOrEqual(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant logicalNot(Expression node, DartObjectImpl evaluationResult) { | 
|  | try { | 
|  | return evaluationResult.logicalNot(_typeSystem); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant logicalShiftRight(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.logicalShiftRight(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant minus(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.minus(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant negated(Expression node, DartObjectImpl evaluationResult) { | 
|  | try { | 
|  | return evaluationResult.negated(_typeSystem); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant notEqual(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.notEqual(_typeSystem, _featureSet, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant performToString(AstNode node, DartObjectImpl evaluationResult) { | 
|  | try { | 
|  | return evaluationResult.performToString(_typeSystem); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant remainder(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.remainder(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant shiftLeft(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.shiftLeft(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant shiftRight(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.shiftRight(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return the result of invoking the 'length' getter on the | 
|  | /// [evaluationResult]. The [node] is the node against which errors should be | 
|  | /// reported. | 
|  | EvaluationResultImpl? stringLength( | 
|  | Expression node, EvaluationResultImpl evaluationResult) { | 
|  | var value = evaluationResult.value; | 
|  | if (value != null) { | 
|  | try { | 
|  | return EvaluationResultImpl(value.stringLength(_typeSystem)); | 
|  | } on EvaluationException catch (exception) { | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | } | 
|  | } | 
|  | return EvaluationResultImpl(null); | 
|  | } | 
|  |  | 
|  | Constant times(BinaryExpression node, DartObjectImpl leftOperand, | 
|  | DartObjectImpl rightOperand) { | 
|  | try { | 
|  | return leftOperand.times(_typeSystem, rightOperand); | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant typeInstantiate( | 
|  | DartObjectImpl function, | 
|  | List<DartType> typeArguments, | 
|  | Expression node, | 
|  | ) { | 
|  | var rawType = function.type; | 
|  | if (rawType is FunctionType) { | 
|  | if (typeArguments.length != rawType.typeFormals.length) { | 
|  | return InvalidConstant( | 
|  | node, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION); | 
|  | } | 
|  | var type = rawType.instantiate(typeArguments); | 
|  | return function.typeInstantiate(_typeSystem, type, typeArguments); | 
|  | } else { | 
|  | return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
|  | } | 
|  | } | 
|  |  | 
|  | Constant typeTest( | 
|  | IsExpression node, DartObjectImpl expression, DartObjectImpl type) { | 
|  | try { | 
|  | DartObjectImpl result = expression.hasType(_typeSystem, type); | 
|  | if (node.notOperator != null) { | 
|  | return result.logicalNot(_typeSystem); | 
|  | } | 
|  | return result; | 
|  | } on EvaluationException catch (exception) { | 
|  | // TODO(kallentu): Don't report error here. | 
|  | _errorReporter.reportErrorForNode(exception.errorCode, node); | 
|  | return InvalidConstant(node, exception.errorCode); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The result of attempting to evaluate an expression. | 
|  | class EvaluationResult { | 
|  | // TODO(brianwilkerson) Merge with EvaluationResultImpl | 
|  | /// The value of the expression. | 
|  | final DartObject? value; | 
|  |  | 
|  | /// The errors that should be reported for the expression(s) that were | 
|  | /// evaluated. | 
|  | final List<AnalysisError>? _errors; | 
|  |  | 
|  | /// Initialize a newly created result object with the given [value] and set of | 
|  | /// [_errors]. Clients should use one of the factory methods: [forErrors] and | 
|  | /// [forValue]. | 
|  | EvaluationResult(this.value, this._errors); | 
|  |  | 
|  | /// Return a list containing the errors that should be reported for the | 
|  | /// expression(s) that were evaluated. If there are no such errors, the list | 
|  | /// will be empty. The list can be empty even if the expression is not a valid | 
|  | /// compile time constant if the errors would have been reported by other | 
|  | /// parts of the analysis engine. | 
|  | List<AnalysisError> get errors => _errors ?? AnalysisError.NO_ERRORS; | 
|  |  | 
|  | /// Return `true` if the expression is a compile-time constant expression that | 
|  | /// would not throw an exception when evaluated. | 
|  | bool get isValid => _errors == null; | 
|  |  | 
|  | /// Return an evaluation result representing the result of evaluating an | 
|  | /// expression that is not a compile-time constant because of the given | 
|  | /// [errors]. | 
|  | static EvaluationResult forErrors(List<AnalysisError> errors) => | 
|  | EvaluationResult(null, errors); | 
|  |  | 
|  | /// Return an evaluation result representing the result of evaluating an | 
|  | /// expression that is a compile-time constant that evaluates to the given | 
|  | /// [value]. | 
|  | static EvaluationResult forValue(DartObject value) => | 
|  | EvaluationResult(value, null); | 
|  | } | 
|  |  | 
|  | /// The result of attempting to evaluate a expression. | 
|  | class EvaluationResultImpl { | 
|  | /// The errors encountered while trying to evaluate the compile time constant. | 
|  | /// These errors may or may not have prevented the expression from being a | 
|  | /// valid compile time constant. | 
|  | final List<AnalysisError> _errors; | 
|  |  | 
|  | /// The value of the expression, or `null` if the value couldn't be computed | 
|  | /// due to errors. | 
|  | final DartObjectImpl? value; | 
|  |  | 
|  | EvaluationResultImpl( | 
|  | this.value, [ | 
|  | this._errors = const [], | 
|  | ]); | 
|  |  | 
|  | List<AnalysisError> get errors => _errors; | 
|  |  | 
|  | bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) { | 
|  | if (value != null) { | 
|  | if (result.value == null) { | 
|  | return false; | 
|  | } | 
|  | return value == result.value; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | String toString() { | 
|  | if (value == null) { | 
|  | return "error"; | 
|  | } | 
|  | return value.toString(); | 
|  | } | 
|  | } | 
|  |  | 
|  | class _EnumConstant { | 
|  | final int index; | 
|  | final String name; | 
|  |  | 
|  | _EnumConstant({ | 
|  | required this.index, | 
|  | required this.name, | 
|  | }); | 
|  | } | 
|  |  | 
|  | /// The result of evaluation the initializers declared on a const constructor. | 
|  | class _InitializersEvaluationResult { | 
|  | /// The result of a const evaluation of an initializer, if one was performed, | 
|  | /// otherwise `null`. | 
|  | /// | 
|  | /// If a redirecting initializer which redirects to a const constructor was | 
|  | /// encountered, [result] is the result of evaluating that call. | 
|  | /// | 
|  | /// If an assert initializer is encountered, and the evaluation of this assert | 
|  | /// results in an error or a `false` value, [result] is `null`. | 
|  | final DartObjectImpl? result; | 
|  |  | 
|  | /// Whether evaluation of the const instance creation expression which led to | 
|  | /// evaluating constructor initializers is complete. | 
|  | /// | 
|  | /// If `true`, `result` should be used as the result of said const instance | 
|  | /// creation expression evaluation. | 
|  | final bool evaluationIsComplete; | 
|  |  | 
|  | /// If a superinitializer was encountered, the name of the super constructor, | 
|  | /// otherwise `null`. | 
|  | final String? superName; | 
|  |  | 
|  | /// If a superinitializer was encountered, the arguments passed to the super | 
|  | /// constructor, otherwise `null`. | 
|  | final List<Expression>? superArguments; | 
|  |  | 
|  | _InitializersEvaluationResult( | 
|  | this.result, { | 
|  | required this.evaluationIsComplete, | 
|  | this.superName, | 
|  | this.superArguments, | 
|  | }); | 
|  | } | 
|  |  | 
|  | /// An evaluator which evaluates a const instance creation expression. | 
|  | /// | 
|  | /// [_InstanceCreationEvaluator.evaluate] is the main entrypoint. | 
|  | class _InstanceCreationEvaluator { | 
|  | /// Parameter to "fromEnvironment" methods that denotes the default value. | 
|  | static const String _defaultValueParam = 'defaultValue'; | 
|  |  | 
|  | /// Source of RegExp matching declarable operator names. | 
|  | /// From sdk/lib/internal/symbol.dart. | 
|  | static const String _operatorPattern = | 
|  | "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)"; | 
|  |  | 
|  | /// Source of RegExp matching any public identifier. | 
|  | /// From sdk/lib/internal/symbol.dart. | 
|  | static const String _publicIdentifierPattern = | 
|  | "(?!$_reservedWordPattern\\b(?!\\\$))[a-zA-Z\$][\\w\$]*"; | 
|  |  | 
|  | /// RegExp that validates a non-empty non-private symbol. | 
|  | /// From sdk/lib/internal/symbol.dart. | 
|  | static final RegExp _publicSymbolPattern = RegExp('^(?:$_operatorPattern\$|' | 
|  | '$_publicIdentifierPattern(?:=?\$|[.](?!\$)))+?\$'); | 
|  |  | 
|  | /// Source of RegExp matching Dart reserved words. | 
|  | /// From sdk/lib/internal/symbol.dart. | 
|  | static const String _reservedWordPattern = | 
|  | "(?:assert|break|c(?:a(?:se|tch)|lass|on(?:st|tinue))|" | 
|  | "d(?:efault|o)|e(?:lse|num|xtends)|f(?:alse|inal(?:ly)?|or)|" | 
|  | "i[fns]|n(?:ew|ull)|ret(?:hrow|urn)|s(?:uper|witch)|t(?:h(?:is|row)|" | 
|  | "r(?:ue|y))|v(?:ar|oid)|w(?:hile|ith))"; | 
|  |  | 
|  | final ConstantEvaluationEngine _evaluationEngine; | 
|  |  | 
|  | /// The set of variables declared on the command line using '-D'. | 
|  | final DeclaredVariables _declaredVariables; | 
|  |  | 
|  | final LibraryElementImpl _library; | 
|  |  | 
|  | final ErrorReporter _errorReporter; | 
|  |  | 
|  | final BooleanErrorListener _externalErrorListener = BooleanErrorListener(); | 
|  |  | 
|  | /// An error reporter for errors determined while computing values for field | 
|  | /// initializers, or default values for the constructor parameters. | 
|  | /// | 
|  | /// Such errors cannot be reported into [_errorReporter], because they usually | 
|  | /// happen in a different source. But they still should cause a constant | 
|  | /// evaluation error for the current node. | 
|  | late final ErrorReporter _externalErrorReporter = ErrorReporter( | 
|  | _externalErrorListener, | 
|  | _constructor.source, | 
|  | isNonNullableByDefault: _library.isNonNullableByDefault, | 
|  | ); | 
|  |  | 
|  | late final ConstantVisitor _initializerVisitor = ConstantVisitor( | 
|  | _evaluationEngine, | 
|  | _constructor.library as LibraryElementImpl, | 
|  | _externalErrorReporter, | 
|  | lexicalEnvironment: _parameterMap, | 
|  | lexicalTypeEnvironment: _typeParameterMap, | 
|  | substitution: Substitution.fromInterfaceType(definingType), | 
|  | ); | 
|  |  | 
|  | /// The node used for most error reporting. | 
|  | final AstNode _errorNode; | 
|  |  | 
|  | final ConstructorElement _constructor; | 
|  |  | 
|  | final List<DartType>? _typeArguments; | 
|  |  | 
|  | final ConstructorInvocation _invocation; | 
|  |  | 
|  | final Map<String, NamedExpression> _namedNodes; | 
|  |  | 
|  | final Map<String, DartObjectImpl> _namedValues; | 
|  |  | 
|  | final List<DartObjectImpl> _argumentValues; | 
|  |  | 
|  | final Map<TypeParameterElement, DartType> _typeParameterMap = HashMap(); | 
|  |  | 
|  | final Map<String, DartObjectImpl> _parameterMap = HashMap(); | 
|  |  | 
|  | final Map<String, DartObjectImpl> _fieldMap = HashMap(); | 
|  |  | 
|  | /// Constructor for [_InstanceCreationEvaluator]. | 
|  | /// | 
|  | /// This constructor is private, as the entry point for using a | 
|  | /// [_InstanceCreationEvaluator] is the static method, | 
|  | /// [_InstanceCreationEvaluator.evaluate]. | 
|  | _InstanceCreationEvaluator._( | 
|  | this._evaluationEngine, | 
|  | this._declaredVariables, | 
|  | this._errorReporter, | 
|  | this._library, | 
|  | this._errorNode, | 
|  | this._constructor, | 
|  | this._typeArguments, { | 
|  | required Map<String, NamedExpression> namedNodes, | 
|  | required Map<String, DartObjectImpl> namedValues, | 
|  | required List<DartObjectImpl> argumentValues, | 
|  | required ConstructorInvocation invocation, | 
|  | })  : _namedNodes = namedNodes, | 
|  | _namedValues = namedValues, | 
|  | _argumentValues = argumentValues, | 
|  | _invocation = invocation; | 
|  |  | 
|  | NamedInstanceType get definingType => _constructor.returnType2; | 
|  |  | 
|  | DartObjectImpl? get firstArgument => _argumentValues[0]; | 
|  |  | 
|  | TypeProvider get typeProvider => _library.typeProvider; | 
|  |  | 
|  | TypeSystemImpl get typeSystem => _library.typeSystem; | 
|  |  | 
|  | /// Evaluates this constructor call as a factory constructor call. | 
|  | DartObjectImpl? evaluateFactoryConstructorCall( | 
|  | List<Expression> arguments, { | 
|  | required bool isNullSafe, | 
|  | }) { | 
|  | final definingClass = _constructor.enclosingElement2; | 
|  | var argumentCount = arguments.length; | 
|  | final definingType = this.definingType; | 
|  | if (definingType is InterfaceType && | 
|  | _constructor.name == "fromEnvironment") { | 
|  | if (!_checkFromEnvironmentArguments(arguments, definingType)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | return null; | 
|  | } | 
|  | String? variableName = | 
|  | argumentCount < 1 ? null : firstArgument?.toStringValue(); | 
|  | if (definingClass == typeProvider.boolElement) { | 
|  | // Special case: https://github.com/dart-lang/sdk/issues/50045 | 
|  | if (variableName == 'dart.library.js_util') { | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | typeProvider.boolType, | 
|  | BoolState.UNKNOWN_VALUE, | 
|  | ); | 
|  | } | 
|  | return FromEnvironmentEvaluator(typeSystem, _declaredVariables) | 
|  | .getBool2(variableName, _namedValues, _constructor); | 
|  | } else if (definingClass == typeProvider.intElement) { | 
|  | return FromEnvironmentEvaluator(typeSystem, _declaredVariables) | 
|  | .getInt2(variableName, _namedValues, _constructor); | 
|  | } else if (definingClass == typeProvider.stringElement) { | 
|  | return FromEnvironmentEvaluator(typeSystem, _declaredVariables) | 
|  | .getString2(variableName, _namedValues, _constructor); | 
|  | } | 
|  | } else if (_constructor.name == 'hasEnvironment' && | 
|  | definingClass == typeProvider.boolElement) { | 
|  | var name = argumentCount < 1 ? null : firstArgument?.toStringValue(); | 
|  | return FromEnvironmentEvaluator(typeSystem, _declaredVariables) | 
|  | .hasEnvironment(name); | 
|  | } else if (_constructor.name == "" && | 
|  | definingClass == typeProvider.symbolElement && | 
|  | argumentCount == 1) { | 
|  | if (!_checkSymbolArguments(arguments, isNullSafe: isNullSafe)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | return null; | 
|  | } | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | definingType, | 
|  | SymbolState(firstArgument?.toStringValue()), | 
|  | ); | 
|  | } | 
|  | // Either it's an external const factory constructor that we can't | 
|  | // emulate, or an error occurred (a cycle, or a const constructor trying to | 
|  | // delegate to a non-const constructor). | 
|  | // | 
|  | // In the former case, the best we can do is consider it an unknown value. | 
|  | // In the latter case, the error has already been reported, so considering | 
|  | // it an unknown value will suppress further errors. | 
|  | return DartObjectImpl.validWithUnknownValue(typeSystem, definingType); | 
|  | } | 
|  |  | 
|  | DartObjectImpl? evaluateGenerativeConstructorCall( | 
|  | List<Expression> arguments) { | 
|  | // Start with final fields that are initialized at their declaration site. | 
|  | _checkFields(); | 
|  |  | 
|  | _checkTypeParameters(); | 
|  | _checkParameters(arguments); | 
|  | var evaluationResult = _checkInitializers(); | 
|  | if (evaluationResult.evaluationIsComplete) { | 
|  | return evaluationResult.result; | 
|  | } | 
|  | _checkSuperConstructorCall( | 
|  | superName: evaluationResult.superName, | 
|  | superArguments: evaluationResult.superArguments); | 
|  | if (_externalErrorListener.errorReported) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | } | 
|  | return DartObjectImpl( | 
|  | typeSystem, | 
|  | definingType, | 
|  | GenericState(definingType, _fieldMap, invocation: _invocation), | 
|  | ); | 
|  | } | 
|  |  | 
|  | void _addImplicitArgumentsFromSuperFormals(List<Expression> superArguments) { | 
|  | var positionalIndex = 0; | 
|  | for (var parameter in _constructor.parameters) { | 
|  | if (parameter is SuperFormalParameterElement) { | 
|  | var value = SimpleIdentifierImpl( | 
|  | StringToken(TokenType.STRING, parameter.name, -1), | 
|  | ) | 
|  | ..staticElement = parameter | 
|  | ..staticType = parameter.type; | 
|  | if (parameter.isPositional) { | 
|  | superArguments.insert(positionalIndex++, value); | 
|  | } else { | 
|  | superArguments.add( | 
|  | NamedExpressionImpl( | 
|  | name: LabelImpl( | 
|  | label: SimpleIdentifierImpl( | 
|  | StringToken(TokenType.STRING, parameter.name, -1), | 
|  | )..staticElement = parameter, | 
|  | colon: StringToken(TokenType.COLON, ':', -1), | 
|  | ), | 
|  | expression: value, | 
|  | )..staticType = value.typeOrThrow, | 
|  | ); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void _checkFields() { | 
|  | var fields = _constructor.enclosingElement2.fields; | 
|  | for (var field in fields) { | 
|  | if ((field.isFinal || field.isConst) && | 
|  | !field.isStatic && | 
|  | field is ConstFieldElementImpl) { | 
|  | var 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 (fieldValue == null) { | 
|  | continue; | 
|  | } | 
|  | // Match the value and the type. | 
|  | var fieldType = FieldMember.from(field, _constructor.returnType2).type; | 
|  | if (!typeSystem.runtimeTypeMatch(fieldValue, fieldType)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, | 
|  | _errorNode, | 
|  | [fieldValue.type, field.name, fieldType]); | 
|  | } | 
|  | _fieldMap[field.name] = fieldValue; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Check that the arguments to a call to `fromEnvironment()` are correct. | 
|  | /// | 
|  | /// The [arguments] are the AST nodes of the arguments. The [argumentValues] | 
|  | /// are the values of the unnamed arguments. The [namedArgumentValues] are the | 
|  | /// values of the named arguments. The [expectedDefaultValueType] is the | 
|  | /// allowed type of the "defaultValue" parameter (if present). Note: | 
|  | /// "defaultValue" is always allowed to be `null`. Return `true` if the | 
|  | /// arguments are correct, `false` otherwise. | 
|  | bool _checkFromEnvironmentArguments( | 
|  | List<Expression> arguments, | 
|  | InterfaceType expectedDefaultValueType, | 
|  | ) { | 
|  | var argumentCount = arguments.length; | 
|  | if (argumentCount < 1 || argumentCount > 2) { | 
|  | return false; | 
|  | } | 
|  | if (arguments[0] is NamedExpression) { | 
|  | return false; | 
|  | } | 
|  | if (firstArgument!.type != typeProvider.stringType) { | 
|  | return false; | 
|  | } | 
|  | if (argumentCount == 2) { | 
|  | var secondArgument = arguments[1]; | 
|  | if (secondArgument is NamedExpression) { | 
|  | if (!(secondArgument.name.label.name == _defaultValueParam)) { | 
|  | return false; | 
|  | } | 
|  | var defaultValueType = _namedValues[_defaultValueParam]!.type; | 
|  | if (!(defaultValueType == expectedDefaultValueType || | 
|  | defaultValueType == typeProvider.nullType)) { | 
|  | return false; | 
|  | } | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | _InitializersEvaluationResult _checkInitializers() { | 
|  | final definingType = this.definingType; | 
|  | if (definingType is! InterfaceType) { | 
|  | return _InitializersEvaluationResult(null, evaluationIsComplete: true); | 
|  | } | 
|  |  | 
|  | var constructorBase = _constructor.declaration as ConstructorElementImpl; | 
|  | // If we encounter a superinitializer, store the name of the constructor, | 
|  | // and the arguments. | 
|  | String? superName; | 
|  | List<Expression>? superArguments; | 
|  | for (var initializer in constructorBase.constantInitializers) { | 
|  | if (initializer is ConstructorFieldInitializer) { | 
|  | var initializerExpression = initializer.expression; | 
|  | var evaluationResult = | 
|  | initializerExpression.accept(_initializerVisitor); | 
|  | if (evaluationResult is DartObjectImpl) { | 
|  | var fieldName = initializer.fieldName.name; | 
|  | if (_fieldMap.containsKey(fieldName)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | } | 
|  | _fieldMap[fieldName] = evaluationResult; | 
|  | var getter = definingType.getGetter(fieldName); | 
|  | if (getter != null) { | 
|  | var field = getter.variable; | 
|  | if (!typeSystem.runtimeTypeMatch(evaluationResult, field.type)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, | 
|  | _errorNode, | 
|  | [evaluationResult.type, fieldName, field.type]); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | } | 
|  | } else if (initializer is SuperConstructorInvocation) { | 
|  | var name = initializer.constructorName; | 
|  | if (name != null) { | 
|  | superName = name.name; | 
|  | } | 
|  | superArguments = initializer.argumentList.arguments.toList(); | 
|  | _addImplicitArgumentsFromSuperFormals(superArguments); | 
|  | } else if (initializer is RedirectingConstructorInvocation) { | 
|  | // This is a redirecting constructor, so just evaluate the constructor | 
|  | // it redirects to. | 
|  | var constructor = initializer.staticElement; | 
|  | if (constructor != null && constructor.isConst) { | 
|  | // Instantiate the constructor with the in-scope type arguments. | 
|  | constructor = ConstructorMember.from(constructor, definingType); | 
|  | var result = _evaluationEngine.evaluateConstructorCall( | 
|  | _library, | 
|  | _errorNode, | 
|  | _typeArguments, | 
|  | initializer.argumentList.arguments, | 
|  | constructor, | 
|  | _initializerVisitor, | 
|  | _externalErrorReporter, | 
|  | invocation: _invocation); | 
|  | if (_externalErrorListener.errorReported) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | } | 
|  | return _InitializersEvaluationResult(result, | 
|  | evaluationIsComplete: true); | 
|  | } | 
|  | } else if (initializer is AssertInitializer) { | 
|  | var condition = initializer.condition; | 
|  | // TODO(kallentu): Rewrite this to handle the constant unwrapping. | 
|  | var evaluationConstant = condition.accept(_initializerVisitor); | 
|  | var evaluationResult = | 
|  | evaluationConstant is DartObjectImpl ? evaluationConstant : null; | 
|  | if (evaluationResult == null || | 
|  | !evaluationResult.isBool || | 
|  | evaluationResult.toBoolValue() == false) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | return _InitializersEvaluationResult(null, | 
|  | evaluationIsComplete: true); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (definingType.superclass != null && superArguments == null) { | 
|  | superArguments = []; | 
|  | _addImplicitArgumentsFromSuperFormals(superArguments); | 
|  | } | 
|  |  | 
|  | return _InitializersEvaluationResult(null, | 
|  | evaluationIsComplete: false, | 
|  | superName: superName, | 
|  | superArguments: superArguments); | 
|  | } | 
|  |  | 
|  | void _checkParameters(List<Expression> arguments) { | 
|  | var parameters = _constructor.parameters; | 
|  | var parameterCount = parameters.length; | 
|  |  | 
|  | for (var i = 0; i < parameterCount; i++) { | 
|  | var parameter = parameters[i]; | 
|  | var baseParameter = parameter.declaration; | 
|  | DartObjectImpl? argumentValue; | 
|  | AstNode? errorTarget; | 
|  | if (baseParameter.isNamed) { | 
|  | argumentValue = _namedValues[baseParameter.name]; | 
|  | errorTarget = _namedNodes[baseParameter.name]; | 
|  | } else if (i < _argumentValues.length) { | 
|  | argumentValue = _argumentValues[i]; | 
|  | errorTarget = arguments[i]; | 
|  | } | 
|  | // No argument node that we can direct error messages to, because we | 
|  | // are handling an optional parameter that wasn't specified.  So just | 
|  | // direct error messages to the constructor call. | 
|  | errorTarget ??= _errorNode; | 
|  | if (argumentValue == null && baseParameter is ParameterElementImpl) { | 
|  | // The parameter is an optional positional parameter for which no value | 
|  | // was provided, so use the default value. | 
|  | var evaluationResult = baseParameter.evaluationResult; | 
|  | if (evaluationResult == null) { | 
|  | // No default was provided, so the default value is null. | 
|  | argumentValue = ConstantEvaluationEngine._nullObject(_library); | 
|  | } else if (evaluationResult.value != null) { | 
|  | argumentValue = evaluationResult.value; | 
|  | } | 
|  | } | 
|  | if (argumentValue != null) { | 
|  | if (!typeSystem.runtimeTypeMatch(argumentValue, parameter.type)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, | 
|  | errorTarget, | 
|  | [argumentValue.type, parameter.type], | 
|  | ); | 
|  | } | 
|  | if (baseParameter.isInitializingFormal) { | 
|  | var field = (parameter as FieldFormalParameterElement).field; | 
|  | if (field != null) { | 
|  | var fieldType = field.type; | 
|  | if (fieldType != parameter.type) { | 
|  | // We've already checked that the argument can be assigned to the | 
|  | // parameter; we also need to check that it can be assigned to | 
|  | // the field. | 
|  | if (!typeSystem.runtimeTypeMatch(argumentValue, fieldType)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, | 
|  | errorTarget, | 
|  | [argumentValue.type, fieldType], | 
|  | ); | 
|  | } | 
|  | } | 
|  | var fieldName = field.name; | 
|  | if (_fieldMap.containsKey(fieldName)) { | 
|  | _errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, _errorNode); | 
|  | } | 
|  | _fieldMap[fieldName] = argumentValue; | 
|  | } | 
|  | } | 
|  | _parameterMap[baseParameter.name] = argumentValue; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Checks an explicit or implicit call to `super()`. | 
|  | /// | 
|  | /// If a superinitializer was declared on the constructor declaration, | 
|  | /// [superName] and [superArguments] are the name of the super constructor | 
|  | /// referenced therein, and the arguments passed to the super constructor. | 
|  | /// Otherwise these parameters are `null`. | 
|  | void _checkSuperConstructorCall({ | 
|  | required String? superName, | 
|  | required List<Expression>? superArguments, | 
|  | }) { | 
|  | final definingType = this.definingType; | 
|  | if (definingType is! InterfaceType) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | var superclass = definingType.superclass; | 
|  | if (superclass != null && !superclass.isDartCoreObject) { | 
|  | var superConstructor = | 
|  | superclass.lookUpConstructor(superName, _constructor.library); | 
|  | if (superConstructor == null) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | var constructor = _constructor; | 
|  | if (constructor is ConstructorMember && constructor.isLegacy) { | 
|  | superConstructor = | 
|  | Member.legacy(superConstructor) as ConstructorElement; | 
|  | } | 
|  | if (superConstructor.isConst) { | 
|  | var evaluationResult = _evaluationEngine.evaluateConstructorCall( | 
|  | _library, | 
|  | _errorNode, | 
|  | superclass.typeArguments, | 
|  | superArguments ?? const [], | 
|  | superConstructor, | 
|  | _initializerVisitor, | 
|  | _externalErrorReporter, | 
|  | ); | 
|  | if (evaluationResult != null) { | 
|  | _fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Checks that the arguments to a call to [Symbol.new] are correct. | 
|  | /// | 
|  | /// The [arguments] are the AST nodes of the arguments. The [argumentValues] | 
|  | /// are the values of the unnamed arguments. The [namedArgumentValues] are the | 
|  | /// values of the named arguments. Returns `true` if the arguments are | 
|  | /// correct, `false` otherwise. | 
|  | bool _checkSymbolArguments(List<Expression> arguments, | 
|  | {required bool isNullSafe}) { | 
|  | if (arguments.length != 1) { | 
|  | return false; | 
|  | } | 
|  | if (arguments[0] is NamedExpression) { | 
|  | return false; | 
|  | } | 
|  | if (firstArgument!.type != typeProvider.stringType) { | 
|  | return false; | 
|  | } | 
|  | var name = firstArgument?.toStringValue(); | 
|  | if (name == null) { | 
|  | return false; | 
|  | } | 
|  | if (isNullSafe) { | 
|  | return true; | 
|  | } | 
|  | return _isValidPublicSymbol(name); | 
|  | } | 
|  |  | 
|  | void _checkTypeParameters() { | 
|  | var typeParameters = _constructor.enclosingElement2.typeParameters; | 
|  | var typeArguments = _typeArguments; | 
|  | if (typeParameters.isNotEmpty && | 
|  | typeArguments != null && | 
|  | typeParameters.length == typeArguments.length) { | 
|  | for (int i = 0; i < typeParameters.length; i++) { | 
|  | var typeParameter = typeParameters[i]; | 
|  | var typeArgument = typeArguments[i]; | 
|  | _typeParameterMap[typeParameter] = typeArgument; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Evaluates [node] as an instance creation expression using [constructor]. | 
|  | static DartObjectImpl? evaluate( | 
|  | ConstantEvaluationEngine evaluationEngine, | 
|  | DeclaredVariables declaredVariables, | 
|  | ErrorReporter errorReporter, | 
|  | LibraryElementImpl library, | 
|  | AstNode node, | 
|  | ConstructorElement constructor, | 
|  | List<DartType>? typeArguments, | 
|  | List<Expression> arguments, | 
|  | ConstantVisitor constantVisitor, { | 
|  | required bool isNullSafe, | 
|  | ConstructorInvocation? invocation, | 
|  | }) { | 
|  | if (!constructor.isConst) { | 
|  | if (node is InstanceCreationExpression && node.keyword != null) { | 
|  | errorReporter.reportErrorForToken( | 
|  | CompileTimeErrorCode.CONST_WITH_NON_CONST, node.keyword!); | 
|  | } else { | 
|  | errorReporter.reportErrorForNode( | 
|  | CompileTimeErrorCode.CONST_WITH_NON_CONST, node); | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | if (!(constructor.declaration as ConstructorElementImpl).isCycleFree) { | 
|  | // It's not safe to evaluate this constructor, so bail out. | 
|  | // TODO(paulberry): ensure that a reasonable error message is produced | 
|  | // in this case, as well as other cases involving constant expression | 
|  | // cycles (e.g. "compile-time constant expression depends on itself"). | 
|  | return DartObjectImpl.validWithUnknownValue( | 
|  | library.typeSystem, | 
|  | constructor.returnType2, | 
|  | ); | 
|  | } | 
|  |  | 
|  | var argumentCount = arguments.length; | 
|  | var argumentValues = <DartObjectImpl>[]; | 
|  | var namedNodes = <String, NamedExpression>{}; | 
|  | var namedValues = <String, DartObjectImpl>{}; | 
|  | for (var i = 0; i < argumentCount; i++) { | 
|  | var argument = arguments[i]; | 
|  | if (argument is NamedExpression) { | 
|  | var name = argument.name.label.name; | 
|  | namedNodes[name] = argument; | 
|  | namedValues[name] = constantVisitor._valueOf(argument.expression); | 
|  | } else { | 
|  | argumentValues.add(constantVisitor._valueOf(argument)); | 
|  | } | 
|  | } | 
|  |  | 
|  | invocation ??= ConstructorInvocation( | 
|  | constructor, | 
|  | argumentValues, | 
|  | namedValues, | 
|  | ); | 
|  |  | 
|  | constructor = _followConstantRedirectionChain(constructor); | 
|  |  | 
|  | var evaluator = _InstanceCreationEvaluator._( | 
|  | evaluationEngine, | 
|  | declaredVariables, | 
|  | errorReporter, | 
|  | library, | 
|  | evaluationEngine.configuration.errorNode(node), | 
|  | constructor, | 
|  | typeArguments, | 
|  | namedNodes: namedNodes, | 
|  | namedValues: namedValues, | 
|  | argumentValues: argumentValues, | 
|  | invocation: invocation, | 
|  | ); | 
|  |  | 
|  | if (constructor.isFactory) { | 
|  | // We couldn't find a non-factory constructor. | 
|  | // See if it's because we reached an external const factory constructor | 
|  | // that we can emulate. | 
|  | return evaluator.evaluateFactoryConstructorCall(arguments, | 
|  | isNullSafe: isNullSafe); | 
|  | } else { | 
|  | return evaluator.evaluateGenerativeConstructorCall(arguments); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Attempt to follow the chain of factory redirections until a constructor is | 
|  | /// reached which is not a const factory constructor. Return the constant | 
|  | /// constructor which terminates the chain of factory redirections, if the | 
|  | /// chain terminates. If there is a problem (e.g. a redirection can't be | 
|  | /// found, or a cycle is encountered), the chain will be followed as far as | 
|  | /// possible and then a const factory constructor will be returned. | 
|  | static ConstructorElement _followConstantRedirectionChain( | 
|  | ConstructorElement constructor) { | 
|  | var constructorsVisited = <ConstructorElement>{}; | 
|  | while (true) { | 
|  | var redirectedConstructor = | 
|  | ConstantEvaluationEngine.getConstRedirectedConstructor(constructor); | 
|  | if (redirectedConstructor == null) { | 
|  | break; | 
|  | } else { | 
|  | var constructorBase = constructor.declaration; | 
|  | constructorsVisited.add(constructorBase); | 
|  | var redirectedConstructorBase = redirectedConstructor.declaration; | 
|  | if (constructorsVisited.contains(redirectedConstructorBase)) { | 
|  | // Cycle in redirecting factory constructors--this is not allowed | 
|  | // and is checked elsewhere--see | 
|  | // [ErrorVerifier.checkForRecursiveFactoryRedirect()]). | 
|  | break; | 
|  | } | 
|  | } | 
|  | constructor = redirectedConstructor; | 
|  | } | 
|  | return constructor; | 
|  | } | 
|  |  | 
|  | /// Determine whether the given string is a valid name for a public symbol | 
|  | /// (i.e. whether it is allowed for a call to the Symbol constructor). | 
|  | static bool _isValidPublicSymbol(String name) => | 
|  | name.isEmpty || name == "void" || _publicSymbolPattern.hasMatch(name); | 
|  | } | 
|  |  | 
|  | extension on NamedType { | 
|  | bool get isTypeLiteralInConstantPattern { | 
|  | final parent = this.parent; | 
|  | return parent is TypeLiteral && parent.parent?.parent is ConstantPattern; | 
|  | } | 
|  | } | 
|  |  | 
|  | extension RuntimeExtensions on TypeSystemImpl { | 
|  | /// Returns whether [obj] matches the [type] according to runtime | 
|  | /// type-checking rules. | 
|  | bool runtimeTypeMatch( | 
|  | DartObjectImpl obj, | 
|  | DartType type, | 
|  | ) { | 
|  | if (!isNonNullableByDefault) { | 
|  | type = toLegacyTypeIfOptOut(type); | 
|  | } | 
|  | var objType = obj.type; | 
|  | return isSubtypeOf(objType, type); | 
|  | } | 
|  | } |