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

Side by Side Diff: packages/analyzer/lib/src/generated/constant.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.constant; 5 library analyzer.src.generated.constant;
6 6
7 import 'dart:collection'; 7 import 'package:analyzer/context/declared_variables.dart';
8 import 'package:analyzer/dart/ast/ast.dart';
9 import 'package:analyzer/error/listener.dart';
10 import 'package:analyzer/src/dart/constant/evaluation.dart';
11 import 'package:analyzer/src/dart/constant/value.dart';
12 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/engine.dart' show RecordingErrorListener;
14 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
15 import 'package:analyzer/src/generated/source.dart' show Source;
16 import 'package:analyzer/src/generated/type_system.dart'
17 show TypeSystem, TypeSystemImpl;
8 18
9 import 'package:analyzer/src/generated/engine.dart'; 19 export 'package:analyzer/context/declared_variables.dart';
10 import 'package:analyzer/src/generated/utilities_general.dart'; 20 export 'package:analyzer/dart/constant/value.dart';
11 import 'package:analyzer/src/task/dart.dart'; 21 export 'package:analyzer/src/dart/constant/evaluation.dart';
12 22 export 'package:analyzer/src/dart/constant/utilities.dart';
13 import 'ast.dart'; 23 export 'package:analyzer/src/dart/constant/value.dart';
14 import 'element.dart';
15 import 'engine.dart' show AnalysisEngine, RecordingErrorListener;
16 import 'error.dart';
17 import 'java_core.dart';
18 import 'resolver.dart' show TypeProvider, TypeSystem, TypeSystemImpl;
19 import 'scanner.dart' show Token, TokenType;
20 import 'source.dart' show Source;
21 import 'utilities_collection.dart';
22 import 'utilities_dart.dart' show ParameterKind;
23
24 /**
25 * Callback used by [ReferenceFinder] to report that a dependency was found.
26 */
27 typedef void ReferenceFinderCallback(ConstantEvaluationTarget dependency);
28
29 /**
30 * The state of an object representing a boolean value.
31 */
32 class BoolState extends InstanceState {
33 /**
34 * An instance representing the boolean value 'false'.
35 */
36 static BoolState FALSE_STATE = new BoolState(false);
37
38 /**
39 * An instance representing the boolean value 'true'.
40 */
41 static BoolState TRUE_STATE = new BoolState(true);
42
43 /**
44 * A state that can be used to represent a boolean whose value is not known.
45 */
46 static BoolState UNKNOWN_VALUE = new BoolState(null);
47
48 /**
49 * The value of this instance.
50 */
51 final bool value;
52
53 /**
54 * Initialize a newly created state to represent the given [value].
55 */
56 BoolState(this.value);
57
58 @override
59 bool get hasExactValue => true;
60
61 @override
62 int get hashCode => value == null ? 0 : (value ? 2 : 3);
63
64 @override
65 bool get isBool => true;
66
67 @override
68 bool get isBoolNumStringOrNull => true;
69
70 @override
71 bool get isUnknown => value == null;
72
73 @override
74 String get typeName => "bool";
75
76 @override
77 bool operator ==(Object object) =>
78 object is BoolState && identical(value, object.value);
79
80 @override
81 BoolState convertToBool() => this;
82
83 @override
84 StringState convertToString() {
85 if (value == null) {
86 return StringState.UNKNOWN_VALUE;
87 }
88 return new StringState(value ? "true" : "false");
89 }
90
91 @override
92 BoolState equalEqual(InstanceState rightOperand) {
93 assertBoolNumStringOrNull(rightOperand);
94 return isIdentical(rightOperand);
95 }
96
97 @override
98 BoolState isIdentical(InstanceState rightOperand) {
99 if (value == null) {
100 return UNKNOWN_VALUE;
101 }
102 if (rightOperand is BoolState) {
103 bool rightValue = rightOperand.value;
104 if (rightValue == null) {
105 return UNKNOWN_VALUE;
106 }
107 return BoolState.from(identical(value, rightValue));
108 } else if (rightOperand is DynamicState) {
109 return UNKNOWN_VALUE;
110 }
111 return FALSE_STATE;
112 }
113
114 @override
115 BoolState logicalAnd(InstanceState rightOperand) {
116 assertBool(rightOperand);
117 if (value == null) {
118 return UNKNOWN_VALUE;
119 }
120 return value ? rightOperand.convertToBool() : FALSE_STATE;
121 }
122
123 @override
124 BoolState logicalNot() {
125 if (value == null) {
126 return UNKNOWN_VALUE;
127 }
128 return value ? FALSE_STATE : TRUE_STATE;
129 }
130
131 @override
132 BoolState logicalOr(InstanceState rightOperand) {
133 assertBool(rightOperand);
134 if (value == null) {
135 return UNKNOWN_VALUE;
136 }
137 return value ? TRUE_STATE : rightOperand.convertToBool();
138 }
139
140 @override
141 String toString() => value == null ? "-unknown-" : (value ? "true" : "false");
142
143 /**
144 * Return the boolean state representing the given boolean [value].
145 */
146 static BoolState from(bool value) =>
147 value ? BoolState.TRUE_STATE : BoolState.FALSE_STATE;
148 }
149
150 /**
151 * An [AstCloner] that copies the necessary information from the AST to allow
152 * constants to be evaluated.
153 */
154 class ConstantAstCloner extends AstCloner {
155 ConstantAstCloner() : super(true);
156
157 @override
158 InstanceCreationExpression visitInstanceCreationExpression(
159 InstanceCreationExpression node) {
160 InstanceCreationExpression expression =
161 super.visitInstanceCreationExpression(node);
162 expression.staticElement = node.staticElement;
163 return expression;
164 }
165
166 @override
167 RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
168 RedirectingConstructorInvocation node) {
169 RedirectingConstructorInvocation invocation =
170 super.visitRedirectingConstructorInvocation(node);
171 invocation.staticElement = node.staticElement;
172 return invocation;
173 }
174
175 @override
176 SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) {
177 SimpleIdentifier identifier = super.visitSimpleIdentifier(node);
178 identifier.staticElement = node.staticElement;
179 return identifier;
180 }
181
182 @override
183 SuperConstructorInvocation visitSuperConstructorInvocation(
184 SuperConstructorInvocation node) {
185 SuperConstructorInvocation invocation =
186 super.visitSuperConstructorInvocation(node);
187 invocation.staticElement = node.staticElement;
188 return invocation;
189 }
190 }
191
192 /**
193 * Helper class encapsulating the methods for evaluating constants and
194 * constant instance creation expressions.
195 */
196 class ConstantEvaluationEngine {
197 /**
198 * Parameter to "fromEnvironment" methods that denotes the default value.
199 */
200 static String _DEFAULT_VALUE_PARAM = "defaultValue";
201
202 /**
203 * Source of RegExp matching any public identifier.
204 * From sdk/lib/internal/symbol.dart.
205 */
206 static String _PUBLIC_IDENTIFIER_RE =
207 "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$ ]*";
208
209 /**
210 * RegExp that validates a non-empty non-private symbol.
211 * From sdk/lib/internal/symbol.dart.
212 */
213 static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp(
214 "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$ |[.](?!\$)))+?\$");
215
216 /**
217 * The type provider used to access the known types.
218 */
219 final TypeProvider typeProvider;
220
221 /**
222 * The type system. This is used to gues the types of constants when their
223 * exact value is unknown.
224 */
225 final TypeSystem typeSystem;
226
227 /**
228 * The set of variables declared on the command line using '-D'.
229 */
230 final DeclaredVariables _declaredVariables;
231
232 /**
233 * Validator used to verify correct dependency analysis when running unit
234 * tests.
235 */
236 final ConstantEvaluationValidator validator;
237
238 /**
239 * Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider]
240 * is used to access known types. [_declaredVariables] is the set of
241 * variables declared on the command line using '-D'. The [validator], if
242 * given, is used to verify correct dependency analysis when running unit
243 * tests.
244 */
245 ConstantEvaluationEngine(this.typeProvider, this._declaredVariables,
246 {ConstantEvaluationValidator validator, TypeSystem typeSystem})
247 : validator = validator != null
248 ? validator
249 : new ConstantEvaluationValidator_ForProduction(),
250 typeSystem = typeSystem != null ? typeSystem : new TypeSystemImpl();
251
252 /**
253 * Check that the arguments to a call to fromEnvironment() are correct. The
254 * [arguments] are the AST nodes of the arguments. The [argumentValues] are
255 * the values of the unnamed arguments. The [namedArgumentValues] are the
256 * values of the named arguments. The [expectedDefaultValueType] is the
257 * allowed type of the "defaultValue" parameter (if present). Note:
258 * "defaultValue" is always allowed to be null. Return `true` if the arguments
259 * are correct, `false` if there is an error.
260 */
261 bool checkFromEnvironmentArguments(
262 NodeList<Expression> arguments,
263 List<DartObjectImpl> argumentValues,
264 HashMap<String, DartObjectImpl> namedArgumentValues,
265 InterfaceType expectedDefaultValueType) {
266 int argumentCount = arguments.length;
267 if (argumentCount < 1 || argumentCount > 2) {
268 return false;
269 }
270 if (arguments[0] is NamedExpression) {
271 return false;
272 }
273 if (!identical(argumentValues[0].type, typeProvider.stringType)) {
274 return false;
275 }
276 if (argumentCount == 2) {
277 if (arguments[1] is! NamedExpression) {
278 return false;
279 }
280 if (!((arguments[1] as NamedExpression).name.label.name ==
281 _DEFAULT_VALUE_PARAM)) {
282 return false;
283 }
284 ParameterizedType defaultValueType =
285 namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
286 if (!(identical(defaultValueType, expectedDefaultValueType) ||
287 identical(defaultValueType, typeProvider.nullType))) {
288 return false;
289 }
290 }
291 return true;
292 }
293
294 /**
295 * Check that the arguments to a call to Symbol() are correct. The [arguments]
296 * are the AST nodes of the arguments. The [argumentValues] are the values of
297 * the unnamed arguments. The [namedArgumentValues] are the values of the
298 * named arguments. Return `true` if the arguments are correct, `false` if
299 * there is an error.
300 */
301 bool checkSymbolArguments(
302 NodeList<Expression> arguments,
303 List<DartObjectImpl> argumentValues,
304 HashMap<String, DartObjectImpl> namedArgumentValues) {
305 if (arguments.length != 1) {
306 return false;
307 }
308 if (arguments[0] is NamedExpression) {
309 return false;
310 }
311 if (!identical(argumentValues[0].type, typeProvider.stringType)) {
312 return false;
313 }
314 String name = argumentValues[0].toStringValue();
315 return isValidPublicSymbol(name);
316 }
317
318 /**
319 * Compute the constant value associated with the given [constant].
320 */
321 void computeConstantValue(ConstantEvaluationTarget constant) {
322 validator.beforeComputeValue(constant);
323 if (constant is ParameterElement) {
324 if (constant.initializer != null) {
325 Expression defaultValue =
326 (constant as PotentiallyConstVariableElement).constantInitializer;
327 if (defaultValue != null) {
328 RecordingErrorListener errorListener = new RecordingErrorListener();
329 ErrorReporter errorReporter =
330 new ErrorReporter(errorListener, constant.source);
331 DartObjectImpl dartObject =
332 defaultValue.accept(new ConstantVisitor(this, errorReporter));
333 (constant as ParameterElementImpl).evaluationResult =
334 new EvaluationResultImpl(dartObject, errorListener.errors);
335 }
336 }
337 } else if (constant is VariableElement) {
338 Expression constantInitializer =
339 (constant as PotentiallyConstVariableElement).constantInitializer;
340 if (constantInitializer != null) {
341 RecordingErrorListener errorListener = new RecordingErrorListener();
342 ErrorReporter errorReporter =
343 new ErrorReporter(errorListener, constant.source);
344 DartObjectImpl dartObject = constantInitializer
345 .accept(new ConstantVisitor(this, errorReporter));
346 // Only check the type for truly const declarations (don't check final
347 // fields with initializers, since their types may be generic. The type
348 // of the final field will be checked later, when the constructor is
349 // invoked).
350 if (dartObject != null && constant.isConst) {
351 if (!runtimeTypeMatch(dartObject, constant.type)) {
352 errorReporter.reportErrorForElement(
353 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
354 constant,
355 [dartObject.type, constant.type]);
356 }
357 }
358 (constant as VariableElementImpl).evaluationResult =
359 new EvaluationResultImpl(dartObject, errorListener.errors);
360 }
361 } else if (constant is ConstructorElement) {
362 if (constant.isConst) {
363 // No evaluation needs to be done; constructor declarations are only in
364 // the dependency graph to ensure that any constants referred to in
365 // initializer lists and parameter defaults are evaluated before
366 // invocations of the constructor. However we do need to annotate the
367 // element as being free of constant evaluation cycles so that later
368 // code will know that it is safe to evaluate.
369 (constant as ConstructorElementImpl).isCycleFree = true;
370 }
371 } else if (constant is ConstantEvaluationTarget_Annotation) {
372 Annotation constNode = constant.annotation;
373 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
374 // elementAnnotation is null if the annotation couldn't be resolved, in
375 // which case we skip it.
376 if (elementAnnotation != null) {
377 Element element = elementAnnotation.element;
378 if (element is PropertyAccessorElement &&
379 element.variable is VariableElementImpl) {
380 // The annotation is a reference to a compile-time constant variable.
381 // Just copy the evaluation result.
382 VariableElementImpl variableElement =
383 element.variable as VariableElementImpl;
384 if (variableElement.evaluationResult != null) {
385 elementAnnotation.evaluationResult =
386 variableElement.evaluationResult;
387 } else {
388 // This could happen in the event that the annotation refers to a
389 // non-constant. The error is detected elsewhere, so just silently
390 // ignore it here.
391 elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
392 }
393 } else if (element is ConstructorElementImpl &&
394 element.isConst &&
395 constNode.arguments != null) {
396 RecordingErrorListener errorListener = new RecordingErrorListener();
397 CompilationUnit sourceCompilationUnit =
398 constNode.getAncestor((node) => node is CompilationUnit);
399 ErrorReporter errorReporter = new ErrorReporter(
400 errorListener, sourceCompilationUnit.element.source);
401 ConstantVisitor constantVisitor =
402 new ConstantVisitor(this, errorReporter);
403 DartObjectImpl result = evaluateConstructorCall(
404 constNode,
405 constNode.arguments.arguments,
406 element,
407 constantVisitor,
408 errorReporter);
409 elementAnnotation.evaluationResult =
410 new EvaluationResultImpl(result, errorListener.errors);
411 } else {
412 // This may happen for invalid code (e.g. failing to pass arguments
413 // to an annotation which references a const constructor). The error
414 // is detected elsewhere, so just silently ignore it here.
415 elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
416 }
417 }
418 } else {
419 // Should not happen.
420 assert(false);
421 AnalysisEngine.instance.logger.logError(
422 "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}");
423 return;
424 }
425 }
426
427 /**
428 * Determine which constant elements need to have their values computed
429 * prior to computing the value of [constant], and report them using
430 * [callback].
431 *
432 * Note that it's possible (in erroneous code) for a constant to depend on a
433 * non-constant. When this happens, we report the dependency anyhow so that
434 * if the non-constant changes to a constant, we will know to recompute the
435 * thing that depends on it. [computeDependencies] and
436 * [computeConstantValue] are responsible for ignoring the request if they
437 * are asked to act on a non-constant target.
438 */
439 void computeDependencies(
440 ConstantEvaluationTarget constant, ReferenceFinderCallback callback) {
441 ReferenceFinder referenceFinder = new ReferenceFinder(callback);
442 if (constant is ParameterElement) {
443 if (constant.initializer != null) {
444 Expression defaultValue =
445 (constant as ConstVariableElement).constantInitializer;
446 if (defaultValue != null) {
447 defaultValue.accept(referenceFinder);
448 }
449 }
450 } else if (constant is PotentiallyConstVariableElement) {
451 Expression initializer = constant.constantInitializer;
452 if (initializer != null) {
453 initializer.accept(referenceFinder);
454 }
455 } else if (constant is ConstructorElementImpl) {
456 if (constant.isConst) {
457 constant.isCycleFree = false;
458 ConstructorElement redirectedConstructor =
459 getConstRedirectedConstructor(constant);
460 if (redirectedConstructor != null) {
461 ConstructorElement redirectedConstructorBase =
462 ConstantEvaluationEngine
463 ._getConstructorBase(redirectedConstructor);
464 callback(redirectedConstructorBase);
465 return;
466 } else if (constant.isFactory) {
467 // Factory constructor, but getConstRedirectedConstructor returned
468 // null. This can happen if we're visiting one of the special externa l
469 // const factory constructors in the SDK, or if the code contains
470 // errors (such as delegating to a non-const constructor, or delegatin g
471 // to a constructor that can't be resolved). In any of these cases,
472 // we'll evaluate calls to this constructor without having to refer to
473 // any other constants. So we don't need to report any dependencies.
474 return;
475 }
476 bool superInvocationFound = false;
477 List<ConstructorInitializer> initializers =
478 constant.constantInitializers;
479 for (ConstructorInitializer initializer in initializers) {
480 if (initializer is SuperConstructorInvocation) {
481 superInvocationFound = true;
482 }
483 initializer.accept(referenceFinder);
484 }
485 if (!superInvocationFound) {
486 // No explicit superconstructor invocation found, so we need to
487 // manually insert a reference to the implicit superconstructor.
488 InterfaceType superclass =
489 (constant.returnType as InterfaceType).superclass;
490 if (superclass != null && !superclass.isObject) {
491 ConstructorElement unnamedConstructor = ConstantEvaluationEngine
492 ._getConstructorBase(superclass.element.unnamedConstructor);
493 if (unnamedConstructor != null) {
494 callback(unnamedConstructor);
495 }
496 }
497 }
498 for (FieldElement field in constant.enclosingElement.fields) {
499 // Note: non-static const isn't allowed but we handle it anyway so
500 // that we won't be confused by incorrect code.
501 if ((field.isFinal || field.isConst) &&
502 !field.isStatic &&
503 field.initializer != null) {
504 callback(field);
505 }
506 }
507 for (ParameterElement parameterElement in constant.parameters) {
508 callback(parameterElement);
509 }
510 }
511 } else if (constant is ConstantEvaluationTarget_Annotation) {
512 Annotation constNode = constant.annotation;
513 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
514 // elementAnnotation is null if the annotation couldn't be resolved, in
515 // which case we skip it.
516 if (elementAnnotation != null) {
517 Element element = elementAnnotation.element;
518 if (element is PropertyAccessorElement &&
519 element.variable is VariableElementImpl) {
520 // The annotation is a reference to a compile-time constant variable,
521 // so it depends on the variable.
522 callback(element.variable);
523 } else if (element is ConstructorElementImpl) {
524 // The annotation is a constructor invocation, so it depends on the
525 // constructor.
526 callback(element);
527 } else {
528 // This could happen in the event of invalid code. The error will be
529 // reported at constant evaluation time.
530 }
531 }
532 if (constNode.arguments != null) {
533 constNode.arguments.accept(referenceFinder);
534 }
535 } else {
536 // Should not happen.
537 assert(false);
538 AnalysisEngine.instance.logger.logError(
539 "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}");
540 }
541 }
542
543 /**
544 * Evaluate a call to fromEnvironment() on the bool, int, or String class. The
545 * [environmentValue] is the value fetched from the environment. The
546 * [builtInDefaultValue] is the value that should be used as the default if no
547 * "defaultValue" argument appears in [namedArgumentValues]. The
548 * [namedArgumentValues] are the values of the named parameters passed to
549 * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the
550 * evaluated result.
551 */
552 DartObjectImpl computeValueFromEnvironment(
553 DartObject environmentValue,
554 DartObjectImpl builtInDefaultValue,
555 HashMap<String, DartObjectImpl> namedArgumentValues) {
556 DartObjectImpl value = environmentValue as DartObjectImpl;
557 if (value.isUnknown || value.isNull) {
558 // The name either doesn't exist in the environment or we couldn't parse
559 // the corresponding value.
560 // If the code supplied an explicit default, use it.
561 if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) {
562 value = namedArgumentValues[_DEFAULT_VALUE_PARAM];
563 } else if (value.isNull) {
564 // The code didn't supply an explicit default.
565 // The name exists in the environment but we couldn't parse the
566 // corresponding value.
567 // So use the built-in default value, because this is what the VM does.
568 value = builtInDefaultValue;
569 } else {
570 // The code didn't supply an explicit default.
571 // The name doesn't exist in the environment.
572 // The VM would use the built-in default value, but we don't want to do
573 // that for analysis because it's likely to lead to cascading errors.
574 // So just leave [value] in the unknown state.
575 }
576 }
577 return value;
578 }
579
580 DartObjectImpl evaluateConstructorCall(
581 AstNode node,
582 NodeList<Expression> arguments,
583 ConstructorElement constructor,
584 ConstantVisitor constantVisitor,
585 ErrorReporter errorReporter) {
586 if (!_getConstructorBase(constructor).isCycleFree) {
587 // It's not safe to evaluate this constructor, so bail out.
588 // TODO(paulberry): ensure that a reasonable error message is produced
589 // in this case, as well as other cases involving constant expression
590 // circularities (e.g. "compile-time constant expression depends on
591 // itself")
592 return new DartObjectImpl.validWithUnknownValue(constructor.returnType);
593 }
594 int argumentCount = arguments.length;
595 List<DartObjectImpl> argumentValues =
596 new List<DartObjectImpl>(argumentCount);
597 List<Expression> argumentNodes = new List<Expression>(argumentCount);
598 HashMap<String, DartObjectImpl> namedArgumentValues =
599 new HashMap<String, DartObjectImpl>();
600 HashMap<String, NamedExpression> namedArgumentNodes =
601 new HashMap<String, NamedExpression>();
602 for (int i = 0; i < argumentCount; i++) {
603 Expression argument = arguments[i];
604 if (argument is NamedExpression) {
605 String name = argument.name.label.name;
606 namedArgumentValues[name] =
607 constantVisitor._valueOf(argument.expression);
608 namedArgumentNodes[name] = argument;
609 argumentValues[i] = typeProvider.nullObject;
610 } else {
611 argumentValues[i] = constantVisitor._valueOf(argument);
612 argumentNodes[i] = argument;
613 }
614 }
615 constructor = followConstantRedirectionChain(constructor);
616 InterfaceType definingClass = constructor.returnType as InterfaceType;
617 if (constructor.isFactory) {
618 // We couldn't find a non-factory constructor.
619 // See if it's because we reached an external const factory constructor
620 // that we can emulate.
621 if (constructor.name == "fromEnvironment") {
622 if (!checkFromEnvironmentArguments(
623 arguments, argumentValues, namedArgumentValues, definingClass)) {
624 errorReporter.reportErrorForNode(
625 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
626 return null;
627 }
628 String variableName =
629 argumentCount < 1 ? null : argumentValues[0].toStringValue();
630 if (identical(definingClass, typeProvider.boolType)) {
631 DartObject valueFromEnvironment;
632 valueFromEnvironment =
633 _declaredVariables.getBool(typeProvider, variableName);
634 return computeValueFromEnvironment(
635 valueFromEnvironment,
636 new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE),
637 namedArgumentValues);
638 } else if (identical(definingClass, typeProvider.intType)) {
639 DartObject valueFromEnvironment;
640 valueFromEnvironment =
641 _declaredVariables.getInt(typeProvider, variableName);
642 return computeValueFromEnvironment(
643 valueFromEnvironment,
644 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
645 namedArgumentValues);
646 } else if (identical(definingClass, typeProvider.stringType)) {
647 DartObject valueFromEnvironment;
648 valueFromEnvironment =
649 _declaredVariables.getString(typeProvider, variableName);
650 return computeValueFromEnvironment(
651 valueFromEnvironment,
652 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
653 namedArgumentValues);
654 }
655 } else if (constructor.name == "" &&
656 identical(definingClass, typeProvider.symbolType) &&
657 argumentCount == 1) {
658 if (!checkSymbolArguments(
659 arguments, argumentValues, namedArgumentValues)) {
660 errorReporter.reportErrorForNode(
661 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
662 return null;
663 }
664 String argumentValue = argumentValues[0].toStringValue();
665 return new DartObjectImpl(
666 definingClass, new SymbolState(argumentValue));
667 }
668 // Either it's an external const factory constructor that we can't
669 // emulate, or an error occurred (a cycle, or a const constructor trying
670 // to delegate to a non-const constructor).
671 // In the former case, the best we can do is consider it an unknown value.
672 // In the latter case, the error has already been reported, so considering
673 // it an unknown value will suppress further errors.
674 return new DartObjectImpl.validWithUnknownValue(definingClass);
675 }
676 ConstructorElementImpl constructorBase = _getConstructorBase(constructor);
677 validator.beforeGetConstantInitializers(constructorBase);
678 List<ConstructorInitializer> initializers =
679 constructorBase.constantInitializers;
680 if (initializers == null) {
681 // This can happen in some cases where there are compile errors in the
682 // code being analyzed (for example if the code is trying to create a
683 // const instance using a non-const constructor, or the node we're
684 // visiting is involved in a cycle). The error has already been reported,
685 // so consider it an unknown value to suppress further errors.
686 return new DartObjectImpl.validWithUnknownValue(definingClass);
687 }
688 HashMap<String, DartObjectImpl> fieldMap =
689 new HashMap<String, DartObjectImpl>();
690 // Start with final fields that are initialized at their declaration site.
691 for (FieldElement field in constructor.enclosingElement.fields) {
692 if ((field.isFinal || field.isConst) &&
693 !field.isStatic &&
694 field is ConstFieldElementImpl) {
695 validator.beforeGetFieldEvaluationResult(field);
696 EvaluationResultImpl evaluationResult = field.evaluationResult;
697 DartType fieldType =
698 FieldMember.from(field, constructor.returnType).type;
699 DartObjectImpl fieldValue = evaluationResult.value;
700 if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) {
701 errorReporter.reportErrorForNode(
702 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA TCH,
703 node,
704 [fieldValue.type, field.name, fieldType]);
705 }
706 fieldMap[field.name] = evaluationResult.value;
707 }
708 }
709 // Now evaluate the constructor declaration.
710 HashMap<String, DartObjectImpl> parameterMap =
711 new HashMap<String, DartObjectImpl>();
712 List<ParameterElement> parameters = constructor.parameters;
713 int parameterCount = parameters.length;
714 for (int i = 0; i < parameterCount; i++) {
715 ParameterElement parameter = parameters[i];
716 ParameterElement baseParameter = parameter;
717 while (baseParameter is ParameterMember) {
718 baseParameter = (baseParameter as ParameterMember).baseElement;
719 }
720 DartObjectImpl argumentValue = null;
721 AstNode errorTarget = null;
722 if (baseParameter.parameterKind == ParameterKind.NAMED) {
723 argumentValue = namedArgumentValues[baseParameter.name];
724 errorTarget = namedArgumentNodes[baseParameter.name];
725 } else if (i < argumentCount) {
726 argumentValue = argumentValues[i];
727 errorTarget = argumentNodes[i];
728 }
729 if (errorTarget == null) {
730 // No argument node that we can direct error messages to, because we
731 // are handling an optional parameter that wasn't specified. So just
732 // direct error messages to the constructor call.
733 errorTarget = node;
734 }
735 if (argumentValue == null && baseParameter is ParameterElementImpl) {
736 // The parameter is an optional positional parameter for which no value
737 // was provided, so use the default value.
738 validator.beforeGetParameterDefault(baseParameter);
739 EvaluationResultImpl evaluationResult = baseParameter.evaluationResult;
740 if (evaluationResult == null) {
741 // No default was provided, so the default value is null.
742 argumentValue = typeProvider.nullObject;
743 } else if (evaluationResult.value != null) {
744 argumentValue = evaluationResult.value;
745 }
746 }
747 if (argumentValue != null) {
748 if (!runtimeTypeMatch(argumentValue, parameter.type)) {
749 errorReporter.reportErrorForNode(
750 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA TCH,
751 errorTarget,
752 [argumentValue.type, parameter.type]);
753 }
754 if (baseParameter.isInitializingFormal) {
755 FieldElement field = (parameter as FieldFormalParameterElement).field;
756 if (field != null) {
757 DartType fieldType = field.type;
758 if (fieldType != parameter.type) {
759 // We've already checked that the argument can be assigned to the
760 // parameter; we also need to check that it can be assigned to
761 // the field.
762 if (!runtimeTypeMatch(argumentValue, fieldType)) {
763 errorReporter.reportErrorForNode(
764 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE _MISMATCH,
765 errorTarget,
766 [argumentValue.type, fieldType]);
767 }
768 }
769 String fieldName = field.name;
770 if (fieldMap.containsKey(fieldName)) {
771 errorReporter.reportErrorForNode(
772 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
773 }
774 fieldMap[fieldName] = argumentValue;
775 }
776 } else {
777 String name = baseParameter.name;
778 parameterMap[name] = argumentValue;
779 }
780 }
781 }
782 ConstantVisitor initializerVisitor = new ConstantVisitor(
783 this, errorReporter,
784 lexicalEnvironment: parameterMap);
785 String superName = null;
786 NodeList<Expression> superArguments = null;
787 for (ConstructorInitializer initializer in initializers) {
788 if (initializer is ConstructorFieldInitializer) {
789 ConstructorFieldInitializer constructorFieldInitializer = initializer;
790 Expression initializerExpression =
791 constructorFieldInitializer.expression;
792 DartObjectImpl evaluationResult =
793 initializerExpression.accept(initializerVisitor);
794 if (evaluationResult != null) {
795 String fieldName = constructorFieldInitializer.fieldName.name;
796 if (fieldMap.containsKey(fieldName)) {
797 errorReporter.reportErrorForNode(
798 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
799 }
800 fieldMap[fieldName] = evaluationResult;
801 PropertyAccessorElement getter = definingClass.getGetter(fieldName);
802 if (getter != null) {
803 PropertyInducingElement field = getter.variable;
804 if (!runtimeTypeMatch(evaluationResult, field.type)) {
805 errorReporter.reportErrorForNode(
806 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_M ISMATCH,
807 node,
808 [evaluationResult.type, fieldName, field.type]);
809 }
810 }
811 }
812 } else if (initializer is SuperConstructorInvocation) {
813 SuperConstructorInvocation superConstructorInvocation = initializer;
814 SimpleIdentifier name = superConstructorInvocation.constructorName;
815 if (name != null) {
816 superName = name.name;
817 }
818 superArguments = superConstructorInvocation.argumentList.arguments;
819 } else if (initializer is RedirectingConstructorInvocation) {
820 // This is a redirecting constructor, so just evaluate the constructor
821 // it redirects to.
822 ConstructorElement constructor = initializer.staticElement;
823 if (constructor != null && constructor.isConst) {
824 return evaluateConstructorCall(
825 node,
826 initializer.argumentList.arguments,
827 constructor,
828 initializerVisitor,
829 errorReporter);
830 }
831 }
832 }
833 // Evaluate explicit or implicit call to super().
834 InterfaceType superclass = definingClass.superclass;
835 if (superclass != null && !superclass.isObject) {
836 ConstructorElement superConstructor =
837 superclass.lookUpConstructor(superName, constructor.library);
838 if (superConstructor != null) {
839 if (superArguments == null) {
840 superArguments = new NodeList<Expression>(null);
841 }
842 evaluateSuperConstructorCall(node, fieldMap, superConstructor,
843 superArguments, initializerVisitor, errorReporter);
844 }
845 }
846 return new DartObjectImpl(definingClass, new GenericState(fieldMap));
847 }
848
849 void evaluateSuperConstructorCall(
850 AstNode node,
851 HashMap<String, DartObjectImpl> fieldMap,
852 ConstructorElement superConstructor,
853 NodeList<Expression> superArguments,
854 ConstantVisitor initializerVisitor,
855 ErrorReporter errorReporter) {
856 if (superConstructor != null && superConstructor.isConst) {
857 DartObjectImpl evaluationResult = evaluateConstructorCall(node,
858 superArguments, superConstructor, initializerVisitor, errorReporter);
859 if (evaluationResult != null) {
860 fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult;
861 }
862 }
863 }
864
865 /**
866 * Attempt to follow the chain of factory redirections until a constructor is
867 * reached which is not a const factory constructor. Return the constant
868 * constructor which terminates the chain of factory redirections, if the
869 * chain terminates. If there is a problem (e.g. a redirection can't be found,
870 * or a cycle is encountered), the chain will be followed as far as possible
871 * and then a const factory constructor will be returned.
872 */
873 ConstructorElement followConstantRedirectionChain(
874 ConstructorElement constructor) {
875 HashSet<ConstructorElement> constructorsVisited =
876 new HashSet<ConstructorElement>();
877 while (true) {
878 ConstructorElement redirectedConstructor =
879 getConstRedirectedConstructor(constructor);
880 if (redirectedConstructor == null) {
881 break;
882 } else {
883 ConstructorElement constructorBase = _getConstructorBase(constructor);
884 constructorsVisited.add(constructorBase);
885 ConstructorElement redirectedConstructorBase =
886 _getConstructorBase(redirectedConstructor);
887 if (constructorsVisited.contains(redirectedConstructorBase)) {
888 // Cycle in redirecting factory constructors--this is not allowed
889 // and is checked elsewhere--see
890 // [ErrorVerifier.checkForRecursiveFactoryRedirect()]).
891 break;
892 }
893 }
894 constructor = redirectedConstructor;
895 }
896 return constructor;
897 }
898
899 /**
900 * Generate an error indicating that the given [constant] is not a valid
901 * compile-time constant because it references at least one of the constants
902 * in the given [cycle], each of which directly or indirectly references the
903 * constant.
904 */
905 void generateCycleError(Iterable<ConstantEvaluationTarget> cycle,
906 ConstantEvaluationTarget constant) {
907 if (constant is VariableElement) {
908 RecordingErrorListener errorListener = new RecordingErrorListener();
909 ErrorReporter errorReporter =
910 new ErrorReporter(errorListener, constant.source);
911 // TODO(paulberry): It would be really nice if we could extract enough
912 // information from the 'cycle' argument to provide the user with a
913 // description of the cycle.
914 errorReporter.reportErrorForElement(
915 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, constant, []);
916 (constant as VariableElementImpl).evaluationResult =
917 new EvaluationResultImpl(null, errorListener.errors);
918 } else if (constant is ConstructorElement) {
919 // We don't report cycle errors on constructor declarations since there
920 // is nowhere to put the error information.
921 } else {
922 // Should not happen. Formal parameter defaults and annotations should
923 // never appear as part of a cycle because they can't be referred to.
924 assert(false);
925 AnalysisEngine.instance.logger.logError(
926 "Constant value computer trying to report a cycle error for a node of type ${constant.runtimeType}");
927 }
928 }
929
930 /**
931 * If [constructor] redirects to another const constructor, return the
932 * const constructor it redirects to. Otherwise return `null`.
933 */
934 ConstructorElement getConstRedirectedConstructor(
935 ConstructorElement constructor) {
936 if (!constructor.isFactory) {
937 return null;
938 }
939 if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
940 // The dart:core.Symbol has a const factory constructor that redirects
941 // to dart:_internal.Symbol. That in turn redirects to an external
942 // const constructor, which we won't be able to evaluate.
943 // So stop following the chain of redirections at dart:core.Symbol, and
944 // let [evaluateInstanceCreationExpression] handle it specially.
945 return null;
946 }
947 ConstructorElement redirectedConstructor =
948 constructor.redirectedConstructor;
949 if (redirectedConstructor == null) {
950 // This can happen if constructor is an external factory constructor.
951 return null;
952 }
953 if (!redirectedConstructor.isConst) {
954 // Delegating to a non-const constructor--this is not allowed (and
955 // is checked elsewhere--see
956 // [ErrorVerifier.checkForRedirectToNonConstConstructor()]).
957 return null;
958 }
959 return redirectedConstructor;
960 }
961
962 /**
963 * Check if the object [obj] matches the type [type] according to runtime type
964 * checking rules.
965 */
966 bool runtimeTypeMatch(DartObjectImpl obj, DartType type) {
967 if (obj.isNull) {
968 return true;
969 }
970 if (type.isUndefined) {
971 return false;
972 }
973 return obj.type.isSubtypeOf(type);
974 }
975
976 /**
977 * Determine whether the given string is a valid name for a public symbol
978 * (i.e. whether it is allowed for a call to the Symbol constructor).
979 */
980 static bool isValidPublicSymbol(String name) => name.isEmpty ||
981 name == "void" ||
982 new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches();
983
984 static ConstructorElementImpl _getConstructorBase(
985 ConstructorElement constructor) {
986 while (constructor is ConstructorMember) {
987 constructor = (constructor as ConstructorMember).baseElement;
988 }
989 return constructor;
990 }
991 }
992
993 /**
994 * Wrapper around an [Annotation] which can be used as a
995 * [ConstantEvaluationTarget].
996 */
997 class ConstantEvaluationTarget_Annotation implements ConstantEvaluationTarget {
998 final AnalysisContext context;
999 final Source source;
1000 final Source librarySource;
1001 final Annotation annotation;
1002
1003 ConstantEvaluationTarget_Annotation(
1004 this.context, this.source, this.librarySource, this.annotation);
1005
1006 @override
1007 int get hashCode => JenkinsSmiHash.hash3(
1008 source.hashCode, librarySource.hashCode, annotation.hashCode);
1009
1010 @override
1011 bool operator ==(other) {
1012 if (other is ConstantEvaluationTarget_Annotation) {
1013 return this.context == other.context &&
1014 this.source == other.source &&
1015 this.librarySource == other.librarySource &&
1016 this.annotation == other.annotation;
1017 } else {
1018 return false;
1019 }
1020 }
1021
1022 @override
1023 String toString() => 'Constant: $annotation';
1024 }
1025
1026 /**
1027 * Interface used by unit tests to verify correct dependency analysis during
1028 * constant evaluation.
1029 */
1030 abstract class ConstantEvaluationValidator {
1031 /**
1032 * This method is called just before computing the constant value associated
1033 * with [constant]. Unit tests will override this method to introduce
1034 * additional error checking.
1035 */
1036 void beforeComputeValue(ConstantEvaluationTarget constant);
1037
1038 /**
1039 * This method is called just before getting the constant initializers
1040 * associated with the [constructor]. Unit tests will override this method to
1041 * introduce additional error checking.
1042 */
1043 void beforeGetConstantInitializers(ConstructorElement constructor);
1044
1045 /**
1046 * This method is called just before retrieving an evaluation result from an
1047 * element. Unit tests will override it to introduce additional error
1048 * checking.
1049 */
1050 void beforeGetEvaluationResult(ConstantEvaluationTarget constant);
1051
1052 /**
1053 * This method is called just before getting the constant value of a field
1054 * with an initializer. Unit tests will override this method to introduce
1055 * additional error checking.
1056 */
1057 void beforeGetFieldEvaluationResult(FieldElementImpl field);
1058
1059 /**
1060 * This method is called just before getting a parameter's default value. Unit
1061 * tests will override this method to introduce additional error checking.
1062 */
1063 void beforeGetParameterDefault(ParameterElement parameter);
1064 }
1065
1066 /**
1067 * Implementation of [ConstantEvaluationValidator] used in production; does no
1068 * validation.
1069 */
1070 class ConstantEvaluationValidator_ForProduction
1071 implements ConstantEvaluationValidator {
1072 @override
1073 void beforeComputeValue(ConstantEvaluationTarget constant) {}
1074
1075 @override
1076 void beforeGetConstantInitializers(ConstructorElement constructor) {}
1077
1078 @override
1079 void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {}
1080
1081 @override
1082 void beforeGetFieldEvaluationResult(FieldElementImpl field) {}
1083
1084 @override
1085 void beforeGetParameterDefault(ParameterElement parameter) {}
1086 }
1087 24
1088 /// Instances of the class [ConstantEvaluator] evaluate constant expressions to 25 /// Instances of the class [ConstantEvaluator] evaluate constant expressions to
1089 /// produce their compile-time value. 26 /// produce their compile-time value.
1090 /// 27 ///
1091 /// According to the Dart Language Specification: 28 /// According to the Dart Language Specification:
1092 /// 29 ///
1093 /// > A constant expression is one of the following: 30 /// > A constant expression is one of the following:
1094 /// > 31 /// >
1095 /// > * A literal number. 32 /// > * A literal number.
1096 /// > * A literal boolean. 33 /// > * A literal boolean.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 /// > evaluates to a boolean value. 90 /// > evaluates to a boolean value.
1154 /// > </span> 91 /// > </span>
1155 /// 92 ///
1156 /// The values returned by instances of this class are therefore `null` and 93 /// The values returned by instances of this class are therefore `null` and
1157 /// instances of the classes `Boolean`, `BigInteger`, `Double`, `String`, and 94 /// instances of the classes `Boolean`, `BigInteger`, `Double`, `String`, and
1158 /// `DartObject`. 95 /// `DartObject`.
1159 /// 96 ///
1160 /// In addition, this class defines several values that can be returned to 97 /// In addition, this class defines several values that can be returned to
1161 /// indicate various conditions encountered during evaluation. These are 98 /// indicate various conditions encountered during evaluation. These are
1162 /// documented with the static fields that define those values. 99 /// documented with the static fields that define those values.
100 @deprecated
1163 class ConstantEvaluator { 101 class ConstantEvaluator {
1164 /** 102 /**
1165 * The source containing the expression(s) that will be evaluated. 103 * The source containing the expression(s) that will be evaluated.
1166 */ 104 */
1167 final Source _source; 105 final Source _source;
1168 106
1169 /** 107 /**
1170 * The type provider used to access the known types. 108 * The type provider used to access the known types.
1171 */ 109 */
1172 final TypeProvider _typeProvider; 110 final TypeProvider _typeProvider;
1173 111
1174 /** 112 /**
1175 * The type system primitives. 113 * The type system primitives.
1176 */ 114 */
1177 final TypeSystem _typeSystem; 115 final TypeSystem _typeSystem;
1178 116
1179 /** 117 /**
1180 * Initialize a newly created evaluator to evaluate expressions in the given 118 * Initialize a newly created evaluator to evaluate expressions in the given
1181 * [source]. The [typeProvider] is the type provider used to access known 119 * [source]. The [typeProvider] is the type provider used to access known
1182 * types. 120 * types.
1183 */ 121 */
1184 ConstantEvaluator(this._source, this._typeProvider, {TypeSystem typeSystem}) 122 ConstantEvaluator(this._source, this._typeProvider, {TypeSystem typeSystem})
1185 : _typeSystem = typeSystem != null ? typeSystem : new TypeSystemImpl(); 123 : _typeSystem = typeSystem ?? new TypeSystemImpl();
1186 124
1187 EvaluationResult evaluate(Expression expression) { 125 EvaluationResult evaluate(Expression expression) {
1188 RecordingErrorListener errorListener = new RecordingErrorListener(); 126 RecordingErrorListener errorListener = new RecordingErrorListener();
1189 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); 127 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
1190 DartObjectImpl result = expression.accept(new ConstantVisitor( 128 DartObjectImpl result = expression.accept(new ConstantVisitor(
1191 new ConstantEvaluationEngine(_typeProvider, new DeclaredVariables(), 129 new ConstantEvaluationEngine(_typeProvider, new DeclaredVariables(),
1192 typeSystem: _typeSystem), 130 typeSystem: _typeSystem),
1193 errorReporter)); 131 errorReporter));
1194 if (result != null) { 132 if (result != null) {
1195 return EvaluationResult.forValue(result); 133 return EvaluationResult.forValue(result);
1196 } 134 }
1197 return EvaluationResult.forErrors(errorListener.errors); 135 return EvaluationResult.forErrors(errorListener.errors);
1198 } 136 }
1199 } 137 }
1200
1201 /**
1202 * A visitor used to traverse the AST structures of all of the compilation units
1203 * being resolved and build tables of the constant variables, constant
1204 * constructors, constant constructor invocations, and annotations found in
1205 * those compilation units.
1206 */
1207 class ConstantFinder extends RecursiveAstVisitor<Object> {
1208 final AnalysisContext context;
1209 final Source source;
1210 final Source librarySource;
1211
1212 /**
1213 * The elements and AST nodes whose constant values need to be computed.
1214 */
1215 HashSet<ConstantEvaluationTarget> constantsToCompute =
1216 new HashSet<ConstantEvaluationTarget>();
1217
1218 /**
1219 * True if instance variables marked as "final" should be treated as "const".
1220 */
1221 bool treatFinalInstanceVarAsConst = false;
1222
1223 ConstantFinder(this.context, this.source, this.librarySource);
1224
1225 @override
1226 Object visitAnnotation(Annotation node) {
1227 super.visitAnnotation(node);
1228 constantsToCompute.add(new ConstantEvaluationTarget_Annotation(
1229 context, source, librarySource, node));
1230 return null;
1231 }
1232
1233 @override
1234 Object visitClassDeclaration(ClassDeclaration node) {
1235 bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst;
1236 if (node.element.constructors.any((ConstructorElement e) => e.isConst)) {
1237 // Instance vars marked "final" need to be included in the dependency
1238 // graph, since constant constructors implicitly use the values in their
1239 // initializers.
1240 treatFinalInstanceVarAsConst = true;
1241 }
1242 try {
1243 return super.visitClassDeclaration(node);
1244 } finally {
1245 treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst;
1246 }
1247 }
1248
1249 @override
1250 Object visitConstructorDeclaration(ConstructorDeclaration node) {
1251 super.visitConstructorDeclaration(node);
1252 if (node.constKeyword != null) {
1253 ConstructorElement element = node.element;
1254 if (element != null) {
1255 constantsToCompute.add(element);
1256 constantsToCompute.addAll(element.parameters);
1257 }
1258 }
1259 return null;
1260 }
1261
1262 @override
1263 Object visitVariableDeclaration(VariableDeclaration node) {
1264 super.visitVariableDeclaration(node);
1265 Expression initializer = node.initializer;
1266 VariableElement element = node.element;
1267 if (initializer != null &&
1268 (node.isConst ||
1269 treatFinalInstanceVarAsConst &&
1270 element is FieldElement &&
1271 node.isFinal &&
1272 !element.isStatic)) {
1273 if (node.element != null) {
1274 constantsToCompute.add(node.element);
1275 }
1276 }
1277 return null;
1278 }
1279 }
1280
1281 /**
1282 * An object used to compute the values of constant variables and constant
1283 * constructor invocations in one or more compilation units. The expected usage
1284 * pattern is for the compilation units to be added to this computer using the
1285 * method [add] and then for the method [computeValues] to be invoked exactly
1286 * once. Any use of an instance after invoking the method [computeValues] will
1287 * result in unpredictable behavior.
1288 */
1289 class ConstantValueComputer {
1290 /**
1291 * Source of RegExp matching declarable operator names.
1292 * From sdk/lib/internal/symbol.dart.
1293 */
1294 static String _OPERATOR_RE =
1295 "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)";
1296
1297 /**
1298 * Source of RegExp matching Dart reserved words.
1299 * From sdk/lib/internal/symbol.dart.
1300 */
1301 static String _RESERVED_WORD_RE =
1302 "(?:assert|break|c(?:a(?:se|tch)|lass|on(?:st|tinue))|d(?:efault|o)|e(?:ls e|num|xtends)|f(?:alse|inal(?:ly)?|or)|i[fns]|n(?:ew|ull)|ret(?:hrow|urn)|s(?:up er|witch)|t(?:h(?:is|row)|r(?:ue|y))|v(?:ar|oid)|w(?:hile|ith))";
1303
1304 /**
1305 * A graph in which the nodes are the constants, and the edges are from each
1306 * constant to the other constants that are referenced by it.
1307 */
1308 DirectedGraph<ConstantEvaluationTarget> referenceGraph =
1309 new DirectedGraph<ConstantEvaluationTarget>();
1310
1311 /**
1312 * The elements whose constant values need to be computed. Any elements
1313 * which appear in [referenceGraph] but not in this set either belong to a
1314 * different library cycle (and hence don't need to be recomputed) or were
1315 * computed during a previous stage of resolution stage (e.g. constants
1316 * associated with enums).
1317 */
1318 HashSet<ConstantEvaluationTarget> _constantsToCompute =
1319 new HashSet<ConstantEvaluationTarget>();
1320
1321 /**
1322 * The evaluation engine that does the work of evaluating instance creation
1323 * expressions.
1324 */
1325 final ConstantEvaluationEngine evaluationEngine;
1326
1327 final AnalysisContext _context;
1328
1329 /**
1330 * Initialize a newly created constant value computer. The [typeProvider] is
1331 * the type provider used to access known types. The [declaredVariables] is
1332 * the set of variables declared on the command line using '-D'.
1333 */
1334 ConstantValueComputer(this._context, TypeProvider typeProvider,
1335 DeclaredVariables declaredVariables,
1336 [ConstantEvaluationValidator validator, TypeSystem typeSystem])
1337 : evaluationEngine = new ConstantEvaluationEngine(
1338 typeProvider, declaredVariables,
1339 validator: validator, typeSystem: typeSystem);
1340
1341 /**
1342 * Add the constants in the given compilation [unit] to the list of constants
1343 * whose value needs to be computed.
1344 */
1345 void add(CompilationUnit unit, Source source, Source librarySource) {
1346 ConstantFinder constantFinder =
1347 new ConstantFinder(_context, source, librarySource);
1348 unit.accept(constantFinder);
1349 _constantsToCompute.addAll(constantFinder.constantsToCompute);
1350 }
1351
1352 /**
1353 * Compute values for all of the constants in the compilation units that were
1354 * added.
1355 */
1356 void computeValues() {
1357 for (ConstantEvaluationTarget constant in _constantsToCompute) {
1358 referenceGraph.addNode(constant);
1359 evaluationEngine.computeDependencies(constant,
1360 (ConstantEvaluationTarget dependency) {
1361 referenceGraph.addEdge(constant, dependency);
1362 });
1363 }
1364 List<List<ConstantEvaluationTarget>> topologicalSort =
1365 referenceGraph.computeTopologicalSort();
1366 for (List<ConstantEvaluationTarget> constantsInCycle in topologicalSort) {
1367 if (constantsInCycle.length == 1) {
1368 ConstantEvaluationTarget constant = constantsInCycle[0];
1369 if (!referenceGraph.getTails(constant).contains(constant)) {
1370 _computeValueFor(constant);
1371 continue;
1372 }
1373 }
1374 for (ConstantEvaluationTarget constant in constantsInCycle) {
1375 evaluationEngine.generateCycleError(constantsInCycle, constant);
1376 }
1377 }
1378 }
1379
1380 /**
1381 * Compute a value for the given [constant].
1382 */
1383 void _computeValueFor(ConstantEvaluationTarget constant) {
1384 if (!_constantsToCompute.contains(constant)) {
1385 // Element is in the dependency graph but should have been computed by
1386 // a previous stage of analysis.
1387 // TODO(paulberry): once we have moved over to the new task model, this
1388 // should only occur for constants associated with enum members. Once
1389 // that happens we should add an assertion to verify that it doesn't
1390 // occur in any other cases.
1391 return;
1392 }
1393 evaluationEngine.computeConstantValue(constant);
1394 }
1395 }
1396
1397 /**
1398 * A visitor used to evaluate constant expressions to produce their compile-time
1399 * value. According to the Dart Language Specification: <blockquote> A constant
1400 * expression is one of the following:
1401 *
1402 * * A literal number.
1403 * * A literal boolean.
1404 * * A literal string where any interpolated expression is a compile-time
1405 * constant that evaluates to a numeric, string or boolean value or to
1406 * <b>null</b>.
1407 * * A literal symbol.
1408 * * <b>null</b>.
1409 * * A qualified reference to a static constant variable.
1410 * * An identifier expression that denotes a constant variable, class or type
1411 * alias.
1412 * * A constant constructor invocation.
1413 * * A constant list literal.
1414 * * A constant map literal.
1415 * * A simple or qualified identifier denoting a top-level function or a static
1416 * method.
1417 * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant
1418 * expression.
1419 * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i>
1420 * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
1421 * expressions and <i>identical()</i> is statically bound to the predefined
1422 * dart function <i>identical()</i> discussed above.
1423 * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or
1424 * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and
1425 * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric,
1426 * string or boolean value.
1427 * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> &amp;&amp;
1428 * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>,
1429 * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate
1430 * to a boolean value.
1431 * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^
1432 * e<sub>2</sub></i>, <i>e<sub>1</sub> &amp; e<sub>2</sub></i>,
1433 * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;&gt;
1434 * e<sub>2</sub></i> or <i>e<sub>1</sub> &lt;&lt; e<sub>2</sub></i>, where
1435 * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
1436 * expressions that evaluate to an integer value or to <b>null</b>.
1437 * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> +
1438 * e<sub>2</sub></i>, <i>e<sub>1</sub> - e<sub>2</sub></i>, <i>e<sub>1</sub> *
1439 * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub>
1440 * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> &gt; e<sub>2</sub></i>,
1441 * <i>e<sub>1</sub> &lt; e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;=
1442 * e<sub>2</sub></i>, <i>e<sub>1</sub> &lt;= e<sub>2</sub></i> or
1443 * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i>
1444 * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a
1445 * numeric value or to <b>null</b>.
1446 * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> :
1447 * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and
1448 * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i>
1449 * evaluates to a boolean value.
1450 * </blockquote>
1451 */
1452 class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1453 /**
1454 * The type provider used to access the known types.
1455 */
1456 final ConstantEvaluationEngine evaluationEngine;
1457
1458 final HashMap<String, DartObjectImpl> _lexicalEnvironment;
1459
1460 /**
1461 * Error reporter that we use to report errors accumulated while computing the
1462 * constant.
1463 */
1464 final ErrorReporter _errorReporter;
1465
1466 /**
1467 * Helper class used to compute constant values.
1468 */
1469 DartObjectComputer _dartObjectComputer;
1470
1471 /**
1472 * Initialize a newly created constant visitor. The [evaluationEngine] is
1473 * used to evaluate instance creation expressions. The [lexicalEnvironment]
1474 * is a map containing values which should override identifiers, or `null` if
1475 * no overriding is necessary. The [_errorReporter] is used to report errors
1476 * found during evaluation. The [validator] is used by unit tests to verify
1477 * correct dependency analysis.
1478 */
1479 ConstantVisitor(this.evaluationEngine, this._errorReporter,
1480 {HashMap<String, DartObjectImpl> lexicalEnvironment})
1481 : _lexicalEnvironment = lexicalEnvironment {
1482 this._dartObjectComputer =
1483 new DartObjectComputer(_errorReporter, evaluationEngine.typeProvider);
1484 }
1485
1486 /**
1487 * Convenience getter to gain access to the [evalationEngine]'s type
1488 * provider.
1489 */
1490 TypeProvider get _typeProvider => evaluationEngine.typeProvider;
1491
1492 /**
1493 * Convenience getter to gain access to the [evaluationEngine]'s type system.
1494 */
1495 TypeSystem get _typeSystem => evaluationEngine.typeSystem;
1496
1497 @override
1498 DartObjectImpl visitAdjacentStrings(AdjacentStrings node) {
1499 DartObjectImpl result = null;
1500 for (StringLiteral string in node.strings) {
1501 if (result == null) {
1502 result = string.accept(this);
1503 } else {
1504 result =
1505 _dartObjectComputer.concatenate(node, result, string.accept(this));
1506 }
1507 }
1508 return result;
1509 }
1510
1511 @override
1512 DartObjectImpl visitBinaryExpression(BinaryExpression node) {
1513 DartObjectImpl leftResult = node.leftOperand.accept(this);
1514 DartObjectImpl rightResult = node.rightOperand.accept(this);
1515 TokenType operatorType = node.operator.type;
1516 // 'null' is almost never good operand
1517 if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) {
1518 if (leftResult != null && leftResult.isNull ||
1519 rightResult != null && rightResult.isNull) {
1520 _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
1521 return null;
1522 }
1523 }
1524 // evaluate operator
1525 while (true) {
1526 if (operatorType == TokenType.AMPERSAND) {
1527 return _dartObjectComputer.bitAnd(node, leftResult, rightResult);
1528 } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
1529 return _dartObjectComputer.logicalAnd(node, leftResult, rightResult);
1530 } else if (operatorType == TokenType.BANG_EQ) {
1531 return _dartObjectComputer.notEqual(node, leftResult, rightResult);
1532 } else if (operatorType == TokenType.BAR) {
1533 return _dartObjectComputer.bitOr(node, leftResult, rightResult);
1534 } else if (operatorType == TokenType.BAR_BAR) {
1535 return _dartObjectComputer.logicalOr(node, leftResult, rightResult);
1536 } else if (operatorType == TokenType.CARET) {
1537 return _dartObjectComputer.bitXor(node, leftResult, rightResult);
1538 } else if (operatorType == TokenType.EQ_EQ) {
1539 return _dartObjectComputer.equalEqual(node, leftResult, rightResult);
1540 } else if (operatorType == TokenType.GT) {
1541 return _dartObjectComputer.greaterThan(node, leftResult, rightResult);
1542 } else if (operatorType == TokenType.GT_EQ) {
1543 return _dartObjectComputer.greaterThanOrEqual(
1544 node, leftResult, rightResult);
1545 } else if (operatorType == TokenType.GT_GT) {
1546 return _dartObjectComputer.shiftRight(node, leftResult, rightResult);
1547 } else if (operatorType == TokenType.LT) {
1548 return _dartObjectComputer.lessThan(node, leftResult, rightResult);
1549 } else if (operatorType == TokenType.LT_EQ) {
1550 return _dartObjectComputer.lessThanOrEqual(
1551 node, leftResult, rightResult);
1552 } else if (operatorType == TokenType.LT_LT) {
1553 return _dartObjectComputer.shiftLeft(node, leftResult, rightResult);
1554 } else if (operatorType == TokenType.MINUS) {
1555 return _dartObjectComputer.minus(node, leftResult, rightResult);
1556 } else if (operatorType == TokenType.PERCENT) {
1557 return _dartObjectComputer.remainder(node, leftResult, rightResult);
1558 } else if (operatorType == TokenType.PLUS) {
1559 return _dartObjectComputer.add(node, leftResult, rightResult);
1560 } else if (operatorType == TokenType.STAR) {
1561 return _dartObjectComputer.times(node, leftResult, rightResult);
1562 } else if (operatorType == TokenType.SLASH) {
1563 return _dartObjectComputer.divide(node, leftResult, rightResult);
1564 } else if (operatorType == TokenType.TILDE_SLASH) {
1565 return _dartObjectComputer.integerDivide(node, leftResult, rightResult);
1566 } else {
1567 // TODO(brianwilkerson) Figure out which error to report.
1568 _error(node, null);
1569 return null;
1570 }
1571 break;
1572 }
1573 }
1574
1575 @override
1576 DartObjectImpl visitBooleanLiteral(BooleanLiteral node) =>
1577 new DartObjectImpl(_typeProvider.boolType, BoolState.from(node.value));
1578
1579 @override
1580 DartObjectImpl visitConditionalExpression(ConditionalExpression node) {
1581 Expression condition = node.condition;
1582 DartObjectImpl conditionResult = condition.accept(this);
1583 DartObjectImpl thenResult = node.thenExpression.accept(this);
1584 DartObjectImpl elseResult = node.elseExpression.accept(this);
1585 if (conditionResult == null) {
1586 return conditionResult;
1587 } else if (!conditionResult.isBool) {
1588 _errorReporter.reportErrorForNode(
1589 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition);
1590 return null;
1591 } else if (thenResult == null) {
1592 return thenResult;
1593 } else if (elseResult == null) {
1594 return elseResult;
1595 }
1596 conditionResult =
1597 _dartObjectComputer.applyBooleanConversion(condition, conditionResult);
1598 if (conditionResult == null) {
1599 return conditionResult;
1600 }
1601 if (conditionResult.toBoolValue() == true) {
1602 return thenResult;
1603 } else if (conditionResult.toBoolValue() == false) {
1604 return elseResult;
1605 }
1606 ParameterizedType thenType = thenResult.type;
1607 ParameterizedType elseType = elseResult.type;
1608 return new DartObjectImpl.validWithUnknownValue(
1609 _typeSystem.getLeastUpperBound(_typeProvider, thenType, elseType)
1610 as InterfaceType);
1611 }
1612
1613 @override
1614 DartObjectImpl visitDoubleLiteral(DoubleLiteral node) =>
1615 new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value));
1616
1617 @override
1618 DartObjectImpl visitInstanceCreationExpression(
1619 InstanceCreationExpression node) {
1620 if (!node.isConst) {
1621 // TODO(brianwilkerson) Figure out which error to report.
1622 _error(node, null);
1623 return null;
1624 }
1625 ConstructorElement constructor = node.staticElement;
1626 if (constructor == null) {
1627 // Couldn't resolve the constructor so we can't compute a value. No
1628 // problem - the error has already been reported.
1629 return null;
1630 }
1631 return evaluationEngine.evaluateConstructorCall(
1632 node, node.argumentList.arguments, constructor, this, _errorReporter);
1633 }
1634
1635 @override
1636 DartObjectImpl visitIntegerLiteral(IntegerLiteral node) =>
1637 new DartObjectImpl(_typeProvider.intType, new IntState(node.value));
1638
1639 @override
1640 DartObjectImpl visitInterpolationExpression(InterpolationExpression node) {
1641 DartObjectImpl result = node.expression.accept(this);
1642 if (result != null && !result.isBoolNumStringOrNull) {
1643 _error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
1644 return null;
1645 }
1646 return _dartObjectComputer.performToString(node, result);
1647 }
1648
1649 @override
1650 DartObjectImpl visitInterpolationString(InterpolationString node) =>
1651 new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
1652
1653 @override
1654 DartObjectImpl visitListLiteral(ListLiteral node) {
1655 if (node.constKeyword == null) {
1656 _errorReporter.reportErrorForNode(
1657 CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL, node);
1658 return null;
1659 }
1660 bool errorOccurred = false;
1661 List<DartObjectImpl> elements = new List<DartObjectImpl>();
1662 for (Expression element in node.elements) {
1663 DartObjectImpl elementResult = element.accept(this);
1664 if (elementResult == null) {
1665 errorOccurred = true;
1666 } else {
1667 elements.add(elementResult);
1668 }
1669 }
1670 if (errorOccurred) {
1671 return null;
1672 }
1673 DartType elementType = _typeProvider.dynamicType;
1674 if (node.typeArguments != null &&
1675 node.typeArguments.arguments.length == 1) {
1676 DartType type = node.typeArguments.arguments[0].type;
1677 if (type != null) {
1678 elementType = type;
1679 }
1680 }
1681 InterfaceType listType = _typeProvider.listType.substitute4([elementType]);
1682 return new DartObjectImpl(listType, new ListState(elements));
1683 }
1684
1685 @override
1686 DartObjectImpl visitMapLiteral(MapLiteral node) {
1687 if (node.constKeyword == null) {
1688 _errorReporter.reportErrorForNode(
1689 CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL, node);
1690 return null;
1691 }
1692 bool errorOccurred = false;
1693 HashMap<DartObjectImpl, DartObjectImpl> map =
1694 new HashMap<DartObjectImpl, DartObjectImpl>();
1695 for (MapLiteralEntry entry in node.entries) {
1696 DartObjectImpl keyResult = entry.key.accept(this);
1697 DartObjectImpl valueResult = entry.value.accept(this);
1698 if (keyResult == null || valueResult == null) {
1699 errorOccurred = true;
1700 } else {
1701 map[keyResult] = valueResult;
1702 }
1703 }
1704 if (errorOccurred) {
1705 return null;
1706 }
1707 DartType keyType = _typeProvider.dynamicType;
1708 DartType valueType = _typeProvider.dynamicType;
1709 if (node.typeArguments != null &&
1710 node.typeArguments.arguments.length == 2) {
1711 DartType keyTypeCandidate = node.typeArguments.arguments[0].type;
1712 if (keyTypeCandidate != null) {
1713 keyType = keyTypeCandidate;
1714 }
1715 DartType valueTypeCandidate = node.typeArguments.arguments[1].type;
1716 if (valueTypeCandidate != null) {
1717 valueType = valueTypeCandidate;
1718 }
1719 }
1720 InterfaceType mapType =
1721 _typeProvider.mapType.substitute4([keyType, valueType]);
1722 return new DartObjectImpl(mapType, new MapState(map));
1723 }
1724
1725 @override
1726 DartObjectImpl visitMethodInvocation(MethodInvocation node) {
1727 Element element = node.methodName.staticElement;
1728 if (element is FunctionElement) {
1729 FunctionElement function = element;
1730 if (function.name == "identical") {
1731 NodeList<Expression> arguments = node.argumentList.arguments;
1732 if (arguments.length == 2) {
1733 Element enclosingElement = function.enclosingElement;
1734 if (enclosingElement is CompilationUnitElement) {
1735 LibraryElement library = enclosingElement.library;
1736 if (library.isDartCore) {
1737 DartObjectImpl leftArgument = arguments[0].accept(this);
1738 DartObjectImpl rightArgument = arguments[1].accept(this);
1739 return _dartObjectComputer.isIdentical(
1740 node, leftArgument, rightArgument);
1741 }
1742 }
1743 }
1744 }
1745 }
1746 // TODO(brianwilkerson) Figure out which error to report.
1747 _error(node, null);
1748 return null;
1749 }
1750
1751 @override
1752 DartObjectImpl visitNamedExpression(NamedExpression node) =>
1753 node.expression.accept(this);
1754
1755 @override
1756 DartObjectImpl visitNode(AstNode node) {
1757 // TODO(brianwilkerson) Figure out which error to report.
1758 _error(node, null);
1759 return null;
1760 }
1761
1762 @override
1763 DartObjectImpl visitNullLiteral(NullLiteral node) => _typeProvider.nullObject;
1764
1765 @override
1766 DartObjectImpl visitParenthesizedExpression(ParenthesizedExpression node) =>
1767 node.expression.accept(this);
1768
1769 @override
1770 DartObjectImpl visitPrefixedIdentifier(PrefixedIdentifier node) {
1771 SimpleIdentifier prefixNode = node.prefix;
1772 Element prefixElement = prefixNode.staticElement;
1773 // String.length
1774 if (prefixElement is! PrefixElement && prefixElement is! ClassElement) {
1775 DartObjectImpl prefixResult = node.prefix.accept(this);
1776 if (_isStringLength(prefixResult, node.identifier)) {
1777 return prefixResult.stringLength(_typeProvider);
1778 }
1779 }
1780 // importPrefix.CONST
1781 if (prefixElement is! PrefixElement) {
1782 DartObjectImpl prefixResult = prefixNode.accept(this);
1783 if (prefixResult == null) {
1784 // The error has already been reported.
1785 return null;
1786 }
1787 }
1788 // validate prefixed identifier
1789 return _getConstantValue(node, node.staticElement);
1790 }
1791
1792 @override
1793 DartObjectImpl visitPrefixExpression(PrefixExpression node) {
1794 DartObjectImpl operand = node.operand.accept(this);
1795 if (operand != null && operand.isNull) {
1796 _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
1797 return null;
1798 }
1799 while (true) {
1800 if (node.operator.type == TokenType.BANG) {
1801 return _dartObjectComputer.logicalNot(node, operand);
1802 } else if (node.operator.type == TokenType.TILDE) {
1803 return _dartObjectComputer.bitNot(node, operand);
1804 } else if (node.operator.type == TokenType.MINUS) {
1805 return _dartObjectComputer.negated(node, operand);
1806 } else {
1807 // TODO(brianwilkerson) Figure out which error to report.
1808 _error(node, null);
1809 return null;
1810 }
1811 break;
1812 }
1813 }
1814
1815 @override
1816 DartObjectImpl visitPropertyAccess(PropertyAccess node) {
1817 if (node.target != null) {
1818 DartObjectImpl prefixResult = node.target.accept(this);
1819 if (_isStringLength(prefixResult, node.propertyName)) {
1820 return prefixResult.stringLength(_typeProvider);
1821 }
1822 }
1823 return _getConstantValue(node, node.propertyName.staticElement);
1824 }
1825
1826 @override
1827 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
1828 if (_lexicalEnvironment != null &&
1829 _lexicalEnvironment.containsKey(node.name)) {
1830 return _lexicalEnvironment[node.name];
1831 }
1832 return _getConstantValue(node, node.staticElement);
1833 }
1834
1835 @override
1836 DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) =>
1837 new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
1838
1839 @override
1840 DartObjectImpl visitStringInterpolation(StringInterpolation node) {
1841 DartObjectImpl result = null;
1842 bool first = true;
1843 for (InterpolationElement element in node.elements) {
1844 if (first) {
1845 result = element.accept(this);
1846 first = false;
1847 } else {
1848 result =
1849 _dartObjectComputer.concatenate(node, result, element.accept(this));
1850 }
1851 }
1852 return result;
1853 }
1854
1855 @override
1856 DartObjectImpl visitSymbolLiteral(SymbolLiteral node) {
1857 StringBuffer buffer = new StringBuffer();
1858 List<Token> components = node.components;
1859 for (int i = 0; i < components.length; i++) {
1860 if (i > 0) {
1861 buffer.writeCharCode(0x2E);
1862 }
1863 buffer.write(components[i].lexeme);
1864 }
1865 return new DartObjectImpl(
1866 _typeProvider.symbolType, new SymbolState(buffer.toString()));
1867 }
1868
1869 /**
1870 * Create an error associated with the given [node]. The error will have the
1871 * given error [code].
1872 */
1873 void _error(AstNode node, ErrorCode code) {
1874 _errorReporter.reportErrorForNode(
1875 code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code, node);
1876 }
1877
1878 /**
1879 * Return the constant value of the static constant represented by the given
1880 * [element]. The [node] is the node to be used if an error needs to be
1881 * reported.
1882 */
1883 DartObjectImpl _getConstantValue(AstNode node, Element element) {
1884 if (element is PropertyAccessorElement) {
1885 element = (element as PropertyAccessorElement).variable;
1886 }
1887 if (element is VariableElementImpl) {
1888 VariableElementImpl variableElementImpl = element;
1889 evaluationEngine.validator.beforeGetEvaluationResult(element);
1890 EvaluationResultImpl value = variableElementImpl.evaluationResult;
1891 if (variableElementImpl.isConst && value != null) {
1892 return value.value;
1893 }
1894 } else if (element is ExecutableElement) {
1895 ExecutableElement function = element;
1896 if (function.isStatic) {
1897 ParameterizedType functionType = function.type;
1898 if (functionType == null) {
1899 functionType = _typeProvider.functionType;
1900 }
1901 return new DartObjectImpl(functionType, new FunctionState(function));
1902 }
1903 } else if (element is ClassElement ||
1904 element is FunctionTypeAliasElement ||
1905 element is DynamicElementImpl) {
1906 return new DartObjectImpl(_typeProvider.typeType, new TypeState(element));
1907 }
1908 // TODO(brianwilkerson) Figure out which error to report.
1909 _error(node, null);
1910 return null;
1911 }
1912
1913 /**
1914 * Return `true` if the given [targetResult] represents a string and the
1915 * [identifier] is "length".
1916 */
1917 bool _isStringLength(
1918 DartObjectImpl targetResult, SimpleIdentifier identifier) {
1919 if (targetResult == null || targetResult.type != _typeProvider.stringType) {
1920 return false;
1921 }
1922 return identifier.name == 'length';
1923 }
1924
1925 /**
1926 * Return the value of the given [expression], or a representation of 'null'
1927 * if the expression cannot be evaluated.
1928 */
1929 DartObjectImpl _valueOf(Expression expression) {
1930 DartObjectImpl expressionValue = expression.accept(this);
1931 if (expressionValue != null) {
1932 return expressionValue;
1933 }
1934 return _typeProvider.nullObject;
1935 }
1936 }
1937
1938 /**
1939 * A representation of the value of a compile-time constant expression.
1940 *
1941 * Note that, unlike the mirrors system, the object being represented does *not*
1942 * exist. This interface allows static analysis tools to determine something
1943 * about the state of the object that would exist if the code that creates the
1944 * object were executed, but none of the code being analyzed is actually
1945 * executed.
1946 */
1947 abstract class DartObject {
1948 /**
1949 * Return the boolean value of this object, or `null` if either the value of
1950 * this object is not known or this object is not of type 'bool'.
1951 *
1952 * Deprecated. Use [toBoolValue].
1953 */
1954 @deprecated
1955 bool get boolValue;
1956
1957 /**
1958 * Return the floating point value of this object, or `null` if either the
1959 * value of this object is not known or this object is not of type 'double'.
1960 *
1961 * Deprecated. Use [toDoubleValue].
1962 */
1963 @deprecated
1964 double get doubleValue;
1965
1966 /**
1967 * Return `true` if this object's value can be represented exactly.
1968 *
1969 * Deprecated. The semantics of this method were not clear. One semantic is
1970 * covered by [hasKnownValue].
1971 */
1972 @deprecated
1973 bool get hasExactValue;
1974
1975 /**
1976 * Return `true` if the value of the object being represented is known.
1977 *
1978 * This method will return `false` if
1979 * * the value being represented is the value of a declared variable (a
1980 * variable whose value is provided at run-time using a `-D` command-line
1981 * option), or
1982 * * the value is a function.
1983 *
1984 * The result of this method does not imply anything about the state of
1985 * object representations returned by the method [getField], those that are
1986 * elements of the list returned by [toListValue], or the keys or values in
1987 * the map returned by [toMapValue]. For example, a representation of a list
1988 * can return `true` even if one or more of the elements of that list would
1989 * return `false`.
1990 */
1991 bool get hasKnownValue;
1992
1993 /**
1994 * Return the integer value of this object, or `null` if either the value of
1995 * this object is not known or this object is not of type 'int'.
1996 *
1997 * Deprecated. Use [toIntValue].
1998 */
1999 @deprecated
2000 int get intValue;
2001
2002 /**
2003 * Return `true` if this object represents the value 'false'.
2004 *
2005 * Deprecated. Use `object.toBoolValue() == false`.
2006 */
2007 @deprecated
2008 bool get isFalse;
2009
2010 /**
2011 * Return `true` if the object being represented represents the value 'null'.
2012 */
2013 bool get isNull;
2014
2015 /**
2016 * Return `true` if this object represents the value 'true'.
2017 *
2018 * Deprecated. Use `object.toBoolValue() == true`.
2019 */
2020 @deprecated
2021 bool get isTrue;
2022
2023 /**
2024 * Return the string value of this object, or `null` if either the value of
2025 * this object is not known or this object is not of type 'String'.
2026 *
2027 * Deprecated. Use [toStringValue].
2028 */
2029 @deprecated
2030 String get stringValue;
2031
2032 /**
2033 * Return a representation of the type of the object being represented.
2034 *
2035 * For values resulting from the invocation of a 'const' constructor, this
2036 * will be a representation of the run-time type of the object.
2037 *
2038 * For values resulting from a literal expression, this will be a
2039 * representation of the static type of the value -- `int` for integer
2040 * literals, `List` for list literals, etc. -- even when the static type is an
2041 * abstract type (such as `List`) and hence will never be the run-time type of
2042 * the represented object.
2043 *
2044 * For values resulting from any other kind of expression, this will be a
2045 * representation of the result of evaluating the expression.
2046 *
2047 * Return `null` if the expression cannot be evaluated, either because it is
2048 * not a valid constant expression or because one or more of the values used
2049 * in the expression does not have a known value.
2050 *
2051 * This method can return a representation of the type, even if this object
2052 * would return `false` from [hasKnownValue].
2053 */
2054 ParameterizedType get type;
2055
2056 /**
2057 * Return this object's value if it can be represented exactly, or `null` if
2058 * either the value cannot be represented exactly or if the value is `null`.
2059 * Clients should use `hasExactValue` to distinguish between these two cases.
2060 *
2061 * Deprecated. Use one of the `isXValue()` methods.
2062 */
2063 @deprecated
2064 Object get value;
2065
2066 /**
2067 * Return a representation of the value of the field with the given [name].
2068 *
2069 * Return `null` if either the object being represented does not have a field
2070 * with the given name or if the implementation of the class of the object is
2071 * invalid, making it impossible to determine that value of the field.
2072 *
2073 * Note that, unlike the mirrors API, this method does *not* invoke a getter;
2074 * it simply returns a representation of the known state of a field.
2075 */
2076 DartObject getField(String name);
2077
2078 /**
2079 * Return a boolean corresponding to the value of the object being
2080 * represented, or `null` if
2081 * * this object is not of type 'bool',
2082 * * the value of the object being represented is not known, or
2083 * * the value of the object being represented is `null`.
2084 */
2085 bool toBoolValue();
2086
2087 /**
2088 * Return a double corresponding to the value of the object being represented,
2089 * or `null`
2090 * if
2091 * * this object is not of type 'double',
2092 * * the value of the object being represented is not known, or
2093 * * the value of the object being represented is `null`.
2094 */
2095 double toDoubleValue();
2096
2097 /**
2098 * Return an integer corresponding to the value of the object being
2099 * represented, or `null` if
2100 * * this object is not of type 'int',
2101 * * the value of the object being represented is not known, or
2102 * * the value of the object being represented is `null`.
2103 */
2104 int toIntValue();
2105
2106 /**
2107 * Return a list corresponding to the value of the object being represented,
2108 * or `null` if
2109 * * this object is not of type 'List', or
2110 * * the value of the object being represented is `null`.
2111 */
2112 List<DartObject> toListValue();
2113
2114 /**
2115 * Return a map corresponding to the value of the object being represented, or
2116 * `null` if
2117 * * this object is not of type 'Map', or
2118 * * the value of the object being represented is `null`.
2119 */
2120 Map<DartObject, DartObject> toMapValue();
2121
2122 /**
2123 * Return a string corresponding to the value of the object being represented,
2124 * or `null` if
2125 * * this object is not of type 'String',
2126 * * the value of the object being represented is not known, or
2127 * * the value of the object being represented is `null`.
2128 */
2129 String toStringValue();
2130
2131 /**
2132 * Return a string corresponding to the value of the object being represented,
2133 * or `null` if
2134 * * this object is not of type 'Symbol', or
2135 * * the value of the object being represented is `null`.
2136 * (We return the string
2137 */
2138 String toSymbolValue();
2139
2140 /**
2141 * Return the representation of the type corresponding to the value of the
2142 * object being represented, or `null` if
2143 * * this object is not of type 'Type', or
2144 * * the value of the object being represented is `null`.
2145 */
2146 ParameterizedType toTypeValue();
2147 }
2148
2149 /**
2150 * A utility class that contains methods for manipulating instances of a Dart
2151 * class and for collecting errors during evaluation.
2152 */
2153 class DartObjectComputer {
2154 /**
2155 * The error reporter that we are using to collect errors.
2156 */
2157 final ErrorReporter _errorReporter;
2158
2159 /**
2160 * The type provider used to create objects of the appropriate types, and to
2161 * identify when an object is of a built-in type.
2162 */
2163 final TypeProvider _typeProvider;
2164
2165 DartObjectComputer(this._errorReporter, this._typeProvider);
2166
2167 DartObjectImpl add(BinaryExpression node, DartObjectImpl leftOperand,
2168 DartObjectImpl rightOperand) {
2169 if (leftOperand != null && rightOperand != null) {
2170 try {
2171 return leftOperand.add(_typeProvider, rightOperand);
2172 } on EvaluationException catch (exception) {
2173 _errorReporter.reportErrorForNode(exception.errorCode, node);
2174 return null;
2175 }
2176 }
2177 return null;
2178 }
2179
2180 /**
2181 * Return the result of applying boolean conversion to the [evaluationResult].
2182 * The [node] is the node against which errors should be reported.
2183 */
2184 DartObjectImpl applyBooleanConversion(
2185 AstNode node, DartObjectImpl evaluationResult) {
2186 if (evaluationResult != null) {
2187 try {
2188 return evaluationResult.convertToBool(_typeProvider);
2189 } on EvaluationException catch (exception) {
2190 _errorReporter.reportErrorForNode(exception.errorCode, node);
2191 }
2192 }
2193 return null;
2194 }
2195
2196 DartObjectImpl bitAnd(BinaryExpression node, DartObjectImpl leftOperand,
2197 DartObjectImpl rightOperand) {
2198 if (leftOperand != null && rightOperand != null) {
2199 try {
2200 return leftOperand.bitAnd(_typeProvider, rightOperand);
2201 } on EvaluationException catch (exception) {
2202 _errorReporter.reportErrorForNode(exception.errorCode, node);
2203 }
2204 }
2205 return null;
2206 }
2207
2208 DartObjectImpl bitNot(Expression node, DartObjectImpl evaluationResult) {
2209 if (evaluationResult != null) {
2210 try {
2211 return evaluationResult.bitNot(_typeProvider);
2212 } on EvaluationException catch (exception) {
2213 _errorReporter.reportErrorForNode(exception.errorCode, node);
2214 }
2215 }
2216 return null;
2217 }
2218
2219 DartObjectImpl bitOr(BinaryExpression node, DartObjectImpl leftOperand,
2220 DartObjectImpl rightOperand) {
2221 if (leftOperand != null && rightOperand != null) {
2222 try {
2223 return leftOperand.bitOr(_typeProvider, rightOperand);
2224 } on EvaluationException catch (exception) {
2225 _errorReporter.reportErrorForNode(exception.errorCode, node);
2226 }
2227 }
2228 return null;
2229 }
2230
2231 DartObjectImpl bitXor(BinaryExpression node, DartObjectImpl leftOperand,
2232 DartObjectImpl rightOperand) {
2233 if (leftOperand != null && rightOperand != null) {
2234 try {
2235 return leftOperand.bitXor(_typeProvider, rightOperand);
2236 } on EvaluationException catch (exception) {
2237 _errorReporter.reportErrorForNode(exception.errorCode, node);
2238 }
2239 }
2240 return null;
2241 }
2242
2243 DartObjectImpl concatenate(Expression node, DartObjectImpl leftOperand,
2244 DartObjectImpl rightOperand) {
2245 if (leftOperand != null && rightOperand != null) {
2246 try {
2247 return leftOperand.concatenate(_typeProvider, rightOperand);
2248 } on EvaluationException catch (exception) {
2249 _errorReporter.reportErrorForNode(exception.errorCode, node);
2250 }
2251 }
2252 return null;
2253 }
2254
2255 DartObjectImpl divide(BinaryExpression node, DartObjectImpl leftOperand,
2256 DartObjectImpl rightOperand) {
2257 if (leftOperand != null && rightOperand != null) {
2258 try {
2259 return leftOperand.divide(_typeProvider, rightOperand);
2260 } on EvaluationException catch (exception) {
2261 _errorReporter.reportErrorForNode(exception.errorCode, node);
2262 }
2263 }
2264 return null;
2265 }
2266
2267 DartObjectImpl equalEqual(Expression node, DartObjectImpl leftOperand,
2268 DartObjectImpl rightOperand) {
2269 if (leftOperand != null && rightOperand != null) {
2270 try {
2271 return leftOperand.equalEqual(_typeProvider, rightOperand);
2272 } on EvaluationException catch (exception) {
2273 _errorReporter.reportErrorForNode(exception.errorCode, node);
2274 }
2275 }
2276 return null;
2277 }
2278
2279 DartObjectImpl greaterThan(BinaryExpression node, DartObjectImpl leftOperand,
2280 DartObjectImpl rightOperand) {
2281 if (leftOperand != null && rightOperand != null) {
2282 try {
2283 return leftOperand.greaterThan(_typeProvider, rightOperand);
2284 } on EvaluationException catch (exception) {
2285 _errorReporter.reportErrorForNode(exception.errorCode, node);
2286 }
2287 }
2288 return null;
2289 }
2290
2291 DartObjectImpl greaterThanOrEqual(BinaryExpression node,
2292 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
2293 if (leftOperand != null && rightOperand != null) {
2294 try {
2295 return leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
2296 } on EvaluationException catch (exception) {
2297 _errorReporter.reportErrorForNode(exception.errorCode, node);
2298 }
2299 }
2300 return null;
2301 }
2302
2303 DartObjectImpl integerDivide(BinaryExpression node,
2304 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
2305 if (leftOperand != null && rightOperand != null) {
2306 try {
2307 return leftOperand.integerDivide(_typeProvider, rightOperand);
2308 } on EvaluationException catch (exception) {
2309 _errorReporter.reportErrorForNode(exception.errorCode, node);
2310 }
2311 }
2312 return null;
2313 }
2314
2315 DartObjectImpl isIdentical(Expression node, DartObjectImpl leftOperand,
2316 DartObjectImpl rightOperand) {
2317 if (leftOperand != null && rightOperand != null) {
2318 try {
2319 return leftOperand.isIdentical(_typeProvider, rightOperand);
2320 } on EvaluationException catch (exception) {
2321 _errorReporter.reportErrorForNode(exception.errorCode, node);
2322 }
2323 }
2324 return null;
2325 }
2326
2327 DartObjectImpl lessThan(BinaryExpression node, DartObjectImpl leftOperand,
2328 DartObjectImpl rightOperand) {
2329 if (leftOperand != null && rightOperand != null) {
2330 try {
2331 return leftOperand.lessThan(_typeProvider, rightOperand);
2332 } on EvaluationException catch (exception) {
2333 _errorReporter.reportErrorForNode(exception.errorCode, node);
2334 }
2335 }
2336 return null;
2337 }
2338
2339 DartObjectImpl lessThanOrEqual(BinaryExpression node,
2340 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
2341 if (leftOperand != null && rightOperand != null) {
2342 try {
2343 return leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
2344 } on EvaluationException catch (exception) {
2345 _errorReporter.reportErrorForNode(exception.errorCode, node);
2346 }
2347 }
2348 return null;
2349 }
2350
2351 DartObjectImpl logicalAnd(BinaryExpression node, DartObjectImpl leftOperand,
2352 DartObjectImpl rightOperand) {
2353 if (leftOperand != null && rightOperand != null) {
2354 try {
2355 return leftOperand.logicalAnd(_typeProvider, rightOperand);
2356 } on EvaluationException catch (exception) {
2357 _errorReporter.reportErrorForNode(exception.errorCode, node);
2358 }
2359 }
2360 return null;
2361 }
2362
2363 DartObjectImpl logicalNot(Expression node, DartObjectImpl evaluationResult) {
2364 if (evaluationResult != null) {
2365 try {
2366 return evaluationResult.logicalNot(_typeProvider);
2367 } on EvaluationException catch (exception) {
2368 _errorReporter.reportErrorForNode(exception.errorCode, node);
2369 }
2370 }
2371 return null;
2372 }
2373
2374 DartObjectImpl logicalOr(BinaryExpression node, DartObjectImpl leftOperand,
2375 DartObjectImpl rightOperand) {
2376 if (leftOperand != null && rightOperand != null) {
2377 try {
2378 return leftOperand.logicalOr(_typeProvider, rightOperand);
2379 } on EvaluationException catch (exception) {
2380 _errorReporter.reportErrorForNode(exception.errorCode, node);
2381 }
2382 }
2383 return null;
2384 }
2385
2386 DartObjectImpl minus(BinaryExpression node, DartObjectImpl leftOperand,
2387 DartObjectImpl rightOperand) {
2388 if (leftOperand != null && rightOperand != null) {
2389 try {
2390 return leftOperand.minus(_typeProvider, rightOperand);
2391 } on EvaluationException catch (exception) {
2392 _errorReporter.reportErrorForNode(exception.errorCode, node);
2393 }
2394 }
2395 return null;
2396 }
2397
2398 DartObjectImpl negated(Expression node, DartObjectImpl evaluationResult) {
2399 if (evaluationResult != null) {
2400 try {
2401 return evaluationResult.negated(_typeProvider);
2402 } on EvaluationException catch (exception) {
2403 _errorReporter.reportErrorForNode(exception.errorCode, node);
2404 }
2405 }
2406 return null;
2407 }
2408
2409 DartObjectImpl notEqual(BinaryExpression node, DartObjectImpl leftOperand,
2410 DartObjectImpl rightOperand) {
2411 if (leftOperand != null && rightOperand != null) {
2412 try {
2413 return leftOperand.notEqual(_typeProvider, rightOperand);
2414 } on EvaluationException catch (exception) {
2415 _errorReporter.reportErrorForNode(exception.errorCode, node);
2416 }
2417 }
2418 return null;
2419 }
2420
2421 DartObjectImpl performToString(
2422 AstNode node, DartObjectImpl evaluationResult) {
2423 if (evaluationResult != null) {
2424 try {
2425 return evaluationResult.performToString(_typeProvider);
2426 } on EvaluationException catch (exception) {
2427 _errorReporter.reportErrorForNode(exception.errorCode, node);
2428 }
2429 }
2430 return null;
2431 }
2432
2433 DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand,
2434 DartObjectImpl rightOperand) {
2435 if (leftOperand != null && rightOperand != null) {
2436 try {
2437 return leftOperand.remainder(_typeProvider, rightOperand);
2438 } on EvaluationException catch (exception) {
2439 _errorReporter.reportErrorForNode(exception.errorCode, node);
2440 }
2441 }
2442 return null;
2443 }
2444
2445 DartObjectImpl shiftLeft(BinaryExpression node, DartObjectImpl leftOperand,
2446 DartObjectImpl rightOperand) {
2447 if (leftOperand != null && rightOperand != null) {
2448 try {
2449 return leftOperand.shiftLeft(_typeProvider, rightOperand);
2450 } on EvaluationException catch (exception) {
2451 _errorReporter.reportErrorForNode(exception.errorCode, node);
2452 }
2453 }
2454 return null;
2455 }
2456
2457 DartObjectImpl shiftRight(BinaryExpression node, DartObjectImpl leftOperand,
2458 DartObjectImpl rightOperand) {
2459 if (leftOperand != null && rightOperand != null) {
2460 try {
2461 return leftOperand.shiftRight(_typeProvider, rightOperand);
2462 } on EvaluationException catch (exception) {
2463 _errorReporter.reportErrorForNode(exception.errorCode, node);
2464 }
2465 }
2466 return null;
2467 }
2468
2469 /**
2470 * Return the result of invoking the 'length' getter on the
2471 * [evaluationResult]. The [node] is the node against which errors should be
2472 * reported.
2473 */
2474 EvaluationResultImpl stringLength(
2475 Expression node, EvaluationResultImpl evaluationResult) {
2476 if (evaluationResult.value != null) {
2477 try {
2478 return new EvaluationResultImpl(
2479 evaluationResult.value.stringLength(_typeProvider));
2480 } on EvaluationException catch (exception) {
2481 _errorReporter.reportErrorForNode(exception.errorCode, node);
2482 }
2483 }
2484 return new EvaluationResultImpl(null);
2485 }
2486
2487 DartObjectImpl times(BinaryExpression node, DartObjectImpl leftOperand,
2488 DartObjectImpl rightOperand) {
2489 if (leftOperand != null && rightOperand != null) {
2490 try {
2491 return leftOperand.times(_typeProvider, rightOperand);
2492 } on EvaluationException catch (exception) {
2493 _errorReporter.reportErrorForNode(exception.errorCode, node);
2494 }
2495 }
2496 return null;
2497 }
2498 }
2499
2500 /**
2501 * An instance of a Dart class.
2502 */
2503 class DartObjectImpl implements DartObject {
2504 /**
2505 * An empty list of objects.
2506 */
2507 static const List<DartObjectImpl> EMPTY_LIST = const <DartObjectImpl>[];
2508
2509 /**
2510 * The run-time type of this object.
2511 */
2512 final ParameterizedType type;
2513
2514 /**
2515 * The state of the object.
2516 */
2517 final InstanceState _state;
2518
2519 /**
2520 * Initialize a newly created object to have the given [type] and [_state].
2521 */
2522 DartObjectImpl(this.type, this._state);
2523
2524 /**
2525 * Create an object to represent an unknown value.
2526 */
2527 factory DartObjectImpl.validWithUnknownValue(InterfaceType type) {
2528 if (type.element.library.isDartCore) {
2529 String typeName = type.name;
2530 if (typeName == "bool") {
2531 return new DartObjectImpl(type, BoolState.UNKNOWN_VALUE);
2532 } else if (typeName == "double") {
2533 return new DartObjectImpl(type, DoubleState.UNKNOWN_VALUE);
2534 } else if (typeName == "int") {
2535 return new DartObjectImpl(type, IntState.UNKNOWN_VALUE);
2536 } else if (typeName == "String") {
2537 return new DartObjectImpl(type, StringState.UNKNOWN_VALUE);
2538 }
2539 }
2540 return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
2541 }
2542
2543 @deprecated
2544 @override
2545 bool get boolValue => toBoolValue();
2546
2547 @deprecated
2548 @override
2549 double get doubleValue => toDoubleValue();
2550
2551 HashMap<String, DartObjectImpl> get fields => _state.fields;
2552
2553 @deprecated
2554 @override
2555 bool get hasExactValue => _state.hasExactValue;
2556
2557 @override
2558 int get hashCode => JenkinsSmiHash.hash2(type.hashCode, _state.hashCode);
2559
2560 @override
2561 bool get hasKnownValue => !_state.isUnknown;
2562
2563 @deprecated
2564 @override
2565 int get intValue => toIntValue();
2566
2567 /**
2568 * Return `true` if this object represents an object whose type is 'bool'.
2569 */
2570 bool get isBool => _state.isBool;
2571
2572 /**
2573 * Return `true` if this object represents an object whose type is either
2574 * 'bool', 'num', 'String', or 'Null'.
2575 */
2576 bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull;
2577
2578 @deprecated
2579 @override
2580 bool get isFalse => toBoolValue() == false;
2581
2582 @override
2583 bool get isNull => _state is NullState;
2584
2585 @deprecated
2586 @override
2587 bool get isTrue =>
2588 _state is BoolState && identical((_state as BoolState).value, true);
2589
2590 /**
2591 * Return `true` if this object represents an unknown value.
2592 */
2593 bool get isUnknown => _state.isUnknown;
2594
2595 /**
2596 * Return `true` if this object represents an instance of a user-defined
2597 * class.
2598 */
2599 bool get isUserDefinedObject => _state is GenericState;
2600
2601 @deprecated
2602 @override
2603 String get stringValue => toStringValue();
2604
2605 @deprecated
2606 @override
2607 Object get value => _state.value;
2608
2609 @override
2610 bool operator ==(Object object) {
2611 if (object is! DartObjectImpl) {
2612 return false;
2613 }
2614 DartObjectImpl dartObject = object as DartObjectImpl;
2615 return type == dartObject.type && _state == dartObject._state;
2616 }
2617
2618 /**
2619 * Return the result of invoking the '+' operator on this object with the
2620 * given [rightOperand]. The [typeProvider] is the type provider used to find
2621 * known types.
2622 *
2623 * Throws an [EvaluationException] if the operator is not appropriate for an
2624 * object of this kind.
2625 */
2626 DartObjectImpl add(TypeProvider typeProvider, DartObjectImpl rightOperand) {
2627 InstanceState result = _state.add(rightOperand._state);
2628 if (result is IntState) {
2629 return new DartObjectImpl(typeProvider.intType, result);
2630 } else if (result is DoubleState) {
2631 return new DartObjectImpl(typeProvider.doubleType, result);
2632 } else if (result is NumState) {
2633 return new DartObjectImpl(typeProvider.numType, result);
2634 } else if (result is StringState) {
2635 return new DartObjectImpl(typeProvider.stringType, result);
2636 }
2637 // We should never get here.
2638 throw new IllegalStateException("add returned a ${result.runtimeType}");
2639 }
2640
2641 /**
2642 * Return the result of invoking the '&' operator on this object with the
2643 * [rightOperand]. The [typeProvider] is the type provider used to find known
2644 * types.
2645 *
2646 * Throws an [EvaluationException] if the operator is not appropriate for an
2647 * object of this kind.
2648 */
2649 DartObjectImpl bitAnd(
2650 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2651 new DartObjectImpl(
2652 typeProvider.intType, _state.bitAnd(rightOperand._state));
2653
2654 /**
2655 * Return the result of invoking the '~' operator on this object. The
2656 * [typeProvider] is the type provider used to find known types.
2657 *
2658 * Throws an [EvaluationException] if the operator is not appropriate for an
2659 * object of this kind.
2660 */
2661 DartObjectImpl bitNot(TypeProvider typeProvider) =>
2662 new DartObjectImpl(typeProvider.intType, _state.bitNot());
2663
2664 /**
2665 * Return the result of invoking the '|' operator on this object with the
2666 * [rightOperand]. The [typeProvider] is the type provider used to find known
2667 * types.
2668 *
2669 * Throws an [EvaluationException] if the operator is not appropriate for an
2670 * object of this kind.
2671 */
2672 DartObjectImpl bitOr(
2673 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2674 new DartObjectImpl(
2675 typeProvider.intType, _state.bitOr(rightOperand._state));
2676
2677 /**
2678 * Return the result of invoking the '^' operator on this object with the
2679 * [rightOperand]. The [typeProvider] is the type provider used to find known
2680 * types.
2681 *
2682 * Throws an [EvaluationException] if the operator is not appropriate for an
2683 * object of this kind.
2684 */
2685 DartObjectImpl bitXor(
2686 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2687 new DartObjectImpl(
2688 typeProvider.intType, _state.bitXor(rightOperand._state));
2689
2690 /**
2691 * Return the result of invoking the ' ' operator on this object with the
2692 * [rightOperand]. The [typeProvider] is the type provider used to find known
2693 * types.
2694 *
2695 * Throws an [EvaluationException] if the operator is not appropriate for an
2696 * object of this kind.
2697 */
2698 DartObjectImpl concatenate(
2699 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2700 new DartObjectImpl(
2701 typeProvider.stringType, _state.concatenate(rightOperand._state));
2702
2703 /**
2704 * Return the result of applying boolean conversion to this object. The
2705 * [typeProvider] is the type provider used to find known types.
2706 *
2707 * Throws an [EvaluationException] if the operator is not appropriate for an
2708 * object of this kind.
2709 */
2710 DartObjectImpl convertToBool(TypeProvider typeProvider) {
2711 InterfaceType boolType = typeProvider.boolType;
2712 if (identical(type, boolType)) {
2713 return this;
2714 }
2715 return new DartObjectImpl(boolType, _state.convertToBool());
2716 }
2717
2718 /**
2719 * Return the result of invoking the '/' operator on this object with the
2720 * [rightOperand]. The [typeProvider] is the type provider used to find known
2721 * types.
2722 *
2723 * Throws an [EvaluationException] if the operator is not appropriate for
2724 * an object of this kind.
2725 */
2726 DartObjectImpl divide(
2727 TypeProvider typeProvider, DartObjectImpl rightOperand) {
2728 InstanceState result = _state.divide(rightOperand._state);
2729 if (result is IntState) {
2730 return new DartObjectImpl(typeProvider.intType, result);
2731 } else if (result is DoubleState) {
2732 return new DartObjectImpl(typeProvider.doubleType, result);
2733 } else if (result is NumState) {
2734 return new DartObjectImpl(typeProvider.numType, result);
2735 }
2736 // We should never get here.
2737 throw new IllegalStateException("divide returned a ${result.runtimeType}");
2738 }
2739
2740 /**
2741 * Return the result of invoking the '==' operator on this object with the
2742 * [rightOperand]. The [typeProvider] is the type provider used to find known
2743 * types.
2744 *
2745 * Throws an [EvaluationException] if the operator is not appropriate for an
2746 * object of this kind.
2747 */
2748 DartObjectImpl equalEqual(
2749 TypeProvider typeProvider, DartObjectImpl rightOperand) {
2750 if (type != rightOperand.type) {
2751 String typeName = type.name;
2752 if (!(typeName == "bool" ||
2753 typeName == "double" ||
2754 typeName == "int" ||
2755 typeName == "num" ||
2756 typeName == "String" ||
2757 typeName == "Null" ||
2758 type.isDynamic)) {
2759 throw new EvaluationException(
2760 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
2761 }
2762 }
2763 return new DartObjectImpl(
2764 typeProvider.boolType, _state.equalEqual(rightOperand._state));
2765 }
2766
2767 @override
2768 DartObject getField(String name) {
2769 if (_state is GenericState) {
2770 return (_state as GenericState).fields[name];
2771 }
2772 return null;
2773 }
2774
2775 /**
2776 * Return the result of invoking the '&gt;' operator on this object with the
2777 * [rightOperand]. The [typeProvider] is the type provider used to find known
2778 * types.
2779 *
2780 * Throws an [EvaluationException] if the operator is not appropriate for an
2781 * object of this kind.
2782 */
2783 DartObjectImpl greaterThan(
2784 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2785 new DartObjectImpl(
2786 typeProvider.boolType, _state.greaterThan(rightOperand._state));
2787
2788 /**
2789 * Return the result of invoking the '&gt;=' operator on this object with the
2790 * [rightOperand]. The [typeProvider] is the type provider used to find known
2791 * types.
2792 *
2793 * Throws an [EvaluationException] if the operator is not appropriate for an
2794 * object of this kind.
2795 */
2796 DartObjectImpl greaterThanOrEqual(
2797 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2798 new DartObjectImpl(typeProvider.boolType,
2799 _state.greaterThanOrEqual(rightOperand._state));
2800
2801 /**
2802 * Return the result of invoking the '~/' operator on this object with the
2803 * [rightOperand]. The [typeProvider] is the type provider used to find known
2804 * types.
2805 *
2806 * Throws an [EvaluationException] if the operator is not appropriate for an
2807 * object of this kind.
2808 */
2809 DartObjectImpl integerDivide(
2810 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2811 new DartObjectImpl(
2812 typeProvider.intType, _state.integerDivide(rightOperand._state));
2813
2814 /**
2815 * Return the result of invoking the identical function on this object with
2816 * the [rightOperand]. The [typeProvider] is the type provider used to find
2817 * known types.
2818 */
2819 DartObjectImpl isIdentical(
2820 TypeProvider typeProvider, DartObjectImpl rightOperand) {
2821 return new DartObjectImpl(
2822 typeProvider.boolType, _state.isIdentical(rightOperand._state));
2823 }
2824
2825 /**
2826 * Return the result of invoking the '&lt;' operator on this object with the
2827 * [rightOperand]. The [typeProvider] is the type provider used to find known
2828 * types.
2829 *
2830 * Throws an [EvaluationException] if the operator is not appropriate for an
2831 * object of this kind.
2832 */
2833 DartObjectImpl lessThan(
2834 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2835 new DartObjectImpl(
2836 typeProvider.boolType, _state.lessThan(rightOperand._state));
2837
2838 /**
2839 * Return the result of invoking the '&lt;=' operator on this object with the
2840 * [rightOperand]. The [typeProvider] is the type provider used to find known
2841 * types.
2842 *
2843 * Throws an [EvaluationException] if the operator is not appropriate for an
2844 * object of this kind.
2845 */
2846 DartObjectImpl lessThanOrEqual(
2847 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2848 new DartObjectImpl(
2849 typeProvider.boolType, _state.lessThanOrEqual(rightOperand._state));
2850
2851 /**
2852 * Return the result of invoking the '&&' operator on this object with the
2853 * [rightOperand]. The [typeProvider] is the type provider used to find known
2854 * types.
2855 *
2856 * Throws an [EvaluationException] if the operator is not appropriate for an
2857 * object of this kind.
2858 */
2859 DartObjectImpl logicalAnd(
2860 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2861 new DartObjectImpl(
2862 typeProvider.boolType, _state.logicalAnd(rightOperand._state));
2863
2864 /**
2865 * Return the result of invoking the '!' operator on this object. The
2866 * [typeProvider] is the type provider used to find known types.
2867 *
2868 * Throws an [EvaluationException] if the operator is not appropriate for an
2869 * object of this kind.
2870 */
2871 DartObjectImpl logicalNot(TypeProvider typeProvider) =>
2872 new DartObjectImpl(typeProvider.boolType, _state.logicalNot());
2873
2874 /**
2875 * Return the result of invoking the '||' operator on this object with the
2876 * [rightOperand]. The [typeProvider] is the type provider used to find known
2877 * types.
2878 *
2879 * Throws an [EvaluationException] if the operator is not appropriate for an
2880 * object of this kind.
2881 */
2882 DartObjectImpl logicalOr(
2883 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
2884 new DartObjectImpl(
2885 typeProvider.boolType, _state.logicalOr(rightOperand._state));
2886
2887 /**
2888 * Return the result of invoking the '-' operator on this object with the
2889 * [rightOperand]. The [typeProvider] is the type provider used to find known
2890 * types.
2891 *
2892 * Throws an [EvaluationException] if the operator is not appropriate for an
2893 * object of this kind.
2894 */
2895 DartObjectImpl minus(TypeProvider typeProvider, DartObjectImpl rightOperand) {
2896 InstanceState result = _state.minus(rightOperand._state);
2897 if (result is IntState) {
2898 return new DartObjectImpl(typeProvider.intType, result);
2899 } else if (result is DoubleState) {
2900 return new DartObjectImpl(typeProvider.doubleType, result);
2901 } else if (result is NumState) {
2902 return new DartObjectImpl(typeProvider.numType, result);
2903 }
2904 // We should never get here.
2905 throw new IllegalStateException("minus returned a ${result.runtimeType}");
2906 }
2907
2908 /**
2909 * Return the result of invoking the '-' operator on this object. The
2910 * [typeProvider] is the type provider used to find known types.
2911 *
2912 * Throws an [EvaluationException] if the operator is not appropriate for an
2913 * object of this kind.
2914 */
2915 DartObjectImpl negated(TypeProvider typeProvider) {
2916 InstanceState result = _state.negated();
2917 if (result is IntState) {
2918 return new DartObjectImpl(typeProvider.intType, result);
2919 } else if (result is DoubleState) {
2920 return new DartObjectImpl(typeProvider.doubleType, result);
2921 } else if (result is NumState) {
2922 return new DartObjectImpl(typeProvider.numType, result);
2923 }
2924 // We should never get here.
2925 throw new IllegalStateException("negated returned a ${result.runtimeType}");
2926 }
2927
2928 /**
2929 * Return the result of invoking the '!=' operator on this object with the
2930 * [rightOperand]. The [typeProvider] is the type provider used to find known
2931 * types.
2932 *
2933 * Throws an [EvaluationException] if the operator is not appropriate for an
2934 * object of this kind.
2935 */
2936 DartObjectImpl notEqual(
2937 TypeProvider typeProvider, DartObjectImpl rightOperand) {
2938 if (type != rightOperand.type) {
2939 String typeName = type.name;
2940 if (typeName != "bool" &&
2941 typeName != "double" &&
2942 typeName != "int" &&
2943 typeName != "num" &&
2944 typeName != "String") {
2945 return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
2946 }
2947 }
2948 return new DartObjectImpl(typeProvider.boolType,
2949 _state.equalEqual(rightOperand._state).logicalNot());
2950 }
2951
2952 /**
2953 * Return the result of converting this object to a 'String'. The
2954 * [typeProvider] is the type provider used to find known types.
2955 *
2956 * Throws an [EvaluationException] if the object cannot be converted to a
2957 * 'String'.
2958 */
2959 DartObjectImpl performToString(TypeProvider typeProvider) {
2960 InterfaceType stringType = typeProvider.stringType;
2961 if (identical(type, stringType)) {
2962 return this;
2963 }
2964 return new DartObjectImpl(stringType, _state.convertToString());
2965 }
2966
2967 /**
2968 * Return the result of invoking the '%' operator on this object with the
2969 * [rightOperand]. The [typeProvider] is the type provider used to find known
2970 * types.
2971 *
2972 * Throws an [EvaluationException] if the operator is not appropriate for an
2973 * object of this kind.
2974 */
2975 DartObjectImpl remainder(
2976 TypeProvider typeProvider, DartObjectImpl rightOperand) {
2977 InstanceState result = _state.remainder(rightOperand._state);
2978 if (result is IntState) {
2979 return new DartObjectImpl(typeProvider.intType, result);
2980 } else if (result is DoubleState) {
2981 return new DartObjectImpl(typeProvider.doubleType, result);
2982 } else if (result is NumState) {
2983 return new DartObjectImpl(typeProvider.numType, result);
2984 }
2985 // We should never get here.
2986 throw new IllegalStateException(
2987 "remainder returned a ${result.runtimeType}");
2988 }
2989
2990 /**
2991 * Return the result of invoking the '&lt;&lt;' operator on this object with
2992 * the [rightOperand]. The [typeProvider] is the type provider used to find
2993 * known types.
2994 *
2995 * Throws an [EvaluationException] if the operator is not appropriate for an
2996 * object of this kind.
2997 */
2998 DartObjectImpl shiftLeft(
2999 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
3000 new DartObjectImpl(
3001 typeProvider.intType, _state.shiftLeft(rightOperand._state));
3002
3003 /**
3004 * Return the result of invoking the '&gt;&gt;' operator on this object with
3005 * the [rightOperand]. The [typeProvider] is the type provider used to find
3006 * known types.
3007 *
3008 * Throws an [EvaluationException] if the operator is not appropriate for an
3009 * object of this kind.
3010 */
3011 DartObjectImpl shiftRight(
3012 TypeProvider typeProvider, DartObjectImpl rightOperand) =>
3013 new DartObjectImpl(
3014 typeProvider.intType, _state.shiftRight(rightOperand._state));
3015
3016 /**
3017 * Return the result of invoking the 'length' getter on this object. The
3018 * [typeProvider] is the type provider used to find known types.
3019 *
3020 * Throws an [EvaluationException] if the operator is not appropriate for an
3021 * object of this kind.
3022 */
3023 DartObjectImpl stringLength(TypeProvider typeProvider) =>
3024 new DartObjectImpl(typeProvider.intType, _state.stringLength());
3025
3026 /**
3027 * Return the result of invoking the '*' operator on this object with the
3028 * [rightOperand]. The [typeProvider] is the type provider used to find known
3029 * types.
3030 *
3031 * Throws an [EvaluationException] if the operator is not appropriate for an
3032 * object of this kind.
3033 */
3034 DartObjectImpl times(TypeProvider typeProvider, DartObjectImpl rightOperand) {
3035 InstanceState result = _state.times(rightOperand._state);
3036 if (result is IntState) {
3037 return new DartObjectImpl(typeProvider.intType, result);
3038 } else if (result is DoubleState) {
3039 return new DartObjectImpl(typeProvider.doubleType, result);
3040 } else if (result is NumState) {
3041 return new DartObjectImpl(typeProvider.numType, result);
3042 }
3043 // We should never get here.
3044 throw new IllegalStateException("times returned a ${result.runtimeType}");
3045 }
3046
3047 @override
3048 bool toBoolValue() {
3049 if (_state is BoolState) {
3050 return (_state as BoolState).value;
3051 }
3052 return null;
3053 }
3054
3055 @override
3056 double toDoubleValue() {
3057 if (_state is DoubleState) {
3058 return (_state as DoubleState).value;
3059 }
3060 return null;
3061 }
3062
3063 @override
3064 int toIntValue() {
3065 if (_state is IntState) {
3066 return (_state as IntState).value;
3067 }
3068 return null;
3069 }
3070
3071 @override
3072 List<DartObject> toListValue() {
3073 if (_state is ListState) {
3074 return (_state as ListState)._elements;
3075 }
3076 return null;
3077 }
3078
3079 @override
3080 Map<DartObject, DartObject> toMapValue() {
3081 if (_state is MapState) {
3082 return (_state as MapState)._entries;
3083 }
3084 return null;
3085 }
3086
3087 @override
3088 String toString() => "${type.displayName} ($_state)";
3089
3090 @override
3091 String toStringValue() {
3092 if (_state is StringState) {
3093 return (_state as StringState).value;
3094 }
3095 return null;
3096 }
3097
3098 @override
3099 String toSymbolValue() {
3100 if (_state is SymbolState) {
3101 return (_state as SymbolState).value;
3102 }
3103 return null;
3104 }
3105
3106 @override
3107 ParameterizedType toTypeValue() {
3108 if (_state is TypeState) {
3109 Element element = (_state as TypeState).value;
3110 if (element is ClassElement) {
3111 return element.type;
3112 }
3113 if (element is FunctionElement) {
3114 return element.type;
3115 }
3116 }
3117 return null;
3118 }
3119 }
3120
3121 /**
3122 * An object used to provide access to the values of variables that have been
3123 * defined on the command line using the `-D` option.
3124 */
3125 class DeclaredVariables {
3126 /**
3127 * A table mapping the names of declared variables to their values.
3128 */
3129 HashMap<String, String> _declaredVariables = new HashMap<String, String>();
3130
3131 /**
3132 * Define a variable with the given [name] to have the given [value].
3133 */
3134 void define(String name, String value) {
3135 _declaredVariables[name] = value;
3136 }
3137
3138 /**
3139 * Return the value of the variable with the given [name] interpreted as a
3140 * 'boolean' value. If the variable is not defined (or [name] is `null`), a
3141 * DartObject representing "unknown" is returned. If the value cannot be
3142 * parsed as a boolean, a DartObject representing 'null' is returned. The
3143 * [typeProvider] is the type provider used to find the type 'bool'.
3144 */
3145 DartObject getBool(TypeProvider typeProvider, String name) {
3146 String value = _declaredVariables[name];
3147 if (value == null) {
3148 return new DartObjectImpl(typeProvider.boolType, BoolState.UNKNOWN_VALUE);
3149 }
3150 if (value == "true") {
3151 return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
3152 } else if (value == "false") {
3153 return new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE);
3154 }
3155 return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
3156 }
3157
3158 /**
3159 * Return the value of the variable with the given [name] interpreted as an
3160 * integer value. If the variable is not defined (or [name] is `null`), a
3161 * DartObject representing "unknown" is returned. If the value cannot be
3162 * parsed as an integer, a DartObject representing 'null' is returned.
3163 */
3164 DartObject getInt(TypeProvider typeProvider, String name) {
3165 String value = _declaredVariables[name];
3166 if (value == null) {
3167 return new DartObjectImpl(typeProvider.intType, IntState.UNKNOWN_VALUE);
3168 }
3169 int bigInteger;
3170 try {
3171 bigInteger = int.parse(value);
3172 } on FormatException {
3173 return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE);
3174 }
3175 return new DartObjectImpl(typeProvider.intType, new IntState(bigInteger));
3176 }
3177
3178 /**
3179 * Return the value of the variable with the given [name] interpreted as a
3180 * String value, or `null` if the variable is not defined. Return the value of
3181 * the variable with the given name interpreted as a String value. If the
3182 * variable is not defined (or [name] is `null`), a DartObject representing
3183 * "unknown" is returned. The [typeProvider] is the type provider used to find
3184 * the type 'String'.
3185 */
3186 DartObject getString(TypeProvider typeProvider, String name) {
3187 String value = _declaredVariables[name];
3188 if (value == null) {
3189 return new DartObjectImpl(
3190 typeProvider.stringType, StringState.UNKNOWN_VALUE);
3191 }
3192 return new DartObjectImpl(typeProvider.stringType, new StringState(value));
3193 }
3194 }
3195
3196 /**
3197 * The state of an object representing a double.
3198 */
3199 class DoubleState extends NumState {
3200 /**
3201 * A state that can be used to represent a double whose value is not known.
3202 */
3203 static DoubleState UNKNOWN_VALUE = new DoubleState(null);
3204
3205 /**
3206 * The value of this instance.
3207 */
3208 final double value;
3209
3210 /**
3211 * Initialize a newly created state to represent a double with the given
3212 * [value].
3213 */
3214 DoubleState(this.value);
3215
3216 @override
3217 bool get hasExactValue => true;
3218
3219 @override
3220 int get hashCode => value == null ? 0 : value.hashCode;
3221
3222 @override
3223 bool get isBoolNumStringOrNull => true;
3224
3225 @override
3226 bool get isUnknown => value == null;
3227
3228 @override
3229 String get typeName => "double";
3230
3231 @override
3232 bool operator ==(Object object) =>
3233 object is DoubleState && (value == object.value);
3234
3235 @override
3236 NumState add(InstanceState rightOperand) {
3237 assertNumOrNull(rightOperand);
3238 if (value == null) {
3239 return UNKNOWN_VALUE;
3240 }
3241 if (rightOperand is IntState) {
3242 int rightValue = rightOperand.value;
3243 if (rightValue == null) {
3244 return UNKNOWN_VALUE;
3245 }
3246 return new DoubleState(value + rightValue.toDouble());
3247 } else if (rightOperand is DoubleState) {
3248 double rightValue = rightOperand.value;
3249 if (rightValue == null) {
3250 return UNKNOWN_VALUE;
3251 }
3252 return new DoubleState(value + rightValue);
3253 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3254 return UNKNOWN_VALUE;
3255 }
3256 throw new EvaluationException(
3257 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3258 }
3259
3260 @override
3261 StringState convertToString() {
3262 if (value == null) {
3263 return StringState.UNKNOWN_VALUE;
3264 }
3265 return new StringState(value.toString());
3266 }
3267
3268 @override
3269 NumState divide(InstanceState rightOperand) {
3270 assertNumOrNull(rightOperand);
3271 if (value == null) {
3272 return UNKNOWN_VALUE;
3273 }
3274 if (rightOperand is IntState) {
3275 int rightValue = rightOperand.value;
3276 if (rightValue == null) {
3277 return UNKNOWN_VALUE;
3278 }
3279 return new DoubleState(value / rightValue.toDouble());
3280 } else if (rightOperand is DoubleState) {
3281 double rightValue = rightOperand.value;
3282 if (rightValue == null) {
3283 return UNKNOWN_VALUE;
3284 }
3285 return new DoubleState(value / rightValue);
3286 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3287 return UNKNOWN_VALUE;
3288 }
3289 throw new EvaluationException(
3290 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3291 }
3292
3293 @override
3294 BoolState equalEqual(InstanceState rightOperand) {
3295 assertBoolNumStringOrNull(rightOperand);
3296 return isIdentical(rightOperand);
3297 }
3298
3299 @override
3300 BoolState greaterThan(InstanceState rightOperand) {
3301 assertNumOrNull(rightOperand);
3302 if (value == null) {
3303 return BoolState.UNKNOWN_VALUE;
3304 }
3305 if (rightOperand is IntState) {
3306 int rightValue = rightOperand.value;
3307 if (rightValue == null) {
3308 return BoolState.UNKNOWN_VALUE;
3309 }
3310 return BoolState.from(value > rightValue.toDouble());
3311 } else if (rightOperand is DoubleState) {
3312 double rightValue = rightOperand.value;
3313 if (rightValue == null) {
3314 return BoolState.UNKNOWN_VALUE;
3315 }
3316 return BoolState.from(value > rightValue);
3317 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3318 return BoolState.UNKNOWN_VALUE;
3319 }
3320 throw new EvaluationException(
3321 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3322 }
3323
3324 @override
3325 BoolState greaterThanOrEqual(InstanceState rightOperand) {
3326 assertNumOrNull(rightOperand);
3327 if (value == null) {
3328 return BoolState.UNKNOWN_VALUE;
3329 }
3330 if (rightOperand is IntState) {
3331 int rightValue = rightOperand.value;
3332 if (rightValue == null) {
3333 return BoolState.UNKNOWN_VALUE;
3334 }
3335 return BoolState.from(value >= rightValue.toDouble());
3336 } else if (rightOperand is DoubleState) {
3337 double rightValue = rightOperand.value;
3338 if (rightValue == null) {
3339 return BoolState.UNKNOWN_VALUE;
3340 }
3341 return BoolState.from(value >= rightValue);
3342 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3343 return BoolState.UNKNOWN_VALUE;
3344 }
3345 throw new EvaluationException(
3346 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3347 }
3348
3349 @override
3350 IntState integerDivide(InstanceState rightOperand) {
3351 assertNumOrNull(rightOperand);
3352 if (value == null) {
3353 return IntState.UNKNOWN_VALUE;
3354 }
3355 if (rightOperand is IntState) {
3356 int rightValue = rightOperand.value;
3357 if (rightValue == null) {
3358 return IntState.UNKNOWN_VALUE;
3359 }
3360 double result = value / rightValue.toDouble();
3361 return new IntState(result.toInt());
3362 } else if (rightOperand is DoubleState) {
3363 double rightValue = rightOperand.value;
3364 if (rightValue == null) {
3365 return IntState.UNKNOWN_VALUE;
3366 }
3367 double result = value / rightValue;
3368 return new IntState(result.toInt());
3369 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3370 return IntState.UNKNOWN_VALUE;
3371 }
3372 throw new EvaluationException(
3373 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3374 }
3375
3376 @override
3377 BoolState isIdentical(InstanceState rightOperand) {
3378 if (value == null) {
3379 return BoolState.UNKNOWN_VALUE;
3380 }
3381 if (rightOperand is DoubleState) {
3382 double rightValue = rightOperand.value;
3383 if (rightValue == null) {
3384 return BoolState.UNKNOWN_VALUE;
3385 }
3386 return BoolState.from(value == rightValue);
3387 } else if (rightOperand is IntState) {
3388 int rightValue = rightOperand.value;
3389 if (rightValue == null) {
3390 return BoolState.UNKNOWN_VALUE;
3391 }
3392 return BoolState.from(value == rightValue.toDouble());
3393 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3394 return BoolState.UNKNOWN_VALUE;
3395 }
3396 return BoolState.FALSE_STATE;
3397 }
3398
3399 @override
3400 BoolState lessThan(InstanceState rightOperand) {
3401 assertNumOrNull(rightOperand);
3402 if (value == null) {
3403 return BoolState.UNKNOWN_VALUE;
3404 }
3405 if (rightOperand is IntState) {
3406 int rightValue = rightOperand.value;
3407 if (rightValue == null) {
3408 return BoolState.UNKNOWN_VALUE;
3409 }
3410 return BoolState.from(value < rightValue.toDouble());
3411 } else if (rightOperand is DoubleState) {
3412 double rightValue = rightOperand.value;
3413 if (rightValue == null) {
3414 return BoolState.UNKNOWN_VALUE;
3415 }
3416 return BoolState.from(value < rightValue);
3417 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3418 return BoolState.UNKNOWN_VALUE;
3419 }
3420 throw new EvaluationException(
3421 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3422 }
3423
3424 @override
3425 BoolState lessThanOrEqual(InstanceState rightOperand) {
3426 assertNumOrNull(rightOperand);
3427 if (value == null) {
3428 return BoolState.UNKNOWN_VALUE;
3429 }
3430 if (rightOperand is IntState) {
3431 int rightValue = rightOperand.value;
3432 if (rightValue == null) {
3433 return BoolState.UNKNOWN_VALUE;
3434 }
3435 return BoolState.from(value <= rightValue.toDouble());
3436 } else if (rightOperand is DoubleState) {
3437 double rightValue = rightOperand.value;
3438 if (rightValue == null) {
3439 return BoolState.UNKNOWN_VALUE;
3440 }
3441 return BoolState.from(value <= rightValue);
3442 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3443 return BoolState.UNKNOWN_VALUE;
3444 }
3445 throw new EvaluationException(
3446 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3447 }
3448
3449 @override
3450 NumState minus(InstanceState rightOperand) {
3451 assertNumOrNull(rightOperand);
3452 if (value == null) {
3453 return UNKNOWN_VALUE;
3454 }
3455 if (rightOperand is IntState) {
3456 int rightValue = rightOperand.value;
3457 if (rightValue == null) {
3458 return UNKNOWN_VALUE;
3459 }
3460 return new DoubleState(value - rightValue.toDouble());
3461 } else if (rightOperand is DoubleState) {
3462 double rightValue = rightOperand.value;
3463 if (rightValue == null) {
3464 return UNKNOWN_VALUE;
3465 }
3466 return new DoubleState(value - rightValue);
3467 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3468 return UNKNOWN_VALUE;
3469 }
3470 throw new EvaluationException(
3471 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3472 }
3473
3474 @override
3475 NumState negated() {
3476 if (value == null) {
3477 return UNKNOWN_VALUE;
3478 }
3479 return new DoubleState(-(value));
3480 }
3481
3482 @override
3483 NumState remainder(InstanceState rightOperand) {
3484 assertNumOrNull(rightOperand);
3485 if (value == null) {
3486 return UNKNOWN_VALUE;
3487 }
3488 if (rightOperand is IntState) {
3489 int rightValue = rightOperand.value;
3490 if (rightValue == null) {
3491 return UNKNOWN_VALUE;
3492 }
3493 return new DoubleState(value % rightValue.toDouble());
3494 } else if (rightOperand is DoubleState) {
3495 double rightValue = rightOperand.value;
3496 if (rightValue == null) {
3497 return UNKNOWN_VALUE;
3498 }
3499 return new DoubleState(value % rightValue);
3500 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3501 return UNKNOWN_VALUE;
3502 }
3503 throw new EvaluationException(
3504 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3505 }
3506
3507 @override
3508 NumState times(InstanceState rightOperand) {
3509 assertNumOrNull(rightOperand);
3510 if (value == null) {
3511 return UNKNOWN_VALUE;
3512 }
3513 if (rightOperand is IntState) {
3514 int rightValue = rightOperand.value;
3515 if (rightValue == null) {
3516 return UNKNOWN_VALUE;
3517 }
3518 return new DoubleState(value * rightValue.toDouble());
3519 } else if (rightOperand is DoubleState) {
3520 double rightValue = rightOperand.value;
3521 if (rightValue == null) {
3522 return UNKNOWN_VALUE;
3523 }
3524 return new DoubleState(value * rightValue);
3525 } else if (rightOperand is DynamicState || rightOperand is NumState) {
3526 return UNKNOWN_VALUE;
3527 }
3528 throw new EvaluationException(
3529 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
3530 }
3531
3532 @override
3533 String toString() => value == null ? "-unknown-" : value.toString();
3534 }
3535
3536 /**
3537 * The state of an object representing a Dart object for which there is no type
3538 * information.
3539 */
3540 class DynamicState extends InstanceState {
3541 /**
3542 * The unique instance of this class.
3543 */
3544 static DynamicState DYNAMIC_STATE = new DynamicState();
3545
3546 @override
3547 bool get isBool => true;
3548
3549 @override
3550 bool get isBoolNumStringOrNull => true;
3551
3552 @override
3553 String get typeName => "dynamic";
3554
3555 @override
3556 NumState add(InstanceState rightOperand) {
3557 assertNumOrNull(rightOperand);
3558 return _unknownNum(rightOperand);
3559 }
3560
3561 @override
3562 IntState bitAnd(InstanceState rightOperand) {
3563 assertIntOrNull(rightOperand);
3564 return IntState.UNKNOWN_VALUE;
3565 }
3566
3567 @override
3568 IntState bitNot() => IntState.UNKNOWN_VALUE;
3569
3570 @override
3571 IntState bitOr(InstanceState rightOperand) {
3572 assertIntOrNull(rightOperand);
3573 return IntState.UNKNOWN_VALUE;
3574 }
3575
3576 @override
3577 IntState bitXor(InstanceState rightOperand) {
3578 assertIntOrNull(rightOperand);
3579 return IntState.UNKNOWN_VALUE;
3580 }
3581
3582 @override
3583 StringState concatenate(InstanceState rightOperand) {
3584 assertString(rightOperand);
3585 return StringState.UNKNOWN_VALUE;
3586 }
3587
3588 @override
3589 BoolState convertToBool() => BoolState.UNKNOWN_VALUE;
3590
3591 @override
3592 StringState convertToString() => StringState.UNKNOWN_VALUE;
3593
3594 @override
3595 NumState divide(InstanceState rightOperand) {
3596 assertNumOrNull(rightOperand);
3597 return _unknownNum(rightOperand);
3598 }
3599
3600 @override
3601 BoolState equalEqual(InstanceState rightOperand) {
3602 assertBoolNumStringOrNull(rightOperand);
3603 return BoolState.UNKNOWN_VALUE;
3604 }
3605
3606 @override
3607 BoolState greaterThan(InstanceState rightOperand) {
3608 assertNumOrNull(rightOperand);
3609 return BoolState.UNKNOWN_VALUE;
3610 }
3611
3612 @override
3613 BoolState greaterThanOrEqual(InstanceState rightOperand) {
3614 assertNumOrNull(rightOperand);
3615 return BoolState.UNKNOWN_VALUE;
3616 }
3617
3618 @override
3619 IntState integerDivide(InstanceState rightOperand) {
3620 assertNumOrNull(rightOperand);
3621 return IntState.UNKNOWN_VALUE;
3622 }
3623
3624 @override
3625 BoolState isIdentical(InstanceState rightOperand) {
3626 return BoolState.UNKNOWN_VALUE;
3627 }
3628
3629 @override
3630 BoolState lessThan(InstanceState rightOperand) {
3631 assertNumOrNull(rightOperand);
3632 return BoolState.UNKNOWN_VALUE;
3633 }
3634
3635 @override
3636 BoolState lessThanOrEqual(InstanceState rightOperand) {
3637 assertNumOrNull(rightOperand);
3638 return BoolState.UNKNOWN_VALUE;
3639 }
3640
3641 @override
3642 BoolState logicalAnd(InstanceState rightOperand) {
3643 assertBool(rightOperand);
3644 return BoolState.UNKNOWN_VALUE;
3645 }
3646
3647 @override
3648 BoolState logicalNot() => BoolState.UNKNOWN_VALUE;
3649
3650 @override
3651 BoolState logicalOr(InstanceState rightOperand) {
3652 assertBool(rightOperand);
3653 return rightOperand.convertToBool();
3654 }
3655
3656 @override
3657 NumState minus(InstanceState rightOperand) {
3658 assertNumOrNull(rightOperand);
3659 return _unknownNum(rightOperand);
3660 }
3661
3662 @override
3663 NumState negated() => NumState.UNKNOWN_VALUE;
3664
3665 @override
3666 NumState remainder(InstanceState rightOperand) {
3667 assertNumOrNull(rightOperand);
3668 return _unknownNum(rightOperand);
3669 }
3670
3671 @override
3672 IntState shiftLeft(InstanceState rightOperand) {
3673 assertIntOrNull(rightOperand);
3674 return IntState.UNKNOWN_VALUE;
3675 }
3676
3677 @override
3678 IntState shiftRight(InstanceState rightOperand) {
3679 assertIntOrNull(rightOperand);
3680 return IntState.UNKNOWN_VALUE;
3681 }
3682
3683 @override
3684 NumState times(InstanceState rightOperand) {
3685 assertNumOrNull(rightOperand);
3686 return _unknownNum(rightOperand);
3687 }
3688
3689 /**
3690 * Return an object representing an unknown numeric value whose type is based
3691 * on the type of the [rightOperand].
3692 */
3693 NumState _unknownNum(InstanceState rightOperand) {
3694 if (rightOperand is IntState) {
3695 return IntState.UNKNOWN_VALUE;
3696 } else if (rightOperand is DoubleState) {
3697 return DoubleState.UNKNOWN_VALUE;
3698 }
3699 return NumState.UNKNOWN_VALUE;
3700 }
3701 }
3702
3703 /**
3704 * A run-time exception that would be thrown during the evaluation of Dart code.
3705 */
3706 class EvaluationException extends JavaException {
3707 /**
3708 * The error code associated with the exception.
3709 */
3710 final ErrorCode errorCode;
3711
3712 /**
3713 * Initialize a newly created exception to have the given [errorCode].
3714 */
3715 EvaluationException(this.errorCode);
3716 }
3717
3718 /**
3719 * The result of attempting to evaluate an expression.
3720 */
3721 class EvaluationResult {
3722 /**
3723 * The value of the expression.
3724 */
3725 final DartObject value;
3726
3727 /**
3728 * The errors that should be reported for the expression(s) that were
3729 * evaluated.
3730 */
3731 final List<AnalysisError> _errors;
3732
3733 /**
3734 * Initialize a newly created result object with the given [value] and set of
3735 * [_errors]. Clients should use one of the factory methods: [forErrors] and
3736 * [forValue].
3737 */
3738 EvaluationResult(this.value, this._errors);
3739
3740 /**
3741 * Return a list containing the errors that should be reported for the
3742 * expression(s) that were evaluated. If there are no such errors, the list
3743 * will be empty. The list can be empty even if the expression is not a valid
3744 * compile time constant if the errors would have been reported by other parts
3745 * of the analysis engine.
3746 */
3747 List<AnalysisError> get errors =>
3748 _errors == null ? AnalysisError.NO_ERRORS : _errors;
3749
3750 /**
3751 * Return `true` if the expression is a compile-time constant expression that
3752 * would not throw an exception when evaluated.
3753 */
3754 bool get isValid => _errors == null;
3755
3756 /**
3757 * Return an evaluation result representing the result of evaluating an
3758 * expression that is not a compile-time constant because of the given
3759 * [errors].
3760 */
3761 static EvaluationResult forErrors(List<AnalysisError> errors) =>
3762 new EvaluationResult(null, errors);
3763
3764 /**
3765 * Return an evaluation result representing the result of evaluating an
3766 * expression that is a compile-time constant that evaluates to the given
3767 * [value].
3768 */
3769 static EvaluationResult forValue(DartObject value) =>
3770 new EvaluationResult(value, null);
3771 }
3772
3773 /**
3774 * The result of attempting to evaluate a expression.
3775 */
3776 class EvaluationResultImpl {
3777 /**
3778 * The errors encountered while trying to evaluate the compile time constant.
3779 * These errors may or may not have prevented the expression from being a
3780 * valid compile time constant.
3781 */
3782 List<AnalysisError> _errors;
3783
3784 /**
3785 * The value of the expression, or `null` if the value couldn't be computed
3786 * due to errors.
3787 */
3788 final DartObjectImpl value;
3789
3790 EvaluationResultImpl(this.value, [List<AnalysisError> errors]) {
3791 this._errors = errors == null ? <AnalysisError>[] : errors;
3792 }
3793
3794 @deprecated // Use new EvaluationResultImpl(value)
3795 EvaluationResultImpl.con1(this.value) {
3796 this._errors = new List<AnalysisError>(0);
3797 }
3798
3799 @deprecated // Use new EvaluationResultImpl(value, errors)
3800 EvaluationResultImpl.con2(this.value, List<AnalysisError> this._errors);
3801
3802 List<AnalysisError> get errors => _errors;
3803
3804 bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) {
3805 if (this.value != null) {
3806 if (result.value == null) {
3807 return false;
3808 }
3809 return value == result.value;
3810 } else {
3811 return false;
3812 }
3813 }
3814
3815 @override
3816 String toString() {
3817 if (value == null) {
3818 return "error";
3819 }
3820 return value.toString();
3821 }
3822 }
3823
3824 /**
3825 * The state of an object representing a function.
3826 */
3827 class FunctionState extends InstanceState {
3828 /**
3829 * The element representing the function being modeled.
3830 */
3831 final ExecutableElement _element;
3832
3833 /**
3834 * Initialize a newly created state to represent the function with the given
3835 * [element].
3836 */
3837 FunctionState(this._element);
3838
3839 @override
3840 int get hashCode => _element == null ? 0 : _element.hashCode;
3841
3842 @override
3843 String get typeName => "Function";
3844
3845 @override
3846 bool operator ==(Object object) =>
3847 object is FunctionState && (_element == object._element);
3848
3849 @override
3850 StringState convertToString() {
3851 if (_element == null) {
3852 return StringState.UNKNOWN_VALUE;
3853 }
3854 return new StringState(_element.name);
3855 }
3856
3857 @override
3858 BoolState equalEqual(InstanceState rightOperand) {
3859 return isIdentical(rightOperand);
3860 }
3861
3862 @override
3863 BoolState isIdentical(InstanceState rightOperand) {
3864 if (_element == null) {
3865 return BoolState.UNKNOWN_VALUE;
3866 }
3867 if (rightOperand is FunctionState) {
3868 ExecutableElement rightElement = rightOperand._element;
3869 if (rightElement == null) {
3870 return BoolState.UNKNOWN_VALUE;
3871 }
3872 return BoolState.from(_element == rightElement);
3873 } else if (rightOperand is DynamicState) {
3874 return BoolState.UNKNOWN_VALUE;
3875 }
3876 return BoolState.FALSE_STATE;
3877 }
3878
3879 @override
3880 String toString() => _element == null ? "-unknown-" : _element.name;
3881 }
3882
3883 /**
3884 * The state of an object representing a Dart object for which there is no more
3885 * specific state.
3886 */
3887 class GenericState extends InstanceState {
3888 /**
3889 * Pseudo-field that we use to represent fields in the superclass.
3890 */
3891 static String SUPERCLASS_FIELD = "(super)";
3892
3893 /**
3894 * A state that can be used to represent an object whose state is not known.
3895 */
3896 static GenericState UNKNOWN_VALUE =
3897 new GenericState(new HashMap<String, DartObjectImpl>());
3898
3899 /**
3900 * The values of the fields of this instance.
3901 */
3902 final HashMap<String, DartObjectImpl> _fieldMap;
3903
3904 /**
3905 * Initialize a newly created state to represent a newly created object. The
3906 * [fieldMap] contains the values of the fields of the instance.
3907 */
3908 GenericState(this._fieldMap);
3909
3910 @override
3911 HashMap<String, DartObjectImpl> get fields => _fieldMap;
3912
3913 @override
3914 int get hashCode {
3915 int hashCode = 0;
3916 for (DartObjectImpl value in _fieldMap.values) {
3917 hashCode += value.hashCode;
3918 }
3919 return hashCode;
3920 }
3921
3922 @override
3923 bool get isUnknown => identical(this, UNKNOWN_VALUE);
3924
3925 @override
3926 String get typeName => "user defined type";
3927
3928 @override
3929 bool operator ==(Object object) {
3930 if (object is! GenericState) {
3931 return false;
3932 }
3933 GenericState state = object as GenericState;
3934 HashSet<String> otherFields =
3935 new HashSet<String>.from(state._fieldMap.keys.toSet());
3936 for (String fieldName in _fieldMap.keys.toSet()) {
3937 if (_fieldMap[fieldName] != state._fieldMap[fieldName]) {
3938 return false;
3939 }
3940 otherFields.remove(fieldName);
3941 }
3942 for (String fieldName in otherFields) {
3943 if (state._fieldMap[fieldName] != _fieldMap[fieldName]) {
3944 return false;
3945 }
3946 }
3947 return true;
3948 }
3949
3950 @override
3951 StringState convertToString() => StringState.UNKNOWN_VALUE;
3952
3953 @override
3954 BoolState equalEqual(InstanceState rightOperand) {
3955 assertBoolNumStringOrNull(rightOperand);
3956 return isIdentical(rightOperand);
3957 }
3958
3959 @override
3960 BoolState isIdentical(InstanceState rightOperand) {
3961 if (rightOperand is DynamicState) {
3962 return BoolState.UNKNOWN_VALUE;
3963 }
3964 return BoolState.from(this == rightOperand);
3965 }
3966
3967 @override
3968 String toString() {
3969 StringBuffer buffer = new StringBuffer();
3970 List<String> fieldNames = _fieldMap.keys.toList();
3971 fieldNames.sort();
3972 bool first = true;
3973 for (String fieldName in fieldNames) {
3974 if (first) {
3975 first = false;
3976 } else {
3977 buffer.write('; ');
3978 }
3979 buffer.write(fieldName);
3980 buffer.write(' = ');
3981 buffer.write(_fieldMap[fieldName]);
3982 }
3983 return buffer.toString();
3984 }
3985 }
3986
3987 /**
3988 * The state of an object representing a Dart object.
3989 */
3990 abstract class InstanceState {
3991 /**
3992 * If this represents a generic dart object, return a map from its field names
3993 * to their values. Otherwise return null.
3994 */
3995 HashMap<String, DartObjectImpl> get fields => null;
3996
3997 /**
3998 * Return `true` if this object's value can be represented exactly.
3999 */
4000 bool get hasExactValue => false;
4001
4002 /**
4003 * Return `true` if this object represents an object whose type is 'bool'.
4004 */
4005 bool get isBool => false;
4006
4007 /**
4008 * Return `true` if this object represents an object whose type is either
4009 * 'bool', 'num', 'String', or 'Null'.
4010 */
4011 bool get isBoolNumStringOrNull => false;
4012
4013 /**
4014 * Return `true` if this object represents an unknown value.
4015 */
4016 bool get isUnknown => false;
4017
4018 /**
4019 * Return the name of the type of this value.
4020 */
4021 String get typeName;
4022
4023 /**
4024 * Return this object's value if it can be represented exactly, or `null` if
4025 * either the value cannot be represented exactly or if the value is `null`.
4026 * Clients should use [hasExactValue] to distinguish between these two cases.
4027 */
4028 Object get value => null;
4029
4030 /**
4031 * Return the result of invoking the '+' operator on this object with the
4032 * [rightOperand].
4033 *
4034 * Throws an [EvaluationException] if the operator is not appropriate for an
4035 * object of this kind.
4036 */
4037 InstanceState add(InstanceState rightOperand) {
4038 if (this is StringState && rightOperand is StringState) {
4039 return concatenate(rightOperand);
4040 }
4041 assertNumOrNull(this);
4042 assertNumOrNull(rightOperand);
4043 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4044 }
4045
4046 /**
4047 * Throw an exception if the given [state] does not represent a boolean value.
4048 */
4049 void assertBool(InstanceState state) {
4050 if (!(state is BoolState || state is DynamicState)) {
4051 throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
4052 }
4053 }
4054
4055 /**
4056 * Throw an exception if the given [state] does not represent a boolean,
4057 * numeric, string or null value.
4058 */
4059 void assertBoolNumStringOrNull(InstanceState state) {
4060 if (!(state is BoolState ||
4061 state is DoubleState ||
4062 state is IntState ||
4063 state is NumState ||
4064 state is StringState ||
4065 state is NullState ||
4066 state is DynamicState)) {
4067 throw new EvaluationException(
4068 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
4069 }
4070 }
4071
4072 /**
4073 * Throw an exception if the given [state] does not represent an integer or
4074 * null value.
4075 */
4076 void assertIntOrNull(InstanceState state) {
4077 if (!(state is IntState ||
4078 state is NumState ||
4079 state is NullState ||
4080 state is DynamicState)) {
4081 throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_INT);
4082 }
4083 }
4084
4085 /**
4086 * Throw an exception if the given [state] does not represent a boolean,
4087 * numeric, string or null value.
4088 */
4089 void assertNumOrNull(InstanceState state) {
4090 if (!(state is DoubleState ||
4091 state is IntState ||
4092 state is NumState ||
4093 state is NullState ||
4094 state is DynamicState)) {
4095 throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_NUM);
4096 }
4097 }
4098
4099 /**
4100 * Throw an exception if the given [state] does not represent a String value.
4101 */
4102 void assertString(InstanceState state) {
4103 if (!(state is StringState || state is DynamicState)) {
4104 throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
4105 }
4106 }
4107
4108 /**
4109 * Return the result of invoking the '&' operator on this object with the
4110 * [rightOperand].
4111 *
4112 * Throws an [EvaluationException] if the operator is not appropriate for an
4113 * object of this kind.
4114 */
4115 IntState bitAnd(InstanceState rightOperand) {
4116 assertIntOrNull(this);
4117 assertIntOrNull(rightOperand);
4118 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4119 }
4120
4121 /**
4122 * Return the result of invoking the '~' operator on this object.
4123 *
4124 * Throws an [EvaluationException] if the operator is not appropriate for an
4125 * object of this kind.
4126 */
4127 IntState bitNot() {
4128 assertIntOrNull(this);
4129 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4130 }
4131
4132 /**
4133 * Return the result of invoking the '|' operator on this object with the
4134 * [rightOperand].
4135 *
4136 * Throws an [EvaluationException] if the operator is not appropriate for an
4137 * object of this kind.
4138 */
4139 IntState bitOr(InstanceState rightOperand) {
4140 assertIntOrNull(this);
4141 assertIntOrNull(rightOperand);
4142 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4143 }
4144
4145 /**
4146 * Return the result of invoking the '^' operator on this object with the
4147 * [rightOperand].
4148 *
4149 * Throws an [EvaluationException] if the operator is not appropriate for an
4150 * object of this kind.
4151 */
4152 IntState bitXor(InstanceState rightOperand) {
4153 assertIntOrNull(this);
4154 assertIntOrNull(rightOperand);
4155 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4156 }
4157
4158 /**
4159 * Return the result of invoking the ' ' operator on this object with the
4160 * [rightOperand].
4161 *
4162 * Throws an [EvaluationException] if the operator is not appropriate for an
4163 * object of this kind.
4164 */
4165 StringState concatenate(InstanceState rightOperand) {
4166 assertString(rightOperand);
4167 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4168 }
4169
4170 /**
4171 * Return the result of applying boolean conversion to this object.
4172 *
4173 * Throws an [EvaluationException] if the operator is not appropriate for an
4174 * object of this kind.
4175 */
4176 BoolState convertToBool() => BoolState.FALSE_STATE;
4177
4178 /**
4179 * Return the result of converting this object to a String.
4180 *
4181 * Throws an [EvaluationException] if the operator is not appropriate for an
4182 * object of this kind.
4183 */
4184 StringState convertToString();
4185
4186 /**
4187 * Return the result of invoking the '/' operator on this object with the
4188 * [rightOperand].
4189 *
4190 * Throws an [EvaluationException] if the operator is not appropriate for an
4191 * object of this kind.
4192 */
4193 NumState divide(InstanceState rightOperand) {
4194 assertNumOrNull(this);
4195 assertNumOrNull(rightOperand);
4196 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4197 }
4198
4199 /**
4200 * Return the result of invoking the '==' operator on this object with the
4201 * [rightOperand].
4202 *
4203 * Throws an [EvaluationException] if the operator is not appropriate for an
4204 * object of this kind.
4205 */
4206 BoolState equalEqual(InstanceState rightOperand);
4207
4208 /**
4209 * Return the result of invoking the '&gt;' operator on this object with the
4210 * [rightOperand].
4211 *
4212 * Throws an [EvaluationException] if the operator is not appropriate for an
4213 * object of this kind.
4214 */
4215 BoolState greaterThan(InstanceState rightOperand) {
4216 assertNumOrNull(this);
4217 assertNumOrNull(rightOperand);
4218 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4219 }
4220
4221 /**
4222 * Return the result of invoking the '&gt;=' operator on this object with the
4223 * [rightOperand].
4224 *
4225 * Throws an [EvaluationException] if the operator is not appropriate for an
4226 * object of this kind.
4227 */
4228 BoolState greaterThanOrEqual(InstanceState rightOperand) {
4229 assertNumOrNull(this);
4230 assertNumOrNull(rightOperand);
4231 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4232 }
4233
4234 /**
4235 * Return the result of invoking the '~/' operator on this object with the
4236 * [rightOperand].
4237 *
4238 * Throws an [EvaluationException] if the operator is not appropriate for an
4239 * object of this kind.
4240 */
4241 IntState integerDivide(InstanceState rightOperand) {
4242 assertNumOrNull(this);
4243 assertNumOrNull(rightOperand);
4244 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4245 }
4246
4247 /**
4248 * Return the result of invoking the identical function on this object with
4249 * the [rightOperand].
4250 */
4251 BoolState isIdentical(InstanceState rightOperand);
4252
4253 /**
4254 * Return the result of invoking the '&lt;' operator on this object with the
4255 * [rightOperand].
4256 *
4257 * Throws an [EvaluationException] if the operator is not appropriate for an
4258 * object of this kind.
4259 */
4260 BoolState lessThan(InstanceState rightOperand) {
4261 assertNumOrNull(this);
4262 assertNumOrNull(rightOperand);
4263 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4264 }
4265
4266 /**
4267 * Return the result of invoking the '&lt;=' operator on this object with the
4268 * [rightOperand].
4269 *
4270 * Throws an [EvaluationException] if the operator is not appropriate for an
4271 * object of this kind.
4272 */
4273 BoolState lessThanOrEqual(InstanceState rightOperand) {
4274 assertNumOrNull(this);
4275 assertNumOrNull(rightOperand);
4276 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4277 }
4278
4279 /**
4280 * Return the result of invoking the '&&' operator on this object with the
4281 * [rightOperand].
4282 *
4283 * Throws an [EvaluationException] if the operator is not appropriate for an
4284 * object of this kind.
4285 */
4286 BoolState logicalAnd(InstanceState rightOperand) {
4287 assertBool(this);
4288 assertBool(rightOperand);
4289 return BoolState.FALSE_STATE;
4290 }
4291
4292 /**
4293 * Return the result of invoking the '!' operator on this object.
4294 *
4295 * Throws an [EvaluationException] if the operator is not appropriate for an
4296 * object of this kind.
4297 */
4298 BoolState logicalNot() {
4299 assertBool(this);
4300 return BoolState.TRUE_STATE;
4301 }
4302
4303 /**
4304 * Return the result of invoking the '||' operator on this object with the
4305 * [rightOperand].
4306 *
4307 * Throws an [EvaluationException] if the operator is not appropriate for an
4308 * object of this kind.
4309 */
4310 BoolState logicalOr(InstanceState rightOperand) {
4311 assertBool(this);
4312 assertBool(rightOperand);
4313 return rightOperand.convertToBool();
4314 }
4315
4316 /**
4317 * Return the result of invoking the '-' operator on this object with the
4318 * [rightOperand].
4319 *
4320 * Throws an [EvaluationException] if the operator is not appropriate for an
4321 * object of this kind.
4322 */
4323 NumState minus(InstanceState rightOperand) {
4324 assertNumOrNull(this);
4325 assertNumOrNull(rightOperand);
4326 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4327 }
4328
4329 /**
4330 * Return the result of invoking the '-' operator on this object.
4331 *
4332 * Throws an [EvaluationException] if the operator is not appropriate for an
4333 * object of this kind.
4334 */
4335 NumState negated() {
4336 assertNumOrNull(this);
4337 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4338 }
4339
4340 /**
4341 * Return the result of invoking the '%' operator on this object with the
4342 * [rightOperand].
4343 *
4344 * Throws an [EvaluationException] if the operator is not appropriate for an
4345 * object of this kind.
4346 */
4347 NumState remainder(InstanceState rightOperand) {
4348 assertNumOrNull(this);
4349 assertNumOrNull(rightOperand);
4350 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4351 }
4352
4353 /**
4354 * Return the result of invoking the '&lt;&lt;' operator on this object with
4355 * the [rightOperand].
4356 *
4357 * Throws an [EvaluationException] if the operator is not appropriate for an
4358 * object of this kind.
4359 */
4360 IntState shiftLeft(InstanceState rightOperand) {
4361 assertIntOrNull(this);
4362 assertIntOrNull(rightOperand);
4363 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4364 }
4365
4366 /**
4367 * Return the result of invoking the '&gt;&gt;' operator on this object with
4368 * the [rightOperand].
4369 *
4370 * Throws an [EvaluationException] if the operator is not appropriate for an
4371 * object of this kind.
4372 */
4373 IntState shiftRight(InstanceState rightOperand) {
4374 assertIntOrNull(this);
4375 assertIntOrNull(rightOperand);
4376 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4377 }
4378
4379 /**
4380 * Return the result of invoking the 'length' getter on this object.
4381 *
4382 * Throws an [EvaluationException] if the operator is not appropriate for an
4383 * object of this kind.
4384 */
4385 IntState stringLength() {
4386 assertString(this);
4387 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4388 }
4389
4390 /**
4391 * Return the result of invoking the '*' operator on this object with the
4392 * [rightOperand].
4393 *
4394 * Throws an [EvaluationException] if the operator is not appropriate for an
4395 * object of this kind.
4396 */
4397 NumState times(InstanceState rightOperand) {
4398 assertNumOrNull(this);
4399 assertNumOrNull(rightOperand);
4400 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
4401 }
4402 }
4403
4404 /**
4405 * The state of an object representing an int.
4406 */
4407 class IntState extends NumState {
4408 /**
4409 * A state that can be used to represent an int whose value is not known.
4410 */
4411 static IntState UNKNOWN_VALUE = new IntState(null);
4412
4413 /**
4414 * The value of this instance.
4415 */
4416 final int value;
4417
4418 /**
4419 * Initialize a newly created state to represent an int with the given
4420 * [value].
4421 */
4422 IntState(this.value);
4423
4424 @override
4425 bool get hasExactValue => true;
4426
4427 @override
4428 int get hashCode => value == null ? 0 : value.hashCode;
4429
4430 @override
4431 bool get isBoolNumStringOrNull => true;
4432
4433 @override
4434 bool get isUnknown => value == null;
4435
4436 @override
4437 String get typeName => "int";
4438
4439 @override
4440 bool operator ==(Object object) =>
4441 object is IntState && (value == object.value);
4442
4443 @override
4444 NumState add(InstanceState rightOperand) {
4445 assertNumOrNull(rightOperand);
4446 if (value == null) {
4447 if (rightOperand is DoubleState) {
4448 return DoubleState.UNKNOWN_VALUE;
4449 }
4450 return UNKNOWN_VALUE;
4451 }
4452 if (rightOperand is IntState) {
4453 int rightValue = rightOperand.value;
4454 if (rightValue == null) {
4455 return UNKNOWN_VALUE;
4456 }
4457 return new IntState(value + rightValue);
4458 } else if (rightOperand is DoubleState) {
4459 double rightValue = rightOperand.value;
4460 if (rightValue == null) {
4461 return DoubleState.UNKNOWN_VALUE;
4462 }
4463 return new DoubleState(value.toDouble() + rightValue);
4464 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4465 return UNKNOWN_VALUE;
4466 }
4467 throw new EvaluationException(
4468 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4469 }
4470
4471 @override
4472 IntState bitAnd(InstanceState rightOperand) {
4473 assertIntOrNull(rightOperand);
4474 if (value == null) {
4475 return UNKNOWN_VALUE;
4476 }
4477 if (rightOperand is IntState) {
4478 int rightValue = rightOperand.value;
4479 if (rightValue == null) {
4480 return UNKNOWN_VALUE;
4481 }
4482 return new IntState(value & rightValue);
4483 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4484 return UNKNOWN_VALUE;
4485 }
4486 throw new EvaluationException(
4487 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4488 }
4489
4490 @override
4491 IntState bitNot() {
4492 if (value == null) {
4493 return UNKNOWN_VALUE;
4494 }
4495 return new IntState(~value);
4496 }
4497
4498 @override
4499 IntState bitOr(InstanceState rightOperand) {
4500 assertIntOrNull(rightOperand);
4501 if (value == null) {
4502 return UNKNOWN_VALUE;
4503 }
4504 if (rightOperand is IntState) {
4505 int rightValue = rightOperand.value;
4506 if (rightValue == null) {
4507 return UNKNOWN_VALUE;
4508 }
4509 return new IntState(value | rightValue);
4510 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4511 return UNKNOWN_VALUE;
4512 }
4513 throw new EvaluationException(
4514 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4515 }
4516
4517 @override
4518 IntState bitXor(InstanceState rightOperand) {
4519 assertIntOrNull(rightOperand);
4520 if (value == null) {
4521 return UNKNOWN_VALUE;
4522 }
4523 if (rightOperand is IntState) {
4524 int rightValue = rightOperand.value;
4525 if (rightValue == null) {
4526 return UNKNOWN_VALUE;
4527 }
4528 return new IntState(value ^ rightValue);
4529 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4530 return UNKNOWN_VALUE;
4531 }
4532 throw new EvaluationException(
4533 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4534 }
4535
4536 @override
4537 StringState convertToString() {
4538 if (value == null) {
4539 return StringState.UNKNOWN_VALUE;
4540 }
4541 return new StringState(value.toString());
4542 }
4543
4544 @override
4545 NumState divide(InstanceState rightOperand) {
4546 assertNumOrNull(rightOperand);
4547 if (value == null) {
4548 return DoubleState.UNKNOWN_VALUE;
4549 }
4550 if (rightOperand is IntState) {
4551 int rightValue = rightOperand.value;
4552 if (rightValue == null) {
4553 return DoubleState.UNKNOWN_VALUE;
4554 } else {
4555 return new DoubleState(value.toDouble() / rightValue.toDouble());
4556 }
4557 } else if (rightOperand is DoubleState) {
4558 double rightValue = rightOperand.value;
4559 if (rightValue == null) {
4560 return DoubleState.UNKNOWN_VALUE;
4561 }
4562 return new DoubleState(value.toDouble() / rightValue);
4563 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4564 return DoubleState.UNKNOWN_VALUE;
4565 }
4566 throw new EvaluationException(
4567 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4568 }
4569
4570 @override
4571 BoolState equalEqual(InstanceState rightOperand) {
4572 assertBoolNumStringOrNull(rightOperand);
4573 return isIdentical(rightOperand);
4574 }
4575
4576 @override
4577 BoolState greaterThan(InstanceState rightOperand) {
4578 assertNumOrNull(rightOperand);
4579 if (value == null) {
4580 return BoolState.UNKNOWN_VALUE;
4581 }
4582 if (rightOperand is IntState) {
4583 int rightValue = rightOperand.value;
4584 if (rightValue == null) {
4585 return BoolState.UNKNOWN_VALUE;
4586 }
4587 return BoolState.from(value.compareTo(rightValue) > 0);
4588 } else if (rightOperand is DoubleState) {
4589 double rightValue = rightOperand.value;
4590 if (rightValue == null) {
4591 return BoolState.UNKNOWN_VALUE;
4592 }
4593 return BoolState.from(value.toDouble() > rightValue);
4594 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4595 return BoolState.UNKNOWN_VALUE;
4596 }
4597 throw new EvaluationException(
4598 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4599 }
4600
4601 @override
4602 BoolState greaterThanOrEqual(InstanceState rightOperand) {
4603 assertNumOrNull(rightOperand);
4604 if (value == null) {
4605 return BoolState.UNKNOWN_VALUE;
4606 }
4607 if (rightOperand is IntState) {
4608 int rightValue = rightOperand.value;
4609 if (rightValue == null) {
4610 return BoolState.UNKNOWN_VALUE;
4611 }
4612 return BoolState.from(value.compareTo(rightValue) >= 0);
4613 } else if (rightOperand is DoubleState) {
4614 double rightValue = rightOperand.value;
4615 if (rightValue == null) {
4616 return BoolState.UNKNOWN_VALUE;
4617 }
4618 return BoolState.from(value.toDouble() >= rightValue);
4619 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4620 return BoolState.UNKNOWN_VALUE;
4621 }
4622 throw new EvaluationException(
4623 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4624 }
4625
4626 @override
4627 IntState integerDivide(InstanceState rightOperand) {
4628 assertNumOrNull(rightOperand);
4629 if (value == null) {
4630 return UNKNOWN_VALUE;
4631 }
4632 if (rightOperand is IntState) {
4633 int rightValue = rightOperand.value;
4634 if (rightValue == null) {
4635 return UNKNOWN_VALUE;
4636 } else if (rightValue == 0) {
4637 throw new EvaluationException(
4638 CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
4639 }
4640 return new IntState(value ~/ rightValue);
4641 } else if (rightOperand is DoubleState) {
4642 double rightValue = rightOperand.value;
4643 if (rightValue == null) {
4644 return UNKNOWN_VALUE;
4645 }
4646 double result = value.toDouble() / rightValue;
4647 return new IntState(result.toInt());
4648 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4649 return UNKNOWN_VALUE;
4650 }
4651 throw new EvaluationException(
4652 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4653 }
4654
4655 @override
4656 BoolState isIdentical(InstanceState rightOperand) {
4657 if (value == null) {
4658 return BoolState.UNKNOWN_VALUE;
4659 }
4660 if (rightOperand is IntState) {
4661 int rightValue = rightOperand.value;
4662 if (rightValue == null) {
4663 return BoolState.UNKNOWN_VALUE;
4664 }
4665 return BoolState.from(value == rightValue);
4666 } else if (rightOperand is DoubleState) {
4667 double rightValue = rightOperand.value;
4668 if (rightValue == null) {
4669 return BoolState.UNKNOWN_VALUE;
4670 }
4671 return BoolState.from(rightValue == value.toDouble());
4672 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4673 return BoolState.UNKNOWN_VALUE;
4674 }
4675 return BoolState.FALSE_STATE;
4676 }
4677
4678 @override
4679 BoolState lessThan(InstanceState rightOperand) {
4680 assertNumOrNull(rightOperand);
4681 if (value == null) {
4682 return BoolState.UNKNOWN_VALUE;
4683 }
4684 if (rightOperand is IntState) {
4685 int rightValue = rightOperand.value;
4686 if (rightValue == null) {
4687 return BoolState.UNKNOWN_VALUE;
4688 }
4689 return BoolState.from(value.compareTo(rightValue) < 0);
4690 } else if (rightOperand is DoubleState) {
4691 double rightValue = rightOperand.value;
4692 if (rightValue == null) {
4693 return BoolState.UNKNOWN_VALUE;
4694 }
4695 return BoolState.from(value.toDouble() < rightValue);
4696 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4697 return BoolState.UNKNOWN_VALUE;
4698 }
4699 throw new EvaluationException(
4700 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4701 }
4702
4703 @override
4704 BoolState lessThanOrEqual(InstanceState rightOperand) {
4705 assertNumOrNull(rightOperand);
4706 if (value == null) {
4707 return BoolState.UNKNOWN_VALUE;
4708 }
4709 if (rightOperand is IntState) {
4710 int rightValue = rightOperand.value;
4711 if (rightValue == null) {
4712 return BoolState.UNKNOWN_VALUE;
4713 }
4714 return BoolState.from(value.compareTo(rightValue) <= 0);
4715 } else if (rightOperand is DoubleState) {
4716 double rightValue = rightOperand.value;
4717 if (rightValue == null) {
4718 return BoolState.UNKNOWN_VALUE;
4719 }
4720 return BoolState.from(value.toDouble() <= rightValue);
4721 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4722 return BoolState.UNKNOWN_VALUE;
4723 }
4724 throw new EvaluationException(
4725 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4726 }
4727
4728 @override
4729 NumState minus(InstanceState rightOperand) {
4730 assertNumOrNull(rightOperand);
4731 if (value == null) {
4732 if (rightOperand is DoubleState) {
4733 return DoubleState.UNKNOWN_VALUE;
4734 }
4735 return UNKNOWN_VALUE;
4736 }
4737 if (rightOperand is IntState) {
4738 int rightValue = rightOperand.value;
4739 if (rightValue == null) {
4740 return UNKNOWN_VALUE;
4741 }
4742 return new IntState(value - rightValue);
4743 } else if (rightOperand is DoubleState) {
4744 double rightValue = rightOperand.value;
4745 if (rightValue == null) {
4746 return DoubleState.UNKNOWN_VALUE;
4747 }
4748 return new DoubleState(value.toDouble() - rightValue);
4749 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4750 return UNKNOWN_VALUE;
4751 }
4752 throw new EvaluationException(
4753 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4754 }
4755
4756 @override
4757 NumState negated() {
4758 if (value == null) {
4759 return UNKNOWN_VALUE;
4760 }
4761 return new IntState(-value);
4762 }
4763
4764 @override
4765 NumState remainder(InstanceState rightOperand) {
4766 assertNumOrNull(rightOperand);
4767 if (value == null) {
4768 if (rightOperand is DoubleState) {
4769 return DoubleState.UNKNOWN_VALUE;
4770 }
4771 return UNKNOWN_VALUE;
4772 }
4773 if (rightOperand is IntState) {
4774 int rightValue = rightOperand.value;
4775 if (rightValue == null) {
4776 return UNKNOWN_VALUE;
4777 } else if (rightValue == 0) {
4778 return new DoubleState(value.toDouble() % rightValue.toDouble());
4779 }
4780 return new IntState(value.remainder(rightValue));
4781 } else if (rightOperand is DoubleState) {
4782 double rightValue = rightOperand.value;
4783 if (rightValue == null) {
4784 return DoubleState.UNKNOWN_VALUE;
4785 }
4786 return new DoubleState(value.toDouble() % rightValue);
4787 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4788 return UNKNOWN_VALUE;
4789 }
4790 throw new EvaluationException(
4791 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4792 }
4793
4794 @override
4795 IntState shiftLeft(InstanceState rightOperand) {
4796 assertIntOrNull(rightOperand);
4797 if (value == null) {
4798 return UNKNOWN_VALUE;
4799 }
4800 if (rightOperand is IntState) {
4801 int rightValue = rightOperand.value;
4802 if (rightValue == null) {
4803 return UNKNOWN_VALUE;
4804 } else if (rightValue.bitLength > 31) {
4805 return UNKNOWN_VALUE;
4806 }
4807 return new IntState(value << rightValue);
4808 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4809 return UNKNOWN_VALUE;
4810 }
4811 throw new EvaluationException(
4812 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4813 }
4814
4815 @override
4816 IntState shiftRight(InstanceState rightOperand) {
4817 assertIntOrNull(rightOperand);
4818 if (value == null) {
4819 return UNKNOWN_VALUE;
4820 }
4821 if (rightOperand is IntState) {
4822 int rightValue = rightOperand.value;
4823 if (rightValue == null) {
4824 return UNKNOWN_VALUE;
4825 } else if (rightValue.bitLength > 31) {
4826 return UNKNOWN_VALUE;
4827 }
4828 return new IntState(value >> rightValue);
4829 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4830 return UNKNOWN_VALUE;
4831 }
4832 throw new EvaluationException(
4833 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4834 }
4835
4836 @override
4837 NumState times(InstanceState rightOperand) {
4838 assertNumOrNull(rightOperand);
4839 if (value == null) {
4840 if (rightOperand is DoubleState) {
4841 return DoubleState.UNKNOWN_VALUE;
4842 }
4843 return UNKNOWN_VALUE;
4844 }
4845 if (rightOperand is IntState) {
4846 int rightValue = rightOperand.value;
4847 if (rightValue == null) {
4848 return UNKNOWN_VALUE;
4849 }
4850 return new IntState(value * rightValue);
4851 } else if (rightOperand is DoubleState) {
4852 double rightValue = rightOperand.value;
4853 if (rightValue == null) {
4854 return DoubleState.UNKNOWN_VALUE;
4855 }
4856 return new DoubleState(value.toDouble() * rightValue);
4857 } else if (rightOperand is DynamicState || rightOperand is NumState) {
4858 return UNKNOWN_VALUE;
4859 }
4860 throw new EvaluationException(
4861 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
4862 }
4863
4864 @override
4865 String toString() => value == null ? "-unknown-" : value.toString();
4866 }
4867
4868 /**
4869 * The state of an object representing a list.
4870 */
4871 class ListState extends InstanceState {
4872 /**
4873 * The elements of the list.
4874 */
4875 final List<DartObjectImpl> _elements;
4876
4877 /**
4878 * Initialize a newly created state to represent a list with the given
4879 * [elements].
4880 */
4881 ListState(this._elements);
4882
4883 @override
4884 bool get hasExactValue {
4885 int count = _elements.length;
4886 for (int i = 0; i < count; i++) {
4887 if (!_elements[i].hasExactValue) {
4888 return false;
4889 }
4890 }
4891 return true;
4892 }
4893
4894 @override
4895 int get hashCode {
4896 int value = 0;
4897 int count = _elements.length;
4898 for (int i = 0; i < count; i++) {
4899 value = (value << 3) ^ _elements[i].hashCode;
4900 }
4901 return value;
4902 }
4903
4904 @override
4905 String get typeName => "List";
4906
4907 @override
4908 List<Object> get value {
4909 int count = _elements.length;
4910 List<Object> result = new List<Object>(count);
4911 for (int i = 0; i < count; i++) {
4912 DartObjectImpl element = _elements[i];
4913 if (!element.hasExactValue) {
4914 return null;
4915 }
4916 result[i] = element.value;
4917 }
4918 return result;
4919 }
4920
4921 @override
4922 bool operator ==(Object object) {
4923 if (object is! ListState) {
4924 return false;
4925 }
4926 List<DartObjectImpl> otherElements = (object as ListState)._elements;
4927 int count = _elements.length;
4928 if (otherElements.length != count) {
4929 return false;
4930 } else if (count == 0) {
4931 return true;
4932 }
4933 for (int i = 0; i < count; i++) {
4934 if (_elements[i] != otherElements[i]) {
4935 return false;
4936 }
4937 }
4938 return true;
4939 }
4940
4941 @override
4942 StringState convertToString() => StringState.UNKNOWN_VALUE;
4943
4944 @override
4945 BoolState equalEqual(InstanceState rightOperand) {
4946 assertBoolNumStringOrNull(rightOperand);
4947 return isIdentical(rightOperand);
4948 }
4949
4950 @override
4951 BoolState isIdentical(InstanceState rightOperand) {
4952 if (rightOperand is DynamicState) {
4953 return BoolState.UNKNOWN_VALUE;
4954 }
4955 return BoolState.from(this == rightOperand);
4956 }
4957
4958 @override
4959 String toString() {
4960 StringBuffer buffer = new StringBuffer();
4961 buffer.write('[');
4962 bool first = true;
4963 _elements.forEach((DartObjectImpl element) {
4964 if (first) {
4965 first = false;
4966 } else {
4967 buffer.write(', ');
4968 }
4969 buffer.write(element);
4970 });
4971 buffer.write(']');
4972 return buffer.toString();
4973 }
4974 }
4975
4976 /**
4977 * The state of an object representing a map.
4978 */
4979 class MapState extends InstanceState {
4980 /**
4981 * The entries in the map.
4982 */
4983 final HashMap<DartObjectImpl, DartObjectImpl> _entries;
4984
4985 /**
4986 * Initialize a newly created state to represent a map with the given
4987 * [entries].
4988 */
4989 MapState(this._entries);
4990
4991 @override
4992 bool get hasExactValue {
4993 for (DartObjectImpl key in _entries.keys) {
4994 if (!key.hasExactValue || !_entries[key].hasExactValue) {
4995 return false;
4996 }
4997 }
4998 return true;
4999 }
5000
5001 @override
5002 int get hashCode {
5003 int value = 0;
5004 for (DartObjectImpl key in _entries.keys.toSet()) {
5005 value = (value << 3) ^ key.hashCode;
5006 }
5007 return value;
5008 }
5009
5010 @override
5011 String get typeName => "Map";
5012
5013 @override
5014 Map<Object, Object> get value {
5015 HashMap<Object, Object> result = new HashMap<Object, Object>();
5016 for (DartObjectImpl key in _entries.keys) {
5017 DartObjectImpl value = _entries[key];
5018 if (!key.hasExactValue || !value.hasExactValue) {
5019 return null;
5020 }
5021 result[key.value] = value.value;
5022 }
5023 return result;
5024 }
5025
5026 @override
5027 bool operator ==(Object object) {
5028 if (object is! MapState) {
5029 return false;
5030 }
5031 HashMap<DartObjectImpl, DartObjectImpl> otherElements =
5032 (object as MapState)._entries;
5033 int count = _entries.length;
5034 if (otherElements.length != count) {
5035 return false;
5036 } else if (count == 0) {
5037 return true;
5038 }
5039 for (DartObjectImpl key in _entries.keys) {
5040 DartObjectImpl value = _entries[key];
5041 DartObjectImpl otherValue = otherElements[key];
5042 if (value != otherValue) {
5043 return false;
5044 }
5045 }
5046 return true;
5047 }
5048
5049 @override
5050 StringState convertToString() => StringState.UNKNOWN_VALUE;
5051
5052 @override
5053 BoolState equalEqual(InstanceState rightOperand) {
5054 assertBoolNumStringOrNull(rightOperand);
5055 return isIdentical(rightOperand);
5056 }
5057
5058 @override
5059 BoolState isIdentical(InstanceState rightOperand) {
5060 if (rightOperand is DynamicState) {
5061 return BoolState.UNKNOWN_VALUE;
5062 }
5063 return BoolState.from(this == rightOperand);
5064 }
5065
5066 @override
5067 String toString() {
5068 StringBuffer buffer = new StringBuffer();
5069 buffer.write('{');
5070 bool first = true;
5071 _entries.forEach((DartObjectImpl key, DartObjectImpl value) {
5072 if (first) {
5073 first = false;
5074 } else {
5075 buffer.write(', ');
5076 }
5077 buffer.write(key);
5078 buffer.write(' = ');
5079 buffer.write(value);
5080 });
5081 buffer.write('}');
5082 return buffer.toString();
5083 }
5084 }
5085
5086 /**
5087 * The state of an object representing the value 'null'.
5088 */
5089 class NullState extends InstanceState {
5090 /**
5091 * An instance representing the boolean value 'null'.
5092 */
5093 static NullState NULL_STATE = new NullState();
5094
5095 @override
5096 bool get hasExactValue => true;
5097
5098 @override
5099 int get hashCode => 0;
5100
5101 @override
5102 bool get isBoolNumStringOrNull => true;
5103
5104 @override
5105 String get typeName => "Null";
5106
5107 @override
5108 bool operator ==(Object object) => object is NullState;
5109
5110 @override
5111 BoolState convertToBool() {
5112 throw new EvaluationException(
5113 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
5114 }
5115
5116 @override
5117 StringState convertToString() => new StringState("null");
5118
5119 @override
5120 BoolState equalEqual(InstanceState rightOperand) {
5121 assertBoolNumStringOrNull(rightOperand);
5122 return isIdentical(rightOperand);
5123 }
5124
5125 @override
5126 BoolState isIdentical(InstanceState rightOperand) {
5127 if (rightOperand is DynamicState) {
5128 return BoolState.UNKNOWN_VALUE;
5129 }
5130 return BoolState.from(rightOperand is NullState);
5131 }
5132
5133 @override
5134 BoolState logicalNot() {
5135 throw new EvaluationException(
5136 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
5137 }
5138
5139 @override
5140 String toString() => "null";
5141 }
5142
5143 /**
5144 * The state of an object representing a number of an unknown type (a 'num').
5145 */
5146 class NumState extends InstanceState {
5147 /**
5148 * A state that can be used to represent a number whose value is not known.
5149 */
5150 static NumState UNKNOWN_VALUE = new NumState();
5151
5152 @override
5153 int get hashCode => 7;
5154
5155 @override
5156 bool get isBoolNumStringOrNull => true;
5157
5158 @override
5159 bool get isUnknown => identical(this, UNKNOWN_VALUE);
5160
5161 @override
5162 String get typeName => "num";
5163
5164 @override
5165 bool operator ==(Object object) => object is NumState;
5166
5167 @override
5168 NumState add(InstanceState rightOperand) {
5169 assertNumOrNull(rightOperand);
5170 return UNKNOWN_VALUE;
5171 }
5172
5173 @override
5174 StringState convertToString() => StringState.UNKNOWN_VALUE;
5175
5176 @override
5177 NumState divide(InstanceState rightOperand) {
5178 assertNumOrNull(rightOperand);
5179 return DoubleState.UNKNOWN_VALUE;
5180 }
5181
5182 @override
5183 BoolState equalEqual(InstanceState rightOperand) {
5184 assertBoolNumStringOrNull(rightOperand);
5185 return BoolState.UNKNOWN_VALUE;
5186 }
5187
5188 @override
5189 BoolState greaterThan(InstanceState rightOperand) {
5190 assertNumOrNull(rightOperand);
5191 return BoolState.UNKNOWN_VALUE;
5192 }
5193
5194 @override
5195 BoolState greaterThanOrEqual(InstanceState rightOperand) {
5196 assertNumOrNull(rightOperand);
5197 return BoolState.UNKNOWN_VALUE;
5198 }
5199
5200 @override
5201 IntState integerDivide(InstanceState rightOperand) {
5202 assertNumOrNull(rightOperand);
5203 if (rightOperand is IntState) {
5204 int rightValue = rightOperand.value;
5205 if (rightValue == null) {
5206 return IntState.UNKNOWN_VALUE;
5207 } else if (rightValue == 0) {
5208 throw new EvaluationException(
5209 CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
5210 }
5211 } else if (rightOperand is DynamicState) {
5212 return IntState.UNKNOWN_VALUE;
5213 }
5214 return IntState.UNKNOWN_VALUE;
5215 }
5216
5217 @override
5218 BoolState isIdentical(InstanceState rightOperand) {
5219 return BoolState.UNKNOWN_VALUE;
5220 }
5221
5222 @override
5223 BoolState lessThan(InstanceState rightOperand) {
5224 assertNumOrNull(rightOperand);
5225 return BoolState.UNKNOWN_VALUE;
5226 }
5227
5228 @override
5229 BoolState lessThanOrEqual(InstanceState rightOperand) {
5230 assertNumOrNull(rightOperand);
5231 return BoolState.UNKNOWN_VALUE;
5232 }
5233
5234 @override
5235 NumState minus(InstanceState rightOperand) {
5236 assertNumOrNull(rightOperand);
5237 return UNKNOWN_VALUE;
5238 }
5239
5240 @override
5241 NumState negated() => UNKNOWN_VALUE;
5242
5243 @override
5244 NumState remainder(InstanceState rightOperand) {
5245 assertNumOrNull(rightOperand);
5246 return UNKNOWN_VALUE;
5247 }
5248
5249 @override
5250 NumState times(InstanceState rightOperand) {
5251 assertNumOrNull(rightOperand);
5252 return UNKNOWN_VALUE;
5253 }
5254
5255 @override
5256 String toString() => "-unknown-";
5257 }
5258
5259 /**
5260 * An object used to add reference information for a given variable to the
5261 * bi-directional mapping used to order the evaluation of constants.
5262 */
5263 class ReferenceFinder extends RecursiveAstVisitor<Object> {
5264 /**
5265 * The callback which should be used to report any dependencies that were
5266 * found.
5267 */
5268 final ReferenceFinderCallback _callback;
5269
5270 /**
5271 * Initialize a newly created reference finder to find references from a given
5272 * variable to other variables and to add those references to the given graph.
5273 * The [_callback] will be invoked for every dependency found.
5274 */
5275 ReferenceFinder(this._callback);
5276
5277 @override
5278 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
5279 if (node.isConst) {
5280 ConstructorElement constructor =
5281 ConstantEvaluationEngine._getConstructorBase(node.staticElement);
5282 if (constructor != null) {
5283 _callback(constructor);
5284 }
5285 }
5286 return super.visitInstanceCreationExpression(node);
5287 }
5288
5289 @override
5290 Object visitLabel(Label node) {
5291 // We are visiting the "label" part of a named expression in a function
5292 // call (presumably a constructor call), e.g. "const C(label: ...)". We
5293 // don't want to visit the SimpleIdentifier for the label because that's a
5294 // reference to a function parameter that needs to be filled in; it's not a
5295 // constant whose value we depend on.
5296 return null;
5297 }
5298
5299 @override
5300 Object visitRedirectingConstructorInvocation(
5301 RedirectingConstructorInvocation node) {
5302 super.visitRedirectingConstructorInvocation(node);
5303 ConstructorElement target =
5304 ConstantEvaluationEngine._getConstructorBase(node.staticElement);
5305 if (target != null) {
5306 _callback(target);
5307 }
5308 return null;
5309 }
5310
5311 @override
5312 Object visitSimpleIdentifier(SimpleIdentifier node) {
5313 Element element = node.staticElement;
5314 if (element is PropertyAccessorElement) {
5315 element = (element as PropertyAccessorElement).variable;
5316 }
5317 if (element is VariableElement) {
5318 _callback(element);
5319 }
5320 return null;
5321 }
5322
5323 @override
5324 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
5325 super.visitSuperConstructorInvocation(node);
5326 ConstructorElement constructor =
5327 ConstantEvaluationEngine._getConstructorBase(node.staticElement);
5328 if (constructor != null) {
5329 _callback(constructor);
5330 }
5331 return null;
5332 }
5333 }
5334
5335 /**
5336 * The state of an object representing a string.
5337 */
5338 class StringState extends InstanceState {
5339 /**
5340 * A state that can be used to represent a double whose value is not known.
5341 */
5342 static StringState UNKNOWN_VALUE = new StringState(null);
5343
5344 /**
5345 * The value of this instance.
5346 */
5347 final String value;
5348
5349 /**
5350 * Initialize a newly created state to represent the given [value].
5351 */
5352 StringState(this.value);
5353
5354 @override
5355 bool get hasExactValue => true;
5356
5357 @override
5358 int get hashCode => value == null ? 0 : value.hashCode;
5359
5360 @override
5361 bool get isBoolNumStringOrNull => true;
5362
5363 @override
5364 bool get isUnknown => value == null;
5365
5366 @override
5367 String get typeName => "String";
5368
5369 @override
5370 bool operator ==(Object object) =>
5371 object is StringState && (value == object.value);
5372
5373 @override
5374 StringState concatenate(InstanceState rightOperand) {
5375 if (value == null) {
5376 return UNKNOWN_VALUE;
5377 }
5378 if (rightOperand is StringState) {
5379 String rightValue = rightOperand.value;
5380 if (rightValue == null) {
5381 return UNKNOWN_VALUE;
5382 }
5383 return new StringState("$value$rightValue");
5384 } else if (rightOperand is DynamicState) {
5385 return UNKNOWN_VALUE;
5386 }
5387 return super.concatenate(rightOperand);
5388 }
5389
5390 @override
5391 StringState convertToString() => this;
5392
5393 @override
5394 BoolState equalEqual(InstanceState rightOperand) {
5395 assertBoolNumStringOrNull(rightOperand);
5396 return isIdentical(rightOperand);
5397 }
5398
5399 @override
5400 BoolState isIdentical(InstanceState rightOperand) {
5401 if (value == null) {
5402 return BoolState.UNKNOWN_VALUE;
5403 }
5404 if (rightOperand is StringState) {
5405 String rightValue = rightOperand.value;
5406 if (rightValue == null) {
5407 return BoolState.UNKNOWN_VALUE;
5408 }
5409 return BoolState.from(value == rightValue);
5410 } else if (rightOperand is DynamicState) {
5411 return BoolState.UNKNOWN_VALUE;
5412 }
5413 return BoolState.FALSE_STATE;
5414 }
5415
5416 @override
5417 IntState stringLength() {
5418 if (value == null) {
5419 return IntState.UNKNOWN_VALUE;
5420 }
5421 return new IntState(value.length);
5422 }
5423
5424 @override
5425 String toString() => value == null ? "-unknown-" : "'$value'";
5426 }
5427
5428 /**
5429 * The state of an object representing a symbol.
5430 */
5431 class SymbolState extends InstanceState {
5432 /**
5433 * The value of this instance.
5434 */
5435 final String value;
5436
5437 /**
5438 * Initialize a newly created state to represent the given [value].
5439 */
5440 SymbolState(this.value);
5441
5442 @override
5443 bool get hasExactValue => true;
5444
5445 @override
5446 int get hashCode => value == null ? 0 : value.hashCode;
5447
5448 @override
5449 String get typeName => "Symbol";
5450
5451 @override
5452 bool operator ==(Object object) =>
5453 object is SymbolState && (value == object.value);
5454
5455 @override
5456 StringState convertToString() {
5457 if (value == null) {
5458 return StringState.UNKNOWN_VALUE;
5459 }
5460 return new StringState(value);
5461 }
5462
5463 @override
5464 BoolState equalEqual(InstanceState rightOperand) {
5465 assertBoolNumStringOrNull(rightOperand);
5466 return isIdentical(rightOperand);
5467 }
5468
5469 @override
5470 BoolState isIdentical(InstanceState rightOperand) {
5471 if (value == null) {
5472 return BoolState.UNKNOWN_VALUE;
5473 }
5474 if (rightOperand is SymbolState) {
5475 String rightValue = rightOperand.value;
5476 if (rightValue == null) {
5477 return BoolState.UNKNOWN_VALUE;
5478 }
5479 return BoolState.from(value == rightValue);
5480 } else if (rightOperand is DynamicState) {
5481 return BoolState.UNKNOWN_VALUE;
5482 }
5483 return BoolState.FALSE_STATE;
5484 }
5485
5486 @override
5487 String toString() => value == null ? "-unknown-" : "#$value";
5488 }
5489
5490 /**
5491 * The state of an object representing a type.
5492 */
5493 class TypeState extends InstanceState {
5494 /**
5495 * The element representing the type being modeled.
5496 */
5497 final Element _element;
5498
5499 /**
5500 * Initialize a newly created state to represent the given [value].
5501 */
5502 TypeState(this._element);
5503
5504 @override
5505 int get hashCode => _element == null ? 0 : _element.hashCode;
5506
5507 @override
5508 String get typeName => "Type";
5509
5510 @override
5511 Element get value => _element;
5512
5513 @override
5514 bool operator ==(Object object) =>
5515 object is TypeState && (_element == object._element);
5516
5517 @override
5518 StringState convertToString() {
5519 if (_element == null) {
5520 return StringState.UNKNOWN_VALUE;
5521 }
5522 return new StringState(_element.name);
5523 }
5524
5525 @override
5526 BoolState equalEqual(InstanceState rightOperand) {
5527 assertBoolNumStringOrNull(rightOperand);
5528 return isIdentical(rightOperand);
5529 }
5530
5531 @override
5532 BoolState isIdentical(InstanceState rightOperand) {
5533 if (_element == null) {
5534 return BoolState.UNKNOWN_VALUE;
5535 }
5536 if (rightOperand is TypeState) {
5537 Element rightElement = rightOperand._element;
5538 if (rightElement == null) {
5539 return BoolState.UNKNOWN_VALUE;
5540 }
5541 return BoolState.from(_element == rightElement);
5542 } else if (rightOperand is DynamicState) {
5543 return BoolState.UNKNOWN_VALUE;
5544 }
5545 return BoolState.FALSE_STATE;
5546 }
5547
5548 @override
5549 String toString() => _element == null ? "-unknown-" : _element.name;
5550 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/generated/bazel.dart ('k') | packages/analyzer/lib/src/generated/element.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698