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

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

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

Powered by Google App Engine
This is Rietveld 408576698