Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1682)

Unified Diff: analyzer/lib/src/generated/constant.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « analyzer/lib/src/generated/ast.dart ('k') | analyzer/lib/src/generated/element.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: analyzer/lib/src/generated/constant.dart
diff --git a/analyzer/lib/src/generated/constant.dart b/analyzer/lib/src/generated/constant.dart
deleted file mode 100644
index 572caab8e0fff2200e8ff794b35ed9de9155d7d0..0000000000000000000000000000000000000000
--- a/analyzer/lib/src/generated/constant.dart
+++ /dev/null
@@ -1,5281 +0,0 @@
-// 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.
-
-// This code was auto-generated, is not intended to be edited, and is subject to
-// significant change. Please see the README file for more information.
-
-library engine.constant;
-
-import 'dart:collection';
-
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/dart.dart';
-
-import 'ast.dart';
-import 'element.dart';
-import 'engine.dart' show AnalysisEngine, RecordingErrorListener;
-import 'error.dart';
-import 'java_core.dart';
-import 'resolver.dart' show TypeProvider, TypeSystem, TypeSystemImpl;
-import 'scanner.dart' show Token, TokenType;
-import 'source.dart' show Source;
-import 'utilities_collection.dart';
-import 'utilities_dart.dart' show ParameterKind;
-
-/**
- * Callback used by [ReferenceFinder] to report that a dependency was found.
- */
-typedef void ReferenceFinderCallback(ConstantEvaluationTarget dependency);
-
-/**
- * The state of an object representing a boolean value.
- */
-class BoolState extends InstanceState {
- /**
- * An instance representing the boolean value 'false'.
- */
- static BoolState FALSE_STATE = new BoolState(false);
-
- /**
- * An instance representing the boolean value 'true'.
- */
- static BoolState TRUE_STATE = new BoolState(true);
-
- /**
- * A state that can be used to represent a boolean whose value is not known.
- */
- static BoolState UNKNOWN_VALUE = new BoolState(null);
-
- /**
- * The value of this instance.
- */
- final bool value;
-
- /**
- * Initialize a newly created state to represent the given [value].
- */
- BoolState(this.value);
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : (value ? 2 : 3);
-
- @override
- bool get isBool => true;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- bool get isUnknown => value == null;
-
- @override
- String get typeName => "bool";
-
- @override
- bool operator ==(Object object) =>
- object is BoolState && identical(value, object.value);
-
- @override
- BoolState convertToBool() => this;
-
- @override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value ? "true" : "false");
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is BoolState) {
- bool rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return BoolState.from(identical(value, rightValue));
- } else if (rightOperand is DynamicState) {
- return UNKNOWN_VALUE;
- }
- return FALSE_STATE;
- }
-
- @override
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? rightOperand.convertToBool() : FALSE_STATE;
- }
-
- @override
- BoolState logicalNot() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? FALSE_STATE : TRUE_STATE;
- }
-
- @override
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? TRUE_STATE : rightOperand.convertToBool();
- }
-
- @override
- String toString() => value == null ? "-unknown-" : (value ? "true" : "false");
-
- /**
- * Return the boolean state representing the given boolean [value].
- */
- static BoolState from(bool value) =>
- value ? BoolState.TRUE_STATE : BoolState.FALSE_STATE;
-}
-
-/**
- * An [AstCloner] that copies the necessary information from the AST to allow
- * constants to be evaluated.
- */
-class ConstantAstCloner extends AstCloner {
- ConstantAstCloner() : super(true);
-
- @override
- InstanceCreationExpression visitInstanceCreationExpression(
- InstanceCreationExpression node) {
- InstanceCreationExpression expression =
- super.visitInstanceCreationExpression(node);
- expression.staticElement = node.staticElement;
- return expression;
- }
-
- @override
- RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
- RedirectingConstructorInvocation node) {
- RedirectingConstructorInvocation invocation =
- super.visitRedirectingConstructorInvocation(node);
- invocation.staticElement = node.staticElement;
- return invocation;
- }
-
- @override
- SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) {
- SimpleIdentifier identifier = super.visitSimpleIdentifier(node);
- identifier.staticElement = node.staticElement;
- return identifier;
- }
-
- @override
- SuperConstructorInvocation visitSuperConstructorInvocation(
- SuperConstructorInvocation node) {
- SuperConstructorInvocation invocation =
- super.visitSuperConstructorInvocation(node);
- invocation.staticElement = node.staticElement;
- return invocation;
- }
-}
-
-/**
- * Helper class encapsulating the methods for evaluating constants and
- * constant instance creation expressions.
- */
-class ConstantEvaluationEngine {
- /**
- * Parameter to "fromEnvironment" methods that denotes the default value.
- */
- static String _DEFAULT_VALUE_PARAM = "defaultValue";
-
- /**
- * Source of RegExp matching any public identifier.
- * From sdk/lib/internal/symbol.dart.
- */
- static String _PUBLIC_IDENTIFIER_RE =
- "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$]*";
-
- /**
- * RegExp that validates a non-empty non-private symbol.
- * From sdk/lib/internal/symbol.dart.
- */
- static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp(
- "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$|[.](?!\$)))+?\$");
-
- /**
- * The type system. This is used to gues the types of constants when their
- * exact value is unknown.
- */
- final TypeSystem typeSystem;
-
- /**
- * The set of variables declared on the command line using '-D'.
- */
- final DeclaredVariables _declaredVariables;
-
- /**
- * Validator used to verify correct dependency analysis when running unit
- * tests.
- */
- final ConstantEvaluationValidator validator;
-
- /**
- * Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider]
- * is used to access known types. [_declaredVariables] is the set of
- * variables declared on the command line using '-D'. The [validator], if
- * given, is used to verify correct dependency analysis when running unit
- * tests.
- */
- ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables,
- {ConstantEvaluationValidator validator})
- : validator = validator != null
- ? validator
- : new ConstantEvaluationValidator_ForProduction(),
- typeSystem = new TypeSystemImpl(typeProvider);
-
- /**
- * The type provider used to access the known types.
- */
- TypeProvider get typeProvider => typeSystem.typeProvider;
-
- /**
- * 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` if there is an error.
- */
- bool checkFromEnvironmentArguments(NodeList<Expression> arguments,
- List<DartObjectImpl> argumentValues,
- HashMap<String, DartObjectImpl> namedArgumentValues,
- InterfaceType expectedDefaultValueType) {
- int argumentCount = arguments.length;
- if (argumentCount < 1 || argumentCount > 2) {
- return false;
- }
- if (arguments[0] is NamedExpression) {
- return false;
- }
- if (!identical(argumentValues[0].type, typeProvider.stringType)) {
- return false;
- }
- if (argumentCount == 2) {
- if (arguments[1] is! NamedExpression) {
- return false;
- }
- if (!((arguments[1] as NamedExpression).name.label.name ==
- _DEFAULT_VALUE_PARAM)) {
- return false;
- }
- ParameterizedType defaultValueType =
- namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
- if (!(identical(defaultValueType, expectedDefaultValueType) ||
- identical(defaultValueType, typeProvider.nullType))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Check that the arguments to a call to Symbol() 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. Return `true` if the arguments are correct, `false` if
- * there is an error.
- */
- bool checkSymbolArguments(NodeList<Expression> arguments,
- List<DartObjectImpl> argumentValues,
- HashMap<String, DartObjectImpl> namedArgumentValues) {
- if (arguments.length != 1) {
- return false;
- }
- if (arguments[0] is NamedExpression) {
- return false;
- }
- if (!identical(argumentValues[0].type, typeProvider.stringType)) {
- return false;
- }
- String name = argumentValues[0].stringValue;
- return isValidPublicSymbol(name);
- }
-
- /**
- * Compute the constant value associated with the given [constant].
- */
- void computeConstantValue(ConstantEvaluationTarget constant) {
- validator.beforeComputeValue(constant);
- if (constant is ParameterElement) {
- if (constant.initializer != null) {
- Expression defaultValue =
- (constant as PotentiallyConstVariableElement).constantInitializer;
- if (defaultValue != null) {
- RecordingErrorListener errorListener = new RecordingErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, constant.source);
- DartObjectImpl dartObject =
- defaultValue.accept(new ConstantVisitor(this, errorReporter));
- (constant as ParameterElementImpl).evaluationResult =
- new EvaluationResultImpl(dartObject, errorListener.errors);
- }
- }
- } else if (constant is VariableElement) {
- Expression constantInitializer =
- (constant as PotentiallyConstVariableElement).constantInitializer;
- if (constantInitializer != null) {
- RecordingErrorListener errorListener = new RecordingErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, constant.source);
- DartObjectImpl dartObject = constantInitializer
- .accept(new ConstantVisitor(this, errorReporter));
- // 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 (!runtimeTypeMatch(dartObject, constant.type)) {
- errorReporter.reportErrorForElement(
- CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
- constant, [dartObject.type, constant.type]);
- }
- }
- (constant as VariableElementImpl).evaluationResult =
- new EvaluationResultImpl(dartObject, errorListener.errors);
- }
- } else if (constant is ConstructorElement) {
- 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. However we do need to annotate the
- // element as being free of constant evaluation cycles so that later
- // code will know that it is safe to evaluate.
- (constant as ConstructorElementImpl).isCycleFree = true;
- }
- } else if (constant is ConstantEvaluationTarget_Annotation) {
- Annotation constNode = constant.annotation;
- ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
- // elementAnnotation is null if the annotation couldn't be resolved, in
- // which case we skip it.
- if (elementAnnotation != null) {
- Element element = elementAnnotation.element;
- if (element is PropertyAccessorElement &&
- element.variable is VariableElementImpl) {
- // The annotation is a reference to a compile-time constant variable.
- // Just copy the evaluation result.
- VariableElementImpl variableElement =
- element.variable as VariableElementImpl;
- if (variableElement.evaluationResult != null) {
- elementAnnotation.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.
- elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
- }
- } else if (element is ConstructorElementImpl &&
- element.isConst &&
- constNode.arguments != null) {
- RecordingErrorListener errorListener = new RecordingErrorListener();
- CompilationUnit sourceCompilationUnit =
- constNode.getAncestor((node) => node is CompilationUnit);
- ErrorReporter errorReporter = new ErrorReporter(
- errorListener, sourceCompilationUnit.element.source);
- ConstantVisitor constantVisitor =
- new ConstantVisitor(this, errorReporter);
- DartObjectImpl result = evaluateConstructorCall(constNode,
- constNode.arguments.arguments, element, constantVisitor,
- errorReporter);
- elementAnnotation.evaluationResult =
- new 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.
- elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
- }
- }
- } else {
- // Should not happen.
- assert(false);
- AnalysisEngine.instance.logger.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].
- *
- * Note that it's possible (in erroneous code) for a constant to depend on a
- * non-constant. When this happens, we report the dependency anyhow so that
- * if the non-constant changes to a constant, we will know to recompute the
- * thing that depends on it. [computeDependencies] and
- * [computeConstantValue] are responsible for ignoring the request if they
- * are asked to act on a non-constant target.
- */
- void computeDependencies(
- ConstantEvaluationTarget constant, ReferenceFinderCallback callback) {
- ReferenceFinder referenceFinder = new ReferenceFinder(callback);
- if (constant is ParameterElement) {
- if (constant.initializer != null) {
- Expression defaultValue =
- (constant as ConstVariableElement).constantInitializer;
- if (defaultValue != null) {
- defaultValue.accept(referenceFinder);
- }
- }
- } else if (constant is PotentiallyConstVariableElement) {
- Expression initializer = constant.constantInitializer;
- if (initializer != null) {
- initializer.accept(referenceFinder);
- }
- } else if (constant is ConstructorElementImpl) {
- if (constant.isConst) {
- constant.isCycleFree = false;
- ConstructorElement redirectedConstructor =
- getConstRedirectedConstructor(constant);
- if (redirectedConstructor != null) {
- ConstructorElement redirectedConstructorBase =
- ConstantEvaluationEngine
- ._getConstructorBase(redirectedConstructor);
- 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;
- }
- bool superInvocationFound = false;
- List<ConstructorInitializer> initializers =
- constant.constantInitializers;
- for (ConstructorInitializer initializer in initializers) {
- if (initializer is SuperConstructorInvocation) {
- superInvocationFound = true;
- }
- initializer.accept(referenceFinder);
- }
- if (!superInvocationFound) {
- // No explicit superconstructor invocation found, so we need to
- // manually insert a reference to the implicit superconstructor.
- InterfaceType superclass =
- (constant.returnType as InterfaceType).superclass;
- if (superclass != null && !superclass.isObject) {
- ConstructorElement unnamedConstructor = ConstantEvaluationEngine
- ._getConstructorBase(superclass.element.unnamedConstructor);
- if (unnamedConstructor != null) {
- callback(unnamedConstructor);
- }
- }
- }
- for (FieldElement field in constant.enclosingElement.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.initializer != null) {
- callback(field);
- }
- }
- for (ParameterElement parameterElement in constant.parameters) {
- callback(parameterElement);
- }
- }
- } else if (constant is ConstantEvaluationTarget_Annotation) {
- Annotation constNode = constant.annotation;
- ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
- // elementAnnotation is null if the annotation couldn't be resolved, in
- // which case we skip it.
- if (elementAnnotation != null) {
- Element element = elementAnnotation.element;
- if (element is PropertyAccessorElement &&
- element.variable is VariableElementImpl) {
- // The annotation is a reference to a compile-time constant variable,
- // so it depends on the variable.
- callback(element.variable);
- } else if (element is ConstructorElementImpl) {
- // The annotation is a constructor invocation, so it depends on the
- // constructor.
- callback(element);
- } 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 {
- // Should not happen.
- assert(false);
- AnalysisEngine.instance.logger.logError(
- "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}");
- }
- }
-
- /**
- * Evaluate a call to fromEnvironment() on the bool, int, or String class. The
- * [environmentValue] is the value fetched from the environment. The
- * [builtInDefaultValue] is the value that should be used as the default if no
- * "defaultValue" argument appears in [namedArgumentValues]. The
- * [namedArgumentValues] are the values of the named parameters passed to
- * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the
- * evaluated result.
- */
- DartObjectImpl computeValueFromEnvironment(DartObject environmentValue,
- DartObjectImpl builtInDefaultValue,
- HashMap<String, DartObjectImpl> namedArgumentValues) {
- DartObjectImpl value = environmentValue as DartObjectImpl;
- if (value.isUnknown || value.isNull) {
- // The name either doesn't exist in the environment or we couldn't parse
- // the corresponding value.
- // If the code supplied an explicit default, use it.
- if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) {
- value = namedArgumentValues[_DEFAULT_VALUE_PARAM];
- } else if (value.isNull) {
- // The code didn't supply an explicit default.
- // The name exists in the environment but we couldn't parse the
- // corresponding value.
- // So use the built-in default value, because this is what the VM does.
- value = builtInDefaultValue;
- } else {
- // The code didn't supply an explicit default.
- // The name doesn't exist in the environment.
- // The VM would use the built-in default value, but we don't want to do
- // that for analysis because it's likely to lead to cascading errors.
- // So just leave [value] in the unknown state.
- }
- }
- return value;
- }
-
- DartObjectImpl evaluateConstructorCall(AstNode node,
- NodeList<Expression> arguments, ConstructorElement constructor,
- ConstantVisitor constantVisitor, ErrorReporter errorReporter) {
- if (!_getConstructorBase(constructor).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
- // circularities (e.g. "compile-time constant expression depends on
- // itself")
- return new DartObjectImpl.validWithUnknownValue(constructor.returnType);
- }
- int argumentCount = arguments.length;
- List<DartObjectImpl> argumentValues =
- new List<DartObjectImpl>(argumentCount);
- List<Expression> argumentNodes = new List<Expression>(argumentCount);
- HashMap<String, DartObjectImpl> namedArgumentValues =
- new HashMap<String, DartObjectImpl>();
- HashMap<String, NamedExpression> namedArgumentNodes =
- new HashMap<String, NamedExpression>();
- for (int i = 0; i < argumentCount; i++) {
- Expression argument = arguments[i];
- if (argument is NamedExpression) {
- String name = argument.name.label.name;
- namedArgumentValues[name] =
- constantVisitor._valueOf(argument.expression);
- namedArgumentNodes[name] = argument;
- argumentValues[i] = typeProvider.nullObject;
- } else {
- argumentValues[i] = constantVisitor._valueOf(argument);
- argumentNodes[i] = argument;
- }
- }
- constructor = followConstantRedirectionChain(constructor);
- InterfaceType definingClass = constructor.returnType as InterfaceType;
- 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.
- if (constructor.name == "fromEnvironment") {
- if (!checkFromEnvironmentArguments(
- arguments, argumentValues, namedArgumentValues, definingClass)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
- return null;
- }
- String variableName =
- argumentCount < 1 ? null : argumentValues[0].stringValue;
- if (identical(definingClass, typeProvider.boolType)) {
- DartObject valueFromEnvironment;
- valueFromEnvironment =
- _declaredVariables.getBool(typeProvider, variableName);
- return computeValueFromEnvironment(valueFromEnvironment,
- new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE),
- namedArgumentValues);
- } else if (identical(definingClass, typeProvider.intType)) {
- DartObject valueFromEnvironment;
- valueFromEnvironment =
- _declaredVariables.getInt(typeProvider, variableName);
- return computeValueFromEnvironment(valueFromEnvironment,
- new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
- namedArgumentValues);
- } else if (identical(definingClass, typeProvider.stringType)) {
- DartObject valueFromEnvironment;
- valueFromEnvironment =
- _declaredVariables.getString(typeProvider, variableName);
- return computeValueFromEnvironment(valueFromEnvironment,
- new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
- namedArgumentValues);
- }
- } else if (constructor.name == "" &&
- identical(definingClass, typeProvider.symbolType) &&
- argumentCount == 1) {
- if (!checkSymbolArguments(
- arguments, argumentValues, namedArgumentValues)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
- return null;
- }
- String argumentValue = argumentValues[0].stringValue;
- return new DartObjectImpl(
- definingClass, new SymbolState(argumentValue));
- }
- // 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 new DartObjectImpl.validWithUnknownValue(definingClass);
- }
- ConstructorElementImpl constructorBase = _getConstructorBase(constructor);
- validator.beforeGetConstantInitializers(constructorBase);
- List<ConstructorInitializer> initializers =
- constructorBase.constantInitializers;
- if (initializers == null) {
- // This can happen in some cases where there are compile errors in the
- // code being analyzed (for example if the code is trying to create a
- // const instance using a non-const constructor, or the node we're
- // visiting is involved in a cycle). The error has already been reported,
- // so consider it an unknown value to suppress further errors.
- return new DartObjectImpl.validWithUnknownValue(definingClass);
- }
- HashMap<String, DartObjectImpl> fieldMap =
- new HashMap<String, DartObjectImpl>();
- // Start with final fields that are initialized at their declaration site.
- for (FieldElement field in constructor.enclosingElement.fields) {
- if ((field.isFinal || field.isConst) &&
- !field.isStatic &&
- field is ConstFieldElementImpl) {
- validator.beforeGetFieldEvaluationResult(field);
- EvaluationResultImpl evaluationResult = field.evaluationResult;
- DartType fieldType =
- FieldMember.from(field, constructor.returnType).type;
- DartObjectImpl fieldValue = evaluationResult.value;
- if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) {
- errorReporter.reportErrorForNode(
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
- node, [fieldValue.type, field.name, fieldType]);
- }
- fieldMap[field.name] = evaluationResult.value;
- }
- }
- // Now evaluate the constructor declaration.
- HashMap<String, DartObjectImpl> parameterMap =
- new HashMap<String, DartObjectImpl>();
- List<ParameterElement> parameters = constructor.parameters;
- int parameterCount = parameters.length;
- for (int i = 0; i < parameterCount; i++) {
- ParameterElement parameter = parameters[i];
- ParameterElement baseParameter = parameter;
- while (baseParameter is ParameterMember) {
- baseParameter = (baseParameter as ParameterMember).baseElement;
- }
- DartObjectImpl argumentValue = null;
- AstNode errorTarget = null;
- if (baseParameter.parameterKind == ParameterKind.NAMED) {
- argumentValue = namedArgumentValues[baseParameter.name];
- errorTarget = namedArgumentNodes[baseParameter.name];
- } else if (i < argumentCount) {
- argumentValue = argumentValues[i];
- errorTarget = argumentNodes[i];
- }
- if (errorTarget == null) {
- // 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 = node;
- }
- if (argumentValue == null && baseParameter is ParameterElementImpl) {
- // The parameter is an optional positional parameter for which no value
- // was provided, so use the default value.
- validator.beforeGetParameterDefault(baseParameter);
- EvaluationResultImpl evaluationResult = baseParameter.evaluationResult;
- if (evaluationResult == null) {
- // No default was provided, so the default value is null.
- argumentValue = typeProvider.nullObject;
- } else if (evaluationResult.value != null) {
- argumentValue = evaluationResult.value;
- }
- }
- if (argumentValue != null) {
- if (!runtimeTypeMatch(argumentValue, parameter.type)) {
- errorReporter.reportErrorForNode(
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
- errorTarget, [argumentValue.type, parameter.type]);
- }
- if (baseParameter.isInitializingFormal) {
- FieldElement field = (parameter as FieldFormalParameterElement).field;
- if (field != null) {
- DartType 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 (!runtimeTypeMatch(argumentValue, fieldType)) {
- errorReporter.reportErrorForNode(
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
- errorTarget, [argumentValue.type, fieldType]);
- }
- }
- String fieldName = field.name;
- if (fieldMap.containsKey(fieldName)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
- }
- fieldMap[fieldName] = argumentValue;
- }
- } else {
- String name = baseParameter.name;
- parameterMap[name] = argumentValue;
- }
- }
- }
- ConstantVisitor initializerVisitor = new ConstantVisitor(
- this, errorReporter, lexicalEnvironment: parameterMap);
- String superName = null;
- NodeList<Expression> superArguments = null;
- for (ConstructorInitializer initializer in initializers) {
- if (initializer is ConstructorFieldInitializer) {
- ConstructorFieldInitializer constructorFieldInitializer = initializer;
- Expression initializerExpression =
- constructorFieldInitializer.expression;
- DartObjectImpl evaluationResult =
- initializerExpression.accept(initializerVisitor);
- if (evaluationResult != null) {
- String fieldName = constructorFieldInitializer.fieldName.name;
- if (fieldMap.containsKey(fieldName)) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
- }
- fieldMap[fieldName] = evaluationResult;
- PropertyAccessorElement getter = definingClass.getGetter(fieldName);
- if (getter != null) {
- PropertyInducingElement field = getter.variable;
- if (!runtimeTypeMatch(evaluationResult, field.type)) {
- errorReporter.reportErrorForNode(
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
- node, [evaluationResult.type, fieldName, field.type]);
- }
- }
- }
- } else if (initializer is SuperConstructorInvocation) {
- SuperConstructorInvocation superConstructorInvocation = initializer;
- SimpleIdentifier name = superConstructorInvocation.constructorName;
- if (name != null) {
- superName = name.name;
- }
- superArguments = superConstructorInvocation.argumentList.arguments;
- } else if (initializer is RedirectingConstructorInvocation) {
- // This is a redirecting constructor, so just evaluate the constructor
- // it redirects to.
- ConstructorElement constructor = initializer.staticElement;
- if (constructor != null && constructor.isConst) {
- return evaluateConstructorCall(node,
- initializer.argumentList.arguments, constructor,
- initializerVisitor, errorReporter);
- }
- }
- }
- // Evaluate explicit or implicit call to super().
- InterfaceType superclass = definingClass.superclass;
- if (superclass != null && !superclass.isObject) {
- ConstructorElement superConstructor =
- superclass.lookUpConstructor(superName, constructor.library);
- if (superConstructor != null) {
- if (superArguments == null) {
- superArguments = new NodeList<Expression>(null);
- }
- evaluateSuperConstructorCall(node, fieldMap, superConstructor,
- superArguments, initializerVisitor, errorReporter);
- }
- }
- return new DartObjectImpl(definingClass, new GenericState(fieldMap));
- }
-
- void evaluateSuperConstructorCall(AstNode node,
- HashMap<String, DartObjectImpl> fieldMap,
- ConstructorElement superConstructor, NodeList<Expression> superArguments,
- ConstantVisitor initializerVisitor, ErrorReporter errorReporter) {
- if (superConstructor != null && superConstructor.isConst) {
- DartObjectImpl evaluationResult = evaluateConstructorCall(node,
- superArguments, superConstructor, initializerVisitor, errorReporter);
- if (evaluationResult != null) {
- fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult;
- }
- }
- }
-
- /**
- * 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.
- */
- ConstructorElement followConstantRedirectionChain(
- ConstructorElement constructor) {
- HashSet<ConstructorElement> constructorsVisited =
- new HashSet<ConstructorElement>();
- while (true) {
- ConstructorElement redirectedConstructor =
- getConstRedirectedConstructor(constructor);
- if (redirectedConstructor == null) {
- break;
- } else {
- ConstructorElement constructorBase = _getConstructorBase(constructor);
- constructorsVisited.add(constructorBase);
- ConstructorElement redirectedConstructorBase =
- _getConstructorBase(redirectedConstructor);
- 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;
- }
-
- /**
- * 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 = new RecordingErrorListener();
- ErrorReporter errorReporter =
- new ErrorReporter(errorListener, constant.source);
- // 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 =
- new 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.logger.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`.
- */
- ConstructorElement getConstRedirectedConstructor(
- ConstructorElement constructor) {
- if (!constructor.isFactory) {
- return null;
- }
- if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
- // 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;
- }
- ConstructorElement 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;
- }
-
- /**
- * Check if the object [obj] matches the type [type] according to runtime type
- * checking rules.
- */
- bool runtimeTypeMatch(DartObjectImpl obj, DartType type) {
- if (obj.isNull) {
- return true;
- }
- if (type.isUndefined) {
- return false;
- }
- return obj.type.isSubtypeOf(type);
- }
-
- /**
- * 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" ||
- new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches();
-
- static ConstructorElementImpl _getConstructorBase(
- ConstructorElement constructor) {
- while (constructor is ConstructorMember) {
- constructor = (constructor as ConstructorMember).baseElement;
- }
- return constructor;
- }
-}
-
-/**
- * Wrapper around an [Annotation] which can be used as a
- * [ConstantEvaluationTarget].
- */
-class ConstantEvaluationTarget_Annotation implements ConstantEvaluationTarget {
- final AnalysisContext context;
- final Source source;
- final Source librarySource;
- final Annotation annotation;
-
- ConstantEvaluationTarget_Annotation(
- this.context, this.source, this.librarySource, this.annotation);
-
- @override
- int get hashCode => JenkinsSmiHash.hash3(
- source.hashCode, librarySource.hashCode, annotation.hashCode);
-
- @override
- bool operator ==(other) {
- if (other is ConstantEvaluationTarget_Annotation) {
- return this.context == other.context &&
- this.source == other.source &&
- this.librarySource == other.librarySource &&
- this.annotation == other.annotation;
- } else {
- return false;
- }
- }
-}
-
-/**
- * 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) {}
-}
-
-/**
- * Instances of the class `ConstantEvaluator` evaluate constant expressions to
- * produce their compile-time value. According to the Dart Language
- * Specification:
- * <blockquote>
- * A constant expression is one of the following:
- * * A literal number.
- * * A literal boolean.
- * * A literal string where any interpolated expression is a compile-time
- * constant that evaluates to a numeric, string or boolean value or to
- * <b>null</b>.
- * * A literal symbol.
- * * <b>null</b>.
- * * A qualified reference to a static constant variable.
- * * An identifier expression that denotes a constant variable, class or type
- * alias.
- * * A constant constructor invocation.
- * * A constant list literal.
- * * A constant map literal.
- * * A simple or qualified identifier denoting a top-level function or a static
- * method.
- * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant
- * expression.
- * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i>
- * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
- * expressions and <i>identical()</i> is statically bound to the predefined
- * dart function <i>identical()</i> discussed above.
- * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or
- * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and
- * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric,
- * string or boolean value.
- * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> &amp;&amp;
- * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>,
- * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate
- * to a boolean value.
- * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^
- * e<sub>2</sub></i>, <i>e<sub>1</sub> &amp; e<sub>2</sub></i>,
- * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;&gt;
- * e<sub>2</sub></i> or <i>e<sub>1</sub> &lt;&lt; e<sub>2</sub></i>, where
- * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
- * expressions that evaluate to an integer value or to <b>null</b>.
- * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> +
- * e<sub>2</sub></i>, <i>e<sub>1</sub> -e<sub>2</sub></i>, <i>e<sub>1</sub> *
- * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub>
- * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> &gt; e<sub>2</sub></i>,
- * <i>e<sub>1</sub> &lt; e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;=
- * e<sub>2</sub></i>, <i>e<sub>1</sub> &lt;= e<sub>2</sub></i> or
- * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i>
- * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a
- * numeric value or to <b>null</b>.
- * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> :
- * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and
- * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i>
- * evaluates to a boolean value.
- * </blockquote>
- */
-class ConstantEvaluator {
- /**
- * The source containing the expression(s) that will be evaluated.
- */
- final Source _source;
-
- /**
- * The type provider used to access the known types.
- */
- final TypeProvider _typeProvider;
-
- /**
- * Initialize a newly created evaluator to evaluate expressions in the given
- * [source]. The [typeProvider] is the type provider used to access known
- * types.
- */
- ConstantEvaluator(this._source, this._typeProvider);
-
- EvaluationResult evaluate(Expression expression) {
- RecordingErrorListener errorListener = new RecordingErrorListener();
- ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
- DartObjectImpl result = expression.accept(new ConstantVisitor(
- new ConstantEvaluationEngine(_typeProvider, new DeclaredVariables()),
- errorReporter));
- if (result != null) {
- return EvaluationResult.forValue(result);
- }
- return EvaluationResult.forErrors(errorListener.errors);
- }
-}
-
-/**
- * A visitor used to traverse the AST structures of all of the compilation units
- * being resolved and build tables of the constant variables, constant
- * constructors, constant constructor invocations, and annotations found in
- * those compilation units.
- */
-class ConstantFinder extends RecursiveAstVisitor<Object> {
- final AnalysisContext context;
- final Source source;
- final Source librarySource;
-
- /**
- * The elements and AST nodes whose constant values need to be computed.
- */
- HashSet<ConstantEvaluationTarget> constantsToCompute =
- new HashSet<ConstantEvaluationTarget>();
-
- /**
- * True if instance variables marked as "final" should be treated as "const".
- */
- bool treatFinalInstanceVarAsConst = false;
-
- ConstantFinder(this.context, this.source, this.librarySource);
-
- @override
- Object visitAnnotation(Annotation node) {
- super.visitAnnotation(node);
- constantsToCompute.add(new ConstantEvaluationTarget_Annotation(
- context, source, librarySource, node));
- return null;
- }
-
- @override
- Object visitClassDeclaration(ClassDeclaration node) {
- bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst;
- if (node.element.constructors.any((ConstructorElement e) => e.isConst)) {
- // Instance vars marked "final" need to be included in the dependency
- // graph, since constant constructors implicitly use the values in their
- // initializers.
- treatFinalInstanceVarAsConst = true;
- }
- try {
- return super.visitClassDeclaration(node);
- } finally {
- treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst;
- }
- }
-
- @override
- Object visitConstructorDeclaration(ConstructorDeclaration node) {
- super.visitConstructorDeclaration(node);
- if (node.constKeyword != null) {
- ConstructorElement element = node.element;
- if (element != null) {
- constantsToCompute.add(element);
- constantsToCompute.addAll(element.parameters);
- }
- }
- return null;
- }
-
- @override
- Object visitVariableDeclaration(VariableDeclaration node) {
- super.visitVariableDeclaration(node);
- Expression initializer = node.initializer;
- VariableElement element = node.element;
- if (initializer != null &&
- (node.isConst ||
- treatFinalInstanceVarAsConst &&
- element is FieldElement &&
- node.isFinal &&
- !element.isStatic)) {
- if (node.element != null) {
- constantsToCompute.add(node.element);
- }
- }
- return null;
- }
-}
-
-/**
- * An object used to compute the values of constant variables and constant
- * constructor invocations in one or more compilation units. The expected usage
- * pattern is for the compilation units to be added to this computer using the
- * method [add] and then for the method [computeValues] to be invoked exactly
- * once. Any use of an instance after invoking the method [computeValues] will
- * result in unpredictable behavior.
- */
-class ConstantValueComputer {
- /**
- * Source of RegExp matching declarable operator names.
- * From sdk/lib/internal/symbol.dart.
- */
- static String _OPERATOR_RE =
- "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)";
-
- /**
- * Source of RegExp matching Dart reserved words.
- * From sdk/lib/internal/symbol.dart.
- */
- static String _RESERVED_WORD_RE =
- "(?: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))";
-
- /**
- * A graph in which the nodes are the constants, and the edges are from each
- * constant to the other constants that are referenced by it.
- */
- DirectedGraph<ConstantEvaluationTarget> referenceGraph =
- new DirectedGraph<ConstantEvaluationTarget>();
-
- /**
- * The elements whose constant values need to be computed. Any elements
- * which appear in [referenceGraph] but not in this set either belong to a
- * different library cycle (and hence don't need to be recomputed) or were
- * computed during a previous stage of resolution stage (e.g. constants
- * associated with enums).
- */
- HashSet<ConstantEvaluationTarget> _constantsToCompute =
- new HashSet<ConstantEvaluationTarget>();
-
- /**
- * The evaluation engine that does the work of evaluating instance creation
- * expressions.
- */
- final ConstantEvaluationEngine evaluationEngine;
-
- final AnalysisContext _context;
-
- /**
- * Initialize a newly created constant value computer. The [typeProvider] is
- * the type provider used to access known types. The [declaredVariables] is
- * the set of variables declared on the command line using '-D'.
- */
- ConstantValueComputer(this._context, TypeProvider typeProvider,
- DeclaredVariables declaredVariables,
- [ConstantEvaluationValidator validator])
- : evaluationEngine = new ConstantEvaluationEngine(
- typeProvider, declaredVariables, validator: validator);
-
- /**
- * Add the constants in the given compilation [unit] to the list of constants
- * whose value needs to be computed.
- */
- void add(CompilationUnit unit, Source source, Source librarySource) {
- ConstantFinder constantFinder =
- new ConstantFinder(_context, source, librarySource);
- unit.accept(constantFinder);
- _constantsToCompute.addAll(constantFinder.constantsToCompute);
- }
-
- /**
- * Compute values for all of the constants in the compilation units that were
- * added.
- */
- void computeValues() {
- for (ConstantEvaluationTarget constant in _constantsToCompute) {
- referenceGraph.addNode(constant);
- evaluationEngine.computeDependencies(constant,
- (ConstantEvaluationTarget dependency) {
- referenceGraph.addEdge(constant, dependency);
- });
- }
- List<List<ConstantEvaluationTarget>> topologicalSort =
- referenceGraph.computeTopologicalSort();
- for (List<ConstantEvaluationTarget> constantsInCycle in topologicalSort) {
- if (constantsInCycle.length == 1) {
- ConstantEvaluationTarget constant = constantsInCycle[0];
- if (!referenceGraph.getTails(constant).contains(constant)) {
- _computeValueFor(constant);
- continue;
- }
- }
- for (ConstantEvaluationTarget constant in constantsInCycle) {
- evaluationEngine.generateCycleError(constantsInCycle, constant);
- }
- }
- }
-
- /**
- * Compute a value for the given [constant].
- */
- void _computeValueFor(ConstantEvaluationTarget constant) {
- if (!_constantsToCompute.contains(constant)) {
- // Element is in the dependency graph but should have been computed by
- // a previous stage of analysis.
- // TODO(paulberry): once we have moved over to the new task model, this
- // should only occur for constants associated with enum members. Once
- // that happens we should add an assertion to verify that it doesn't
- // occur in any other cases.
- return;
- }
- evaluationEngine.computeConstantValue(constant);
- }
-}
-
-/**
- * A visitor used to evaluate constant expressions to produce their compile-time
- * value. According to the Dart Language Specification: <blockquote> A constant
- * expression is one of the following:
- *
- * * A literal number.
- * * A literal boolean.
- * * A literal string where any interpolated expression is a compile-time
- * constant that evaluates to a numeric, string or boolean value or to
- * <b>null</b>.
- * * A literal symbol.
- * * <b>null</b>.
- * * A qualified reference to a static constant variable.
- * * An identifier expression that denotes a constant variable, class or type
- * alias.
- * * A constant constructor invocation.
- * * A constant list literal.
- * * A constant map literal.
- * * A simple or qualified identifier denoting a top-level function or a static
- * method.
- * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant
- * expression.
- * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i>
- * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
- * expressions and <i>identical()</i> is statically bound to the predefined
- * dart function <i>identical()</i> discussed above.
- * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or
- * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and
- * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric,
- * string or boolean value.
- * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> &amp;&amp;
- * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>,
- * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate
- * to a boolean value.
- * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^
- * e<sub>2</sub></i>, <i>e<sub>1</sub> &amp; e<sub>2</sub></i>,
- * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;&gt;
- * e<sub>2</sub></i> or <i>e<sub>1</sub> &lt;&lt; e<sub>2</sub></i>, where
- * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
- * expressions that evaluate to an integer value or to <b>null</b>.
- * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> +
- * e<sub>2</sub></i>, <i>e<sub>1</sub> - e<sub>2</sub></i>, <i>e<sub>1</sub> *
- * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub>
- * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> &gt; e<sub>2</sub></i>,
- * <i>e<sub>1</sub> &lt; e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;=
- * e<sub>2</sub></i>, <i>e<sub>1</sub> &lt;= e<sub>2</sub></i> or
- * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i>
- * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a
- * numeric value or to <b>null</b>.
- * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> :
- * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and
- * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i>
- * evaluates to a boolean value.
- * </blockquote>
- */
-class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
- /**
- * The type provider used to access the known types.
- */
- final ConstantEvaluationEngine evaluationEngine;
-
- final HashMap<String, DartObjectImpl> _lexicalEnvironment;
-
- /**
- * Error reporter that we use to report errors accumulated while computing the
- * constant.
- */
- final ErrorReporter _errorReporter;
-
- /**
- * Helper class used to compute constant values.
- */
- 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.
- */
- ConstantVisitor(this.evaluationEngine, this._errorReporter,
- {HashMap<String, DartObjectImpl> lexicalEnvironment})
- : _lexicalEnvironment = lexicalEnvironment {
- this._dartObjectComputer =
- new DartObjectComputer(_errorReporter, evaluationEngine.typeProvider);
- }
-
- /**
- * Convenience getter to gain access to the [evalationEngine]'s type
- * provider.
- */
- TypeProvider get _typeProvider => evaluationEngine.typeProvider;
-
- /**
- * Convenience getter to gain access to the [evaluationEngine]'s type system.
- */
- TypeSystem get _typeSystem => evaluationEngine.typeSystem;
-
- @override
- DartObjectImpl visitAdjacentStrings(AdjacentStrings node) {
- DartObjectImpl result = null;
- for (StringLiteral string in node.strings) {
- if (result == null) {
- result = string.accept(this);
- } else {
- result =
- _dartObjectComputer.concatenate(node, result, string.accept(this));
- }
- }
- return result;
- }
-
- @override
- DartObjectImpl visitBinaryExpression(BinaryExpression node) {
- DartObjectImpl leftResult = node.leftOperand.accept(this);
- DartObjectImpl rightResult = node.rightOperand.accept(this);
- TokenType operatorType = node.operator.type;
- // 'null' is almost never good operand
- if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) {
- if (leftResult != null && leftResult.isNull ||
- rightResult != null && rightResult.isNull) {
- _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- return null;
- }
- }
- // evaluate operator
- while (true) {
- if (operatorType == TokenType.AMPERSAND) {
- return _dartObjectComputer.bitAnd(node, leftResult, rightResult);
- } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
- return _dartObjectComputer.logicalAnd(node, leftResult, rightResult);
- } else if (operatorType == TokenType.BANG_EQ) {
- return _dartObjectComputer.notEqual(node, leftResult, rightResult);
- } else if (operatorType == TokenType.BAR) {
- return _dartObjectComputer.bitOr(node, leftResult, rightResult);
- } else if (operatorType == TokenType.BAR_BAR) {
- return _dartObjectComputer.logicalOr(node, leftResult, rightResult);
- } else if (operatorType == TokenType.CARET) {
- return _dartObjectComputer.bitXor(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.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(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
- break;
- }
- }
-
- @override
- DartObjectImpl visitBooleanLiteral(BooleanLiteral node) =>
- new DartObjectImpl(_typeProvider.boolType, BoolState.from(node.value));
-
- @override
- DartObjectImpl visitConditionalExpression(ConditionalExpression node) {
- Expression condition = node.condition;
- DartObjectImpl conditionResult = condition.accept(this);
- DartObjectImpl thenResult = node.thenExpression.accept(this);
- DartObjectImpl elseResult = node.elseExpression.accept(this);
- if (conditionResult == null) {
- return conditionResult;
- } else if (!conditionResult.isBool) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition);
- return null;
- } else if (thenResult == null) {
- return thenResult;
- } else if (elseResult == null) {
- return elseResult;
- }
- conditionResult =
- _dartObjectComputer.applyBooleanConversion(condition, conditionResult);
- if (conditionResult == null) {
- return conditionResult;
- }
- if (conditionResult.isTrue) {
- return thenResult;
- } else if (conditionResult.isFalse) {
- return elseResult;
- }
- ParameterizedType thenType = thenResult.type;
- ParameterizedType elseType = elseResult.type;
- return new DartObjectImpl.validWithUnknownValue(
- _typeSystem.getLeastUpperBound(thenType, elseType) as InterfaceType);
- }
-
- @override
- DartObjectImpl visitDoubleLiteral(DoubleLiteral node) =>
- new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value));
-
- @override
- DartObjectImpl visitInstanceCreationExpression(
- InstanceCreationExpression node) {
- if (!node.isConst) {
- // TODO(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
- ConstructorElement constructor = node.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(
- node, node.argumentList.arguments, constructor, this, _errorReporter);
- }
-
- @override
- DartObjectImpl visitIntegerLiteral(IntegerLiteral node) =>
- new DartObjectImpl(_typeProvider.intType, new IntState(node.value));
-
- @override
- DartObjectImpl visitInterpolationExpression(InterpolationExpression node) {
- DartObjectImpl result = node.expression.accept(this);
- if (result != null && !result.isBoolNumStringOrNull) {
- _error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
- return null;
- }
- return _dartObjectComputer.performToString(node, result);
- }
-
- @override
- DartObjectImpl visitInterpolationString(InterpolationString node) =>
- new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
-
- @override
- DartObjectImpl visitListLiteral(ListLiteral node) {
- if (node.constKeyword == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL, node);
- return null;
- }
- bool errorOccurred = false;
- List<DartObjectImpl> elements = new List<DartObjectImpl>();
- for (Expression element in node.elements) {
- DartObjectImpl elementResult = element.accept(this);
- if (elementResult == null) {
- errorOccurred = true;
- } else {
- elements.add(elementResult);
- }
- }
- if (errorOccurred) {
- return null;
- }
- DartType elementType = _typeProvider.dynamicType;
- if (node.typeArguments != null &&
- node.typeArguments.arguments.length == 1) {
- DartType type = node.typeArguments.arguments[0].type;
- if (type != null) {
- elementType = type;
- }
- }
- InterfaceType listType = _typeProvider.listType.substitute4([elementType]);
- return new DartObjectImpl(listType, new ListState(elements));
- }
-
- @override
- DartObjectImpl visitMapLiteral(MapLiteral node) {
- if (node.constKeyword == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL, node);
- return null;
- }
- bool errorOccurred = false;
- HashMap<DartObjectImpl, DartObjectImpl> map =
- new HashMap<DartObjectImpl, DartObjectImpl>();
- for (MapLiteralEntry entry in node.entries) {
- DartObjectImpl keyResult = entry.key.accept(this);
- DartObjectImpl valueResult = entry.value.accept(this);
- if (keyResult == null || valueResult == null) {
- errorOccurred = true;
- } else {
- map[keyResult] = valueResult;
- }
- }
- if (errorOccurred) {
- return null;
- }
- DartType keyType = _typeProvider.dynamicType;
- DartType valueType = _typeProvider.dynamicType;
- if (node.typeArguments != null &&
- node.typeArguments.arguments.length == 2) {
- DartType keyTypeCandidate = node.typeArguments.arguments[0].type;
- if (keyTypeCandidate != null) {
- keyType = keyTypeCandidate;
- }
- DartType valueTypeCandidate = node.typeArguments.arguments[1].type;
- if (valueTypeCandidate != null) {
- valueType = valueTypeCandidate;
- }
- }
- InterfaceType mapType =
- _typeProvider.mapType.substitute4([keyType, valueType]);
- return new DartObjectImpl(mapType, new MapState(map));
- }
-
- @override
- DartObjectImpl visitMethodInvocation(MethodInvocation node) {
- Element element = node.methodName.staticElement;
- if (element is FunctionElement) {
- FunctionElement function = element;
- if (function.name == "identical") {
- NodeList<Expression> arguments = node.argumentList.arguments;
- if (arguments.length == 2) {
- Element enclosingElement = function.enclosingElement;
- if (enclosingElement is CompilationUnitElement) {
- LibraryElement library = enclosingElement.library;
- if (library.isDartCore) {
- DartObjectImpl leftArgument = arguments[0].accept(this);
- DartObjectImpl rightArgument = arguments[1].accept(this);
- return _dartObjectComputer.isIdentical(
- node, leftArgument, rightArgument);
- }
- }
- }
- }
- }
- // TODO(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
-
- @override
- DartObjectImpl visitNamedExpression(NamedExpression node) =>
- node.expression.accept(this);
-
- @override
- DartObjectImpl visitNode(AstNode node) {
- // TODO(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
-
- @override
- DartObjectImpl visitNullLiteral(NullLiteral node) => _typeProvider.nullObject;
-
- @override
- DartObjectImpl visitParenthesizedExpression(ParenthesizedExpression node) =>
- node.expression.accept(this);
-
- @override
- DartObjectImpl visitPrefixedIdentifier(PrefixedIdentifier node) {
- SimpleIdentifier prefixNode = node.prefix;
- Element prefixElement = prefixNode.staticElement;
- // String.length
- if (prefixElement is! PrefixElement && prefixElement is! ClassElement) {
- DartObjectImpl prefixResult = node.prefix.accept(this);
- if (_isStringLength(prefixResult, node.identifier)) {
- return prefixResult.stringLength(_typeProvider);
- }
- }
- // importPrefix.CONST
- if (prefixElement is! PrefixElement) {
- DartObjectImpl prefixResult = prefixNode.accept(this);
- if (prefixResult == null) {
- // The error has already been reported.
- return null;
- }
- }
- // validate prefixed identifier
- return _getConstantValue(node, node.staticElement);
- }
-
- @override
- DartObjectImpl visitPrefixExpression(PrefixExpression node) {
- DartObjectImpl operand = node.operand.accept(this);
- if (operand != null && operand.isNull) {
- _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- return null;
- }
- while (true) {
- 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(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
- break;
- }
- }
-
- @override
- DartObjectImpl visitPropertyAccess(PropertyAccess node) {
- if (node.target != null) {
- DartObjectImpl prefixResult = node.target.accept(this);
- if (_isStringLength(prefixResult, node.propertyName)) {
- return prefixResult.stringLength(_typeProvider);
- }
- }
- return _getConstantValue(node, node.propertyName.staticElement);
- }
-
- @override
- DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
- if (_lexicalEnvironment != null &&
- _lexicalEnvironment.containsKey(node.name)) {
- return _lexicalEnvironment[node.name];
- }
- return _getConstantValue(node, node.staticElement);
- }
-
- @override
- DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) =>
- new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
-
- @override
- DartObjectImpl visitStringInterpolation(StringInterpolation node) {
- DartObjectImpl result = null;
- bool first = true;
- for (InterpolationElement element in node.elements) {
- if (first) {
- result = element.accept(this);
- first = false;
- } else {
- result =
- _dartObjectComputer.concatenate(node, result, element.accept(this));
- }
- }
- return result;
- }
-
- @override
- DartObjectImpl visitSymbolLiteral(SymbolLiteral node) {
- StringBuffer buffer = new 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 new DartObjectImpl(
- _typeProvider.symbolType, new SymbolState(buffer.toString()));
- }
-
- /**
- * Create an error associated with the given [node]. The error will have the
- * given error [code].
- */
- void _error(AstNode node, ErrorCode code) {
- _errorReporter.reportErrorForNode(
- code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code, node);
- }
-
- /**
- * Return the constant value of the static constant represented by the given
- * [element]. The [node] is the node to be used if an error needs to be
- * reported.
- */
- DartObjectImpl _getConstantValue(AstNode node, Element element) {
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- if (element is VariableElementImpl) {
- VariableElementImpl variableElementImpl = element;
- evaluationEngine.validator.beforeGetEvaluationResult(element);
- EvaluationResultImpl value = variableElementImpl.evaluationResult;
- if (variableElementImpl.isConst && value != null) {
- return value.value;
- }
- } else if (element is ExecutableElement) {
- ExecutableElement function = element;
- if (function.isStatic) {
- ParameterizedType functionType = function.type;
- if (functionType == null) {
- functionType = _typeProvider.functionType;
- }
- return new DartObjectImpl(functionType, new FunctionState(function));
- }
- } else if (element is ClassElement ||
- element is FunctionTypeAliasElement ||
- element is DynamicElementImpl) {
- return new DartObjectImpl(_typeProvider.typeType, new TypeState(element));
- }
- // TODO(brianwilkerson) Figure out which error to report.
- _error(node, null);
- return null;
- }
-
- /**
- * Return `true` if the given [targetResult] represents a string and the
- * [identifier] is "length".
- */
- bool _isStringLength(
- DartObjectImpl targetResult, SimpleIdentifier identifier) {
- if (targetResult == null || targetResult.type != _typeProvider.stringType) {
- return false;
- }
- return identifier.name == 'length';
- }
-
- /**
- * Return the value of the given [expression], or a representation of 'null'
- * if the expression cannot be evaluated.
- */
- DartObjectImpl _valueOf(Expression expression) {
- DartObjectImpl expressionValue = expression.accept(this);
- if (expressionValue != null) {
- return expressionValue;
- }
- return _typeProvider.nullObject;
- }
-}
-
-/**
- * The state of a Dart object.
- */
-abstract class DartObject {
- /**
- * Return the boolean value of this object, or `null` if either the value of
- * this object is not known or this object is not of type 'bool'.
- */
- bool get boolValue;
-
- /**
- * Return the floating point value of this object, or `null` if either the
- * value of this object is not known or this object is not of type 'double'.
- */
- double get doubleValue;
-
- /**
- * Return `true` if this object's value can be represented exactly.
- */
- bool get hasExactValue;
-
- /**
- * Return the integer value of this object, or `null` if either the value of
- * this object is not known or this object is not of type 'int'.
- */
- int get intValue;
-
- /**
- * Return `true` if this object represents the value 'false'.
- */
- bool get isFalse;
-
- /**
- * Return `true` if this object represents the value 'null'.
- */
- bool get isNull;
-
- /**
- * Return `true` if this object represents the value 'true'.
- */
- bool get isTrue;
-
- /**
- * Return the string value of this object, or `null` if either the value of
- * this object is not known or this object is not of type 'String'.
- */
- String get stringValue;
-
- /**
- * Return the run-time type of this object.
- */
- ParameterizedType get type;
-
- /**
- * Return this object's value if it can be represented exactly, or `null` if
- * either the value cannot be represented exactly or if the value is `null`.
- * Clients should use [hasExactValue] to distinguish between these two cases.
- */
- Object get value;
-}
-
-/**
- * A utility class that contains methods for manipulating instances of a Dart
- * class and for collecting errors during evaluation.
- */
-class DartObjectComputer {
- /**
- * The error reporter that we are using to collect errors.
- */
- final ErrorReporter _errorReporter;
-
- /**
- * The type provider used to create objects of the appropriate types, and to
- * identify when an object is of a built-in type.
- */
- final TypeProvider _typeProvider;
-
- DartObjectComputer(this._errorReporter, this._typeProvider);
-
- DartObjectImpl add(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.add(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- return null;
- }
- }
- return null;
- }
-
- /**
- * Return the result of applying boolean conversion to the [evaluationResult].
- * The [node] is the node against which errors should be reported.
- */
- DartObjectImpl applyBooleanConversion(
- AstNode node, DartObjectImpl evaluationResult) {
- if (evaluationResult != null) {
- try {
- return evaluationResult.convertToBool(_typeProvider);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl bitAnd(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.bitAnd(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl bitNot(Expression node, DartObjectImpl evaluationResult) {
- if (evaluationResult != null) {
- try {
- return evaluationResult.bitNot(_typeProvider);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl bitOr(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.bitOr(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl bitXor(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.bitXor(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl concatenate(Expression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.concatenate(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl divide(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.divide(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl equalEqual(Expression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.equalEqual(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl greaterThan(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.greaterThan(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl greaterThanOrEqual(BinaryExpression node,
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl integerDivide(BinaryExpression node,
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.integerDivide(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl isIdentical(Expression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.isIdentical(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl lessThan(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.lessThan(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl lessThanOrEqual(BinaryExpression node,
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl logicalAnd(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.logicalAnd(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl logicalNot(Expression node, DartObjectImpl evaluationResult) {
- if (evaluationResult != null) {
- try {
- return evaluationResult.logicalNot(_typeProvider);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl logicalOr(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.logicalOr(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl minus(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.minus(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl negated(Expression node, DartObjectImpl evaluationResult) {
- if (evaluationResult != null) {
- try {
- return evaluationResult.negated(_typeProvider);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl notEqual(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.notEqual(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl performToString(
- AstNode node, DartObjectImpl evaluationResult) {
- if (evaluationResult != null) {
- try {
- return evaluationResult.performToString(_typeProvider);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.remainder(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl shiftLeft(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.shiftLeft(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- DartObjectImpl shiftRight(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.shiftRight(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-
- /**
- * 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) {
- if (evaluationResult.value != null) {
- try {
- return new EvaluationResultImpl(
- evaluationResult.value.stringLength(_typeProvider));
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return new EvaluationResultImpl(null);
- }
-
- DartObjectImpl times(BinaryExpression node, DartObjectImpl leftOperand,
- DartObjectImpl rightOperand) {
- if (leftOperand != null && rightOperand != null) {
- try {
- return leftOperand.times(_typeProvider, rightOperand);
- } on EvaluationException catch (exception) {
- _errorReporter.reportErrorForNode(exception.errorCode, node);
- }
- }
- return null;
- }
-}
-
-/**
- * An instance of a Dart class.
- */
-class DartObjectImpl implements DartObject {
- /**
- * An empty list of objects.
- */
- static const List<DartObjectImpl> EMPTY_LIST = const <DartObjectImpl>[];
-
- /**
- * The run-time type of this object.
- */
- final ParameterizedType type;
-
- /**
- * The state of the object.
- */
- final InstanceState _state;
-
- /**
- * Initialize a newly created object to have the given [type] and [_state].
- */
- DartObjectImpl(this.type, this._state);
-
- /**
- * Create an object to represent an unknown value.
- */
- factory DartObjectImpl.validWithUnknownValue(InterfaceType type) {
- if (type.element.library.isDartCore) {
- String typeName = type.name;
- if (typeName == "bool") {
- return new DartObjectImpl(type, BoolState.UNKNOWN_VALUE);
- } else if (typeName == "double") {
- return new DartObjectImpl(type, DoubleState.UNKNOWN_VALUE);
- } else if (typeName == "int") {
- return new DartObjectImpl(type, IntState.UNKNOWN_VALUE);
- } else if (typeName == "String") {
- return new DartObjectImpl(type, StringState.UNKNOWN_VALUE);
- }
- }
- return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
- }
-
- @override
- bool get boolValue {
- if (_state is BoolState) {
- return (_state as BoolState).value;
- }
- return null;
- }
-
- @override
- double get doubleValue {
- if (_state is DoubleState) {
- return (_state as DoubleState).value;
- }
- return null;
- }
-
- HashMap<String, DartObjectImpl> get fields => _state.fields;
-
- @override
- bool get hasExactValue => _state.hasExactValue;
-
- @override
- int get hashCode => JenkinsSmiHash.hash2(type.hashCode, _state.hashCode);
-
- @override
- int get intValue {
- if (_state is IntState) {
- return (_state as IntState).value;
- }
- return null;
- }
-
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- */
- bool get isBool => _state.isBool;
-
- /**
- * Return `true` if this object represents an object whose type is either
- * 'bool', 'num', 'String', or 'Null'.
- */
- bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull;
-
- @override
- bool get isFalse =>
- _state is BoolState && identical((_state as BoolState).value, false);
-
- @override
- bool get isNull => _state is NullState;
-
- @override
- bool get isTrue =>
- _state is BoolState && identical((_state as BoolState).value, true);
-
- /**
- * Return `true` if this object represents an unknown value.
- */
- bool get isUnknown => _state.isUnknown;
-
- /**
- * Return `true` if this object represents an instance of a user-defined
- * class.
- */
- bool get isUserDefinedObject => _state is GenericState;
-
- @override
- String get stringValue {
- if (_state is StringState) {
- return (_state as StringState).value;
- }
- return null;
- }
-
- @override
- Object get value => _state.value;
-
- @override
- bool operator ==(Object object) {
- if (object is! DartObjectImpl) {
- return false;
- }
- DartObjectImpl dartObject = object as DartObjectImpl;
- return type == dartObject.type && _state == dartObject._state;
- }
-
- /**
- * Return the result of invoking the '+' operator on this object with the
- * given [rightOperand]. The [typeProvider] is the type provider used to find
- * known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl add(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.add(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- } else if (result is StringState) {
- return new DartObjectImpl(typeProvider.stringType, result);
- }
- // We should never get here.
- throw new IllegalStateException("add returned a ${result.runtimeType}");
- }
-
- /**
- * Return the result of invoking the '&' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl bitAnd(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.bitAnd(rightOperand._state));
-
- /**
- * Return the result of invoking the '~' operator on this object. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl bitNot(TypeProvider typeProvider) =>
- new DartObjectImpl(typeProvider.intType, _state.bitNot());
-
- /**
- * Return the result of invoking the '|' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl bitOr(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.bitOr(rightOperand._state));
-
- /**
- * Return the result of invoking the '^' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl bitXor(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.bitXor(rightOperand._state));
-
- /**
- * Return the result of invoking the ' ' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl concatenate(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.stringType, _state.concatenate(rightOperand._state));
-
- /**
- * Return the result of applying boolean conversion to this object. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl convertToBool(TypeProvider typeProvider) {
- InterfaceType boolType = typeProvider.boolType;
- if (identical(type, boolType)) {
- return this;
- }
- return new DartObjectImpl(boolType, _state.convertToBool());
- }
-
- /**
- * Return the result of invoking the '/' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for
- * an object of this kind.
- */
- DartObjectImpl divide(
- TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.divide(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("divide returned a ${result.runtimeType}");
- }
-
- /**
- * Return the result of invoking the '==' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl equalEqual(
- TypeProvider typeProvider, DartObjectImpl rightOperand) {
- if (type != rightOperand.type) {
- String typeName = type.name;
- if (!(typeName == "bool" ||
- typeName == "double" ||
- typeName == "int" ||
- typeName == "num" ||
- typeName == "String" ||
- typeName == "Null" ||
- type.isDynamic)) {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
- }
- }
- return new DartObjectImpl(
- typeProvider.boolType, _state.equalEqual(rightOperand._state));
- }
-
- /**
- * Return the result of invoking the '&gt;' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl greaterThan(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.boolType, _state.greaterThan(rightOperand._state));
-
- /**
- * Return the result of invoking the '&gt;=' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl greaterThanOrEqual(TypeProvider typeProvider,
- DartObjectImpl rightOperand) => new DartObjectImpl(
- typeProvider.boolType, _state.greaterThanOrEqual(rightOperand._state));
-
- /**
- * Return the result of invoking the '~/' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl integerDivide(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.integerDivide(rightOperand._state));
-
- /**
- * Return the result of invoking the identical function on this object with
- * the [rightOperand]. The [typeProvider] is the type provider used to find
- * known types.
- */
- DartObjectImpl isIdentical(
- TypeProvider typeProvider, DartObjectImpl rightOperand) {
- return new DartObjectImpl(
- typeProvider.boolType, _state.isIdentical(rightOperand._state));
- }
-
- /**
- * Return the result of invoking the '&lt;' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl lessThan(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.boolType, _state.lessThan(rightOperand._state));
-
- /**
- * Return the result of invoking the '&lt;=' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl lessThanOrEqual(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.boolType, _state.lessThanOrEqual(rightOperand._state));
-
- /**
- * Return the result of invoking the '&&' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl logicalAnd(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.boolType, _state.logicalAnd(rightOperand._state));
-
- /**
- * Return the result of invoking the '!' operator on this object. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl logicalNot(TypeProvider typeProvider) =>
- new DartObjectImpl(typeProvider.boolType, _state.logicalNot());
-
- /**
- * Return the result of invoking the '||' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl logicalOr(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.boolType, _state.logicalOr(rightOperand._state));
-
- /**
- * Return the result of invoking the '-' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl minus(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.minus(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("minus returned a ${result.runtimeType}");
- }
-
- /**
- * Return the result of invoking the '-' operator on this object. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl negated(TypeProvider typeProvider) {
- InstanceState result = _state.negated();
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("negated returned a ${result.runtimeType}");
- }
-
- /**
- * Return the result of invoking the '!=' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl notEqual(
- TypeProvider typeProvider, DartObjectImpl rightOperand) {
- if (type != rightOperand.type) {
- String typeName = type.name;
- if (typeName != "bool" &&
- typeName != "double" &&
- typeName != "int" &&
- typeName != "num" &&
- typeName != "String") {
- return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
- }
- }
- return new DartObjectImpl(typeProvider.boolType,
- _state.equalEqual(rightOperand._state).logicalNot());
- }
-
- /**
- * Return the result of converting this object to a 'String'. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the object cannot be converted to a
- * 'String'.
- */
- DartObjectImpl performToString(TypeProvider typeProvider) {
- InterfaceType stringType = typeProvider.stringType;
- if (identical(type, stringType)) {
- return this;
- }
- return new DartObjectImpl(stringType, _state.convertToString());
- }
-
- /**
- * Return the result of invoking the '%' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl remainder(
- TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.remainder(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException(
- "remainder returned a ${result.runtimeType}");
- }
-
- /**
- * Return the result of invoking the '&lt;&lt;' operator on this object with
- * the [rightOperand]. The [typeProvider] is the type provider used to find
- * known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl shiftLeft(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.shiftLeft(rightOperand._state));
-
- /**
- * Return the result of invoking the '&gt;&gt;' operator on this object with
- * the [rightOperand]. The [typeProvider] is the type provider used to find
- * known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl shiftRight(
- TypeProvider typeProvider, DartObjectImpl rightOperand) =>
- new DartObjectImpl(
- typeProvider.intType, _state.shiftRight(rightOperand._state));
-
- /**
- * Return the result of invoking the 'length' getter on this object. The
- * [typeProvider] is the type provider used to find known types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl stringLength(TypeProvider typeProvider) =>
- new DartObjectImpl(typeProvider.intType, _state.stringLength());
-
- /**
- * Return the result of invoking the '*' operator on this object with the
- * [rightOperand]. The [typeProvider] is the type provider used to find known
- * types.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- DartObjectImpl times(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.times(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("times returned a ${result.runtimeType}");
- }
-
- @override
- String toString() => "${type.displayName} ($_state)";
-}
-
-/**
- * An object used to provide access to the values of variables that have been
- * defined on the command line using the `-D` option.
- */
-class DeclaredVariables {
- /**
- * A table mapping the names of declared variables to their values.
- */
- HashMap<String, String> _declaredVariables = new HashMap<String, String>();
-
- /**
- * Define a variable with the given [name] to have the given [value].
- */
- void define(String name, String value) {
- _declaredVariables[name] = value;
- }
-
- /**
- * Return the value of the variable with the given [name] interpreted as a
- * 'boolean' value. If the variable is not defined (or [name] is `null`), a
- * DartObject representing "unknown" is returned. If the value cannot be
- * parsed as a boolean, a DartObject representing 'null' is returned. The
- * [typeProvider] is the type provider used to find the type 'bool'.
- */
- DartObject getBool(TypeProvider typeProvider, String name) {
- String value = _declaredVariables[name];
- if (value == null) {
- return new DartObjectImpl(typeProvider.boolType, BoolState.UNKNOWN_VALUE);
- }
- if (value == "true") {
- return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
- } else if (value == "false") {
- return new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE);
- }
- return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
- }
-
- /**
- * Return the value of the variable with the given [name] interpreted as an
- * integer value. If the variable is not defined (or [name] is `null`), a
- * DartObject representing "unknown" is returned. If the value cannot be
- * parsed as an integer, a DartObject representing 'null' is returned.
- */
- DartObject getInt(TypeProvider typeProvider, String name) {
- String value = _declaredVariables[name];
- if (value == null) {
- return new DartObjectImpl(typeProvider.intType, IntState.UNKNOWN_VALUE);
- }
- int bigInteger;
- try {
- bigInteger = int.parse(value);
- } on FormatException {
- return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
- }
- return new DartObjectImpl(typeProvider.intType, new IntState(bigInteger));
- }
-
- /**
- * Return the value of the variable with the given [name] interpreted as a
- * String value, or `null` if the variable is not defined. Return the value of
- * the variable with the given name interpreted as a String value. If the
- * variable is not defined (or [name] is `null`), a DartObject representing
- * "unknown" is returned. The [typeProvider] is the type provider used to find
- * the type 'String'.
- */
- DartObject getString(TypeProvider typeProvider, String name) {
- String value = _declaredVariables[name];
- if (value == null) {
- return new DartObjectImpl(
- typeProvider.stringType, StringState.UNKNOWN_VALUE);
- }
- return new DartObjectImpl(typeProvider.stringType, new StringState(value));
- }
-}
-
-/**
- * The state of an object representing a double.
- */
-class DoubleState extends NumState {
- /**
- * A state that can be used to represent a double whose value is not known.
- */
- static DoubleState UNKNOWN_VALUE = new DoubleState(null);
-
- /**
- * The value of this instance.
- */
- final double value;
-
- /**
- * Initialize a newly created state to represent a double with the given
- * [value].
- */
- DoubleState(this.value);
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- bool get isUnknown => value == null;
-
- @override
- String get typeName => "double";
-
- @override
- bool operator ==(Object object) =>
- object is DoubleState && (value == object.value);
-
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value + rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value + rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value.toString());
- }
-
- @override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value / rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value / rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value > rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value > rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value >= rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value >= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return IntState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- }
- double result = value / rightValue.toDouble();
- return new IntState(result.toInt());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- }
- double result = value / rightValue;
- return new IntState(result.toInt());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return IntState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue.toDouble());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value < rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value < rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value <= rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value <= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value - rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value - rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState negated() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(-(value));
- }
-
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value % rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value % rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value * rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value * rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- String toString() => value == null ? "-unknown-" : value.toString();
-}
-
-/**
- * The state of an object representing a Dart object for which there is no type
- * information.
- */
-class DynamicState extends InstanceState {
- /**
- * The unique instance of this class.
- */
- static DynamicState DYNAMIC_STATE = new DynamicState();
-
- @override
- bool get isBool => true;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- String get typeName => "dynamic";
-
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
-
- @override
- IntState bitAnd(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- IntState bitNot() => IntState.UNKNOWN_VALUE;
-
- @override
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- StringState concatenate(InstanceState rightOperand) {
- assertString(rightOperand);
- return StringState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState convertToBool() => BoolState.UNKNOWN_VALUE;
-
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
-
- @override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState logicalNot() => BoolState.UNKNOWN_VALUE;
-
- @override
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(rightOperand);
- return rightOperand.convertToBool();
- }
-
- @override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
-
- @override
- NumState negated() => NumState.UNKNOWN_VALUE;
-
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
-
- @override
- IntState shiftLeft(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- IntState shiftRight(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
-
- /**
- * Return an object representing an unknown numeric value whose type is based
- * on the type of the [rightOperand].
- */
- NumState _unknownNum(InstanceState rightOperand) {
- if (rightOperand is IntState) {
- return IntState.UNKNOWN_VALUE;
- } else if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return NumState.UNKNOWN_VALUE;
- }
-}
-
-/**
- * A run-time exception that would be thrown during the evaluation of Dart code.
- */
-class EvaluationException extends JavaException {
- /**
- * The error code associated with the exception.
- */
- final ErrorCode errorCode;
-
- /**
- * Initialize a newly created exception to have the given [errorCode].
- */
- EvaluationException(this.errorCode);
-}
-
-/**
- * The result of attempting to evaluate an expression.
- */
-class EvaluationResult {
- /**
- * 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 == null ? AnalysisError.NO_ERRORS : _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) =>
- new 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) =>
- new 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.
- */
- 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, [List<AnalysisError> errors]) {
- this._errors = errors == null ? <AnalysisError>[] : errors;
- }
-
- @deprecated // Use new EvaluationResultImpl(value)
- EvaluationResultImpl.con1(this.value) {
- this._errors = new List<AnalysisError>(0);
- }
-
- @deprecated // Use new EvaluationResultImpl(value, errors)
- EvaluationResultImpl.con2(this.value, List<AnalysisError> errors) {
- this._errors = errors;
- }
-
- List<AnalysisError> get errors => _errors;
-
- bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) {
- if (this.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();
- }
-}
-
-/**
- * The state of an object representing a function.
- */
-class FunctionState extends InstanceState {
- /**
- * The element representing the function being modeled.
- */
- final ExecutableElement _element;
-
- /**
- * Initialize a newly created state to represent the function with the given
- * [element].
- */
- FunctionState(this._element);
-
- @override
- int get hashCode => _element == null ? 0 : _element.hashCode;
-
- @override
- String get typeName => "Function";
-
- @override
- bool operator ==(Object object) =>
- object is FunctionState && (_element == object._element);
-
- @override
- StringState convertToString() {
- if (_element == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(_element.name);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (_element == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is FunctionState) {
- ExecutableElement rightElement = rightOperand._element;
- if (rightElement == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(_element == rightElement);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- String toString() => _element == null ? "-unknown-" : _element.name;
-}
-
-/**
- * The state of an object representing a Dart object for which there is no more
- * specific state.
- */
-class GenericState extends InstanceState {
- /**
- * Pseudo-field that we use to represent fields in the superclass.
- */
- static String SUPERCLASS_FIELD = "(super)";
-
- /**
- * A state that can be used to represent an object whose state is not known.
- */
- static GenericState UNKNOWN_VALUE =
- new GenericState(new HashMap<String, DartObjectImpl>());
-
- /**
- * The values of the fields of this instance.
- */
- final HashMap<String, DartObjectImpl> _fieldMap;
-
- /**
- * Initialize a newly created state to represent a newly created object. The
- * [fieldMap] contains the values of the fields of the instance.
- */
- GenericState(this._fieldMap);
-
- @override
- HashMap<String, DartObjectImpl> get fields => _fieldMap;
-
- @override
- int get hashCode {
- int hashCode = 0;
- for (DartObjectImpl value in _fieldMap.values) {
- hashCode += value.hashCode;
- }
- return hashCode;
- }
-
- @override
- bool get isUnknown => identical(this, UNKNOWN_VALUE);
-
- @override
- String get typeName => "user defined type";
-
- @override
- bool operator ==(Object object) {
- if (object is! GenericState) {
- return false;
- }
- GenericState state = object as GenericState;
- HashSet<String> otherFields =
- new HashSet<String>.from(state._fieldMap.keys.toSet());
- for (String fieldName in _fieldMap.keys.toSet()) {
- if (_fieldMap[fieldName] != state._fieldMap[fieldName]) {
- return false;
- }
- otherFields.remove(fieldName);
- }
- for (String fieldName in otherFields) {
- if (state._fieldMap[fieldName] != _fieldMap[fieldName]) {
- return false;
- }
- }
- return true;
- }
-
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(this == rightOperand);
- }
-
- @override
- String toString() {
- StringBuffer buffer = new StringBuffer();
- List<String> fieldNames = _fieldMap.keys.toList();
- fieldNames.sort();
- bool first = true;
- for (String fieldName in fieldNames) {
- if (first) {
- first = false;
- } else {
- buffer.write('; ');
- }
- buffer.write(fieldName);
- buffer.write(' = ');
- buffer.write(_fieldMap[fieldName]);
- }
- return buffer.toString();
- }
-}
-
-/**
- * The state of an object representing a Dart object.
- */
-abstract class InstanceState {
- /**
- * If this represents a generic dart object, return a map from its field names
- * to their values. Otherwise return null.
- */
- HashMap<String, DartObjectImpl> get fields => null;
-
- /**
- * Return `true` if this object's value can be represented exactly.
- */
- bool get hasExactValue => false;
-
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- */
- bool get isBool => false;
-
- /**
- * Return `true` if this object represents an object whose type is either
- * 'bool', 'num', 'String', or 'Null'.
- */
- bool get isBoolNumStringOrNull => false;
-
- /**
- * Return `true` if this object represents an unknown value.
- */
- bool get isUnknown => false;
-
- /**
- * Return the name of the type of this value.
- */
- String get typeName;
-
- /**
- * Return this object's value if it can be represented exactly, or `null` if
- * either the value cannot be represented exactly or if the value is `null`.
- * Clients should use [hasExactValue] to distinguish between these two cases.
- */
- Object get value => null;
-
- /**
- * Return the result of invoking the '+' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- InstanceState add(InstanceState rightOperand) {
- if (this is StringState && rightOperand is StringState) {
- return concatenate(rightOperand);
- }
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Throw an exception if the given [state] does not represent a boolean value.
- */
- void assertBool(InstanceState state) {
- if (!(state is BoolState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
- }
- }
-
- /**
- * Throw an exception if the given [state] does not represent a boolean,
- * numeric, string or null value.
- */
- void assertBoolNumStringOrNull(InstanceState state) {
- if (!(state is BoolState ||
- state is DoubleState ||
- state is IntState ||
- state is NumState ||
- state is StringState ||
- state is NullState ||
- state is DynamicState)) {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
- }
- }
-
- /**
- * Throw an exception if the given [state] does not represent an integer or
- * null value.
- */
- void assertIntOrNull(InstanceState state) {
- if (!(state is IntState ||
- state is NumState ||
- state is NullState ||
- state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_INT);
- }
- }
-
- /**
- * Throw an exception if the given [state] does not represent a boolean,
- * numeric, string or null value.
- */
- void assertNumOrNull(InstanceState state) {
- if (!(state is DoubleState ||
- state is IntState ||
- state is NumState ||
- state is NullState ||
- state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_NUM);
- }
- }
-
- /**
- * Throw an exception if the given [state] does not represent a String value.
- */
- void assertString(InstanceState state) {
- if (!(state is StringState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
- }
- }
-
- /**
- * Return the result of invoking the '&' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState bitAnd(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '~' operator on this object.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState bitNot() {
- assertIntOrNull(this);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '|' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '^' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the ' ' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- StringState concatenate(InstanceState rightOperand) {
- assertString(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of applying boolean conversion to this object.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState convertToBool() => BoolState.FALSE_STATE;
-
- /**
- * Return the result of converting this object to a String.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- StringState convertToString();
-
- /**
- * Return the result of invoking the '/' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '==' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState equalEqual(InstanceState rightOperand);
-
- /**
- * Return the result of invoking the '&gt;' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&gt;=' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '~/' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the identical function on this object with
- * the [rightOperand].
- */
- BoolState isIdentical(InstanceState rightOperand);
-
- /**
- * Return the result of invoking the '&lt;' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&lt;=' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&&' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(this);
- assertBool(rightOperand);
- return BoolState.FALSE_STATE;
- }
-
- /**
- * Return the result of invoking the '!' operator on this object.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState logicalNot() {
- assertBool(this);
- return BoolState.TRUE_STATE;
- }
-
- /**
- * Return the result of invoking the '||' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(this);
- assertBool(rightOperand);
- return rightOperand.convertToBool();
- }
-
- /**
- * Return the result of invoking the '-' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '-' operator on this object.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- NumState negated() {
- assertNumOrNull(this);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '%' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&lt;&lt;' operator on this object with
- * the [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState shiftLeft(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&gt;&gt;' operator on this object with
- * the [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState shiftRight(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the 'length' getter on this object.
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- IntState stringLength() {
- assertString(this);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '*' operator on this object with the
- * [rightOperand].
- *
- * Throws an [EvaluationException] if the operator is not appropriate for an
- * object of this kind.
- */
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(this);
- assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-}
-
-/**
- * The state of an object representing an int.
- */
-class IntState extends NumState {
- /**
- * A state that can be used to represent an int whose value is not known.
- */
- static IntState UNKNOWN_VALUE = new IntState(null);
-
- /**
- * The value of this instance.
- */
- final int value;
-
- /**
- * Initialize a newly created state to represent an int with the given
- * [value].
- */
- IntState(this.value);
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- bool get isUnknown => value == null;
-
- @override
- String get typeName => "int";
-
- @override
- bool operator ==(Object object) =>
- object is IntState && (value == object.value);
-
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value + rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() + rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState bitAnd(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value & rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState bitNot() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(~value);
- }
-
- @override
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value | rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value ^ rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value.toString());
- }
-
- @override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- } else {
- return new DoubleState(value.toDouble() / rightValue.toDouble());
- }
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() / rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) > 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() > rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) >= 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() >= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
- }
- return new IntState(value ~/ rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- double result = value.toDouble() / rightValue;
- return new IntState(result.toInt());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(rightValue == value.toDouble());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) < 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() < rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) <= 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() <= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value - rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() - rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState negated() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(-value);
- }
-
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- return new DoubleState(value.toDouble() % rightValue.toDouble());
- }
- return new IntState(value.remainder(rightValue));
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() % rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState shiftLeft(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue.bitLength > 31) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value << rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- IntState shiftRight(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue.bitLength > 31) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value >> rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value * rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() * rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- String toString() => value == null ? "-unknown-" : value.toString();
-}
-
-/**
- * The state of an object representing a list.
- */
-class ListState extends InstanceState {
- /**
- * The elements of the list.
- */
- final List<DartObjectImpl> _elements;
-
- /**
- * Initialize a newly created state to represent a list with the given
- * [elements].
- */
- ListState(this._elements);
-
- @override
- bool get hasExactValue {
- int count = _elements.length;
- for (int i = 0; i < count; i++) {
- if (!_elements[i].hasExactValue) {
- return false;
- }
- }
- return true;
- }
-
- @override
- int get hashCode {
- int value = 0;
- int count = _elements.length;
- for (int i = 0; i < count; i++) {
- value = (value << 3) ^ _elements[i].hashCode;
- }
- return value;
- }
-
- @override
- String get typeName => "List";
-
- @override
- List<Object> get value {
- int count = _elements.length;
- List<Object> result = new List<Object>(count);
- for (int i = 0; i < count; i++) {
- DartObjectImpl element = _elements[i];
- if (!element.hasExactValue) {
- return null;
- }
- result[i] = element.value;
- }
- return result;
- }
-
- @override
- bool operator ==(Object object) {
- if (object is! ListState) {
- return false;
- }
- List<DartObjectImpl> otherElements = (object as ListState)._elements;
- int count = _elements.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
- return true;
- }
- for (int i = 0; i < count; i++) {
- if (_elements[i] != otherElements[i]) {
- return false;
- }
- }
- return true;
- }
-
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(this == rightOperand);
- }
-
- @override
- String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.write('[');
- bool first = true;
- _elements.forEach((DartObjectImpl element) {
- if (first) {
- first = false;
- } else {
- buffer.write(', ');
- }
- buffer.write(element);
- });
- buffer.write(']');
- return buffer.toString();
- }
-}
-
-/**
- * The state of an object representing a map.
- */
-class MapState extends InstanceState {
- /**
- * The entries in the map.
- */
- final HashMap<DartObjectImpl, DartObjectImpl> _entries;
-
- /**
- * Initialize a newly created state to represent a map with the given
- * [entries].
- */
- MapState(this._entries);
-
- @override
- bool get hasExactValue {
- for (DartObjectImpl key in _entries.keys) {
- if (!key.hasExactValue || !_entries[key].hasExactValue) {
- return false;
- }
- }
- return true;
- }
-
- @override
- int get hashCode {
- int value = 0;
- for (DartObjectImpl key in _entries.keys.toSet()) {
- value = (value << 3) ^ key.hashCode;
- }
- return value;
- }
-
- @override
- String get typeName => "Map";
-
- @override
- Map<Object, Object> get value {
- HashMap<Object, Object> result = new HashMap<Object, Object>();
- for (DartObjectImpl key in _entries.keys) {
- DartObjectImpl value = _entries[key];
- if (!key.hasExactValue || !value.hasExactValue) {
- return null;
- }
- result[key.value] = value.value;
- }
- return result;
- }
-
- @override
- bool operator ==(Object object) {
- if (object is! MapState) {
- return false;
- }
- HashMap<DartObjectImpl, DartObjectImpl> otherElements =
- (object as MapState)._entries;
- int count = _entries.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
- return true;
- }
- for (DartObjectImpl key in _entries.keys) {
- DartObjectImpl value = _entries[key];
- DartObjectImpl otherValue = otherElements[key];
- if (value != otherValue) {
- return false;
- }
- }
- return true;
- }
-
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(this == rightOperand);
- }
-
- @override
- String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.write('{');
- bool first = true;
- _entries.forEach((DartObjectImpl key, DartObjectImpl value) {
- if (first) {
- first = false;
- } else {
- buffer.write(', ');
- }
- buffer.write(key);
- buffer.write(' = ');
- buffer.write(value);
- });
- buffer.write('}');
- return buffer.toString();
- }
-}
-
-/**
- * The state of an object representing the value 'null'.
- */
-class NullState extends InstanceState {
- /**
- * An instance representing the boolean value 'null'.
- */
- static NullState NULL_STATE = new NullState();
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => 0;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- String get typeName => "Null";
-
- @override
- bool operator ==(Object object) => object is NullState;
-
- @override
- BoolState convertToBool() {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- StringState convertToString() => new StringState("null");
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(rightOperand is NullState);
- }
-
- @override
- BoolState logicalNot() {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
-
- @override
- String toString() => "null";
-}
-
-/**
- * The state of an object representing a number of an unknown type (a 'num').
- */
-class NumState extends InstanceState {
- /**
- * A state that can be used to represent a number whose value is not known.
- */
- static NumState UNKNOWN_VALUE = new NumState();
-
- @override
- int get hashCode => 7;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- bool get isUnknown => identical(this, UNKNOWN_VALUE);
-
- @override
- String get typeName => "num";
-
- @override
- bool operator ==(Object object) => object is NumState;
-
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
-
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
-
- @override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return DoubleState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- throw new EvaluationException(
- CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
- }
- } else if (rightOperand is DynamicState) {
- return IntState.UNKNOWN_VALUE;
- }
- return IntState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
-
- @override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
-
- @override
- NumState negated() => UNKNOWN_VALUE;
-
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
-
- @override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
-
- @override
- String toString() => "-unknown-";
-}
-
-/**
- * An object used to add reference information for a given variable to the
- * bi-directional mapping used to order the evaluation of constants.
- */
-class ReferenceFinder extends RecursiveAstVisitor<Object> {
- /**
- * The callback which should be used to report any dependencies that were
- * found.
- */
- final ReferenceFinderCallback _callback;
-
- /**
- * Initialize a newly created reference finder to find references from a given
- * variable to other variables and to add those references to the given graph.
- * The [_callback] will be invoked for every dependency found.
- */
- ReferenceFinder(this._callback);
-
- @override
- Object visitInstanceCreationExpression(InstanceCreationExpression node) {
- if (node.isConst) {
- ConstructorElement constructor =
- ConstantEvaluationEngine._getConstructorBase(node.staticElement);
- if (constructor != null) {
- _callback(constructor);
- }
- }
- return super.visitInstanceCreationExpression(node);
- }
-
- @override
- Object visitLabel(Label node) {
- // We are visiting the "label" part of a named expression in a function
- // call (presumably a constructor call), e.g. "const C(label: ...)". We
- // don't want to visit the SimpleIdentifier for the label because that's a
- // reference to a function parameter that needs to be filled in; it's not a
- // constant whose value we depend on.
- return null;
- }
-
- @override
- Object visitRedirectingConstructorInvocation(
- RedirectingConstructorInvocation node) {
- super.visitRedirectingConstructorInvocation(node);
- ConstructorElement target =
- ConstantEvaluationEngine._getConstructorBase(node.staticElement);
- if (target != null) {
- _callback(target);
- }
- return null;
- }
-
- @override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
- Element element = node.staticElement;
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- if (element is VariableElement) {
- _callback(element);
- }
- return null;
- }
-
- @override
- Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- super.visitSuperConstructorInvocation(node);
- ConstructorElement constructor =
- ConstantEvaluationEngine._getConstructorBase(node.staticElement);
- if (constructor != null) {
- _callback(constructor);
- }
- return null;
- }
-}
-
-/**
- * The state of an object representing a string.
- */
-class StringState extends InstanceState {
- /**
- * A state that can be used to represent a double whose value is not known.
- */
- static StringState UNKNOWN_VALUE = new StringState(null);
-
- /**
- * The value of this instance.
- */
- final String value;
-
- /**
- * Initialize a newly created state to represent the given [value].
- */
- StringState(this.value);
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
-
- @override
- bool get isBoolNumStringOrNull => true;
-
- @override
- bool get isUnknown => value == null;
-
- @override
- String get typeName => "String";
-
- @override
- bool operator ==(Object object) =>
- object is StringState && (value == object.value);
-
- @override
- StringState concatenate(InstanceState rightOperand) {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is StringState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new StringState("$value$rightValue");
- } else if (rightOperand is DynamicState) {
- return UNKNOWN_VALUE;
- }
- return super.concatenate(rightOperand);
- }
-
- @override
- StringState convertToString() => this;
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is StringState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- IntState stringLength() {
- if (value == null) {
- return IntState.UNKNOWN_VALUE;
- }
- return new IntState(value.length);
- }
-
- @override
- String toString() => value == null ? "-unknown-" : "'$value'";
-}
-
-/**
- * The state of an object representing a symbol.
- */
-class SymbolState extends InstanceState {
- /**
- * The value of this instance.
- */
- final String value;
-
- /**
- * Initialize a newly created state to represent the given [value].
- */
- SymbolState(this.value);
-
- @override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
-
- @override
- String get typeName => "Symbol";
-
- @override
- bool operator ==(Object object) =>
- object is SymbolState && (value == object.value);
-
- @override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is SymbolState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- String toString() => value == null ? "-unknown-" : "#$value";
-}
-
-/**
- * The state of an object representing a type.
- */
-class TypeState extends InstanceState {
- /**
- * The element representing the type being modeled.
- */
- final Element _element;
-
- /**
- * Initialize a newly created state to represent the given [value].
- */
- TypeState(this._element);
-
- @override
- int get hashCode => _element == null ? 0 : _element.hashCode;
-
- @override
- String get typeName => "Type";
-
- @override
- Element get value => _element;
-
- @override
- bool operator ==(Object object) =>
- object is TypeState && (_element == object._element);
-
- @override
- StringState convertToString() {
- if (_element == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(_element.name);
- }
-
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return isIdentical(rightOperand);
- }
-
- @override
- BoolState isIdentical(InstanceState rightOperand) {
- if (_element == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is TypeState) {
- Element rightElement = rightOperand._element;
- if (rightElement == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(_element == rightElement);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
-
- @override
- String toString() => _element == null ? "-unknown-" : _element.name;
-}
« no previous file with comments | « analyzer/lib/src/generated/ast.dart ('k') | analyzer/lib/src/generated/element.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698