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

Side by Side Diff: mojo/public/dart/third_party/analyzer/lib/src/generated/constant.dart

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

Powered by Google App Engine
This is Rietveld 408576698