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

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

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.dart.constant.evaluation;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/context/declared_variables.dart';
10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/ast/token.dart';
12 import 'package:analyzer/dart/ast/visitor.dart';
13 import 'package:analyzer/dart/constant/value.dart';
14 import 'package:analyzer/dart/element/element.dart';
15 import 'package:analyzer/dart/element/type.dart';
16 import 'package:analyzer/error/error.dart';
17 import 'package:analyzer/error/listener.dart';
18 import 'package:analyzer/src/dart/constant/utilities.dart';
19 import 'package:analyzer/src/dart/constant/value.dart';
20 import 'package:analyzer/src/dart/element/element.dart';
21 import 'package:analyzer/src/dart/element/member.dart';
22 import 'package:analyzer/src/error/codes.dart';
23 import 'package:analyzer/src/generated/engine.dart';
24 import 'package:analyzer/src/generated/engine.dart'
25 show AnalysisEngine, RecordingErrorListener;
26 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
27 import 'package:analyzer/src/generated/type_system.dart'
28 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/task/dart.dart';
32
33 /**
34 * Helper class encapsulating the methods for evaluating constants and
35 * constant instance creation expressions.
36 */
37 class ConstantEvaluationEngine {
38 /**
39 * Parameter to "fromEnvironment" methods that denotes the default value.
40 */
41 static String _DEFAULT_VALUE_PARAM = "defaultValue";
42
43 /**
44 * Source of RegExp matching any public identifier.
45 * From sdk/lib/internal/symbol.dart.
46 */
47 static String _PUBLIC_IDENTIFIER_RE =
48 "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$ ]*";
49
50 /**
51 * RegExp that validates a non-empty non-private symbol.
52 * From sdk/lib/internal/symbol.dart.
53 */
54 static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp(
55 "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$ |[.](?!\$)))+?\$");
56
57 /**
58 * The type provider used to access the known types.
59 */
60 final TypeProvider typeProvider;
61
62 /**
63 * The type system. This is used to guess the types of constants when their
64 * exact value is unknown.
65 */
66 final TypeSystem typeSystem;
67
68 /**
69 * The set of variables declared on the command line using '-D'.
70 */
71 final DeclaredVariables _declaredVariables;
72
73 /**
74 * Validator used to verify correct dependency analysis when running unit
75 * tests.
76 */
77 final ConstantEvaluationValidator validator;
78
79 /** Whether we are running in strong mode. */
80 final bool strongMode;
81
82 /**
83 * Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider]
84 * is used to access known types. [_declaredVariables] is the set of
85 * variables declared on the command line using '-D'. The [validator], if
86 * given, is used to verify correct dependency analysis when running unit
87 * tests.
88 */
89 ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables,
90 {ConstantEvaluationValidator validator, TypeSystem typeSystem})
91 : typeProvider = typeProvider,
92 strongMode =
93 typeProvider.objectType.element.context.analysisOptions.strongMode,
94 validator =
95 validator ?? new ConstantEvaluationValidator_ForProduction(),
96 typeSystem = typeSystem ?? new TypeSystemImpl();
97
98 /**
99 * Check that the arguments to a call to fromEnvironment() are correct. The
100 * [arguments] are the AST nodes of the arguments. The [argumentValues] are
101 * the values of the unnamed arguments. The [namedArgumentValues] are the
102 * values of the named arguments. The [expectedDefaultValueType] is the
103 * allowed type of the "defaultValue" parameter (if present). Note:
104 * "defaultValue" is always allowed to be null. Return `true` if the arguments
105 * are correct, `false` if there is an error.
106 */
107 bool checkFromEnvironmentArguments(
108 NodeList<Expression> arguments,
109 List<DartObjectImpl> argumentValues,
110 HashMap<String, DartObjectImpl> namedArgumentValues,
111 InterfaceType expectedDefaultValueType) {
112 int argumentCount = arguments.length;
113 if (argumentCount < 1 || argumentCount > 2) {
114 return false;
115 }
116 if (arguments[0] is NamedExpression) {
117 return false;
118 }
119 if (!identical(argumentValues[0].type, typeProvider.stringType)) {
120 return false;
121 }
122 if (argumentCount == 2) {
123 Expression secondArgument = arguments[1];
124 if (secondArgument is NamedExpression) {
125 if (!(secondArgument.name.label.name == _DEFAULT_VALUE_PARAM)) {
126 return false;
127 }
128 ParameterizedType defaultValueType =
129 namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
130 if (!(identical(defaultValueType, expectedDefaultValueType) ||
131 identical(defaultValueType, typeProvider.nullType))) {
132 return false;
133 }
134 } else {
135 return false;
136 }
137 }
138 return true;
139 }
140
141 /**
142 * Check that the arguments to a call to Symbol() are correct. The [arguments]
143 * are the AST nodes of the arguments. The [argumentValues] are the values of
144 * the unnamed arguments. The [namedArgumentValues] are the values of the
145 * named arguments. Return `true` if the arguments are correct, `false` if
146 * there is an error.
147 */
148 bool checkSymbolArguments(
149 NodeList<Expression> arguments,
150 List<DartObjectImpl> argumentValues,
151 HashMap<String, DartObjectImpl> namedArgumentValues) {
152 if (arguments.length != 1) {
153 return false;
154 }
155 if (arguments[0] is NamedExpression) {
156 return false;
157 }
158 if (!identical(argumentValues[0].type, typeProvider.stringType)) {
159 return false;
160 }
161 String name = argumentValues[0].toStringValue();
162 return isValidPublicSymbol(name);
163 }
164
165 /**
166 * Compute the constant value associated with the given [constant].
167 */
168 void computeConstantValue(ConstantEvaluationTarget constant) {
169 validator.beforeComputeValue(constant);
170 if (constant is ParameterElementImpl) {
171 Expression defaultValue = constant.constantInitializer;
172 if (defaultValue != null) {
173 RecordingErrorListener errorListener = new RecordingErrorListener();
174 ErrorReporter errorReporter =
175 new ErrorReporter(errorListener, constant.source);
176 DartObjectImpl dartObject =
177 defaultValue.accept(new ConstantVisitor(this, errorReporter));
178 constant.evaluationResult =
179 new EvaluationResultImpl(dartObject, errorListener.errors);
180 }
181 } else if (constant is VariableElementImpl) {
182 Expression constantInitializer = constant.constantInitializer;
183 if (constantInitializer != null) {
184 RecordingErrorListener errorListener = new RecordingErrorListener();
185 ErrorReporter errorReporter =
186 new ErrorReporter(errorListener, constant.source);
187 DartObjectImpl dartObject = constantInitializer
188 .accept(new ConstantVisitor(this, errorReporter));
189 // Only check the type for truly const declarations (don't check final
190 // fields with initializers, since their types may be generic. The type
191 // of the final field will be checked later, when the constructor is
192 // invoked).
193 if (dartObject != null && constant.isConst) {
194 if (!runtimeTypeMatch(dartObject, constant.type)) {
195 errorReporter.reportErrorForElement(
196 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
197 constant,
198 [dartObject.type, constant.type]);
199 }
200 }
201 constant.evaluationResult =
202 new EvaluationResultImpl(dartObject, errorListener.errors);
203 }
204 } else if (constant is ConstructorElement) {
205 if (constant.isConst) {
206 // No evaluation needs to be done; constructor declarations are only in
207 // the dependency graph to ensure that any constants referred to in
208 // initializer lists and parameter defaults are evaluated before
209 // invocations of the constructor. However we do need to annotate the
210 // element as being free of constant evaluation cycles so that later
211 // code will know that it is safe to evaluate.
212 (constant as ConstructorElementImpl).isCycleFree = true;
213 }
214 } else if (constant is ElementAnnotationImpl) {
215 Annotation constNode = constant.annotationAst;
216 Element element = constant.element;
217 if (element is PropertyAccessorElement &&
218 element.variable is VariableElementImpl) {
219 // The annotation is a reference to a compile-time constant variable.
220 // Just copy the evaluation result.
221 VariableElementImpl variableElement =
222 element.variable as VariableElementImpl;
223 if (variableElement.evaluationResult != null) {
224 constant.evaluationResult = variableElement.evaluationResult;
225 } else {
226 // This could happen in the event that the annotation refers to a
227 // non-constant. The error is detected elsewhere, so just silently
228 // ignore it here.
229 constant.evaluationResult = new EvaluationResultImpl(null);
230 }
231 } else if (element is ConstructorElementImpl &&
232 element.isConst &&
233 constNode.arguments != null) {
234 RecordingErrorListener errorListener = new RecordingErrorListener();
235 ErrorReporter errorReporter =
236 new ErrorReporter(errorListener, constant.source);
237 ConstantVisitor constantVisitor =
238 new ConstantVisitor(this, errorReporter);
239 DartObjectImpl result = evaluateConstructorCall(
240 constNode,
241 constNode.arguments.arguments,
242 element,
243 constantVisitor,
244 errorReporter);
245 constant.evaluationResult =
246 new EvaluationResultImpl(result, errorListener.errors);
247 } else {
248 // This may happen for invalid code (e.g. failing to pass arguments
249 // to an annotation which references a const constructor). The error
250 // is detected elsewhere, so just silently ignore it here.
251 constant.evaluationResult = new EvaluationResultImpl(null);
252 }
253 } else if (constant is VariableElement) {
254 // constant is a VariableElement but not a VariableElementImpl. This can
255 // happen sometimes in the case of invalid user code (for example, a
256 // constant expression that refers to a non-static field inside a generic
257 // class will wind up referring to a FieldMember). The error is detected
258 // elsewhere, so just silently ignore it here.
259 } else {
260 // Should not happen.
261 assert(false);
262 AnalysisEngine.instance.logger.logError(
263 "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}");
264 return;
265 }
266 }
267
268 /**
269 * Determine which constant elements need to have their values computed
270 * prior to computing the value of [constant], and report them using
271 * [callback].
272 */
273 void computeDependencies(
274 ConstantEvaluationTarget constant, ReferenceFinderCallback callback) {
275 ReferenceFinder referenceFinder = new ReferenceFinder(callback);
276 if (constant is ConstructorElement) {
277 constant = getConstructorImpl(constant);
278 }
279 if (constant is VariableElementImpl) {
280 Expression initializer = constant.constantInitializer;
281 if (initializer != null) {
282 initializer.accept(referenceFinder);
283 }
284 } else if (constant is ConstructorElementImpl) {
285 if (constant.isConst) {
286 constant.isCycleFree = false;
287 ConstructorElement redirectedConstructor =
288 getConstRedirectedConstructor(constant);
289 if (redirectedConstructor != null) {
290 ConstructorElement redirectedConstructorBase =
291 getConstructorImpl(redirectedConstructor);
292 callback(redirectedConstructorBase);
293 return;
294 } else if (constant.isFactory) {
295 // Factory constructor, but getConstRedirectedConstructor returned
296 // null. This can happen if we're visiting one of the special externa l
297 // const factory constructors in the SDK, or if the code contains
298 // errors (such as delegating to a non-const constructor, or delegatin g
299 // to a constructor that can't be resolved). In any of these cases,
300 // we'll evaluate calls to this constructor without having to refer to
301 // any other constants. So we don't need to report any dependencies.
302 return;
303 }
304 bool defaultSuperInvocationNeeded = true;
305 List<ConstructorInitializer> initializers =
306 constant.constantInitializers;
307 for (ConstructorInitializer initializer in initializers) {
308 if (initializer is SuperConstructorInvocation ||
309 initializer is RedirectingConstructorInvocation) {
310 defaultSuperInvocationNeeded = false;
311 }
312 initializer.accept(referenceFinder);
313 }
314 if (defaultSuperInvocationNeeded) {
315 // No explicit superconstructor invocation found, so we need to
316 // manually insert a reference to the implicit superconstructor.
317 InterfaceType superclass =
318 (constant.returnType as InterfaceType).superclass;
319 if (superclass != null && !superclass.isObject) {
320 ConstructorElement unnamedConstructor =
321 getConstructorImpl(superclass.element.unnamedConstructor);
322 if (unnamedConstructor != null) {
323 callback(unnamedConstructor);
324 }
325 }
326 }
327 for (FieldElement field in constant.enclosingElement.fields) {
328 // Note: non-static const isn't allowed but we handle it anyway so
329 // that we won't be confused by incorrect code.
330 if ((field.isFinal || field.isConst) &&
331 !field.isStatic &&
332 field.initializer != null) {
333 callback(field);
334 }
335 }
336 for (ParameterElement parameterElement in constant.parameters) {
337 callback(parameterElement);
338 }
339 }
340 } else if (constant is ElementAnnotationImpl) {
341 Annotation constNode = constant.annotationAst;
342 Element element = constant.element;
343 if (element is PropertyAccessorElement &&
344 element.variable is VariableElementImpl) {
345 // The annotation is a reference to a compile-time constant variable,
346 // so it depends on the variable.
347 callback(element.variable);
348 } else if (element is ConstructorElementImpl) {
349 // The annotation is a constructor invocation, so it depends on the
350 // constructor.
351 callback(element);
352 } else {
353 // This could happen in the event of invalid code. The error will be
354 // reported at constant evaluation time.
355 }
356 if (constNode == null) {
357 // We cannot determine what element the annotation is on, nor the offset
358 // of the annotation, so there's not a lot of information in this
359 // message, but it's better than getting an exception.
360 // https://github.com/dart-lang/sdk/issues/26811
361 AnalysisEngine.instance.logger.logInformation(
362 'No annotationAst for $constant in ${constant.compilationUnit}');
363 } else if (constNode.arguments != null) {
364 constNode.arguments.accept(referenceFinder);
365 }
366 } else if (constant is VariableElement) {
367 // constant is a VariableElement but not a VariableElementImpl. This can
368 // happen sometimes in the case of invalid user code (for example, a
369 // constant expression that refers to a non-static field inside a generic
370 // class will wind up referring to a FieldMember). So just don't bother
371 // computing any dependencies.
372 } else {
373 // Should not happen.
374 assert(false);
375 AnalysisEngine.instance.logger.logError(
376 "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}");
377 }
378 }
379
380 /**
381 * Evaluate a call to fromEnvironment() on the bool, int, or String class. The
382 * [environmentValue] is the value fetched from the environment. The
383 * [builtInDefaultValue] is the value that should be used as the default if no
384 * "defaultValue" argument appears in [namedArgumentValues]. The
385 * [namedArgumentValues] are the values of the named parameters passed to
386 * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the
387 * evaluated result.
388 */
389 DartObjectImpl computeValueFromEnvironment(
390 DartObject environmentValue,
391 DartObjectImpl builtInDefaultValue,
392 HashMap<String, DartObjectImpl> namedArgumentValues) {
393 DartObjectImpl value = environmentValue as DartObjectImpl;
394 if (value.isUnknown || value.isNull) {
395 // The name either doesn't exist in the environment or we couldn't parse
396 // the corresponding value.
397 // If the code supplied an explicit default, use it.
398 if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) {
399 value = namedArgumentValues[_DEFAULT_VALUE_PARAM];
400 } else if (value.isNull) {
401 // The code didn't supply an explicit default.
402 // The name exists in the environment but we couldn't parse the
403 // corresponding value.
404 // So use the built-in default value, because this is what the VM does.
405 value = builtInDefaultValue;
406 } else {
407 // The code didn't supply an explicit default.
408 // The name doesn't exist in the environment.
409 // The VM would use the built-in default value, but we don't want to do
410 // that for analysis because it's likely to lead to cascading errors.
411 // So just leave [value] in the unknown state.
412 }
413 }
414 return value;
415 }
416
417 DartObjectImpl evaluateConstructorCall(
418 AstNode node,
419 List<Expression> arguments,
420 ConstructorElement constructor,
421 ConstantVisitor constantVisitor,
422 ErrorReporter errorReporter) {
423 if (!getConstructorImpl(constructor).isCycleFree) {
424 // It's not safe to evaluate this constructor, so bail out.
425 // TODO(paulberry): ensure that a reasonable error message is produced
426 // in this case, as well as other cases involving constant expression
427 // circularities (e.g. "compile-time constant expression depends on
428 // itself")
429 return new DartObjectImpl.validWithUnknownValue(constructor.returnType);
430 }
431 int argumentCount = arguments.length;
432 List<DartObjectImpl> argumentValues =
433 new List<DartObjectImpl>(argumentCount);
434 List<Expression> argumentNodes = new List<Expression>(argumentCount);
435 HashMap<String, DartObjectImpl> namedArgumentValues =
436 new HashMap<String, DartObjectImpl>();
437 HashMap<String, NamedExpression> namedArgumentNodes =
438 new HashMap<String, NamedExpression>();
439 for (int i = 0; i < argumentCount; i++) {
440 Expression argument = arguments[i];
441 if (argument is NamedExpression) {
442 String name = argument.name.label.name;
443 namedArgumentValues[name] =
444 constantVisitor._valueOf(argument.expression);
445 namedArgumentNodes[name] = argument;
446 argumentValues[i] = typeProvider.nullObject;
447 } else {
448 argumentValues[i] = constantVisitor._valueOf(argument);
449 argumentNodes[i] = argument;
450 }
451 }
452 constructor = followConstantRedirectionChain(constructor);
453 InterfaceType definingClass = constructor.returnType as InterfaceType;
454 if (constructor.isFactory) {
455 // We couldn't find a non-factory constructor.
456 // See if it's because we reached an external const factory constructor
457 // that we can emulate.
458 if (constructor.name == "fromEnvironment") {
459 if (!checkFromEnvironmentArguments(
460 arguments, argumentValues, namedArgumentValues, definingClass)) {
461 errorReporter.reportErrorForNode(
462 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
463 return null;
464 }
465 String variableName =
466 argumentCount < 1 ? null : argumentValues[0].toStringValue();
467 if (identical(definingClass, typeProvider.boolType)) {
468 DartObject valueFromEnvironment;
469 valueFromEnvironment =
470 _declaredVariables.getBool(typeProvider, variableName);
471 return computeValueFromEnvironment(
472 valueFromEnvironment,
473 new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE),
474 namedArgumentValues);
475 } else if (identical(definingClass, typeProvider.intType)) {
476 DartObject valueFromEnvironment;
477 valueFromEnvironment =
478 _declaredVariables.getInt(typeProvider, variableName);
479 return computeValueFromEnvironment(
480 valueFromEnvironment,
481 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
482 namedArgumentValues);
483 } else if (identical(definingClass, typeProvider.stringType)) {
484 DartObject valueFromEnvironment;
485 valueFromEnvironment =
486 _declaredVariables.getString(typeProvider, variableName);
487 return computeValueFromEnvironment(
488 valueFromEnvironment,
489 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE),
490 namedArgumentValues);
491 }
492 } else if (constructor.name == "" &&
493 identical(definingClass, typeProvider.symbolType) &&
494 argumentCount == 1) {
495 if (!checkSymbolArguments(
496 arguments, argumentValues, namedArgumentValues)) {
497 errorReporter.reportErrorForNode(
498 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
499 return null;
500 }
501 String argumentValue = argumentValues[0].toStringValue();
502 return new DartObjectImpl(
503 definingClass, new SymbolState(argumentValue));
504 }
505 // Either it's an external const factory constructor that we can't
506 // emulate, or an error occurred (a cycle, or a const constructor trying
507 // to delegate to a non-const constructor).
508 // In the former case, the best we can do is consider it an unknown value.
509 // In the latter case, the error has already been reported, so considering
510 // it an unknown value will suppress further errors.
511 return new DartObjectImpl.validWithUnknownValue(definingClass);
512 }
513 ConstructorElementImpl constructorBase = getConstructorImpl(constructor);
514 validator.beforeGetConstantInitializers(constructorBase);
515 List<ConstructorInitializer> initializers =
516 constructorBase.constantInitializers;
517 if (initializers == null) {
518 // This can happen in some cases where there are compile errors in the
519 // code being analyzed (for example if the code is trying to create a
520 // const instance using a non-const constructor, or the node we're
521 // visiting is involved in a cycle). The error has already been reported,
522 // so consider it an unknown value to suppress further errors.
523 return new DartObjectImpl.validWithUnknownValue(definingClass);
524 }
525
526 // In strong mode, we allow constants to have type arguments.
527 //
528 // They will be added to the lexical environment when evaluating
529 // subexpressions.
530 HashMap<String, DartObjectImpl> typeArgumentMap;
531 if (strongMode) {
532 // Instantiate the constructor with the in-scope type arguments.
533 definingClass = constantVisitor.evaluateType(definingClass);
534 constructor = ConstructorMember.from(constructorBase, definingClass);
535
536 typeArgumentMap = new HashMap<String, DartObjectImpl>.fromIterables(
537 definingClass.typeParameters.map((t) => t.name),
538 definingClass.typeArguments.map(constantVisitor.typeConstant));
539 }
540
541 var fieldMap = new HashMap<String, DartObjectImpl>();
542 var fieldInitVisitor = new ConstantVisitor(this, errorReporter,
543 lexicalEnvironment: typeArgumentMap);
544 // Start with final fields that are initialized at their declaration site.
545 List<FieldElement> fields = constructor.enclosingElement.fields;
546 for (int i = 0; i < fields.length; i++) {
547 FieldElement field = fields[i];
548 if ((field.isFinal || field.isConst) &&
549 !field.isStatic &&
550 field is ConstFieldElementImpl) {
551 validator.beforeGetFieldEvaluationResult(field);
552
553 DartObjectImpl fieldValue;
554 if (strongMode) {
555 fieldValue = field.constantInitializer.accept(fieldInitVisitor);
556 } else {
557 fieldValue = field.evaluationResult?.value;
558 }
559 // It is possible that the evaluation result is null.
560 // This happens for example when we have duplicate fields.
561 // class Test {final x = 1; final x = 2; const Test();}
562 if (fieldValue == null) {
563 continue;
564 }
565 // Match the value and the type.
566 DartType fieldType =
567 FieldMember.from(field, constructor.returnType).type;
568 if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) {
569 errorReporter.reportErrorForNode(
570 CheckedModeCompileTimeErrorCode
571 .CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
572 node,
573 [fieldValue.type, field.name, fieldType]);
574 }
575 fieldMap[field.name] = fieldValue;
576 }
577 }
578 // Now evaluate the constructor declaration.
579 HashMap<String, DartObjectImpl> parameterMap =
580 new HashMap<String, DartObjectImpl>();
581 List<ParameterElement> parameters = constructor.parameters;
582 int parameterCount = parameters.length;
583
584 for (int i = 0; i < parameterCount; i++) {
585 ParameterElement parameter = parameters[i];
586 ParameterElement baseParameter = parameter;
587 while (baseParameter is ParameterMember) {
588 baseParameter = (baseParameter as ParameterMember).baseElement;
589 }
590 DartObjectImpl argumentValue = null;
591 AstNode errorTarget = null;
592 if (baseParameter.parameterKind == ParameterKind.NAMED) {
593 argumentValue = namedArgumentValues[baseParameter.name];
594 errorTarget = namedArgumentNodes[baseParameter.name];
595 } else if (i < argumentCount) {
596 argumentValue = argumentValues[i];
597 errorTarget = argumentNodes[i];
598 }
599 if (errorTarget == null) {
600 // No argument node that we can direct error messages to, because we
601 // are handling an optional parameter that wasn't specified. So just
602 // direct error messages to the constructor call.
603 errorTarget = node;
604 }
605 if (argumentValue == null && baseParameter is ParameterElementImpl) {
606 // The parameter is an optional positional parameter for which no value
607 // was provided, so use the default value.
608 validator.beforeGetParameterDefault(baseParameter);
609 if (strongMode && baseParameter is ConstVariableElement) {
610 var defaultValue =
611 (baseParameter as ConstVariableElement).constantInitializer;
612 if (defaultValue == null) {
613 argumentValue = typeProvider.nullObject;
614 } else {
615 argumentValue = defaultValue.accept(fieldInitVisitor);
616 }
617 } else {
618 EvaluationResultImpl evaluationResult =
619 baseParameter.evaluationResult;
620 if (evaluationResult == null) {
621 // No default was provided, so the default value is null.
622 argumentValue = typeProvider.nullObject;
623 } else if (evaluationResult.value != null) {
624 argumentValue = evaluationResult.value;
625 }
626 }
627 }
628 if (argumentValue != null) {
629 if (!runtimeTypeMatch(argumentValue, parameter.type)) {
630 errorReporter.reportErrorForNode(
631 CheckedModeCompileTimeErrorCode
632 .CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
633 errorTarget,
634 [argumentValue.type, parameter.type]);
635 }
636 if (baseParameter.isInitializingFormal) {
637 FieldElement field = (parameter as FieldFormalParameterElement).field;
638 if (field != null) {
639 DartType fieldType = field.type;
640 if (fieldType != parameter.type) {
641 // We've already checked that the argument can be assigned to the
642 // parameter; we also need to check that it can be assigned to
643 // the field.
644 if (!runtimeTypeMatch(argumentValue, fieldType)) {
645 errorReporter.reportErrorForNode(
646 CheckedModeCompileTimeErrorCode
647 .CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
648 errorTarget,
649 [argumentValue.type, fieldType]);
650 }
651 }
652 String fieldName = field.name;
653 if (fieldMap.containsKey(fieldName)) {
654 errorReporter.reportErrorForNode(
655 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
656 }
657 fieldMap[fieldName] = argumentValue;
658 }
659 }
660 String name = baseParameter.name;
661 parameterMap[name] = argumentValue;
662 }
663 }
664 ConstantVisitor initializerVisitor = new ConstantVisitor(
665 this, errorReporter,
666 lexicalEnvironment: parameterMap);
667 String superName = null;
668 NodeList<Expression> superArguments = null;
669 for (ConstructorInitializer initializer in initializers) {
670 if (initializer is ConstructorFieldInitializer) {
671 Expression initializerExpression = initializer.expression;
672 DartObjectImpl evaluationResult =
673 initializerExpression.accept(initializerVisitor);
674 if (evaluationResult != null) {
675 String fieldName = initializer.fieldName.name;
676 if (fieldMap.containsKey(fieldName)) {
677 errorReporter.reportErrorForNode(
678 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node);
679 }
680 fieldMap[fieldName] = evaluationResult;
681 PropertyAccessorElement getter = definingClass.getGetter(fieldName);
682 if (getter != null) {
683 PropertyInducingElement field = getter.variable;
684 if (!runtimeTypeMatch(evaluationResult, field.type)) {
685 errorReporter.reportErrorForNode(
686 CheckedModeCompileTimeErrorCode
687 .CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
688 node,
689 [evaluationResult.type, fieldName, field.type]);
690 }
691 }
692 }
693 } else if (initializer is SuperConstructorInvocation) {
694 SimpleIdentifier name = initializer.constructorName;
695 if (name != null) {
696 superName = name.name;
697 }
698 superArguments = initializer.argumentList.arguments;
699 } else if (initializer is RedirectingConstructorInvocation) {
700 // This is a redirecting constructor, so just evaluate the constructor
701 // it redirects to.
702 ConstructorElement constructor = initializer.staticElement;
703 if (constructor != null && constructor.isConst) {
704 return evaluateConstructorCall(
705 node,
706 initializer.argumentList.arguments,
707 constructor,
708 initializerVisitor,
709 errorReporter);
710 }
711 }
712 }
713 // Evaluate explicit or implicit call to super().
714 InterfaceType superclass = definingClass.superclass;
715 if (superclass != null && !superclass.isObject) {
716 ConstructorElement superConstructor =
717 superclass.lookUpConstructor(superName, constructor.library);
718 if (superConstructor != null) {
719 if (superArguments == null) {
720 superArguments = new NodeList<Expression>(null);
721 }
722
723 evaluateSuperConstructorCall(node, fieldMap, superConstructor,
724 superArguments, initializerVisitor, errorReporter);
725 }
726 }
727 return new DartObjectImpl(definingClass, new GenericState(fieldMap));
728 }
729
730 void evaluateSuperConstructorCall(
731 AstNode node,
732 HashMap<String, DartObjectImpl> fieldMap,
733 ConstructorElement superConstructor,
734 List<Expression> superArguments,
735 ConstantVisitor initializerVisitor,
736 ErrorReporter errorReporter) {
737 if (superConstructor != null && superConstructor.isConst) {
738 DartObjectImpl evaluationResult = evaluateConstructorCall(node,
739 superArguments, superConstructor, initializerVisitor, errorReporter);
740 if (evaluationResult != null) {
741 fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult;
742 }
743 }
744 }
745
746 /**
747 * Attempt to follow the chain of factory redirections until a constructor is
748 * reached which is not a const factory constructor. Return the constant
749 * constructor which terminates the chain of factory redirections, if the
750 * chain terminates. If there is a problem (e.g. a redirection can't be found,
751 * or a cycle is encountered), the chain will be followed as far as possible
752 * and then a const factory constructor will be returned.
753 */
754 ConstructorElement followConstantRedirectionChain(
755 ConstructorElement constructor) {
756 HashSet<ConstructorElement> constructorsVisited =
757 new HashSet<ConstructorElement>();
758 while (true) {
759 ConstructorElement redirectedConstructor =
760 getConstRedirectedConstructor(constructor);
761 if (redirectedConstructor == null) {
762 break;
763 } else {
764 ConstructorElement constructorBase = getConstructorImpl(constructor);
765 constructorsVisited.add(constructorBase);
766 ConstructorElement redirectedConstructorBase =
767 getConstructorImpl(redirectedConstructor);
768 if (constructorsVisited.contains(redirectedConstructorBase)) {
769 // Cycle in redirecting factory constructors--this is not allowed
770 // and is checked elsewhere--see
771 // [ErrorVerifier.checkForRecursiveFactoryRedirect()]).
772 break;
773 }
774 }
775 constructor = redirectedConstructor;
776 }
777 return constructor;
778 }
779
780 /**
781 * Generate an error indicating that the given [constant] is not a valid
782 * compile-time constant because it references at least one of the constants
783 * in the given [cycle], each of which directly or indirectly references the
784 * constant.
785 */
786 void generateCycleError(Iterable<ConstantEvaluationTarget> cycle,
787 ConstantEvaluationTarget constant) {
788 if (constant is VariableElement) {
789 RecordingErrorListener errorListener = new RecordingErrorListener();
790 ErrorReporter errorReporter =
791 new ErrorReporter(errorListener, constant.source);
792 // TODO(paulberry): It would be really nice if we could extract enough
793 // information from the 'cycle' argument to provide the user with a
794 // description of the cycle.
795 errorReporter.reportErrorForElement(
796 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, constant, []);
797 (constant as VariableElementImpl).evaluationResult =
798 new EvaluationResultImpl(null, errorListener.errors);
799 } else if (constant is ConstructorElement) {
800 // We don't report cycle errors on constructor declarations since there
801 // is nowhere to put the error information.
802 } else {
803 // Should not happen. Formal parameter defaults and annotations should
804 // never appear as part of a cycle because they can't be referred to.
805 assert(false);
806 AnalysisEngine.instance.logger.logError(
807 "Constant value computer trying to report a cycle error for a node of type ${constant.runtimeType}");
808 }
809 }
810
811 /**
812 * If [constructor] redirects to another const constructor, return the
813 * const constructor it redirects to. Otherwise return `null`.
814 */
815 ConstructorElement getConstRedirectedConstructor(
816 ConstructorElement constructor) {
817 if (!constructor.isFactory) {
818 return null;
819 }
820 if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
821 // The dart:core.Symbol has a const factory constructor that redirects
822 // to dart:_internal.Symbol. That in turn redirects to an external
823 // const constructor, which we won't be able to evaluate.
824 // So stop following the chain of redirections at dart:core.Symbol, and
825 // let [evaluateInstanceCreationExpression] handle it specially.
826 return null;
827 }
828 ConstructorElement redirectedConstructor =
829 constructor.redirectedConstructor;
830 if (redirectedConstructor == null) {
831 // This can happen if constructor is an external factory constructor.
832 return null;
833 }
834 if (!redirectedConstructor.isConst) {
835 // Delegating to a non-const constructor--this is not allowed (and
836 // is checked elsewhere--see
837 // [ErrorVerifier.checkForRedirectToNonConstConstructor()]).
838 return null;
839 }
840 return redirectedConstructor;
841 }
842
843 /**
844 * Check if the object [obj] matches the type [type] according to runtime type
845 * checking rules.
846 */
847 bool runtimeTypeMatch(DartObjectImpl obj, DartType type) {
848 if (obj.isNull) {
849 return true;
850 }
851 if (type.isUndefined) {
852 return false;
853 }
854 return obj.type.isSubtypeOf(type);
855 }
856
857 /**
858 * Determine whether the given string is a valid name for a public symbol
859 * (i.e. whether it is allowed for a call to the Symbol constructor).
860 */
861 static bool isValidPublicSymbol(String name) =>
862 name.isEmpty || name == "void" || _PUBLIC_SYMBOL_PATTERN.hasMatch(name);
863 }
864
865 /**
866 * Interface used by unit tests to verify correct dependency analysis during
867 * constant evaluation.
868 */
869 abstract class ConstantEvaluationValidator {
870 /**
871 * This method is called just before computing the constant value associated
872 * with [constant]. Unit tests will override this method to introduce
873 * additional error checking.
874 */
875 void beforeComputeValue(ConstantEvaluationTarget constant);
876
877 /**
878 * This method is called just before getting the constant initializers
879 * associated with the [constructor]. Unit tests will override this method to
880 * introduce additional error checking.
881 */
882 void beforeGetConstantInitializers(ConstructorElement constructor);
883
884 /**
885 * This method is called just before retrieving an evaluation result from an
886 * element. Unit tests will override it to introduce additional error
887 * checking.
888 */
889 void beforeGetEvaluationResult(ConstantEvaluationTarget constant);
890
891 /**
892 * This method is called just before getting the constant value of a field
893 * with an initializer. Unit tests will override this method to introduce
894 * additional error checking.
895 */
896 void beforeGetFieldEvaluationResult(FieldElementImpl field);
897
898 /**
899 * This method is called just before getting a parameter's default value. Unit
900 * tests will override this method to introduce additional error checking.
901 */
902 void beforeGetParameterDefault(ParameterElement parameter);
903 }
904
905 /**
906 * Implementation of [ConstantEvaluationValidator] used in production; does no
907 * validation.
908 */
909 class ConstantEvaluationValidator_ForProduction
910 implements ConstantEvaluationValidator {
911 @override
912 void beforeComputeValue(ConstantEvaluationTarget constant) {}
913
914 @override
915 void beforeGetConstantInitializers(ConstructorElement constructor) {}
916
917 @override
918 void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {}
919
920 @override
921 void beforeGetFieldEvaluationResult(FieldElementImpl field) {}
922
923 @override
924 void beforeGetParameterDefault(ParameterElement parameter) {}
925 }
926
927 /**
928 * An object used to compute the values of constant variables and constant
929 * constructor invocations in one or more compilation units. The expected usage
930 * pattern is for the compilation units to be added to this computer using the
931 * method [add] and then for the method [computeValues] to be invoked exactly
932 * once. Any use of an instance after invoking the method [computeValues] will
933 * result in unpredictable behavior.
934 */
935 class ConstantValueComputer {
936 /**
937 * Source of RegExp matching declarable operator names.
938 * From sdk/lib/internal/symbol.dart.
939 */
940 static String _OPERATOR_RE =
941 "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)";
942
943 /**
944 * Source of RegExp matching Dart reserved words.
945 * From sdk/lib/internal/symbol.dart.
946 */
947 static String _RESERVED_WORD_RE =
948 "(?: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))";
949
950 /**
951 * A graph in which the nodes are the constants, and the edges are from each
952 * constant to the other constants that are referenced by it.
953 */
954 DirectedGraph<ConstantEvaluationTarget> referenceGraph =
955 new DirectedGraph<ConstantEvaluationTarget>();
956
957 /**
958 * The elements whose constant values need to be computed. Any elements
959 * which appear in [referenceGraph] but not in this set either belong to a
960 * different library cycle (and hence don't need to be recomputed) or were
961 * computed during a previous stage of resolution stage (e.g. constants
962 * associated with enums).
963 */
964 HashSet<ConstantEvaluationTarget> _constantsToCompute =
965 new HashSet<ConstantEvaluationTarget>();
966
967 /**
968 * The evaluation engine that does the work of evaluating instance creation
969 * expressions.
970 */
971 final ConstantEvaluationEngine evaluationEngine;
972
973 /**
974 * Initialize a newly created constant value computer. The [typeProvider] is
975 * the type provider used to access known types. The [declaredVariables] is
976 * the set of variables declared on the command line using '-D'.
977 */
978 ConstantValueComputer(
979 TypeProvider typeProvider, DeclaredVariables declaredVariables,
980 [ConstantEvaluationValidator validator, TypeSystem typeSystem])
981 : evaluationEngine = new ConstantEvaluationEngine(
982 typeProvider, declaredVariables,
983 validator: validator, typeSystem: typeSystem);
984
985 /**
986 * Add the constants in the given compilation [unit] to the list of constants
987 * whose value needs to be computed.
988 */
989 void add(CompilationUnit unit) {
990 ConstantFinder constantFinder = new ConstantFinder();
991 unit.accept(constantFinder);
992 _constantsToCompute.addAll(constantFinder.constantsToCompute);
993 }
994
995 /**
996 * Compute values for all of the constants in the compilation units that were
997 * added.
998 */
999 void computeValues() {
1000 for (ConstantEvaluationTarget constant in _constantsToCompute) {
1001 referenceGraph.addNode(constant);
1002 evaluationEngine.computeDependencies(constant,
1003 (ConstantEvaluationTarget dependency) {
1004 referenceGraph.addEdge(constant, dependency);
1005 });
1006 }
1007 List<List<ConstantEvaluationTarget>> topologicalSort =
1008 referenceGraph.computeTopologicalSort();
1009 for (List<ConstantEvaluationTarget> constantsInCycle in topologicalSort) {
1010 if (constantsInCycle.length == 1) {
1011 ConstantEvaluationTarget constant = constantsInCycle[0];
1012 if (!referenceGraph.getTails(constant).contains(constant)) {
1013 _computeValueFor(constant);
1014 continue;
1015 }
1016 }
1017 for (ConstantEvaluationTarget constant in constantsInCycle) {
1018 evaluationEngine.generateCycleError(constantsInCycle, constant);
1019 }
1020 }
1021 }
1022
1023 /**
1024 * Compute a value for the given [constant].
1025 */
1026 void _computeValueFor(ConstantEvaluationTarget constant) {
1027 if (!_constantsToCompute.contains(constant)) {
1028 // Element is in the dependency graph but should have been computed by
1029 // a previous stage of analysis.
1030 // TODO(paulberry): once we have moved over to the new task model, this
1031 // should only occur for constants associated with enum members. Once
1032 // that happens we should add an assertion to verify that it doesn't
1033 // occur in any other cases.
1034 return;
1035 }
1036 evaluationEngine.computeConstantValue(constant);
1037 }
1038 }
1039
1040 /**
1041 * A visitor used to evaluate constant expressions to produce their compile-time
1042 * value. According to the Dart Language Specification: <blockquote> A constant
1043 * expression is one of the following:
1044 *
1045 * * A literal number.
1046 * * A literal boolean.
1047 * * A literal string where any interpolated expression is a compile-time
1048 * constant that evaluates to a numeric, string or boolean value or to
1049 * <b>null</b>.
1050 * * A literal symbol.
1051 * * <b>null</b>.
1052 * * A qualified reference to a static constant variable.
1053 * * An identifier expression that denotes a constant variable, class or type
1054 * alias.
1055 * * A constant constructor invocation.
1056 * * A constant list literal.
1057 * * A constant map literal.
1058 * * A simple or qualified identifier denoting a top-level function or a static
1059 * method.
1060 * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant
1061 * expression.
1062 * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i>
1063 * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
1064 * expressions and <i>identical()</i> is statically bound to the predefined
1065 * dart function <i>identical()</i> discussed above.
1066 * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or
1067 * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and
1068 * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric,
1069 * string or boolean value.
1070 * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> &amp;&amp;
1071 * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>,
1072 * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate
1073 * to a boolean value.
1074 * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^
1075 * e<sub>2</sub></i>, <i>e<sub>1</sub> &amp; e<sub>2</sub></i>,
1076 * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;&gt;
1077 * e<sub>2</sub></i> or <i>e<sub>1</sub> &lt;&lt; e<sub>2</sub></i>, where
1078 * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant
1079 * expressions that evaluate to an integer value or to <b>null</b>.
1080 * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> +
1081 * e<sub>2</sub></i>, <i>e<sub>1</sub> - e<sub>2</sub></i>, <i>e<sub>1</sub> *
1082 * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub>
1083 * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> &gt; e<sub>2</sub></i>,
1084 * <i>e<sub>1</sub> &lt; e<sub>2</sub></i>, <i>e<sub>1</sub> &gt;=
1085 * e<sub>2</sub></i>, <i>e<sub>1</sub> &lt;= e<sub>2</sub></i> or
1086 * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i>
1087 * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a
1088 * numeric value or to <b>null</b>.
1089 * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> :
1090 * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and
1091 * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i>
1092 * evaluates to a boolean value.
1093 * </blockquote>
1094 */
1095 class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
1096 /**
1097 * The type provider used to access the known types.
1098 */
1099 final ConstantEvaluationEngine evaluationEngine;
1100
1101 final HashMap<String, DartObjectImpl> _lexicalEnvironment;
1102
1103 /**
1104 * Error reporter that we use to report errors accumulated while computing the
1105 * constant.
1106 */
1107 final ErrorReporter _errorReporter;
1108
1109 /**
1110 * Helper class used to compute constant values.
1111 */
1112 DartObjectComputer _dartObjectComputer;
1113
1114 /**
1115 * Initialize a newly created constant visitor. The [evaluationEngine] is
1116 * used to evaluate instance creation expressions. The [lexicalEnvironment]
1117 * is a map containing values which should override identifiers, or `null` if
1118 * no overriding is necessary. The [_errorReporter] is used to report errors
1119 * found during evaluation. The [validator] is used by unit tests to verify
1120 * correct dependency analysis.
1121 */
1122 ConstantVisitor(this.evaluationEngine, this._errorReporter,
1123 {HashMap<String, DartObjectImpl> lexicalEnvironment})
1124 : _lexicalEnvironment = lexicalEnvironment {
1125 this._dartObjectComputer =
1126 new DartObjectComputer(_errorReporter, evaluationEngine.typeProvider);
1127 }
1128
1129 /**
1130 * Convenience getter to gain access to the [evalationEngine]'s type
1131 * provider.
1132 */
1133 TypeProvider get _typeProvider => evaluationEngine.typeProvider;
1134
1135 /**
1136 * Convenience getter to gain access to the [evaluationEngine]'s type system.
1137 */
1138 TypeSystem get _typeSystem => evaluationEngine.typeSystem;
1139
1140 /**
1141 * Given a [type] that may contain free type variables, evaluate them against
1142 * the current lexical environment and return the substituted type.
1143 */
1144 DartType evaluateType(DartType type) {
1145 if (type is TypeParameterType) {
1146 // Constants may only refer to type parameters in strong mode.
1147 if (!evaluationEngine.strongMode) {
1148 return null;
1149 }
1150
1151 String name = type.name;
1152 if (_lexicalEnvironment != null) {
1153 return _lexicalEnvironment[name]?.toTypeValue() ?? type;
1154 }
1155 return type;
1156 }
1157 if (type is ParameterizedType) {
1158 List<DartType> typeArguments;
1159 for (int i = 0; i < type.typeArguments.length; i++) {
1160 DartType ta = type.typeArguments[i];
1161 DartType t = evaluateType(ta);
1162 if (!identical(t, ta)) {
1163 if (typeArguments == null) {
1164 typeArguments = type.typeArguments.toList(growable: false);
1165 }
1166 typeArguments[i] = t;
1167 }
1168 }
1169 if (typeArguments == null) return type;
1170 return type.substitute2(typeArguments, type.typeArguments);
1171 }
1172 return type;
1173 }
1174
1175 /**
1176 * Given a [type], returns the constant value that contains that type value.
1177 */
1178 DartObjectImpl typeConstant(DartType type) {
1179 return new DartObjectImpl(_typeProvider.typeType, new TypeState(type));
1180 }
1181
1182 @override
1183 DartObjectImpl visitAdjacentStrings(AdjacentStrings node) {
1184 DartObjectImpl result = null;
1185 for (StringLiteral string in node.strings) {
1186 if (result == null) {
1187 result = string.accept(this);
1188 } else {
1189 result =
1190 _dartObjectComputer.concatenate(node, result, string.accept(this));
1191 }
1192 }
1193 return result;
1194 }
1195
1196 @override
1197 DartObjectImpl visitBinaryExpression(BinaryExpression node) {
1198 DartObjectImpl leftResult = node.leftOperand.accept(this);
1199 DartObjectImpl rightResult = node.rightOperand.accept(this);
1200 TokenType operatorType = node.operator.type;
1201 // 'null' is almost never good operand
1202 if (operatorType != TokenType.BANG_EQ &&
1203 operatorType != TokenType.EQ_EQ &&
1204 operatorType != TokenType.QUESTION_QUESTION) {
1205 if (leftResult != null && leftResult.isNull ||
1206 rightResult != null && rightResult.isNull) {
1207 _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
1208 return null;
1209 }
1210 }
1211 // evaluate operator
1212 if (operatorType == TokenType.AMPERSAND) {
1213 return _dartObjectComputer.bitAnd(node, leftResult, rightResult);
1214 } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
1215 return _dartObjectComputer.logicalAnd(node, leftResult, rightResult);
1216 } else if (operatorType == TokenType.BANG_EQ) {
1217 return _dartObjectComputer.notEqual(node, leftResult, rightResult);
1218 } else if (operatorType == TokenType.BAR) {
1219 return _dartObjectComputer.bitOr(node, leftResult, rightResult);
1220 } else if (operatorType == TokenType.BAR_BAR) {
1221 return _dartObjectComputer.logicalOr(node, leftResult, rightResult);
1222 } else if (operatorType == TokenType.CARET) {
1223 return _dartObjectComputer.bitXor(node, leftResult, rightResult);
1224 } else if (operatorType == TokenType.EQ_EQ) {
1225 return _dartObjectComputer.equalEqual(node, leftResult, rightResult);
1226 } else if (operatorType == TokenType.GT) {
1227 return _dartObjectComputer.greaterThan(node, leftResult, rightResult);
1228 } else if (operatorType == TokenType.GT_EQ) {
1229 return _dartObjectComputer.greaterThanOrEqual(
1230 node, leftResult, rightResult);
1231 } else if (operatorType == TokenType.GT_GT) {
1232 return _dartObjectComputer.shiftRight(node, leftResult, rightResult);
1233 } else if (operatorType == TokenType.LT) {
1234 return _dartObjectComputer.lessThan(node, leftResult, rightResult);
1235 } else if (operatorType == TokenType.LT_EQ) {
1236 return _dartObjectComputer.lessThanOrEqual(node, leftResult, rightResult);
1237 } else if (operatorType == TokenType.LT_LT) {
1238 return _dartObjectComputer.shiftLeft(node, leftResult, rightResult);
1239 } else if (operatorType == TokenType.MINUS) {
1240 return _dartObjectComputer.minus(node, leftResult, rightResult);
1241 } else if (operatorType == TokenType.PERCENT) {
1242 return _dartObjectComputer.remainder(node, leftResult, rightResult);
1243 } else if (operatorType == TokenType.PLUS) {
1244 return _dartObjectComputer.add(node, leftResult, rightResult);
1245 } else if (operatorType == TokenType.STAR) {
1246 return _dartObjectComputer.times(node, leftResult, rightResult);
1247 } else if (operatorType == TokenType.SLASH) {
1248 return _dartObjectComputer.divide(node, leftResult, rightResult);
1249 } else if (operatorType == TokenType.TILDE_SLASH) {
1250 return _dartObjectComputer.integerDivide(node, leftResult, rightResult);
1251 } else if (operatorType == TokenType.QUESTION_QUESTION) {
1252 return _dartObjectComputer.questionQuestion(
1253 node, leftResult, rightResult);
1254 } else {
1255 // TODO(brianwilkerson) Figure out which error to report.
1256 _error(node, null);
1257 return null;
1258 }
1259 }
1260
1261 @override
1262 DartObjectImpl visitBooleanLiteral(BooleanLiteral node) =>
1263 new DartObjectImpl(_typeProvider.boolType, BoolState.from(node.value));
1264
1265 @override
1266 DartObjectImpl visitConditionalExpression(ConditionalExpression node) {
1267 Expression condition = node.condition;
1268 DartObjectImpl conditionResult = condition.accept(this);
1269 DartObjectImpl thenResult = node.thenExpression.accept(this);
1270 DartObjectImpl elseResult = node.elseExpression.accept(this);
1271 if (conditionResult == null) {
1272 return conditionResult;
1273 } else if (!conditionResult.isBool) {
1274 _errorReporter.reportErrorForNode(
1275 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition);
1276 return null;
1277 } else if (thenResult == null) {
1278 return thenResult;
1279 } else if (elseResult == null) {
1280 return elseResult;
1281 }
1282 conditionResult =
1283 _dartObjectComputer.applyBooleanConversion(condition, conditionResult);
1284 if (conditionResult == null) {
1285 return conditionResult;
1286 }
1287 if (conditionResult.toBoolValue() == true) {
1288 return thenResult;
1289 } else if (conditionResult.toBoolValue() == false) {
1290 return elseResult;
1291 }
1292 ParameterizedType thenType = thenResult.type;
1293 ParameterizedType elseType = elseResult.type;
1294 return new DartObjectImpl.validWithUnknownValue(
1295 _typeSystem.getLeastUpperBound(_typeProvider, thenType, elseType)
1296 as InterfaceType);
1297 }
1298
1299 @override
1300 DartObjectImpl visitDoubleLiteral(DoubleLiteral node) =>
1301 new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value));
1302
1303 @override
1304 DartObjectImpl visitInstanceCreationExpression(
1305 InstanceCreationExpression node) {
1306 if (!node.isConst) {
1307 // TODO(brianwilkerson) Figure out which error to report.
1308 _error(node, null);
1309 return null;
1310 }
1311 ConstructorElement constructor = node.staticElement;
1312 if (constructor == null) {
1313 // Couldn't resolve the constructor so we can't compute a value. No
1314 // problem - the error has already been reported.
1315 return null;
1316 }
1317
1318 return evaluationEngine.evaluateConstructorCall(
1319 node, node.argumentList.arguments, constructor, this, _errorReporter);
1320 }
1321
1322 @override
1323 DartObjectImpl visitIntegerLiteral(IntegerLiteral node) =>
1324 new DartObjectImpl(_typeProvider.intType, new IntState(node.value));
1325
1326 @override
1327 DartObjectImpl visitInterpolationExpression(InterpolationExpression node) {
1328 DartObjectImpl result = node.expression.accept(this);
1329 if (result != null && !result.isBoolNumStringOrNull) {
1330 _error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
1331 return null;
1332 }
1333 return _dartObjectComputer.performToString(node, result);
1334 }
1335
1336 @override
1337 DartObjectImpl visitInterpolationString(InterpolationString node) =>
1338 new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
1339
1340 @override
1341 DartObjectImpl visitListLiteral(ListLiteral node) {
1342 if (node.constKeyword == null) {
1343 _errorReporter.reportErrorForNode(
1344 CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL, node);
1345 return null;
1346 }
1347 bool errorOccurred = false;
1348 List<DartObjectImpl> elements = new List<DartObjectImpl>();
1349 for (Expression element in node.elements) {
1350 DartObjectImpl elementResult = element.accept(this);
1351 if (elementResult == null) {
1352 errorOccurred = true;
1353 } else {
1354 elements.add(elementResult);
1355 }
1356 }
1357 if (errorOccurred) {
1358 return null;
1359 }
1360 DartType elementType = _typeProvider.dynamicType;
1361 NodeList<TypeName> typeArgs = node.typeArguments?.arguments;
1362 if (typeArgs?.length == 1) {
1363 DartType type = visitTypeName(typeArgs[0])?.toTypeValue();
1364 if (type != null) {
1365 elementType = type;
1366 }
1367 }
1368 InterfaceType listType = _typeProvider.listType.instantiate([elementType]);
1369 return new DartObjectImpl(listType, new ListState(elements));
1370 }
1371
1372 @override
1373 DartObjectImpl visitMapLiteral(MapLiteral node) {
1374 if (node.constKeyword == null) {
1375 _errorReporter.reportErrorForNode(
1376 CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL, node);
1377 return null;
1378 }
1379 bool errorOccurred = false;
1380 LinkedHashMap<DartObjectImpl, DartObjectImpl> map =
1381 new LinkedHashMap<DartObjectImpl, DartObjectImpl>();
1382 for (MapLiteralEntry entry in node.entries) {
1383 DartObjectImpl keyResult = entry.key.accept(this);
1384 DartObjectImpl valueResult = entry.value.accept(this);
1385 if (keyResult == null || valueResult == null) {
1386 errorOccurred = true;
1387 } else {
1388 map[keyResult] = valueResult;
1389 }
1390 }
1391 if (errorOccurred) {
1392 return null;
1393 }
1394 DartType keyType = _typeProvider.dynamicType;
1395 DartType valueType = _typeProvider.dynamicType;
1396 NodeList<TypeName> typeArgs = node.typeArguments?.arguments;
1397 if (typeArgs?.length == 2) {
1398 DartType keyTypeCandidate = visitTypeName(typeArgs[0])?.toTypeValue();
1399 if (keyTypeCandidate != null) {
1400 keyType = keyTypeCandidate;
1401 }
1402 DartType valueTypeCandidate = visitTypeName(typeArgs[1])?.toTypeValue();
1403 if (valueTypeCandidate != null) {
1404 valueType = valueTypeCandidate;
1405 }
1406 }
1407 InterfaceType mapType =
1408 _typeProvider.mapType.instantiate([keyType, valueType]);
1409 return new DartObjectImpl(mapType, new MapState(map));
1410 }
1411
1412 @override
1413 DartObjectImpl visitMethodInvocation(MethodInvocation node) {
1414 Element element = node.methodName.staticElement;
1415 if (element is FunctionElement) {
1416 if (element.name == "identical") {
1417 NodeList<Expression> arguments = node.argumentList.arguments;
1418 if (arguments.length == 2) {
1419 Element enclosingElement = element.enclosingElement;
1420 if (enclosingElement is CompilationUnitElement) {
1421 LibraryElement library = enclosingElement.library;
1422 if (library.isDartCore) {
1423 DartObjectImpl leftArgument = arguments[0].accept(this);
1424 DartObjectImpl rightArgument = arguments[1].accept(this);
1425 return _dartObjectComputer.isIdentical(
1426 node, leftArgument, rightArgument);
1427 }
1428 }
1429 }
1430 }
1431 }
1432 // TODO(brianwilkerson) Figure out which error to report.
1433 _error(node, null);
1434 return null;
1435 }
1436
1437 @override
1438 DartObjectImpl visitNamedExpression(NamedExpression node) =>
1439 node.expression.accept(this);
1440
1441 @override
1442 DartObjectImpl visitNode(AstNode node) {
1443 // TODO(brianwilkerson) Figure out which error to report.
1444 _error(node, null);
1445 return null;
1446 }
1447
1448 @override
1449 DartObjectImpl visitNullLiteral(NullLiteral node) => _typeProvider.nullObject;
1450
1451 @override
1452 DartObjectImpl visitParenthesizedExpression(ParenthesizedExpression node) =>
1453 node.expression.accept(this);
1454
1455 @override
1456 DartObjectImpl visitPrefixedIdentifier(PrefixedIdentifier node) {
1457 SimpleIdentifier prefixNode = node.prefix;
1458 Element prefixElement = prefixNode.staticElement;
1459 // String.length
1460 if (prefixElement is! PrefixElement && prefixElement is! ClassElement) {
1461 DartObjectImpl prefixResult = node.prefix.accept(this);
1462 if (_isStringLength(prefixResult, node.identifier)) {
1463 return prefixResult.stringLength(_typeProvider);
1464 }
1465 }
1466 // importPrefix.CONST
1467 if (prefixElement is! PrefixElement) {
1468 DartObjectImpl prefixResult = prefixNode.accept(this);
1469 if (prefixResult == null) {
1470 // The error has already been reported.
1471 return null;
1472 }
1473 }
1474 // validate prefixed identifier
1475 return _getConstantValue(node, node.staticElement);
1476 }
1477
1478 @override
1479 DartObjectImpl visitPrefixExpression(PrefixExpression node) {
1480 DartObjectImpl operand = node.operand.accept(this);
1481 if (operand != null && operand.isNull) {
1482 _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
1483 return null;
1484 }
1485 if (node.operator.type == TokenType.BANG) {
1486 return _dartObjectComputer.logicalNot(node, operand);
1487 } else if (node.operator.type == TokenType.TILDE) {
1488 return _dartObjectComputer.bitNot(node, operand);
1489 } else if (node.operator.type == TokenType.MINUS) {
1490 return _dartObjectComputer.negated(node, operand);
1491 } else {
1492 // TODO(brianwilkerson) Figure out which error to report.
1493 _error(node, null);
1494 return null;
1495 }
1496 }
1497
1498 @override
1499 DartObjectImpl visitPropertyAccess(PropertyAccess node) {
1500 if (node.target != null) {
1501 DartObjectImpl prefixResult = node.target.accept(this);
1502 if (_isStringLength(prefixResult, node.propertyName)) {
1503 return prefixResult.stringLength(_typeProvider);
1504 }
1505 }
1506 return _getConstantValue(node, node.propertyName.staticElement);
1507 }
1508
1509 @override
1510 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
1511 if (_lexicalEnvironment != null &&
1512 _lexicalEnvironment.containsKey(node.name)) {
1513 return _lexicalEnvironment[node.name];
1514 }
1515 return _getConstantValue(node, node.staticElement);
1516 }
1517
1518 @override
1519 DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) =>
1520 new DartObjectImpl(_typeProvider.stringType, new StringState(node.value));
1521
1522 @override
1523 DartObjectImpl visitStringInterpolation(StringInterpolation node) {
1524 DartObjectImpl result = null;
1525 bool first = true;
1526 for (InterpolationElement element in node.elements) {
1527 if (first) {
1528 result = element.accept(this);
1529 first = false;
1530 } else {
1531 result =
1532 _dartObjectComputer.concatenate(node, result, element.accept(this));
1533 }
1534 }
1535 return result;
1536 }
1537
1538 @override
1539 DartObjectImpl visitSymbolLiteral(SymbolLiteral node) {
1540 StringBuffer buffer = new StringBuffer();
1541 List<Token> components = node.components;
1542 for (int i = 0; i < components.length; i++) {
1543 if (i > 0) {
1544 buffer.writeCharCode(0x2E);
1545 }
1546 buffer.write(components[i].lexeme);
1547 }
1548 return new DartObjectImpl(
1549 _typeProvider.symbolType, new SymbolState(buffer.toString()));
1550 }
1551
1552 @override
1553 DartObjectImpl visitTypeName(TypeName node) {
1554 DartType type = evaluateType(node.type);
1555 if (type == null) {
1556 return super.visitTypeName(node);
1557 }
1558 return typeConstant(type);
1559 }
1560
1561 /**
1562 * Create an error associated with the given [node]. The error will have the
1563 * given error [code].
1564 */
1565 void _error(AstNode node, ErrorCode code) {
1566 _errorReporter.reportErrorForNode(
1567 code ?? CompileTimeErrorCode.INVALID_CONSTANT, node);
1568 }
1569
1570 /**
1571 * Return the constant value of the static constant represented by the given
1572 * [element]. The [node] is the node to be used if an error needs to be
1573 * reported.
1574 */
1575 DartObjectImpl _getConstantValue(AstNode node, Element element) {
1576 Element variableElement =
1577 element is PropertyAccessorElement ? element.variable : element;
1578 if (variableElement is VariableElementImpl) {
1579 evaluationEngine.validator.beforeGetEvaluationResult(variableElement);
1580 EvaluationResultImpl value = variableElement.evaluationResult;
1581 if (variableElement.isConst && value != null) {
1582 return value.value;
1583 }
1584 } else if (variableElement is ExecutableElement) {
1585 ExecutableElement function = element;
1586 if (function.isStatic) {
1587 ParameterizedType functionType = function.type;
1588 if (functionType == null) {
1589 functionType = _typeProvider.functionType;
1590 }
1591 return new DartObjectImpl(functionType, new FunctionState(function));
1592 }
1593 } else if (variableElement is TypeDefiningElement) {
1594 // Constants may only refer to type parameters in strong mode.
1595 if (evaluationEngine.strongMode ||
1596 variableElement is! TypeParameterElement) {
1597 return new DartObjectImpl(
1598 _typeProvider.typeType, new TypeState(variableElement.type));
1599 }
1600 }
1601 // TODO(brianwilkerson) Figure out which error to report.
1602 _error(node, null);
1603 return null;
1604 }
1605
1606 /**
1607 * Return `true` if the given [targetResult] represents a string and the
1608 * [identifier] is "length".
1609 */
1610 bool _isStringLength(
1611 DartObjectImpl targetResult, SimpleIdentifier identifier) {
1612 if (targetResult == null || targetResult.type != _typeProvider.stringType) {
1613 return false;
1614 }
1615 return identifier.name == 'length';
1616 }
1617
1618 /**
1619 * Return the value of the given [expression], or a representation of 'null'
1620 * if the expression cannot be evaluated.
1621 */
1622 DartObjectImpl _valueOf(Expression expression) {
1623 DartObjectImpl expressionValue = expression.accept(this);
1624 if (expressionValue != null) {
1625 return expressionValue;
1626 }
1627 return _typeProvider.nullObject;
1628 }
1629 }
1630
1631 /**
1632 * A utility class that contains methods for manipulating instances of a Dart
1633 * class and for collecting errors during evaluation.
1634 */
1635 class DartObjectComputer {
1636 /**
1637 * The error reporter that we are using to collect errors.
1638 */
1639 final ErrorReporter _errorReporter;
1640
1641 /**
1642 * The type provider used to create objects of the appropriate types, and to
1643 * identify when an object is of a built-in type.
1644 */
1645 final TypeProvider _typeProvider;
1646
1647 DartObjectComputer(this._errorReporter, this._typeProvider);
1648
1649 DartObjectImpl add(BinaryExpression node, DartObjectImpl leftOperand,
1650 DartObjectImpl rightOperand) {
1651 if (leftOperand != null && rightOperand != null) {
1652 try {
1653 return leftOperand.add(_typeProvider, rightOperand);
1654 } on EvaluationException catch (exception) {
1655 _errorReporter.reportErrorForNode(exception.errorCode, node);
1656 return null;
1657 }
1658 }
1659 return null;
1660 }
1661
1662 /**
1663 * Return the result of applying boolean conversion to the [evaluationResult].
1664 * The [node] is the node against which errors should be reported.
1665 */
1666 DartObjectImpl applyBooleanConversion(
1667 AstNode node, DartObjectImpl evaluationResult) {
1668 if (evaluationResult != null) {
1669 try {
1670 return evaluationResult.convertToBool(_typeProvider);
1671 } on EvaluationException catch (exception) {
1672 _errorReporter.reportErrorForNode(exception.errorCode, node);
1673 }
1674 }
1675 return null;
1676 }
1677
1678 DartObjectImpl bitAnd(BinaryExpression node, DartObjectImpl leftOperand,
1679 DartObjectImpl rightOperand) {
1680 if (leftOperand != null && rightOperand != null) {
1681 try {
1682 return leftOperand.bitAnd(_typeProvider, rightOperand);
1683 } on EvaluationException catch (exception) {
1684 _errorReporter.reportErrorForNode(exception.errorCode, node);
1685 }
1686 }
1687 return null;
1688 }
1689
1690 DartObjectImpl bitNot(Expression node, DartObjectImpl evaluationResult) {
1691 if (evaluationResult != null) {
1692 try {
1693 return evaluationResult.bitNot(_typeProvider);
1694 } on EvaluationException catch (exception) {
1695 _errorReporter.reportErrorForNode(exception.errorCode, node);
1696 }
1697 }
1698 return null;
1699 }
1700
1701 DartObjectImpl bitOr(BinaryExpression node, DartObjectImpl leftOperand,
1702 DartObjectImpl rightOperand) {
1703 if (leftOperand != null && rightOperand != null) {
1704 try {
1705 return leftOperand.bitOr(_typeProvider, rightOperand);
1706 } on EvaluationException catch (exception) {
1707 _errorReporter.reportErrorForNode(exception.errorCode, node);
1708 }
1709 }
1710 return null;
1711 }
1712
1713 DartObjectImpl bitXor(BinaryExpression node, DartObjectImpl leftOperand,
1714 DartObjectImpl rightOperand) {
1715 if (leftOperand != null && rightOperand != null) {
1716 try {
1717 return leftOperand.bitXor(_typeProvider, rightOperand);
1718 } on EvaluationException catch (exception) {
1719 _errorReporter.reportErrorForNode(exception.errorCode, node);
1720 }
1721 }
1722 return null;
1723 }
1724
1725 DartObjectImpl concatenate(Expression node, DartObjectImpl leftOperand,
1726 DartObjectImpl rightOperand) {
1727 if (leftOperand != null && rightOperand != null) {
1728 try {
1729 return leftOperand.concatenate(_typeProvider, rightOperand);
1730 } on EvaluationException catch (exception) {
1731 _errorReporter.reportErrorForNode(exception.errorCode, node);
1732 }
1733 }
1734 return null;
1735 }
1736
1737 DartObjectImpl divide(BinaryExpression node, DartObjectImpl leftOperand,
1738 DartObjectImpl rightOperand) {
1739 if (leftOperand != null && rightOperand != null) {
1740 try {
1741 return leftOperand.divide(_typeProvider, rightOperand);
1742 } on EvaluationException catch (exception) {
1743 _errorReporter.reportErrorForNode(exception.errorCode, node);
1744 }
1745 }
1746 return null;
1747 }
1748
1749 DartObjectImpl equalEqual(Expression node, DartObjectImpl leftOperand,
1750 DartObjectImpl rightOperand) {
1751 if (leftOperand != null && rightOperand != null) {
1752 try {
1753 return leftOperand.equalEqual(_typeProvider, rightOperand);
1754 } on EvaluationException catch (exception) {
1755 _errorReporter.reportErrorForNode(exception.errorCode, node);
1756 }
1757 }
1758 return null;
1759 }
1760
1761 DartObjectImpl greaterThan(BinaryExpression node, DartObjectImpl leftOperand,
1762 DartObjectImpl rightOperand) {
1763 if (leftOperand != null && rightOperand != null) {
1764 try {
1765 return leftOperand.greaterThan(_typeProvider, rightOperand);
1766 } on EvaluationException catch (exception) {
1767 _errorReporter.reportErrorForNode(exception.errorCode, node);
1768 }
1769 }
1770 return null;
1771 }
1772
1773 DartObjectImpl greaterThanOrEqual(BinaryExpression node,
1774 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
1775 if (leftOperand != null && rightOperand != null) {
1776 try {
1777 return leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
1778 } on EvaluationException catch (exception) {
1779 _errorReporter.reportErrorForNode(exception.errorCode, node);
1780 }
1781 }
1782 return null;
1783 }
1784
1785 DartObjectImpl integerDivide(BinaryExpression node,
1786 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
1787 if (leftOperand != null && rightOperand != null) {
1788 try {
1789 return leftOperand.integerDivide(_typeProvider, rightOperand);
1790 } on EvaluationException catch (exception) {
1791 _errorReporter.reportErrorForNode(exception.errorCode, node);
1792 }
1793 }
1794 return null;
1795 }
1796
1797 DartObjectImpl isIdentical(Expression node, DartObjectImpl leftOperand,
1798 DartObjectImpl rightOperand) {
1799 if (leftOperand != null && rightOperand != null) {
1800 try {
1801 return leftOperand.isIdentical(_typeProvider, rightOperand);
1802 } on EvaluationException catch (exception) {
1803 _errorReporter.reportErrorForNode(exception.errorCode, node);
1804 }
1805 }
1806 return null;
1807 }
1808
1809 DartObjectImpl lessThan(BinaryExpression node, DartObjectImpl leftOperand,
1810 DartObjectImpl rightOperand) {
1811 if (leftOperand != null && rightOperand != null) {
1812 try {
1813 return leftOperand.lessThan(_typeProvider, rightOperand);
1814 } on EvaluationException catch (exception) {
1815 _errorReporter.reportErrorForNode(exception.errorCode, node);
1816 }
1817 }
1818 return null;
1819 }
1820
1821 DartObjectImpl lessThanOrEqual(BinaryExpression node,
1822 DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
1823 if (leftOperand != null && rightOperand != null) {
1824 try {
1825 return leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
1826 } on EvaluationException catch (exception) {
1827 _errorReporter.reportErrorForNode(exception.errorCode, node);
1828 }
1829 }
1830 return null;
1831 }
1832
1833 DartObjectImpl logicalAnd(BinaryExpression node, DartObjectImpl leftOperand,
1834 DartObjectImpl rightOperand) {
1835 if (leftOperand != null && rightOperand != null) {
1836 try {
1837 return leftOperand.logicalAnd(_typeProvider, rightOperand);
1838 } on EvaluationException catch (exception) {
1839 _errorReporter.reportErrorForNode(exception.errorCode, node);
1840 }
1841 }
1842 return null;
1843 }
1844
1845 DartObjectImpl logicalNot(Expression node, DartObjectImpl evaluationResult) {
1846 if (evaluationResult != null) {
1847 try {
1848 return evaluationResult.logicalNot(_typeProvider);
1849 } on EvaluationException catch (exception) {
1850 _errorReporter.reportErrorForNode(exception.errorCode, node);
1851 }
1852 }
1853 return null;
1854 }
1855
1856 DartObjectImpl logicalOr(BinaryExpression node, DartObjectImpl leftOperand,
1857 DartObjectImpl rightOperand) {
1858 if (leftOperand != null && rightOperand != null) {
1859 try {
1860 return leftOperand.logicalOr(_typeProvider, rightOperand);
1861 } on EvaluationException catch (exception) {
1862 _errorReporter.reportErrorForNode(exception.errorCode, node);
1863 }
1864 }
1865 return null;
1866 }
1867
1868 DartObjectImpl minus(BinaryExpression node, DartObjectImpl leftOperand,
1869 DartObjectImpl rightOperand) {
1870 if (leftOperand != null && rightOperand != null) {
1871 try {
1872 return leftOperand.minus(_typeProvider, rightOperand);
1873 } on EvaluationException catch (exception) {
1874 _errorReporter.reportErrorForNode(exception.errorCode, node);
1875 }
1876 }
1877 return null;
1878 }
1879
1880 DartObjectImpl negated(Expression node, DartObjectImpl evaluationResult) {
1881 if (evaluationResult != null) {
1882 try {
1883 return evaluationResult.negated(_typeProvider);
1884 } on EvaluationException catch (exception) {
1885 _errorReporter.reportErrorForNode(exception.errorCode, node);
1886 }
1887 }
1888 return null;
1889 }
1890
1891 DartObjectImpl notEqual(BinaryExpression node, DartObjectImpl leftOperand,
1892 DartObjectImpl rightOperand) {
1893 if (leftOperand != null && rightOperand != null) {
1894 try {
1895 return leftOperand.notEqual(_typeProvider, rightOperand);
1896 } on EvaluationException catch (exception) {
1897 _errorReporter.reportErrorForNode(exception.errorCode, node);
1898 }
1899 }
1900 return null;
1901 }
1902
1903 DartObjectImpl performToString(
1904 AstNode node, DartObjectImpl evaluationResult) {
1905 if (evaluationResult != null) {
1906 try {
1907 return evaluationResult.performToString(_typeProvider);
1908 } on EvaluationException catch (exception) {
1909 _errorReporter.reportErrorForNode(exception.errorCode, node);
1910 }
1911 }
1912 return null;
1913 }
1914
1915 DartObjectImpl questionQuestion(Expression node, DartObjectImpl leftOperand,
1916 DartObjectImpl rightOperand) {
1917 if (leftOperand != null && rightOperand != null) {
1918 if (leftOperand.isNull) {
1919 return rightOperand;
1920 }
1921 return leftOperand;
1922 }
1923 return null;
1924 }
1925
1926 DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand,
1927 DartObjectImpl rightOperand) {
1928 if (leftOperand != null && rightOperand != null) {
1929 try {
1930 return leftOperand.remainder(_typeProvider, rightOperand);
1931 } on EvaluationException catch (exception) {
1932 _errorReporter.reportErrorForNode(exception.errorCode, node);
1933 }
1934 }
1935 return null;
1936 }
1937
1938 DartObjectImpl shiftLeft(BinaryExpression node, DartObjectImpl leftOperand,
1939 DartObjectImpl rightOperand) {
1940 if (leftOperand != null && rightOperand != null) {
1941 try {
1942 return leftOperand.shiftLeft(_typeProvider, rightOperand);
1943 } on EvaluationException catch (exception) {
1944 _errorReporter.reportErrorForNode(exception.errorCode, node);
1945 }
1946 }
1947 return null;
1948 }
1949
1950 DartObjectImpl shiftRight(BinaryExpression node, DartObjectImpl leftOperand,
1951 DartObjectImpl rightOperand) {
1952 if (leftOperand != null && rightOperand != null) {
1953 try {
1954 return leftOperand.shiftRight(_typeProvider, rightOperand);
1955 } on EvaluationException catch (exception) {
1956 _errorReporter.reportErrorForNode(exception.errorCode, node);
1957 }
1958 }
1959 return null;
1960 }
1961
1962 /**
1963 * Return the result of invoking the 'length' getter on the
1964 * [evaluationResult]. The [node] is the node against which errors should be
1965 * reported.
1966 */
1967 EvaluationResultImpl stringLength(
1968 Expression node, EvaluationResultImpl evaluationResult) {
1969 if (evaluationResult.value != null) {
1970 try {
1971 return new EvaluationResultImpl(
1972 evaluationResult.value.stringLength(_typeProvider));
1973 } on EvaluationException catch (exception) {
1974 _errorReporter.reportErrorForNode(exception.errorCode, node);
1975 }
1976 }
1977 return new EvaluationResultImpl(null);
1978 }
1979
1980 DartObjectImpl times(BinaryExpression node, DartObjectImpl leftOperand,
1981 DartObjectImpl rightOperand) {
1982 if (leftOperand != null && rightOperand != null) {
1983 try {
1984 return leftOperand.times(_typeProvider, rightOperand);
1985 } on EvaluationException catch (exception) {
1986 _errorReporter.reportErrorForNode(exception.errorCode, node);
1987 }
1988 }
1989 return null;
1990 }
1991 }
1992
1993 /**
1994 * The result of attempting to evaluate an expression.
1995 */
1996 class EvaluationResult {
1997 // TODO(brianwilkerson) Merge with EvaluationResultImpl
1998 /**
1999 * The value of the expression.
2000 */
2001 final DartObject value;
2002
2003 /**
2004 * The errors that should be reported for the expression(s) that were
2005 * evaluated.
2006 */
2007 final List<AnalysisError> _errors;
2008
2009 /**
2010 * Initialize a newly created result object with the given [value] and set of
2011 * [_errors]. Clients should use one of the factory methods: [forErrors] and
2012 * [forValue].
2013 */
2014 EvaluationResult(this.value, this._errors);
2015
2016 /**
2017 * Return a list containing the errors that should be reported for the
2018 * expression(s) that were evaluated. If there are no such errors, the list
2019 * will be empty. The list can be empty even if the expression is not a valid
2020 * compile time constant if the errors would have been reported by other parts
2021 * of the analysis engine.
2022 */
2023 List<AnalysisError> get errors => _errors ?? AnalysisError.NO_ERRORS;
2024
2025 /**
2026 * Return `true` if the expression is a compile-time constant expression that
2027 * would not throw an exception when evaluated.
2028 */
2029 bool get isValid => _errors == null;
2030
2031 /**
2032 * Return an evaluation result representing the result of evaluating an
2033 * expression that is not a compile-time constant because of the given
2034 * [errors].
2035 */
2036 static EvaluationResult forErrors(List<AnalysisError> errors) =>
2037 new EvaluationResult(null, errors);
2038
2039 /**
2040 * Return an evaluation result representing the result of evaluating an
2041 * expression that is a compile-time constant that evaluates to the given
2042 * [value].
2043 */
2044 static EvaluationResult forValue(DartObject value) =>
2045 new EvaluationResult(value, null);
2046 }
2047
2048 /**
2049 * The result of attempting to evaluate a expression.
2050 */
2051 class EvaluationResultImpl {
2052 /**
2053 * The errors encountered while trying to evaluate the compile time constant.
2054 * These errors may or may not have prevented the expression from being a
2055 * valid compile time constant.
2056 */
2057 List<AnalysisError> _errors;
2058
2059 /**
2060 * The value of the expression, or `null` if the value couldn't be computed
2061 * due to errors.
2062 */
2063 final DartObjectImpl value;
2064
2065 EvaluationResultImpl(this.value, [List<AnalysisError> errors]) {
2066 this._errors = errors ?? <AnalysisError>[];
2067 }
2068
2069 List<AnalysisError> get errors => _errors;
2070
2071 bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) {
2072 if (this.value != null) {
2073 if (result.value == null) {
2074 return false;
2075 }
2076 return value == result.value;
2077 } else {
2078 return false;
2079 }
2080 }
2081
2082 @override
2083 String toString() {
2084 if (value == null) {
2085 return "error";
2086 }
2087 return value.toString();
2088 }
2089 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/dart/ast/utilities.dart ('k') | packages/analyzer/lib/src/dart/constant/utilities.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698