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

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

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

Powered by Google App Engine
This is Rietveld 408576698