| OLD | NEW |
| 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 // This code was auto-generated, is not intended to be edited, and is subject to | 5 // This code was auto-generated, is not intended to be edited, and is subject to |
| 6 // significant change. Please see the README file for more information. | 6 // significant change. Please see the README file for more information. |
| 7 | 7 |
| 8 library engine.constant; | 8 library engine.constant; |
| 9 | 9 |
| 10 import 'dart:collection'; | 10 import 'dart:collection'; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 SuperConstructorInvocation visitSuperConstructorInvocation( | 179 SuperConstructorInvocation visitSuperConstructorInvocation( |
| 180 SuperConstructorInvocation node) { | 180 SuperConstructorInvocation node) { |
| 181 SuperConstructorInvocation invocation = | 181 SuperConstructorInvocation invocation = |
| 182 super.visitSuperConstructorInvocation(node); | 182 super.visitSuperConstructorInvocation(node); |
| 183 invocation.staticElement = node.staticElement; | 183 invocation.staticElement = node.staticElement; |
| 184 return invocation; | 184 return invocation; |
| 185 } | 185 } |
| 186 } | 186 } |
| 187 | 187 |
| 188 /** | 188 /** |
| 189 * Helper class encapsulating the methods for evaluating constant instance |
| 190 * constant instance creation expressions. |
| 191 */ |
| 192 class ConstantEvaluationEngine { |
| 193 /** |
| 194 * Parameter to "fromEnvironment" methods that denotes the default value. |
| 195 */ |
| 196 static String _DEFAULT_VALUE_PARAM = "defaultValue"; |
| 197 |
| 198 /** |
| 199 * Source of RegExp matching any public identifier. |
| 200 * From sdk/lib/internal/symbol.dart. |
| 201 */ |
| 202 static String _PUBLIC_IDENTIFIER_RE = |
| 203 "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$
]*"; |
| 204 |
| 205 /** |
| 206 * RegExp that validates a non-empty non-private symbol. |
| 207 * From sdk/lib/internal/symbol.dart. |
| 208 */ |
| 209 static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp( |
| 210 "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$
|[.](?!\$)))+?\$"); |
| 211 |
| 212 /** |
| 213 * The type provider used to access the known types. |
| 214 */ |
| 215 final TypeProvider typeProvider; |
| 216 |
| 217 /** |
| 218 * The set of variables declared on the command line using '-D'. |
| 219 */ |
| 220 final DeclaredVariables _declaredVariables; |
| 221 |
| 222 /** |
| 223 * Validator used to verify correct dependency analysis when running unit |
| 224 * tests. |
| 225 */ |
| 226 final ConstantEvaluationValidator validator; |
| 227 |
| 228 /** |
| 229 * Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider] |
| 230 * is used to access known types. [_declaredVariables] is the set of |
| 231 * variables declared on the command line using '-D'. The [validator], if |
| 232 * given, is used to verify correct dependency analysis when running unit |
| 233 * tests. |
| 234 */ |
| 235 ConstantEvaluationEngine(this.typeProvider, this._declaredVariables, |
| 236 {ConstantEvaluationValidator validator}) |
| 237 : validator = validator != null |
| 238 ? validator |
| 239 : new ConstantEvaluationValidator_ForProduction(); |
| 240 |
| 241 /** |
| 242 * Check that the arguments to a call to fromEnvironment() are correct. The |
| 243 * [arguments] are the AST nodes of the arguments. The [argumentValues] are |
| 244 * the values of the unnamed arguments. The [namedArgumentValues] are the |
| 245 * values of the named arguments. The [expectedDefaultValueType] is the |
| 246 * allowed type of the "defaultValue" parameter (if present). Note: |
| 247 * "defaultValue" is always allowed to be null. Return `true` if the arguments |
| 248 * are correct, `false` if there is an error. |
| 249 */ |
| 250 bool checkFromEnvironmentArguments(NodeList<Expression> arguments, |
| 251 List<DartObjectImpl> argumentValues, |
| 252 HashMap<String, DartObjectImpl> namedArgumentValues, |
| 253 InterfaceType expectedDefaultValueType) { |
| 254 int argumentCount = arguments.length; |
| 255 if (argumentCount < 1 || argumentCount > 2) { |
| 256 return false; |
| 257 } |
| 258 if (arguments[0] is NamedExpression) { |
| 259 return false; |
| 260 } |
| 261 if (!identical(argumentValues[0].type, typeProvider.stringType)) { |
| 262 return false; |
| 263 } |
| 264 if (argumentCount == 2) { |
| 265 if (arguments[1] is! NamedExpression) { |
| 266 return false; |
| 267 } |
| 268 if (!((arguments[1] as NamedExpression).name.label.name == |
| 269 _DEFAULT_VALUE_PARAM)) { |
| 270 return false; |
| 271 } |
| 272 ParameterizedType defaultValueType = |
| 273 namedArgumentValues[_DEFAULT_VALUE_PARAM].type; |
| 274 if (!(identical(defaultValueType, expectedDefaultValueType) || |
| 275 identical(defaultValueType, typeProvider.nullType))) { |
| 276 return false; |
| 277 } |
| 278 } |
| 279 return true; |
| 280 } |
| 281 |
| 282 /** |
| 283 * Check that the arguments to a call to Symbol() are correct. The [arguments] |
| 284 * are the AST nodes of the arguments. The [argumentValues] are the values of |
| 285 * the unnamed arguments. The [namedArgumentValues] are the values of the |
| 286 * named arguments. Return `true` if the arguments are correct, `false` if |
| 287 * there is an error. |
| 288 */ |
| 289 bool checkSymbolArguments(NodeList<Expression> arguments, |
| 290 List<DartObjectImpl> argumentValues, |
| 291 HashMap<String, DartObjectImpl> namedArgumentValues) { |
| 292 if (arguments.length != 1) { |
| 293 return false; |
| 294 } |
| 295 if (arguments[0] is NamedExpression) { |
| 296 return false; |
| 297 } |
| 298 if (!identical(argumentValues[0].type, typeProvider.stringType)) { |
| 299 return false; |
| 300 } |
| 301 String name = argumentValues[0].stringValue; |
| 302 return isValidPublicSymbol(name); |
| 303 } |
| 304 |
| 305 /** |
| 306 * Evaluate a call to fromEnvironment() on the bool, int, or String class. The |
| 307 * [environmentValue] is the value fetched from the environment. The |
| 308 * [builtInDefaultValue] is the value that should be used as the default if no |
| 309 * "defaultValue" argument appears in [namedArgumentValues]. The |
| 310 * [namedArgumentValues] are the values of the named parameters passed to |
| 311 * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the |
| 312 * evaluated result. |
| 313 */ |
| 314 DartObjectImpl computeValueFromEnvironment(DartObject environmentValue, |
| 315 DartObjectImpl builtInDefaultValue, |
| 316 HashMap<String, DartObjectImpl> namedArgumentValues) { |
| 317 DartObjectImpl value = environmentValue as DartObjectImpl; |
| 318 if (value.isUnknown || value.isNull) { |
| 319 // The name either doesn't exist in the environment or we couldn't parse |
| 320 // the corresponding value. |
| 321 // If the code supplied an explicit default, use it. |
| 322 if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) { |
| 323 value = namedArgumentValues[_DEFAULT_VALUE_PARAM]; |
| 324 } else if (value.isNull) { |
| 325 // The code didn't supply an explicit default. |
| 326 // The name exists in the environment but we couldn't parse the |
| 327 // corresponding value. |
| 328 // So use the built-in default value, because this is what the VM does. |
| 329 value = builtInDefaultValue; |
| 330 } else { |
| 331 // The code didn't supply an explicit default. |
| 332 // The name doesn't exist in the environment. |
| 333 // The VM would use the built-in default value, but we don't want to do |
| 334 // that for analysis because it's likely to lead to cascading errors. |
| 335 // So just leave [value] in the unknown state. |
| 336 } |
| 337 } |
| 338 return value; |
| 339 } |
| 340 |
| 341 DartObjectImpl evaluateConstructorCall(AstNode node, |
| 342 NodeList<Expression> arguments, ConstructorElement constructor, |
| 343 ConstantVisitor constantVisitor, ErrorReporter errorReporter) { |
| 344 if (!_getConstructorBase(constructor).isCycleFree) { |
| 345 // It's not safe to evaluate this constructor, so bail out. |
| 346 // TODO(paulberry): ensure that a reasonable error message is produced |
| 347 // in this case, as well as other cases involving constant expression |
| 348 // circularities (e.g. "compile-time constant expression depends on |
| 349 // itself") |
| 350 return new DartObjectImpl.validWithUnknownValue(constructor.returnType); |
| 351 } |
| 352 int argumentCount = arguments.length; |
| 353 List<DartObjectImpl> argumentValues = |
| 354 new List<DartObjectImpl>(argumentCount); |
| 355 List<Expression> argumentNodes = new List<Expression>(argumentCount); |
| 356 HashMap<String, DartObjectImpl> namedArgumentValues = |
| 357 new HashMap<String, DartObjectImpl>(); |
| 358 HashMap<String, NamedExpression> namedArgumentNodes = |
| 359 new HashMap<String, NamedExpression>(); |
| 360 for (int i = 0; i < argumentCount; i++) { |
| 361 Expression argument = arguments[i]; |
| 362 if (argument is NamedExpression) { |
| 363 String name = argument.name.label.name; |
| 364 namedArgumentValues[name] = |
| 365 constantVisitor._valueOf(argument.expression); |
| 366 namedArgumentNodes[name] = argument; |
| 367 argumentValues[i] = typeProvider.nullObject; |
| 368 } else { |
| 369 argumentValues[i] = constantVisitor._valueOf(argument); |
| 370 argumentNodes[i] = argument; |
| 371 } |
| 372 } |
| 373 constructor = followConstantRedirectionChain(constructor); |
| 374 InterfaceType definingClass = constructor.returnType as InterfaceType; |
| 375 if (constructor.isFactory) { |
| 376 // We couldn't find a non-factory constructor. |
| 377 // See if it's because we reached an external const factory constructor |
| 378 // that we can emulate. |
| 379 if (constructor.name == "fromEnvironment") { |
| 380 if (!checkFromEnvironmentArguments( |
| 381 arguments, argumentValues, namedArgumentValues, definingClass)) { |
| 382 errorReporter.reportErrorForNode( |
| 383 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
| 384 return null; |
| 385 } |
| 386 String variableName = |
| 387 argumentCount < 1 ? null : argumentValues[0].stringValue; |
| 388 if (identical(definingClass, typeProvider.boolType)) { |
| 389 DartObject valueFromEnvironment; |
| 390 valueFromEnvironment = |
| 391 _declaredVariables.getBool(typeProvider, variableName); |
| 392 return computeValueFromEnvironment(valueFromEnvironment, |
| 393 new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE), |
| 394 namedArgumentValues); |
| 395 } else if (identical(definingClass, typeProvider.intType)) { |
| 396 DartObject valueFromEnvironment; |
| 397 valueFromEnvironment = |
| 398 _declaredVariables.getInt(typeProvider, variableName); |
| 399 return computeValueFromEnvironment(valueFromEnvironment, |
| 400 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), |
| 401 namedArgumentValues); |
| 402 } else if (identical(definingClass, typeProvider.stringType)) { |
| 403 DartObject valueFromEnvironment; |
| 404 valueFromEnvironment = |
| 405 _declaredVariables.getString(typeProvider, variableName); |
| 406 return computeValueFromEnvironment(valueFromEnvironment, |
| 407 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), |
| 408 namedArgumentValues); |
| 409 } |
| 410 } else if (constructor.name == "" && |
| 411 identical(definingClass, typeProvider.symbolType) && |
| 412 argumentCount == 1) { |
| 413 if (!checkSymbolArguments( |
| 414 arguments, argumentValues, namedArgumentValues)) { |
| 415 errorReporter.reportErrorForNode( |
| 416 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
| 417 return null; |
| 418 } |
| 419 String argumentValue = argumentValues[0].stringValue; |
| 420 return new DartObjectImpl( |
| 421 definingClass, new SymbolState(argumentValue)); |
| 422 } |
| 423 // Either it's an external const factory constructor that we can't |
| 424 // emulate, or an error occurred (a cycle, or a const constructor trying |
| 425 // to delegate to a non-const constructor). |
| 426 // In the former case, the best we can do is consider it an unknown value. |
| 427 // In the latter case, the error has already been reported, so considering |
| 428 // it an unknown value will suppress further errors. |
| 429 return new DartObjectImpl.validWithUnknownValue(definingClass); |
| 430 } |
| 431 validator.beforeGetConstantInitializers(constructor); |
| 432 ConstructorElementImpl constructorBase = _getConstructorBase(constructor); |
| 433 List<ConstructorInitializer> initializers = |
| 434 constructorBase.constantInitializers; |
| 435 if (initializers == null) { |
| 436 // This can happen in some cases where there are compile errors in the |
| 437 // code being analyzed (for example if the code is trying to create a |
| 438 // const instance using a non-const constructor, or the node we're |
| 439 // visiting is involved in a cycle). The error has already been reported, |
| 440 // so consider it an unknown value to suppress further errors. |
| 441 return new DartObjectImpl.validWithUnknownValue(definingClass); |
| 442 } |
| 443 HashMap<String, DartObjectImpl> fieldMap = |
| 444 new HashMap<String, DartObjectImpl>(); |
| 445 // Start with final fields that are initialized at their declaration site. |
| 446 for (FieldElement field in constructor.enclosingElement.fields) { |
| 447 if ((field.isFinal || field.isConst) && |
| 448 !field.isStatic && |
| 449 field is ConstFieldElementImpl) { |
| 450 validator.beforeGetFieldEvaluationResult(field); |
| 451 EvaluationResultImpl evaluationResult = field.evaluationResult; |
| 452 DartType fieldType = |
| 453 FieldMember.from(field, constructor.returnType).type; |
| 454 DartObjectImpl fieldValue = evaluationResult.value; |
| 455 if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) { |
| 456 errorReporter.reportErrorForNode( |
| 457 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA
TCH, |
| 458 node, [fieldValue.type, field.name, fieldType]); |
| 459 } |
| 460 fieldMap[field.name] = evaluationResult.value; |
| 461 } |
| 462 } |
| 463 // Now evaluate the constructor declaration. |
| 464 HashMap<String, DartObjectImpl> parameterMap = |
| 465 new HashMap<String, DartObjectImpl>(); |
| 466 List<ParameterElement> parameters = constructor.parameters; |
| 467 int parameterCount = parameters.length; |
| 468 for (int i = 0; i < parameterCount; i++) { |
| 469 ParameterElement parameter = parameters[i]; |
| 470 ParameterElement baseParameter = parameter; |
| 471 while (baseParameter is ParameterMember) { |
| 472 baseParameter = (baseParameter as ParameterMember).baseElement; |
| 473 } |
| 474 DartObjectImpl argumentValue = null; |
| 475 AstNode errorTarget = null; |
| 476 if (baseParameter.parameterKind == ParameterKind.NAMED) { |
| 477 argumentValue = namedArgumentValues[baseParameter.name]; |
| 478 errorTarget = namedArgumentNodes[baseParameter.name]; |
| 479 } else if (i < argumentCount) { |
| 480 argumentValue = argumentValues[i]; |
| 481 errorTarget = argumentNodes[i]; |
| 482 } |
| 483 if (errorTarget == null) { |
| 484 // No argument node that we can direct error messages to, because we |
| 485 // are handling an optional parameter that wasn't specified. So just |
| 486 // direct error messages to the constructor call. |
| 487 errorTarget = node; |
| 488 } |
| 489 if (argumentValue == null && baseParameter is ParameterElementImpl) { |
| 490 // The parameter is an optional positional parameter for which no value |
| 491 // was provided, so use the default value. |
| 492 validator.beforeGetParameterDefault(baseParameter); |
| 493 EvaluationResultImpl evaluationResult = baseParameter.evaluationResult; |
| 494 if (evaluationResult == null) { |
| 495 // No default was provided, so the default value is null. |
| 496 argumentValue = typeProvider.nullObject; |
| 497 } else if (evaluationResult.value != null) { |
| 498 argumentValue = evaluationResult.value; |
| 499 } |
| 500 } |
| 501 if (argumentValue != null) { |
| 502 if (!runtimeTypeMatch(argumentValue, parameter.type)) { |
| 503 errorReporter.reportErrorForNode( |
| 504 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA
TCH, |
| 505 errorTarget, [argumentValue.type, parameter.type]); |
| 506 } |
| 507 if (baseParameter.isInitializingFormal) { |
| 508 FieldElement field = (parameter as FieldFormalParameterElement).field; |
| 509 if (field != null) { |
| 510 DartType fieldType = field.type; |
| 511 if (fieldType != parameter.type) { |
| 512 // We've already checked that the argument can be assigned to the |
| 513 // parameter; we also need to check that it can be assigned to |
| 514 // the field. |
| 515 if (!runtimeTypeMatch(argumentValue, fieldType)) { |
| 516 errorReporter.reportErrorForNode( |
| 517 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE
_MISMATCH, |
| 518 errorTarget, [argumentValue.type, fieldType]); |
| 519 } |
| 520 } |
| 521 String fieldName = field.name; |
| 522 fieldMap[fieldName] = argumentValue; |
| 523 } |
| 524 } else { |
| 525 String name = baseParameter.name; |
| 526 parameterMap[name] = argumentValue; |
| 527 } |
| 528 } |
| 529 } |
| 530 ConstantVisitor initializerVisitor = new ConstantVisitor( |
| 531 this, errorReporter, lexicalEnvironment: parameterMap); |
| 532 String superName = null; |
| 533 NodeList<Expression> superArguments = null; |
| 534 for (ConstructorInitializer initializer in initializers) { |
| 535 if (initializer is ConstructorFieldInitializer) { |
| 536 ConstructorFieldInitializer constructorFieldInitializer = initializer; |
| 537 Expression initializerExpression = |
| 538 constructorFieldInitializer.expression; |
| 539 DartObjectImpl evaluationResult = |
| 540 initializerExpression.accept(initializerVisitor); |
| 541 if (evaluationResult != null) { |
| 542 String fieldName = constructorFieldInitializer.fieldName.name; |
| 543 fieldMap[fieldName] = evaluationResult; |
| 544 PropertyAccessorElement getter = definingClass.getGetter(fieldName); |
| 545 if (getter != null) { |
| 546 PropertyInducingElement field = getter.variable; |
| 547 if (!runtimeTypeMatch(evaluationResult, field.type)) { |
| 548 errorReporter.reportErrorForNode( |
| 549 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_M
ISMATCH, |
| 550 node, [evaluationResult.type, fieldName, field.type]); |
| 551 } |
| 552 } |
| 553 } |
| 554 } else if (initializer is SuperConstructorInvocation) { |
| 555 SuperConstructorInvocation superConstructorInvocation = initializer; |
| 556 SimpleIdentifier name = superConstructorInvocation.constructorName; |
| 557 if (name != null) { |
| 558 superName = name.name; |
| 559 } |
| 560 superArguments = superConstructorInvocation.argumentList.arguments; |
| 561 } else if (initializer is RedirectingConstructorInvocation) { |
| 562 // This is a redirecting constructor, so just evaluate the constructor |
| 563 // it redirects to. |
| 564 ConstructorElement constructor = initializer.staticElement; |
| 565 if (constructor != null && constructor.isConst) { |
| 566 return evaluateConstructorCall(node, |
| 567 initializer.argumentList.arguments, constructor, |
| 568 initializerVisitor, errorReporter); |
| 569 } |
| 570 } |
| 571 } |
| 572 // Evaluate explicit or implicit call to super(). |
| 573 InterfaceType superclass = definingClass.superclass; |
| 574 if (superclass != null && !superclass.isObject) { |
| 575 ConstructorElement superConstructor = |
| 576 superclass.lookUpConstructor(superName, constructor.library); |
| 577 if (superConstructor != null) { |
| 578 if (superArguments == null) { |
| 579 superArguments = new NodeList<Expression>(null); |
| 580 } |
| 581 evaluateSuperConstructorCall(node, fieldMap, superConstructor, |
| 582 superArguments, initializerVisitor, errorReporter); |
| 583 } |
| 584 } |
| 585 return new DartObjectImpl(definingClass, new GenericState(fieldMap)); |
| 586 } |
| 587 |
| 588 void evaluateSuperConstructorCall(AstNode node, |
| 589 HashMap<String, DartObjectImpl> fieldMap, |
| 590 ConstructorElement superConstructor, NodeList<Expression> superArguments, |
| 591 ConstantVisitor initializerVisitor, ErrorReporter errorReporter) { |
| 592 if (superConstructor != null && superConstructor.isConst) { |
| 593 DartObjectImpl evaluationResult = evaluateConstructorCall(node, |
| 594 superArguments, superConstructor, initializerVisitor, errorReporter); |
| 595 if (evaluationResult != null) { |
| 596 fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult; |
| 597 } |
| 598 } |
| 599 } |
| 600 |
| 601 /** |
| 602 * Attempt to follow the chain of factory redirections until a constructor is |
| 603 * reached which is not a const factory constructor. Return the constant |
| 604 * constructor which terminates the chain of factory redirections, if the |
| 605 * chain terminates. If there is a problem (e.g. a redirection can't be found, |
| 606 * or a cycle is encountered), the chain will be followed as far as possible |
| 607 * and then a const factory constructor will be returned. |
| 608 */ |
| 609 ConstructorElement followConstantRedirectionChain( |
| 610 ConstructorElement constructor) { |
| 611 HashSet<ConstructorElement> constructorsVisited = |
| 612 new HashSet<ConstructorElement>(); |
| 613 while (true) { |
| 614 ConstructorElement redirectedConstructor = |
| 615 getConstRedirectedConstructor(constructor); |
| 616 if (redirectedConstructor == null) { |
| 617 break; |
| 618 } else { |
| 619 ConstructorElement constructorBase = _getConstructorBase(constructor); |
| 620 constructorsVisited.add(constructorBase); |
| 621 ConstructorElement redirectedConstructorBase = |
| 622 _getConstructorBase(redirectedConstructor); |
| 623 if (constructorsVisited.contains(redirectedConstructorBase)) { |
| 624 // Cycle in redirecting factory constructors--this is not allowed |
| 625 // and is checked elsewhere--see |
| 626 // [ErrorVerifier.checkForRecursiveFactoryRedirect()]). |
| 627 break; |
| 628 } |
| 629 } |
| 630 constructor = redirectedConstructor; |
| 631 } |
| 632 return constructor; |
| 633 } |
| 634 |
| 635 /** |
| 636 * If [constructor] redirects to another const constructor, return the |
| 637 * const constructor it redirects to. Otherwise return `null`. |
| 638 */ |
| 639 ConstructorElement getConstRedirectedConstructor( |
| 640 ConstructorElement constructor) { |
| 641 if (!constructor.isFactory) { |
| 642 return null; |
| 643 } |
| 644 if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) { |
| 645 // The dart:core.Symbol has a const factory constructor that redirects |
| 646 // to dart:_internal.Symbol. That in turn redirects to an external |
| 647 // const constructor, which we won't be able to evaluate. |
| 648 // So stop following the chain of redirections at dart:core.Symbol, and |
| 649 // let [evaluateInstanceCreationExpression] handle it specially. |
| 650 return null; |
| 651 } |
| 652 ConstructorElement redirectedConstructor = |
| 653 constructor.redirectedConstructor; |
| 654 if (redirectedConstructor == null) { |
| 655 // This can happen if constructor is an external factory constructor. |
| 656 return null; |
| 657 } |
| 658 if (!redirectedConstructor.isConst) { |
| 659 // Delegating to a non-const constructor--this is not allowed (and |
| 660 // is checked elsewhere--see |
| 661 // [ErrorVerifier.checkForRedirectToNonConstConstructor()]). |
| 662 return null; |
| 663 } |
| 664 return redirectedConstructor; |
| 665 } |
| 666 |
| 667 /** |
| 668 * Check if the object [obj] matches the type [type] according to runtime type |
| 669 * checking rules. |
| 670 */ |
| 671 bool runtimeTypeMatch(DartObjectImpl obj, DartType type) { |
| 672 if (obj.isNull) { |
| 673 return true; |
| 674 } |
| 675 if (type.isUndefined) { |
| 676 return false; |
| 677 } |
| 678 return obj.type.isSubtypeOf(type); |
| 679 } |
| 680 |
| 681 ConstructorElementImpl _getConstructorBase(ConstructorElement constructor) { |
| 682 while (constructor is ConstructorMember) { |
| 683 constructor = (constructor as ConstructorMember).baseElement; |
| 684 } |
| 685 return constructor; |
| 686 } |
| 687 |
| 688 /** |
| 689 * Determine whether the given string is a valid name for a public symbol |
| 690 * (i.e. whether it is allowed for a call to the Symbol constructor). |
| 691 */ |
| 692 static bool isValidPublicSymbol(String name) => name.isEmpty || |
| 693 name == "void" || |
| 694 new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches(); |
| 695 } |
| 696 |
| 697 /** |
| 189 * Interface used by unit tests to verify correct dependency analysis during | 698 * Interface used by unit tests to verify correct dependency analysis during |
| 190 * constant evaluation. | 699 * constant evaluation. |
| 191 */ | 700 */ |
| 192 abstract class ConstantEvaluationValidator { | 701 abstract class ConstantEvaluationValidator { |
| 193 /** | 702 /** |
| 194 * This method is called just before computing the constant value associated | 703 * This method is called just before computing the constant value associated |
| 195 * with [constNode]. Unit tests will override this method to introduce | 704 * with [constNode]. Unit tests will override this method to introduce |
| 196 * additional error checking. | 705 * additional error checking. |
| 197 */ | 706 */ |
| 198 void beforeComputeValue(AstNode constNode); | 707 void beforeComputeValue(AstNode constNode); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 /** | 826 /** |
| 318 * Initialize a newly created evaluator to evaluate expressions in the given | 827 * Initialize a newly created evaluator to evaluate expressions in the given |
| 319 * [source]. The [typeProvider] is the type provider used to access known | 828 * [source]. The [typeProvider] is the type provider used to access known |
| 320 * types. | 829 * types. |
| 321 */ | 830 */ |
| 322 ConstantEvaluator(this._source, this._typeProvider); | 831 ConstantEvaluator(this._source, this._typeProvider); |
| 323 | 832 |
| 324 EvaluationResult evaluate(Expression expression) { | 833 EvaluationResult evaluate(Expression expression) { |
| 325 RecordingErrorListener errorListener = new RecordingErrorListener(); | 834 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 326 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); | 835 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); |
| 327 DartObjectImpl result = | 836 DartObjectImpl result = expression.accept(new ConstantVisitor( |
| 328 expression.accept(new ConstantVisitor(_typeProvider, errorReporter)); | 837 new ConstantEvaluationEngine(_typeProvider, new DeclaredVariables()), |
| 838 errorReporter)); |
| 329 if (result != null) { | 839 if (result != null) { |
| 330 return EvaluationResult.forValue(result); | 840 return EvaluationResult.forValue(result); |
| 331 } | 841 } |
| 332 return EvaluationResult.forErrors(errorListener.errors); | 842 return EvaluationResult.forErrors(errorListener.errors); |
| 333 } | 843 } |
| 334 } | 844 } |
| 335 | 845 |
| 336 /** | 846 /** |
| 337 * A visitor used to traverse the AST structures of all of the compilation units | 847 * A visitor used to traverse the AST structures of all of the compilation units |
| 338 * being resolved and build tables of the constant variables, constant | 848 * being resolved and build tables of the constant variables, constant |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 /** | 946 /** |
| 437 * An object used to compute the values of constant variables and constant | 947 * An object used to compute the values of constant variables and constant |
| 438 * constructor invocations in one or more compilation units. The expected usage | 948 * constructor invocations in one or more compilation units. The expected usage |
| 439 * pattern is for the compilation units to be added to this computer using the | 949 * pattern is for the compilation units to be added to this computer using the |
| 440 * method [add] and then for the method [computeValues] to be invoked exactly | 950 * method [add] and then for the method [computeValues] to be invoked exactly |
| 441 * once. Any use of an instance after invoking the method [computeValues] will | 951 * once. Any use of an instance after invoking the method [computeValues] will |
| 442 * result in unpredictable behavior. | 952 * result in unpredictable behavior. |
| 443 */ | 953 */ |
| 444 class ConstantValueComputer { | 954 class ConstantValueComputer { |
| 445 /** | 955 /** |
| 446 * Parameter to "fromEnvironment" methods that denotes the default value. | |
| 447 */ | |
| 448 static String _DEFAULT_VALUE_PARAM = "defaultValue"; | |
| 449 | |
| 450 /** | |
| 451 * Source of RegExp matching declarable operator names. | 956 * Source of RegExp matching declarable operator names. |
| 452 * From sdk/lib/internal/symbol.dart. | 957 * From sdk/lib/internal/symbol.dart. |
| 453 */ | 958 */ |
| 454 static String _OPERATOR_RE = | 959 static String _OPERATOR_RE = |
| 455 "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)"; | 960 "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)"; |
| 456 | 961 |
| 457 /** | 962 /** |
| 458 * Source of RegExp matching any public identifier. | |
| 459 * From sdk/lib/internal/symbol.dart. | |
| 460 */ | |
| 461 static String _PUBLIC_IDENTIFIER_RE = | |
| 462 "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$
]*"; | |
| 463 | |
| 464 /** | |
| 465 * Source of RegExp matching Dart reserved words. | 963 * Source of RegExp matching Dart reserved words. |
| 466 * From sdk/lib/internal/symbol.dart. | 964 * From sdk/lib/internal/symbol.dart. |
| 467 */ | 965 */ |
| 468 static String _RESERVED_WORD_RE = | 966 static String _RESERVED_WORD_RE = |
| 469 "(?: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))"; | 967 "(?: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))"; |
| 470 | 968 |
| 471 /** | 969 /** |
| 472 * RegExp that validates a non-empty non-private symbol. | |
| 473 * From sdk/lib/internal/symbol.dart. | |
| 474 */ | |
| 475 static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp( | |
| 476 "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$
|[.](?!\$)))+?\$"); | |
| 477 | |
| 478 /** | |
| 479 * The type provider used to access the known types. | |
| 480 */ | |
| 481 final TypeProvider typeProvider; | |
| 482 | |
| 483 /** | |
| 484 * Validator used to verify correct dependency analysis when running unit | |
| 485 * tests. | |
| 486 */ | |
| 487 final ConstantEvaluationValidator validator; | |
| 488 | |
| 489 /** | |
| 490 * The object used to find constant variables and constant constructor | 970 * The object used to find constant variables and constant constructor |
| 491 * invocations in the compilation units that were added. | 971 * invocations in the compilation units that were added. |
| 492 */ | 972 */ |
| 493 ConstantFinder _constantFinder = new ConstantFinder(); | 973 ConstantFinder _constantFinder = new ConstantFinder(); |
| 494 | 974 |
| 495 /** | 975 /** |
| 496 * A graph in which the nodes are the constants, and the edges are from each | 976 * A graph in which the nodes are the constants, and the edges are from each |
| 497 * constant to the other constants that are referenced by it. | 977 * constant to the other constants that are referenced by it. |
| 498 */ | 978 */ |
| 499 DirectedGraph<AstNode> referenceGraph = new DirectedGraph<AstNode>(); | 979 DirectedGraph<AstNode> referenceGraph = new DirectedGraph<AstNode>(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 513 * A collection of constant constructor invocations. | 993 * A collection of constant constructor invocations. |
| 514 */ | 994 */ |
| 515 List<InstanceCreationExpression> _constructorInvocations; | 995 List<InstanceCreationExpression> _constructorInvocations; |
| 516 | 996 |
| 517 /** | 997 /** |
| 518 * A collection of annotations. | 998 * A collection of annotations. |
| 519 */ | 999 */ |
| 520 List<Annotation> _annotations; | 1000 List<Annotation> _annotations; |
| 521 | 1001 |
| 522 /** | 1002 /** |
| 523 * The set of variables declared on the command line using '-D'. | 1003 * The evaluation engine that does the work of evaluating instance creation |
| 524 */ | 1004 * expressions. |
| 525 final DeclaredVariables _declaredVariables; | 1005 */ |
| 1006 final ConstantEvaluationEngine evaluationEngine; |
| 526 | 1007 |
| 527 /** | 1008 /** |
| 528 * Initialize a newly created constant value computer. The [typeProvider] is | 1009 * Initialize a newly created constant value computer. The [typeProvider] is |
| 529 * the type provider used to access known types. The [declaredVariables] is | 1010 * the type provider used to access known types. The [declaredVariables] is |
| 530 * the set of variables declared on the command line using '-D'. | 1011 * the set of variables declared on the command line using '-D'. |
| 531 */ | 1012 */ |
| 532 ConstantValueComputer(this.typeProvider, this._declaredVariables, | 1013 ConstantValueComputer( |
| 1014 TypeProvider typeProvider, DeclaredVariables declaredVariables, |
| 533 [ConstantEvaluationValidator validator]) | 1015 [ConstantEvaluationValidator validator]) |
| 534 : validator = validator != null | 1016 : evaluationEngine = new ConstantEvaluationEngine( |
| 535 ? validator | 1017 typeProvider, declaredVariables, validator: validator); |
| 536 : new ConstantEvaluationValidator_ForProduction(); | |
| 537 | 1018 |
| 538 /** | 1019 /** |
| 539 * Add the constants in the given compilation [unit] to the list of constants | 1020 * Add the constants in the given compilation [unit] to the list of constants |
| 540 * whose value needs to be computed. | 1021 * whose value needs to be computed. |
| 541 */ | 1022 */ |
| 542 void add(CompilationUnit unit) { | 1023 void add(CompilationUnit unit) { |
| 543 unit.accept(_constantFinder); | 1024 unit.accept(_constantFinder); |
| 544 } | 1025 } |
| 545 | 1026 |
| 546 /** | 1027 /** |
| 547 * Compute values for all of the constants in the compilation units that were | 1028 * Compute values for all of the constants in the compilation units that were |
| 548 * added. | 1029 * added. |
| 549 */ | 1030 */ |
| 550 void computeValues() { | 1031 void computeValues() { |
| 551 _variableDeclarationMap = _constantFinder.variableMap; | 1032 _variableDeclarationMap = _constantFinder.variableMap; |
| 552 constructorDeclarationMap = _constantFinder.constructorMap; | 1033 constructorDeclarationMap = _constantFinder.constructorMap; |
| 553 _constructorInvocations = _constantFinder.constructorInvocations; | 1034 _constructorInvocations = _constantFinder.constructorInvocations; |
| 554 _annotations = _constantFinder.annotations; | 1035 _annotations = _constantFinder.annotations; |
| 555 _variableDeclarationMap.values.forEach((VariableDeclaration declaration) { | 1036 _variableDeclarationMap.values.forEach((VariableDeclaration declaration) { |
| 556 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, | 1037 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, |
| 557 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); | 1038 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 558 referenceGraph.addNode(declaration); | 1039 referenceGraph.addNode(declaration); |
| 559 declaration.initializer.accept(referenceFinder); | 1040 declaration.initializer.accept(referenceFinder); |
| 560 }); | 1041 }); |
| 561 constructorDeclarationMap.forEach((ConstructorElementImpl element, | 1042 constructorDeclarationMap.forEach((ConstructorElementImpl element, |
| 562 ConstructorDeclaration declaration) { | 1043 ConstructorDeclaration declaration) { |
| 563 element.isCycleFree = false; | 1044 element.isCycleFree = false; |
| 564 ConstructorElement redirectedConstructor = | 1045 ConstructorElement redirectedConstructor = |
| 565 _getConstRedirectedConstructor(element); | 1046 evaluationEngine.getConstRedirectedConstructor(element); |
| 566 if (redirectedConstructor != null) { | 1047 if (redirectedConstructor != null) { |
| 567 ConstructorElement redirectedConstructorBase = | 1048 ConstructorElement redirectedConstructorBase = |
| 568 _getConstructorBase(redirectedConstructor); | 1049 evaluationEngine._getConstructorBase(redirectedConstructor); |
| 569 ConstructorDeclaration redirectedConstructorDeclaration = | 1050 ConstructorDeclaration redirectedConstructorDeclaration = |
| 570 findConstructorDeclaration(redirectedConstructorBase); | 1051 findConstructorDeclaration(redirectedConstructorBase); |
| 571 referenceGraph.addEdge(declaration, redirectedConstructorDeclaration); | 1052 referenceGraph.addEdge(declaration, redirectedConstructorDeclaration); |
| 572 return; | 1053 return; |
| 573 } | 1054 } |
| 574 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, | 1055 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, |
| 575 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); | 1056 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 576 referenceGraph.addNode(declaration); | 1057 referenceGraph.addNode(declaration); |
| 577 bool superInvocationFound = false; | 1058 bool superInvocationFound = false; |
| 578 NodeList<ConstructorInitializer> initializers = declaration.initializers; | 1059 NodeList<ConstructorInitializer> initializers = declaration.initializers; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 } | 1132 } |
| 652 // Since no constant can depend on an annotation, we don't waste time | 1133 // Since no constant can depend on an annotation, we don't waste time |
| 653 // including them in the topological sort. We just process all the | 1134 // including them in the topological sort. We just process all the |
| 654 // annotations after all other constants are finished. | 1135 // annotations after all other constants are finished. |
| 655 for (Annotation annotation in _annotations) { | 1136 for (Annotation annotation in _annotations) { |
| 656 _computeValueFor(annotation); | 1137 _computeValueFor(annotation); |
| 657 } | 1138 } |
| 658 } | 1139 } |
| 659 | 1140 |
| 660 ConstructorDeclaration findConstructorDeclaration( | 1141 ConstructorDeclaration findConstructorDeclaration( |
| 661 ConstructorElement constructor) => | 1142 ConstructorElement constructor) => constructorDeclarationMap[ |
| 662 constructorDeclarationMap[_getConstructorBase(constructor)]; | 1143 evaluationEngine._getConstructorBase(constructor)]; |
| 663 | 1144 |
| 664 VariableDeclaration findVariableDeclaration( | 1145 VariableDeclaration findVariableDeclaration( |
| 665 PotentiallyConstVariableElement variable) => | 1146 PotentiallyConstVariableElement variable) => |
| 666 _variableDeclarationMap[variable]; | 1147 _variableDeclarationMap[variable]; |
| 667 | 1148 |
| 668 /** | 1149 /** |
| 669 * Check that the arguments to a call to fromEnvironment() are correct. The | |
| 670 * [arguments] are the AST nodes of the arguments. The [argumentValues] are | |
| 671 * the values of the unnamed arguments. The [namedArgumentValues] are the | |
| 672 * values of the named arguments. The [expectedDefaultValueType] is the | |
| 673 * allowed type of the "defaultValue" parameter (if present). Note: | |
| 674 * "defaultValue" is always allowed to be null. Return `true` if the arguments | |
| 675 * are correct, `false` if there is an error. | |
| 676 */ | |
| 677 bool _checkFromEnvironmentArguments(NodeList<Expression> arguments, | |
| 678 List<DartObjectImpl> argumentValues, | |
| 679 HashMap<String, DartObjectImpl> namedArgumentValues, | |
| 680 InterfaceType expectedDefaultValueType) { | |
| 681 int argumentCount = arguments.length; | |
| 682 if (argumentCount < 1 || argumentCount > 2) { | |
| 683 return false; | |
| 684 } | |
| 685 if (arguments[0] is NamedExpression) { | |
| 686 return false; | |
| 687 } | |
| 688 if (!identical(argumentValues[0].type, typeProvider.stringType)) { | |
| 689 return false; | |
| 690 } | |
| 691 if (argumentCount == 2) { | |
| 692 if (arguments[1] is! NamedExpression) { | |
| 693 return false; | |
| 694 } | |
| 695 if (!((arguments[1] as NamedExpression).name.label.name == | |
| 696 _DEFAULT_VALUE_PARAM)) { | |
| 697 return false; | |
| 698 } | |
| 699 ParameterizedType defaultValueType = | |
| 700 namedArgumentValues[_DEFAULT_VALUE_PARAM].type; | |
| 701 if (!(identical(defaultValueType, expectedDefaultValueType) || | |
| 702 identical(defaultValueType, typeProvider.nullType))) { | |
| 703 return false; | |
| 704 } | |
| 705 } | |
| 706 return true; | |
| 707 } | |
| 708 | |
| 709 /** | |
| 710 * Check that the arguments to a call to Symbol() are correct. The [arguments] | |
| 711 * are the AST nodes of the arguments. The [argumentValues] are the values of | |
| 712 * the unnamed arguments. The [namedArgumentValues] are the values of the | |
| 713 * named arguments. Return `true` if the arguments are correct, `false` if | |
| 714 * there is an error. | |
| 715 */ | |
| 716 bool _checkSymbolArguments(NodeList<Expression> arguments, | |
| 717 List<DartObjectImpl> argumentValues, | |
| 718 HashMap<String, DartObjectImpl> namedArgumentValues) { | |
| 719 if (arguments.length != 1) { | |
| 720 return false; | |
| 721 } | |
| 722 if (arguments[0] is NamedExpression) { | |
| 723 return false; | |
| 724 } | |
| 725 if (!identical(argumentValues[0].type, typeProvider.stringType)) { | |
| 726 return false; | |
| 727 } | |
| 728 String name = argumentValues[0].stringValue; | |
| 729 return isValidPublicSymbol(name); | |
| 730 } | |
| 731 | |
| 732 /** | |
| 733 * Compute a value for the given [constNode]. | 1150 * Compute a value for the given [constNode]. |
| 734 */ | 1151 */ |
| 735 void _computeValueFor(AstNode constNode) { | 1152 void _computeValueFor(AstNode constNode) { |
| 736 validator.beforeComputeValue(constNode); | 1153 evaluationEngine.validator.beforeComputeValue(constNode); |
| 737 if (constNode is VariableDeclaration) { | 1154 if (constNode is VariableDeclaration) { |
| 738 VariableElement element = constNode.element; | 1155 VariableElement element = constNode.element; |
| 739 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1156 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 740 ErrorReporter errorReporter = | 1157 ErrorReporter errorReporter = |
| 741 new ErrorReporter(errorListener, element.source); | 1158 new ErrorReporter(errorListener, element.source); |
| 742 DartObjectImpl dartObject = | 1159 DartObjectImpl dartObject = |
| 743 (element as PotentiallyConstVariableElement).constantInitializer | 1160 (element as PotentiallyConstVariableElement).constantInitializer |
| 744 .accept(new ConstantVisitor(typeProvider, errorReporter, | 1161 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); |
| 745 validator: validator)); | |
| 746 if (dartObject != null) { | 1162 if (dartObject != null) { |
| 747 if (!_runtimeTypeMatch(dartObject, element.type)) { | 1163 if (!evaluationEngine.runtimeTypeMatch(dartObject, element.type)) { |
| 748 errorReporter.reportErrorForElement( | 1164 errorReporter.reportErrorForElement( |
| 749 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, element, [ | 1165 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, element, [ |
| 750 dartObject.type, | 1166 dartObject.type, |
| 751 element.type | 1167 element.type |
| 752 ]); | 1168 ]); |
| 753 } | 1169 } |
| 754 } | 1170 } |
| 755 (element as VariableElementImpl).evaluationResult = | 1171 (element as VariableElementImpl).evaluationResult = |
| 756 new EvaluationResultImpl.con2(dartObject, errorListener.errors); | 1172 new EvaluationResultImpl.con2(dartObject, errorListener.errors); |
| 757 } else if (constNode is InstanceCreationExpression) { | 1173 } else if (constNode is InstanceCreationExpression) { |
| 758 InstanceCreationExpression expression = constNode; | 1174 InstanceCreationExpression expression = constNode; |
| 759 ConstructorElement constructor = expression.staticElement; | 1175 ConstructorElement constructor = expression.staticElement; |
| 760 if (constructor == null) { | 1176 if (constructor == null) { |
| 761 // Couldn't resolve the constructor so we can't compute a value. | 1177 // Couldn't resolve the constructor so we can't compute a value. |
| 762 // No problem - the error has already been reported. | 1178 // No problem - the error has already been reported. |
| 763 // But we still need to store an evaluation result. | 1179 // But we still need to store an evaluation result. |
| 764 expression.constantHandle.evaluationResult = | 1180 expression.constantHandle.evaluationResult = |
| 765 new EvaluationResultImpl.con1(null); | 1181 new EvaluationResultImpl.con1(null); |
| 766 return; | 1182 return; |
| 767 } | 1183 } |
| 768 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1184 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 769 CompilationUnit sourceCompilationUnit = | 1185 CompilationUnit sourceCompilationUnit = |
| 770 expression.getAncestor((node) => node is CompilationUnit); | 1186 expression.getAncestor((node) => node is CompilationUnit); |
| 771 ErrorReporter errorReporter = new ErrorReporter( | 1187 ErrorReporter errorReporter = new ErrorReporter( |
| 772 errorListener, sourceCompilationUnit.element.source); | 1188 errorListener, sourceCompilationUnit.element.source); |
| 773 ConstantVisitor constantVisitor = new ConstantVisitor( | 1189 ConstantVisitor constantVisitor = |
| 774 typeProvider, errorReporter, validator: validator); | 1190 new ConstantVisitor(evaluationEngine, errorReporter); |
| 775 DartObjectImpl result = _evaluateConstructorCall(constNode, | 1191 DartObjectImpl result = evaluationEngine.evaluateConstructorCall( |
| 776 expression.argumentList.arguments, constructor, constantVisitor, | 1192 constNode, expression.argumentList.arguments, constructor, |
| 777 errorReporter); | 1193 constantVisitor, errorReporter); |
| 778 expression.constantHandle.evaluationResult = | 1194 expression.constantHandle.evaluationResult = |
| 779 new EvaluationResultImpl.con2(result, errorListener.errors); | 1195 new EvaluationResultImpl.con2(result, errorListener.errors); |
| 780 } else if (constNode is ConstructorDeclaration) { | 1196 } else if (constNode is ConstructorDeclaration) { |
| 781 // No evaluation needs to be done; constructor declarations are only in | 1197 // No evaluation needs to be done; constructor declarations are only in |
| 782 // the dependency graph to ensure that any constants referred to in | 1198 // the dependency graph to ensure that any constants referred to in |
| 783 // initializer lists and parameter defaults are evaluated before | 1199 // initializer lists and parameter defaults are evaluated before |
| 784 // invocations of the constructor. However we do need to annotate the | 1200 // invocations of the constructor. However we do need to annotate the |
| 785 // element as being free of constant evaluation cycles so that later code | 1201 // element as being free of constant evaluation cycles so that later code |
| 786 // will know that it is safe to evaluate. | 1202 // will know that it is safe to evaluate. |
| 787 ConstructorElementImpl constructor = constNode.element; | 1203 ConstructorElementImpl constructor = constNode.element; |
| 788 constructor.isCycleFree = true; | 1204 constructor.isCycleFree = true; |
| 789 } else if (constNode is FormalParameter) { | 1205 } else if (constNode is FormalParameter) { |
| 790 if (constNode is DefaultFormalParameter) { | 1206 if (constNode is DefaultFormalParameter) { |
| 791 DefaultFormalParameter parameter = constNode; | 1207 DefaultFormalParameter parameter = constNode; |
| 792 ParameterElement element = parameter.element; | 1208 ParameterElement element = parameter.element; |
| 793 Expression defaultValue = parameter.defaultValue; | 1209 Expression defaultValue = parameter.defaultValue; |
| 794 if (defaultValue != null) { | 1210 if (defaultValue != null) { |
| 795 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1211 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 796 ErrorReporter errorReporter = | 1212 ErrorReporter errorReporter = |
| 797 new ErrorReporter(errorListener, element.source); | 1213 new ErrorReporter(errorListener, element.source); |
| 798 DartObjectImpl dartObject = defaultValue.accept(new ConstantVisitor( | 1214 DartObjectImpl dartObject = defaultValue |
| 799 typeProvider, errorReporter, validator: validator)); | 1215 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); |
| 800 (element as ParameterElementImpl).evaluationResult = | 1216 (element as ParameterElementImpl).evaluationResult = |
| 801 new EvaluationResultImpl.con2(dartObject, errorListener.errors); | 1217 new EvaluationResultImpl.con2(dartObject, errorListener.errors); |
| 802 } | 1218 } |
| 803 } | 1219 } |
| 804 } else if (constNode is Annotation) { | 1220 } else if (constNode is Annotation) { |
| 805 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; | 1221 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; |
| 806 // elementAnnotation is null if the annotation couldn't be resolved, in | 1222 // elementAnnotation is null if the annotation couldn't be resolved, in |
| 807 // which case we skip it. | 1223 // which case we skip it. |
| 808 if (elementAnnotation != null) { | 1224 if (elementAnnotation != null) { |
| 809 Element element = elementAnnotation.element; | 1225 Element element = elementAnnotation.element; |
| 810 if (element is PropertyAccessorElement && | 1226 if (element is PropertyAccessorElement && |
| 811 element.variable is VariableElementImpl) { | 1227 element.variable is VariableElementImpl) { |
| 812 // The annotation is a reference to a compile-time constant variable. | 1228 // The annotation is a reference to a compile-time constant variable. |
| 813 // Just copy the evaluation result. | 1229 // Just copy the evaluation result. |
| 814 VariableElementImpl variableElement = | 1230 VariableElementImpl variableElement = |
| 815 element.variable as VariableElementImpl; | 1231 element.variable as VariableElementImpl; |
| 816 elementAnnotation.evaluationResult = variableElement.evaluationResult; | 1232 elementAnnotation.evaluationResult = variableElement.evaluationResult; |
| 817 } else if (element is ConstructorElementImpl && | 1233 } else if (element is ConstructorElementImpl && |
| 818 constNode.arguments != null) { | 1234 constNode.arguments != null) { |
| 819 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1235 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 820 CompilationUnit sourceCompilationUnit = | 1236 CompilationUnit sourceCompilationUnit = |
| 821 constNode.getAncestor((node) => node is CompilationUnit); | 1237 constNode.getAncestor((node) => node is CompilationUnit); |
| 822 ErrorReporter errorReporter = new ErrorReporter( | 1238 ErrorReporter errorReporter = new ErrorReporter( |
| 823 errorListener, sourceCompilationUnit.element.source); | 1239 errorListener, sourceCompilationUnit.element.source); |
| 824 ConstantVisitor constantVisitor = new ConstantVisitor( | 1240 ConstantVisitor constantVisitor = |
| 825 typeProvider, errorReporter, validator: validator); | 1241 new ConstantVisitor(evaluationEngine, errorReporter); |
| 826 DartObjectImpl result = _evaluateConstructorCall(constNode, | 1242 DartObjectImpl result = evaluationEngine.evaluateConstructorCall( |
| 827 constNode.arguments.arguments, element, constantVisitor, | 1243 constNode, constNode.arguments.arguments, element, |
| 828 errorReporter); | 1244 constantVisitor, errorReporter); |
| 829 elementAnnotation.evaluationResult = | 1245 elementAnnotation.evaluationResult = |
| 830 new EvaluationResultImpl.con2(result, errorListener.errors); | 1246 new EvaluationResultImpl.con2(result, errorListener.errors); |
| 831 } else { | 1247 } else { |
| 832 // This may happen for invalid code (e.g. failing to pass arguments | 1248 // This may happen for invalid code (e.g. failing to pass arguments |
| 833 // to an annotation which references a const constructor). The error | 1249 // to an annotation which references a const constructor). The error |
| 834 // is detected elsewhere, so just silently ignore it here. | 1250 // is detected elsewhere, so just silently ignore it here. |
| 835 elementAnnotation.evaluationResult = | 1251 elementAnnotation.evaluationResult = |
| 836 new EvaluationResultImpl.con1(null); | 1252 new EvaluationResultImpl.con1(null); |
| 837 } | 1253 } |
| 838 } | 1254 } |
| 839 } else { | 1255 } else { |
| 840 // Should not happen. | 1256 // Should not happen. |
| 841 AnalysisEngine.instance.logger.logError( | 1257 AnalysisEngine.instance.logger.logError( |
| 842 "Constant value computer trying to compute the value of a node which i
s not a VariableDeclaration, InstanceCreationExpression, FormalParameter, or Con
structorDeclaration"); | 1258 "Constant value computer trying to compute the value of a node which i
s not a VariableDeclaration, InstanceCreationExpression, FormalParameter, or Con
structorDeclaration"); |
| 843 return; | 1259 return; |
| 844 } | 1260 } |
| 845 } | 1261 } |
| 846 | 1262 |
| 847 /** | 1263 /** |
| 848 * Evaluate a call to fromEnvironment() on the bool, int, or String class. The | |
| 849 * [environmentValue] is the value fetched from the environment. The | |
| 850 * [builtInDefaultValue] is the value that should be used as the default if no | |
| 851 * "defaultValue" argument appears in [namedArgumentValues]. The | |
| 852 * [namedArgumentValues] are the values of the named parameters passed to | |
| 853 * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the | |
| 854 * evaluated result. | |
| 855 */ | |
| 856 DartObjectImpl _computeValueFromEnvironment(DartObject environmentValue, | |
| 857 DartObjectImpl builtInDefaultValue, | |
| 858 HashMap<String, DartObjectImpl> namedArgumentValues) { | |
| 859 DartObjectImpl value = environmentValue as DartObjectImpl; | |
| 860 if (value.isUnknown || value.isNull) { | |
| 861 // The name either doesn't exist in the environment or we couldn't parse | |
| 862 // the corresponding value. | |
| 863 // If the code supplied an explicit default, use it. | |
| 864 if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) { | |
| 865 value = namedArgumentValues[_DEFAULT_VALUE_PARAM]; | |
| 866 } else if (value.isNull) { | |
| 867 // The code didn't supply an explicit default. | |
| 868 // The name exists in the environment but we couldn't parse the | |
| 869 // corresponding value. | |
| 870 // So use the built-in default value, because this is what the VM does. | |
| 871 value = builtInDefaultValue; | |
| 872 } else { | |
| 873 // The code didn't supply an explicit default. | |
| 874 // The name doesn't exist in the environment. | |
| 875 // The VM would use the built-in default value, but we don't want to do | |
| 876 // that for analysis because it's likely to lead to cascading errors. | |
| 877 // So just leave [value] in the unknown state. | |
| 878 } | |
| 879 } | |
| 880 return value; | |
| 881 } | |
| 882 | |
| 883 DartObjectImpl _evaluateConstructorCall(AstNode node, | |
| 884 NodeList<Expression> arguments, ConstructorElement constructor, | |
| 885 ConstantVisitor constantVisitor, ErrorReporter errorReporter) { | |
| 886 if (!_getConstructorBase(constructor).isCycleFree) { | |
| 887 // It's not safe to evaluate this constructor, so bail out. | |
| 888 // TODO(paulberry): ensure that a reasonable error message is produced | |
| 889 // in this case, as well as other cases involving constant expression | |
| 890 // circularities (e.g. "compile-time constant expression depends on | |
| 891 // itself") | |
| 892 return new DartObjectImpl.validWithUnknownValue(constructor.returnType); | |
| 893 } | |
| 894 int argumentCount = arguments.length; | |
| 895 List<DartObjectImpl> argumentValues = | |
| 896 new List<DartObjectImpl>(argumentCount); | |
| 897 List<Expression> argumentNodes = new List<Expression>(argumentCount); | |
| 898 HashMap<String, DartObjectImpl> namedArgumentValues = | |
| 899 new HashMap<String, DartObjectImpl>(); | |
| 900 HashMap<String, NamedExpression> namedArgumentNodes = | |
| 901 new HashMap<String, NamedExpression>(); | |
| 902 for (int i = 0; i < argumentCount; i++) { | |
| 903 Expression argument = arguments[i]; | |
| 904 if (argument is NamedExpression) { | |
| 905 String name = argument.name.label.name; | |
| 906 namedArgumentValues[name] = | |
| 907 constantVisitor._valueOf(argument.expression); | |
| 908 namedArgumentNodes[name] = argument; | |
| 909 argumentValues[i] = typeProvider.nullObject; | |
| 910 } else { | |
| 911 argumentValues[i] = constantVisitor._valueOf(argument); | |
| 912 argumentNodes[i] = argument; | |
| 913 } | |
| 914 } | |
| 915 constructor = _followConstantRedirectionChain(constructor); | |
| 916 InterfaceType definingClass = constructor.returnType as InterfaceType; | |
| 917 if (constructor.isFactory) { | |
| 918 // We couldn't find a non-factory constructor. | |
| 919 // See if it's because we reached an external const factory constructor | |
| 920 // that we can emulate. | |
| 921 if (constructor.name == "fromEnvironment") { | |
| 922 if (!_checkFromEnvironmentArguments( | |
| 923 arguments, argumentValues, namedArgumentValues, definingClass)) { | |
| 924 errorReporter.reportErrorForNode( | |
| 925 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); | |
| 926 return null; | |
| 927 } | |
| 928 String variableName = | |
| 929 argumentCount < 1 ? null : argumentValues[0].stringValue; | |
| 930 if (identical(definingClass, typeProvider.boolType)) { | |
| 931 DartObject valueFromEnvironment; | |
| 932 valueFromEnvironment = | |
| 933 _declaredVariables.getBool(typeProvider, variableName); | |
| 934 return _computeValueFromEnvironment(valueFromEnvironment, | |
| 935 new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE), | |
| 936 namedArgumentValues); | |
| 937 } else if (identical(definingClass, typeProvider.intType)) { | |
| 938 DartObject valueFromEnvironment; | |
| 939 valueFromEnvironment = | |
| 940 _declaredVariables.getInt(typeProvider, variableName); | |
| 941 return _computeValueFromEnvironment(valueFromEnvironment, | |
| 942 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), | |
| 943 namedArgumentValues); | |
| 944 } else if (identical(definingClass, typeProvider.stringType)) { | |
| 945 DartObject valueFromEnvironment; | |
| 946 valueFromEnvironment = | |
| 947 _declaredVariables.getString(typeProvider, variableName); | |
| 948 return _computeValueFromEnvironment(valueFromEnvironment, | |
| 949 new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), | |
| 950 namedArgumentValues); | |
| 951 } | |
| 952 } else if (constructor.name == "" && | |
| 953 identical(definingClass, typeProvider.symbolType) && | |
| 954 argumentCount == 1) { | |
| 955 if (!_checkSymbolArguments( | |
| 956 arguments, argumentValues, namedArgumentValues)) { | |
| 957 errorReporter.reportErrorForNode( | |
| 958 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); | |
| 959 return null; | |
| 960 } | |
| 961 String argumentValue = argumentValues[0].stringValue; | |
| 962 return new DartObjectImpl( | |
| 963 definingClass, new SymbolState(argumentValue)); | |
| 964 } | |
| 965 // Either it's an external const factory constructor that we can't | |
| 966 // emulate, or an error occurred (a cycle, or a const constructor trying | |
| 967 // to delegate to a non-const constructor). | |
| 968 // In the former case, the best we can do is consider it an unknown value. | |
| 969 // In the latter case, the error has already been reported, so considering | |
| 970 // it an unknown value will suppress further errors. | |
| 971 return new DartObjectImpl.validWithUnknownValue(definingClass); | |
| 972 } | |
| 973 validator.beforeGetConstantInitializers(constructor); | |
| 974 ConstructorElementImpl constructorBase = _getConstructorBase(constructor); | |
| 975 List<ConstructorInitializer> initializers = | |
| 976 constructorBase.constantInitializers; | |
| 977 if (initializers == null) { | |
| 978 // This can happen in some cases where there are compile errors in the | |
| 979 // code being analyzed (for example if the code is trying to create a | |
| 980 // const instance using a non-const constructor, or the node we're | |
| 981 // visiting is involved in a cycle). The error has already been reported, | |
| 982 // so consider it an unknown value to suppress further errors. | |
| 983 return new DartObjectImpl.validWithUnknownValue(definingClass); | |
| 984 } | |
| 985 HashMap<String, DartObjectImpl> fieldMap = | |
| 986 new HashMap<String, DartObjectImpl>(); | |
| 987 // Start with final fields that are initialized at their declaration site. | |
| 988 for (FieldElement field in constructor.enclosingElement.fields) { | |
| 989 if ((field.isFinal || field.isConst) && | |
| 990 !field.isStatic && | |
| 991 field is ConstFieldElementImpl) { | |
| 992 validator.beforeGetFieldEvaluationResult(field); | |
| 993 EvaluationResultImpl evaluationResult = field.evaluationResult; | |
| 994 DartType fieldType = | |
| 995 FieldMember.from(field, constructor.returnType).type; | |
| 996 DartObjectImpl fieldValue = evaluationResult.value; | |
| 997 if (fieldValue != null && !_runtimeTypeMatch(fieldValue, fieldType)) { | |
| 998 errorReporter.reportErrorForNode( | |
| 999 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA
TCH, | |
| 1000 node, [fieldValue.type, field.name, fieldType]); | |
| 1001 } | |
| 1002 fieldMap[field.name] = evaluationResult.value; | |
| 1003 } | |
| 1004 } | |
| 1005 // Now evaluate the constructor declaration. | |
| 1006 HashMap<String, DartObjectImpl> parameterMap = | |
| 1007 new HashMap<String, DartObjectImpl>(); | |
| 1008 List<ParameterElement> parameters = constructor.parameters; | |
| 1009 int parameterCount = parameters.length; | |
| 1010 for (int i = 0; i < parameterCount; i++) { | |
| 1011 ParameterElement parameter = parameters[i]; | |
| 1012 ParameterElement baseParameter = parameter; | |
| 1013 while (baseParameter is ParameterMember) { | |
| 1014 baseParameter = (baseParameter as ParameterMember).baseElement; | |
| 1015 } | |
| 1016 DartObjectImpl argumentValue = null; | |
| 1017 AstNode errorTarget = null; | |
| 1018 if (baseParameter.parameterKind == ParameterKind.NAMED) { | |
| 1019 argumentValue = namedArgumentValues[baseParameter.name]; | |
| 1020 errorTarget = namedArgumentNodes[baseParameter.name]; | |
| 1021 } else if (i < argumentCount) { | |
| 1022 argumentValue = argumentValues[i]; | |
| 1023 errorTarget = argumentNodes[i]; | |
| 1024 } | |
| 1025 if (errorTarget == null) { | |
| 1026 // No argument node that we can direct error messages to, because we | |
| 1027 // are handling an optional parameter that wasn't specified. So just | |
| 1028 // direct error messages to the constructor call. | |
| 1029 errorTarget = node; | |
| 1030 } | |
| 1031 if (argumentValue == null && baseParameter is ParameterElementImpl) { | |
| 1032 // The parameter is an optional positional parameter for which no value | |
| 1033 // was provided, so use the default value. | |
| 1034 validator.beforeGetParameterDefault(baseParameter); | |
| 1035 EvaluationResultImpl evaluationResult = baseParameter.evaluationResult; | |
| 1036 if (evaluationResult == null) { | |
| 1037 // No default was provided, so the default value is null. | |
| 1038 argumentValue = typeProvider.nullObject; | |
| 1039 } else if (evaluationResult.value != null) { | |
| 1040 argumentValue = evaluationResult.value; | |
| 1041 } | |
| 1042 } | |
| 1043 if (argumentValue != null) { | |
| 1044 if (!_runtimeTypeMatch(argumentValue, parameter.type)) { | |
| 1045 errorReporter.reportErrorForNode( | |
| 1046 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA
TCH, | |
| 1047 errorTarget, [argumentValue.type, parameter.type]); | |
| 1048 } | |
| 1049 if (baseParameter.isInitializingFormal) { | |
| 1050 FieldElement field = (parameter as FieldFormalParameterElement).field; | |
| 1051 if (field != null) { | |
| 1052 DartType fieldType = field.type; | |
| 1053 if (fieldType != parameter.type) { | |
| 1054 // We've already checked that the argument can be assigned to the | |
| 1055 // parameter; we also need to check that it can be assigned to | |
| 1056 // the field. | |
| 1057 if (!_runtimeTypeMatch(argumentValue, fieldType)) { | |
| 1058 errorReporter.reportErrorForNode( | |
| 1059 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE
_MISMATCH, | |
| 1060 errorTarget, [argumentValue.type, fieldType]); | |
| 1061 } | |
| 1062 } | |
| 1063 String fieldName = field.name; | |
| 1064 fieldMap[fieldName] = argumentValue; | |
| 1065 } | |
| 1066 } else { | |
| 1067 String name = baseParameter.name; | |
| 1068 parameterMap[name] = argumentValue; | |
| 1069 } | |
| 1070 } | |
| 1071 } | |
| 1072 ConstantVisitor initializerVisitor = new ConstantVisitor( | |
| 1073 typeProvider, errorReporter, | |
| 1074 validator: validator, lexicalEnvironment: parameterMap); | |
| 1075 String superName = null; | |
| 1076 NodeList<Expression> superArguments = null; | |
| 1077 for (ConstructorInitializer initializer in initializers) { | |
| 1078 if (initializer is ConstructorFieldInitializer) { | |
| 1079 ConstructorFieldInitializer constructorFieldInitializer = initializer; | |
| 1080 Expression initializerExpression = | |
| 1081 constructorFieldInitializer.expression; | |
| 1082 DartObjectImpl evaluationResult = | |
| 1083 initializerExpression.accept(initializerVisitor); | |
| 1084 if (evaluationResult != null) { | |
| 1085 String fieldName = constructorFieldInitializer.fieldName.name; | |
| 1086 fieldMap[fieldName] = evaluationResult; | |
| 1087 PropertyAccessorElement getter = definingClass.getGetter(fieldName); | |
| 1088 if (getter != null) { | |
| 1089 PropertyInducingElement field = getter.variable; | |
| 1090 if (!_runtimeTypeMatch(evaluationResult, field.type)) { | |
| 1091 errorReporter.reportErrorForNode( | |
| 1092 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_M
ISMATCH, | |
| 1093 node, [evaluationResult.type, fieldName, field.type]); | |
| 1094 } | |
| 1095 } | |
| 1096 } | |
| 1097 } else if (initializer is SuperConstructorInvocation) { | |
| 1098 SuperConstructorInvocation superConstructorInvocation = initializer; | |
| 1099 SimpleIdentifier name = superConstructorInvocation.constructorName; | |
| 1100 if (name != null) { | |
| 1101 superName = name.name; | |
| 1102 } | |
| 1103 superArguments = superConstructorInvocation.argumentList.arguments; | |
| 1104 } else if (initializer is RedirectingConstructorInvocation) { | |
| 1105 // This is a redirecting constructor, so just evaluate the constructor | |
| 1106 // it redirects to. | |
| 1107 ConstructorElement constructor = initializer.staticElement; | |
| 1108 if (constructor != null && constructor.isConst) { | |
| 1109 return _evaluateConstructorCall(node, | |
| 1110 initializer.argumentList.arguments, constructor, | |
| 1111 initializerVisitor, errorReporter); | |
| 1112 } | |
| 1113 } | |
| 1114 } | |
| 1115 // Evaluate explicit or implicit call to super(). | |
| 1116 InterfaceType superclass = definingClass.superclass; | |
| 1117 if (superclass != null && !superclass.isObject) { | |
| 1118 ConstructorElement superConstructor = | |
| 1119 superclass.lookUpConstructor(superName, constructor.library); | |
| 1120 if (superConstructor != null) { | |
| 1121 if (superArguments == null) { | |
| 1122 superArguments = new NodeList<Expression>(null); | |
| 1123 } | |
| 1124 _evaluateSuperConstructorCall(node, fieldMap, superConstructor, | |
| 1125 superArguments, initializerVisitor, errorReporter); | |
| 1126 } | |
| 1127 } | |
| 1128 return new DartObjectImpl(definingClass, new GenericState(fieldMap)); | |
| 1129 } | |
| 1130 | |
| 1131 void _evaluateSuperConstructorCall(AstNode node, | |
| 1132 HashMap<String, DartObjectImpl> fieldMap, | |
| 1133 ConstructorElement superConstructor, NodeList<Expression> superArguments, | |
| 1134 ConstantVisitor initializerVisitor, ErrorReporter errorReporter) { | |
| 1135 if (superConstructor != null && superConstructor.isConst) { | |
| 1136 DartObjectImpl evaluationResult = _evaluateConstructorCall(node, | |
| 1137 superArguments, superConstructor, initializerVisitor, errorReporter); | |
| 1138 if (evaluationResult != null) { | |
| 1139 fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult; | |
| 1140 } | |
| 1141 } | |
| 1142 } | |
| 1143 | |
| 1144 /** | |
| 1145 * Attempt to follow the chain of factory redirections until a constructor is | |
| 1146 * reached which is not a const factory constructor. Return the constant | |
| 1147 * constructor which terminates the chain of factory redirections, if the | |
| 1148 * chain terminates. If there is a problem (e.g. a redirection can't be found, | |
| 1149 * or a cycle is encountered), the chain will be followed as far as possible | |
| 1150 * and then a const factory constructor will be returned. | |
| 1151 */ | |
| 1152 ConstructorElement _followConstantRedirectionChain( | |
| 1153 ConstructorElement constructor) { | |
| 1154 HashSet<ConstructorElement> constructorsVisited = | |
| 1155 new HashSet<ConstructorElement>(); | |
| 1156 while (true) { | |
| 1157 ConstructorElement redirectedConstructor = | |
| 1158 _getConstRedirectedConstructor(constructor); | |
| 1159 if (redirectedConstructor == null) { | |
| 1160 break; | |
| 1161 } else { | |
| 1162 ConstructorElement constructorBase = _getConstructorBase(constructor); | |
| 1163 constructorsVisited.add(constructorBase); | |
| 1164 ConstructorElement redirectedConstructorBase = | |
| 1165 _getConstructorBase(redirectedConstructor); | |
| 1166 if (constructorsVisited.contains(redirectedConstructorBase)) { | |
| 1167 // Cycle in redirecting factory constructors--this is not allowed | |
| 1168 // and is checked elsewhere--see | |
| 1169 // [ErrorVerifier.checkForRecursiveFactoryRedirect()]). | |
| 1170 break; | |
| 1171 } | |
| 1172 } | |
| 1173 constructor = redirectedConstructor; | |
| 1174 } | |
| 1175 return constructor; | |
| 1176 } | |
| 1177 | |
| 1178 /** | |
| 1179 * Generate an error indicating that the given [constant] is not a valid | 1264 * Generate an error indicating that the given [constant] is not a valid |
| 1180 * compile-time constant because it references at least one of the constants | 1265 * compile-time constant because it references at least one of the constants |
| 1181 * in the given [cycle], each of which directly or indirectly references the | 1266 * in the given [cycle], each of which directly or indirectly references the |
| 1182 * constant. | 1267 * constant. |
| 1183 */ | 1268 */ |
| 1184 void _generateCycleError(List<AstNode> cycle, AstNode constant) { | 1269 void _generateCycleError(List<AstNode> cycle, AstNode constant) { |
| 1185 // TODO(brianwilkerson) Implement this. | 1270 // TODO(brianwilkerson) Implement this. |
| 1186 } | 1271 } |
| 1187 | |
| 1188 /** | |
| 1189 * If [constructor] redirects to another const constructor, return the | |
| 1190 * const constructor it redirects to. Otherwise return `null`. | |
| 1191 */ | |
| 1192 ConstructorElement _getConstRedirectedConstructor( | |
| 1193 ConstructorElement constructor) { | |
| 1194 if (!constructor.isFactory) { | |
| 1195 return null; | |
| 1196 } | |
| 1197 if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) { | |
| 1198 // The dart:core.Symbol has a const factory constructor that redirects | |
| 1199 // to dart:_internal.Symbol. That in turn redirects to an external | |
| 1200 // const constructor, which we won't be able to evaluate. | |
| 1201 // So stop following the chain of redirections at dart:core.Symbol, and | |
| 1202 // let [evaluateInstanceCreationExpression] handle it specially. | |
| 1203 return null; | |
| 1204 } | |
| 1205 ConstructorElement redirectedConstructor = | |
| 1206 constructor.redirectedConstructor; | |
| 1207 if (redirectedConstructor == null) { | |
| 1208 // This can happen if constructor is an external factory constructor. | |
| 1209 return null; | |
| 1210 } | |
| 1211 if (!redirectedConstructor.isConst) { | |
| 1212 // Delegating to a non-const constructor--this is not allowed (and | |
| 1213 // is checked elsewhere--see | |
| 1214 // [ErrorVerifier.checkForRedirectToNonConstConstructor()]). | |
| 1215 return null; | |
| 1216 } | |
| 1217 return redirectedConstructor; | |
| 1218 } | |
| 1219 | |
| 1220 ConstructorElementImpl _getConstructorBase(ConstructorElement constructor) { | |
| 1221 while (constructor is ConstructorMember) { | |
| 1222 constructor = (constructor as ConstructorMember).baseElement; | |
| 1223 } | |
| 1224 return constructor; | |
| 1225 } | |
| 1226 | |
| 1227 /** | |
| 1228 * Check if the object [obj] matches the type [type] according to runtime type | |
| 1229 * checking rules. | |
| 1230 */ | |
| 1231 bool _runtimeTypeMatch(DartObjectImpl obj, DartType type) { | |
| 1232 if (obj.isNull) { | |
| 1233 return true; | |
| 1234 } | |
| 1235 if (type.isUndefined) { | |
| 1236 return false; | |
| 1237 } | |
| 1238 return obj.type.isSubtypeOf(type); | |
| 1239 } | |
| 1240 | |
| 1241 /** | |
| 1242 * Determine whether the given string is a valid name for a public symbol | |
| 1243 * (i.e. whether it is allowed for a call to the Symbol constructor). | |
| 1244 */ | |
| 1245 static bool isValidPublicSymbol(String name) => name.isEmpty || | |
| 1246 name == "void" || | |
| 1247 new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches(); | |
| 1248 } | 1272 } |
| 1249 | 1273 |
| 1250 /** | 1274 /** |
| 1251 * A visitor used to evaluate constant expressions to produce their compile-time | 1275 * A visitor used to evaluate constant expressions to produce their compile-time |
| 1252 * value. According to the Dart Language Specification: <blockquote> A constant | 1276 * value. According to the Dart Language Specification: <blockquote> A constant |
| 1253 * expression is one of the following: | 1277 * expression is one of the following: |
| 1254 * | 1278 * |
| 1255 * * A literal number. | 1279 * * A literal number. |
| 1256 * * A literal boolean. | 1280 * * A literal boolean. |
| 1257 * * A literal string where any interpolated expression is a compile-time | 1281 * * A literal string where any interpolated expression is a compile-time |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1299 * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> : | 1323 * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> : |
| 1300 * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and | 1324 * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and |
| 1301 * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i> | 1325 * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i> |
| 1302 * evaluates to a boolean value. | 1326 * evaluates to a boolean value. |
| 1303 * </blockquote> | 1327 * </blockquote> |
| 1304 */ | 1328 */ |
| 1305 class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { | 1329 class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { |
| 1306 /** | 1330 /** |
| 1307 * The type provider used to access the known types. | 1331 * The type provider used to access the known types. |
| 1308 */ | 1332 */ |
| 1309 final TypeProvider _typeProvider; | 1333 final ConstantEvaluationEngine evaluationEngine; |
| 1310 | 1334 |
| 1311 final HashMap<String, DartObjectImpl> _lexicalEnvironment; | 1335 final HashMap<String, DartObjectImpl> _lexicalEnvironment; |
| 1312 | 1336 |
| 1313 /** | 1337 /** |
| 1314 * Validator used to verify correct dependency analysis when running unit | |
| 1315 * tests. | |
| 1316 */ | |
| 1317 final ConstantEvaluationValidator validator; | |
| 1318 | |
| 1319 /** | |
| 1320 * Error reporter that we use to report errors accumulated while computing the | 1338 * Error reporter that we use to report errors accumulated while computing the |
| 1321 * constant. | 1339 * constant. |
| 1322 */ | 1340 */ |
| 1323 final ErrorReporter _errorReporter; | 1341 final ErrorReporter _errorReporter; |
| 1324 | 1342 |
| 1325 /** | 1343 /** |
| 1326 * Helper class used to compute constant values. | 1344 * Helper class used to compute constant values. |
| 1327 */ | 1345 */ |
| 1328 DartObjectComputer _dartObjectComputer; | 1346 DartObjectComputer _dartObjectComputer; |
| 1329 | 1347 |
| 1330 /** | 1348 /** |
| 1331 * Initialize a newly created constant visitor. The [_typeProvider] is the | 1349 * Initialize a newly created constant visitor. The [evaluationEngine] is |
| 1332 * type provider used to access known types. The [lexicalEnvironment] is a | 1350 * used to evaluate instance creation expressions. The [lexicalEnvironment] |
| 1333 * map containing values which should override identifiers, or `null` if no | 1351 * is a map containing values which should override identifiers, or `null` if |
| 1334 * overriding is necessary. The [_errorReporter] is used to report errors | 1352 * no overriding is necessary. The [_errorReporter] is used to report errors |
| 1335 * found during evaluation. The [validator] is used by unit tests to verify | 1353 * found during evaluation. The [validator] is used by unit tests to verify |
| 1336 * correct dependency analysis. | 1354 * correct dependency analysis. |
| 1337 */ | 1355 */ |
| 1338 ConstantVisitor(this._typeProvider, this._errorReporter, | 1356 ConstantVisitor(this.evaluationEngine, this._errorReporter, |
| 1339 {ConstantEvaluationValidator validator, | 1357 {HashMap<String, DartObjectImpl> lexicalEnvironment}) |
| 1340 HashMap<String, DartObjectImpl> lexicalEnvironment}) | 1358 : _lexicalEnvironment = lexicalEnvironment { |
| 1341 : validator = validator != null | |
| 1342 ? validator | |
| 1343 : new ConstantEvaluationValidator_ForProduction(), | |
| 1344 _lexicalEnvironment = lexicalEnvironment { | |
| 1345 this._dartObjectComputer = | 1359 this._dartObjectComputer = |
| 1346 new DartObjectComputer(_errorReporter, _typeProvider); | 1360 new DartObjectComputer(_errorReporter, evaluationEngine.typeProvider); |
| 1347 } | 1361 } |
| 1348 | 1362 |
| 1363 /** |
| 1364 * Convenience getter to gain access to the [evalationEngine]'s type |
| 1365 * provider. |
| 1366 */ |
| 1367 TypeProvider get _typeProvider => evaluationEngine.typeProvider; |
| 1368 |
| 1349 @override | 1369 @override |
| 1350 DartObjectImpl visitAdjacentStrings(AdjacentStrings node) { | 1370 DartObjectImpl visitAdjacentStrings(AdjacentStrings node) { |
| 1351 DartObjectImpl result = null; | 1371 DartObjectImpl result = null; |
| 1352 for (StringLiteral string in node.strings) { | 1372 for (StringLiteral string in node.strings) { |
| 1353 if (result == null) { | 1373 if (result == null) { |
| 1354 result = string.accept(this); | 1374 result = string.accept(this); |
| 1355 } else { | 1375 } else { |
| 1356 result = | 1376 result = |
| 1357 _dartObjectComputer.concatenate(node, result, string.accept(this)); | 1377 _dartObjectComputer.concatenate(node, result, string.accept(this)); |
| 1358 } | 1378 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value)); | 1486 new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value)); |
| 1467 | 1487 |
| 1468 @override | 1488 @override |
| 1469 DartObjectImpl visitInstanceCreationExpression( | 1489 DartObjectImpl visitInstanceCreationExpression( |
| 1470 InstanceCreationExpression node) { | 1490 InstanceCreationExpression node) { |
| 1471 if (!node.isConst) { | 1491 if (!node.isConst) { |
| 1472 // TODO(brianwilkerson) Figure out which error to report. | 1492 // TODO(brianwilkerson) Figure out which error to report. |
| 1473 _error(node, null); | 1493 _error(node, null); |
| 1474 return null; | 1494 return null; |
| 1475 } | 1495 } |
| 1476 validator.beforeGetEvaluationResult(node); | 1496 evaluationEngine.validator.beforeGetEvaluationResult(node); |
| 1477 EvaluationResultImpl result = node.evaluationResult; | 1497 EvaluationResultImpl result = node.evaluationResult; |
| 1478 if (result != null) { | 1498 if (result != null) { |
| 1479 return result.value; | 1499 return result.value; |
| 1480 } | 1500 } |
| 1481 // TODO(brianwilkerson) Figure out which error to report. | 1501 // TODO(brianwilkerson) Figure out which error to report. |
| 1482 _error(node, null); | 1502 _error(node, null); |
| 1483 return null; | 1503 return null; |
| 1484 } | 1504 } |
| 1485 | 1505 |
| 1486 @override | 1506 @override |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1730 * Return the constant value of the static constant represented by the given | 1750 * Return the constant value of the static constant represented by the given |
| 1731 * [element]. The [node] is the node to be used if an error needs to be | 1751 * [element]. The [node] is the node to be used if an error needs to be |
| 1732 * reported. | 1752 * reported. |
| 1733 */ | 1753 */ |
| 1734 DartObjectImpl _getConstantValue(AstNode node, Element element) { | 1754 DartObjectImpl _getConstantValue(AstNode node, Element element) { |
| 1735 if (element is PropertyAccessorElement) { | 1755 if (element is PropertyAccessorElement) { |
| 1736 element = (element as PropertyAccessorElement).variable; | 1756 element = (element as PropertyAccessorElement).variable; |
| 1737 } | 1757 } |
| 1738 if (element is VariableElementImpl) { | 1758 if (element is VariableElementImpl) { |
| 1739 VariableElementImpl variableElementImpl = element; | 1759 VariableElementImpl variableElementImpl = element; |
| 1740 validator.beforeGetEvaluationResult(node); | 1760 evaluationEngine.validator.beforeGetEvaluationResult(node); |
| 1741 EvaluationResultImpl value = variableElementImpl.evaluationResult; | 1761 EvaluationResultImpl value = variableElementImpl.evaluationResult; |
| 1742 if (variableElementImpl.isConst && value != null) { | 1762 if (variableElementImpl.isConst && value != null) { |
| 1743 return value.value; | 1763 return value.value; |
| 1744 } | 1764 } |
| 1745 } else if (element is ExecutableElement) { | 1765 } else if (element is ExecutableElement) { |
| 1746 ExecutableElement function = element; | 1766 ExecutableElement function = element; |
| 1747 if (function.isStatic) { | 1767 if (function.isStatic) { |
| 1748 ParameterizedType functionType = function.type; | 1768 ParameterizedType functionType = function.type; |
| 1749 if (functionType == null) { | 1769 if (functionType == null) { |
| 1750 functionType = _typeProvider.functionType; | 1770 functionType = _typeProvider.functionType; |
| (...skipping 3449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5200 return BoolState.from(_element == rightElement); | 5220 return BoolState.from(_element == rightElement); |
| 5201 } else if (rightOperand is DynamicState) { | 5221 } else if (rightOperand is DynamicState) { |
| 5202 return BoolState.UNKNOWN_VALUE; | 5222 return BoolState.UNKNOWN_VALUE; |
| 5203 } | 5223 } |
| 5204 return BoolState.FALSE_STATE; | 5224 return BoolState.FALSE_STATE; |
| 5205 } | 5225 } |
| 5206 | 5226 |
| 5207 @override | 5227 @override |
| 5208 String toString() => _element == null ? "-unknown-" : _element.name; | 5228 String toString() => _element == null ? "-unknown-" : _element.name; |
| 5209 } | 5229 } |
| OLD | NEW |