| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.resolution.members; | 5 library dart2js.resolution.members; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/names.dart' show | 8 import '../common/names.dart' show |
| 9 Selectors; | 9 Selectors; |
| 10 import '../compiler.dart' show | 10 import '../compiler.dart' show |
| 11 Compiler; | 11 Compiler; |
| 12 import '../constants/constructors.dart' show | 12 import '../constants/constructors.dart' show |
| 13 ErroneousConstantConstructor, |
| 13 RedirectingFactoryConstantConstructor; | 14 RedirectingFactoryConstantConstructor; |
| 15 import '../constants/evaluation.dart' show |
| 16 ConstantTypeChecker, |
| 17 ConstantTypeInfo; |
| 14 import '../constants/expressions.dart'; | 18 import '../constants/expressions.dart'; |
| 15 import '../constants/values.dart'; | 19 import '../constants/values.dart'; |
| 16 import '../core_types.dart'; | 20 import '../core_types.dart'; |
| 17 import '../dart_types.dart'; | 21 import '../dart_types.dart'; |
| 18 import '../elements/elements.dart'; | 22 import '../elements/elements.dart'; |
| 19 import '../elements/modelx.dart' show | 23 import '../elements/modelx.dart' show |
| 20 ConstructorElementX, | 24 ConstructorElementX, |
| 21 ErroneousElementX, | 25 ErroneousElementX, |
| 22 FunctionElementX, | 26 FunctionElementX, |
| 23 JumpTargetX, | 27 JumpTargetX, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 import 'scope.dart' show | 64 import 'scope.dart' show |
| 61 BlockScope, | 65 BlockScope, |
| 62 MethodScope, | 66 MethodScope, |
| 63 Scope; | 67 Scope; |
| 64 import 'signatures.dart' show | 68 import 'signatures.dart' show |
| 65 SignatureResolver; | 69 SignatureResolver; |
| 66 import 'variables.dart' show | 70 import 'variables.dart' show |
| 67 VariableDefinitionsVisitor; | 71 VariableDefinitionsVisitor; |
| 68 | 72 |
| 69 /// The state of constants in resolutions. | 73 /// The state of constants in resolutions. |
| 70 enum ConstantState { | 74 abstract class ConstantState { |
| 71 /// Expressions are not required to be constants. | |
| 72 NON_CONSTANT, | |
| 73 | 75 |
| 74 /// Expressions are required to be constants. | 76 /// `true` if expressions are required to be constant. |
| 77 bool get requiresConstant; |
| 78 |
| 79 /// `true` if parameter references are considered constant. This is the case |
| 80 /// in const constructor initializers. |
| 81 bool get parameterReferenceIsConstant; |
| 82 |
| 83 /// Returns the constant state corresponding to this state but where |
| 84 /// expression are required to be constants. |
| 85 ConstantState get requireConstant; |
| 86 |
| 87 /// Constant state where expressions are not required to be constants. |
| 88 static const ConstantState NON_CONSTANT = const _NoneConstantState(); |
| 89 |
| 90 /// Constant state where expressions are required to be constants. |
| 75 /// | 91 /// |
| 76 /// For instance the values of a constant list literal. | 92 /// For instance the values of a constant list literal. |
| 77 CONSTANT, | 93 static const ConstantState CONSTANT = const _RequiredConstantState(); |
| 78 | 94 |
| 79 /// Expressions are required to be constants and parameter references are | 95 /// Constant state where expressions are required to be constants and |
| 80 /// also considered constant. | 96 /// parameter references are also considered constant. |
| 81 /// | 97 /// |
| 82 /// This is used for resolving constructor initializers of constant | 98 /// This is used for resolving constructor initializers of constant |
| 83 /// constructors. | 99 /// constructors. |
| 84 CONSTANT_INITIALIZER, | 100 static const ConstantState CONSTANT_INITIALIZER = |
| 101 const _ConstantInitializerState(); |
| 102 } |
| 103 |
| 104 /// Constant state where expressions are not required to be constants. |
| 105 class _NoneConstantState implements ConstantState { |
| 106 const _NoneConstantState(); |
| 107 |
| 108 @override |
| 109 bool get requiresConstant => false; |
| 110 |
| 111 @override |
| 112 bool get parameterReferenceIsConstant => false; |
| 113 |
| 114 @override |
| 115 ConstantState get requireConstant => ConstantState.CONSTANT; |
| 116 } |
| 117 |
| 118 /// Constant state where expressions are required to be constants. |
| 119 /// |
| 120 /// For instance the values of a constant list literal. |
| 121 class _RequiredConstantState implements ConstantState { |
| 122 const _RequiredConstantState(); |
| 123 |
| 124 @override |
| 125 bool get requiresConstant => true; |
| 126 |
| 127 @override |
| 128 bool get parameterReferenceIsConstant => false; |
| 129 |
| 130 @override |
| 131 ConstantState get requireConstant => this; |
| 132 } |
| 133 |
| 134 /// Constant state where expressions are required to be constants and parameter |
| 135 /// references are also considered constant. |
| 136 /// |
| 137 /// This is used for resolving constructor initializers of constant |
| 138 /// constructors. |
| 139 class _ConstantInitializerState implements ConstantState { |
| 140 const _ConstantInitializerState(); |
| 141 |
| 142 @override |
| 143 bool get requiresConstant => true; |
| 144 |
| 145 @override |
| 146 bool get parameterReferenceIsConstant => true; |
| 147 |
| 148 @override |
| 149 ConstantState get requireConstant => this; |
| 85 } | 150 } |
| 86 | 151 |
| 87 /** | 152 /** |
| 88 * Core implementation of resolution. | 153 * Core implementation of resolution. |
| 89 * | 154 * |
| 90 * Do not subclass or instantiate this class outside this library | 155 * Do not subclass or instantiate this class outside this library |
| 91 * except for testing. | 156 * except for testing. |
| 92 */ | 157 */ |
| 93 class ResolverVisitor extends MappingVisitor<ResolutionResult> { | 158 class ResolverVisitor extends MappingVisitor<ResolutionResult> { |
| 94 /** | 159 /** |
| 95 * The current enclosing element for the visited AST nodes. | 160 * The current enclosing element for the visited AST nodes. |
| 96 * | 161 * |
| 97 * This field is updated when nested closures are visited. | 162 * This field is updated when nested closures are visited. |
| 98 */ | 163 */ |
| 99 Element enclosingElement; | 164 Element enclosingElement; |
| 100 | 165 |
| 101 /// Whether we are in a context where `this` is accessible (this will be false | 166 /// Whether we are in a context where `this` is accessible (this will be false |
| 102 /// in static contexts, factory methods, and field initializers). | 167 /// in static contexts, factory methods, and field initializers). |
| 103 bool inInstanceContext; | 168 bool inInstanceContext; |
| 104 bool inCheckContext; | 169 bool inCheckContext; |
| 105 bool inCatchBlock; | 170 bool inCatchBlock; |
| 106 ConstantState constantState; | 171 ConstantState constantState; |
| 172 final ConstantNodeChecker constantExpressionChecker; |
| 173 final ConstantNodeChecker constantExpressionValidator; |
| 107 | 174 |
| 108 Scope scope; | 175 Scope scope; |
| 109 ClassElement currentClass; | 176 ClassElement currentClass; |
| 110 ExpressionStatement currentExpressionStatement; | 177 ExpressionStatement currentExpressionStatement; |
| 111 | 178 |
| 112 /// `true` if a [Send] or [SendSet] is visited as the prefix of member access. | 179 /// `true` if a [Send] or [SendSet] is visited as the prefix of member access. |
| 113 /// For instance `Class` in `Class.staticField` or `prefix.Class` in | 180 /// For instance `Class` in `Class.staticField` or `prefix.Class` in |
| 114 /// `prefix.Class.staticMethod()`. | 181 /// `prefix.Class.staticMethod()`. |
| 115 bool sendIsMemberAccess = false; | 182 bool sendIsMemberAccess = false; |
| 116 | 183 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 ? Scope.buildEnclosingScope(element) : element.buildScope(), | 242 ? Scope.buildEnclosingScope(element) : element.buildScope(), |
| 176 // The type annotations on a typedef do not imply type checks. | 243 // The type annotations on a typedef do not imply type checks. |
| 177 // TODO(karlklose): clean this up (dartbug.com/8870). | 244 // TODO(karlklose): clean this up (dartbug.com/8870). |
| 178 inCheckContext = compiler.enableTypeAssertions && | 245 inCheckContext = compiler.enableTypeAssertions && |
| 179 !element.isLibrary && | 246 !element.isLibrary && |
| 180 !element.isTypedef && | 247 !element.isTypedef && |
| 181 !element.enclosingElement.isTypedef, | 248 !element.enclosingElement.isTypedef, |
| 182 inCatchBlock = false, | 249 inCatchBlock = false, |
| 183 constantState = element.isConst | 250 constantState = element.isConst |
| 184 ? ConstantState.CONSTANT : ConstantState.NON_CONSTANT, | 251 ? ConstantState.CONSTANT : ConstantState.NON_CONSTANT, |
| 252 constantExpressionChecker = new ConstantNodeChecker( |
| 253 compiler, constantIsRequired: true), |
| 254 constantExpressionValidator = new ConstantNodeChecker( |
| 255 compiler, constantIsRequired: false), |
| 185 super(compiler, registry); | 256 super(compiler, registry); |
| 186 | 257 |
| 187 CoreTypes get coreTypes => compiler.coreTypes; | 258 CoreTypes get coreTypes => compiler.coreTypes; |
| 188 | 259 |
| 260 ConstantNodeChecker get constantChecker { |
| 261 if (constantState.requiresConstant) { |
| 262 return constantExpressionChecker; |
| 263 } else { |
| 264 return constantExpressionValidator; |
| 265 } |
| 266 } |
| 267 |
| 189 AsyncMarker get currentAsyncMarker { | 268 AsyncMarker get currentAsyncMarker { |
| 190 if (enclosingElement is FunctionElement) { | 269 if (enclosingElement is FunctionElement) { |
| 191 FunctionElement function = enclosingElement; | 270 FunctionElement function = enclosingElement; |
| 192 return function.asyncMarker; | 271 return function.asyncMarker; |
| 193 } | 272 } |
| 194 return AsyncMarker.SYNC; | 273 return AsyncMarker.SYNC; |
| 195 } | 274 } |
| 196 | 275 |
| 197 Element reportLookupErrorIfAny(Element result, Node node, String name) { | 276 Element reportLookupErrorIfAny(Element result, Node node, String name) { |
| 198 if (!Elements.isUnresolved(result)) { | 277 if (!Elements.isUnresolved(result)) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 return result; | 336 return result; |
| 258 } | 337 } |
| 259 | 338 |
| 260 ResolutionResult visitInStaticContext(Node node, | 339 ResolutionResult visitInStaticContext(Node node, |
| 261 {bool inConstantInitializer: false}) { | 340 {bool inConstantInitializer: false}) { |
| 262 return inStaticContext( | 341 return inStaticContext( |
| 263 () => visit(node), | 342 () => visit(node), |
| 264 inConstantInitializer: inConstantInitializer); | 343 inConstantInitializer: inConstantInitializer); |
| 265 } | 344 } |
| 266 | 345 |
| 346 /// Execute [action] where the constant state is `ConstantState.NON_CONSTANT`. |
| 347 inNonConstantContext(action()) { |
| 348 ConstantState oldConstantState = constantState; |
| 349 constantState = ConstantState.NON_CONSTANT; |
| 350 var result = action(); |
| 351 constantState = oldConstantState; |
| 352 return result; |
| 353 } |
| 354 |
| 267 /// Execute [action] where the constant state is `ConstantState.CONSTANT` if | 355 /// Execute [action] where the constant state is `ConstantState.CONSTANT` if |
| 268 /// not already `ConstantState.CONSTANT_INITIALIZER`. | 356 /// not already `ConstantState.CONSTANT_INITIALIZER`. |
| 269 inConstantContext(action()) { | 357 inConstantContext(action()) { |
| 270 ConstantState oldConstantState = constantState; | 358 ConstantState oldConstantState = constantState; |
| 271 if (constantState != ConstantState.CONSTANT_INITIALIZER) { | 359 constantState = constantState.requireConstant; |
| 272 constantState = ConstantState.CONSTANT; | |
| 273 } | |
| 274 var result = action(); | 360 var result = action(); |
| 275 constantState = oldConstantState; | 361 constantState = oldConstantState; |
| 276 return result; | 362 return result; |
| 277 } | 363 } |
| 278 | 364 |
| 365 bool checkConstantInvariant(Node node, ResolutionResult result) { |
| 366 return invariant( |
| 367 node, |
| 368 !constantState.requiresConstant || result.isConstant, |
| 369 message: "No constant computed for expression."); |
| 370 } |
| 371 |
| 372 |
| 279 /// Visit [node] where the constant state is `ConstantState.CONSTANT` if | 373 /// Visit [node] where the constant state is `ConstantState.CONSTANT` if |
| 280 /// not already `ConstantState.CONSTANT_INITIALIZER`. | 374 /// not already `ConstantState.CONSTANT_INITIALIZER`. |
| 281 ResolutionResult visitInConstantContext(Node node) { | 375 ResolutionResult visitInConstantContext(Node node) { |
| 282 ResolutionResult result = inConstantContext(() => visit(node)); | 376 ResolutionResult result = inConstantContext(() => visit(node)); |
| 283 assert(invariant(node, result != null, | 377 assert(invariant(node, result != null, |
| 284 message: "No resolution result for $node.")); | 378 message: "No resolution result for $node.")); |
| 285 | 379 |
| 286 return result; | 380 return result; |
| 287 } | 381 } |
| 288 | 382 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 // TODO(karlklose): should be a list of [FormalElement]s, but the actual | 550 // TODO(karlklose): should be a list of [FormalElement]s, but the actual |
| 457 // implementation uses [Element]. | 551 // implementation uses [Element]. |
| 458 List<Element> optionals = functionParameters.optionalParameters; | 552 List<Element> optionals = functionParameters.optionalParameters; |
| 459 if (!optionals.isEmpty && element == optionals.first) { | 553 if (!optionals.isEmpty && element == optionals.first) { |
| 460 NodeList nodes = parameterNodes.head; | 554 NodeList nodes = parameterNodes.head; |
| 461 parameterNodes = nodes.nodes; | 555 parameterNodes = nodes.nodes; |
| 462 } | 556 } |
| 463 if (element.isOptional) { | 557 if (element.isOptional) { |
| 464 if (element.initializer != null) { | 558 if (element.initializer != null) { |
| 465 ResolutionResult result = visitInConstantContext(element.initializer); | 559 ResolutionResult result = visitInConstantContext(element.initializer); |
| 466 if (result.isConstant) { | 560 assert(invariant(element, result.isConstant, |
| 467 element.constant = result.constant; | 561 message: "No default value computed for $element.")); |
| 468 } | 562 element.constant = result.constant; |
| 469 } else { | 563 } else { |
| 470 element.constant = new NullConstantExpression(); | 564 element.constant = new NullConstantExpression(); |
| 471 } | 565 } |
| 472 } | 566 } |
| 473 VariableDefinitions variableDefinitions = parameterNodes.head; | 567 VariableDefinitions variableDefinitions = parameterNodes.head; |
| 474 Node parameterNode = variableDefinitions.definitions.nodes.head; | 568 Node parameterNode = variableDefinitions.definitions.nodes.head; |
| 475 // Field parameters (this.x) are not visible inside the constructor. The | 569 // Field parameters (this.x) are not visible inside the constructor. The |
| 476 // fields they reference are visible, but must be resolved independently. | 570 // fields they reference are visible, but must be resolved independently. |
| 477 if (element.isInitializingFormal) { | 571 if (element.isInitializingFormal) { |
| 478 registry.useElement(parameterNode, element); | 572 registry.useElement(parameterNode, element); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 addToScope(function); | 719 addToScope(function); |
| 626 } | 720 } |
| 627 Scope oldScope = scope; // The scope is modified by [setupFunction]. | 721 Scope oldScope = scope; // The scope is modified by [setupFunction]. |
| 628 setupFunction(node, function); | 722 setupFunction(node, function); |
| 629 | 723 |
| 630 Element previousEnclosingElement = enclosingElement; | 724 Element previousEnclosingElement = enclosingElement; |
| 631 enclosingElement = function; | 725 enclosingElement = function; |
| 632 // Run the body in a fresh statement scope. | 726 // Run the body in a fresh statement scope. |
| 633 StatementScope oldStatementScope = statementScope; | 727 StatementScope oldStatementScope = statementScope; |
| 634 statementScope = new StatementScope(); | 728 statementScope = new StatementScope(); |
| 635 visit(node.body); | 729 inNonConstantContext(() => visit(node.body)); |
| 636 statementScope = oldStatementScope; | 730 statementScope = oldStatementScope; |
| 637 | 731 |
| 638 scope = oldScope; | 732 scope = oldScope; |
| 639 enclosingElement = previousEnclosingElement; | 733 enclosingElement = previousEnclosingElement; |
| 640 | 734 |
| 641 registry.registerClosure(function); | 735 registry.registerClosure(function); |
| 642 registry.registerInstantiatedClass(compiler.functionClass); | 736 registry.registerInstantiatedClass(compiler.functionClass); |
| 643 return const NoneResult(); | 737 return ensureConstantResult(node, const NoneResult()); |
| 738 } |
| 739 |
| 740 ResolutionResult ensureConstantResult(Node node, ResolutionResult result) { |
| 741 if (constantState.requiresConstant && !result.isConstant) { |
| 742 reporter.reportErrorMessage( |
| 743 node, MessageKind.NOT_A_COMPILE_TIME_CONSTANT); |
| 744 return new ConstantResult( |
| 745 node, new ErroneousConstantExpression(), element: result.element); |
| 746 } |
| 747 return result; |
| 644 } | 748 } |
| 645 | 749 |
| 646 ResolutionResult visitIf(If node) { | 750 ResolutionResult visitIf(If node) { |
| 647 doInPromotionScope(node.condition.expression, () => visit(node.condition)); | 751 doInPromotionScope(node.condition.expression, () => visit(node.condition)); |
| 648 doInPromotionScope(node.thenPart, | 752 doInPromotionScope(node.thenPart, |
| 649 () => visitIn(node.thenPart, new BlockScope(scope))); | 753 () => visitIn(node.thenPart, new BlockScope(scope))); |
| 650 visitIn(node.elsePart, new BlockScope(scope)); | 754 visitIn(node.elsePart, new BlockScope(scope)); |
| 651 return const NoneResult(); | 755 return const NoneResult(); |
| 652 } | 756 } |
| 653 | 757 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 bool isValidAsConstant = true; | 838 bool isValidAsConstant = true; |
| 735 List<ResolutionResult> argumentResults = <ResolutionResult>[]; | 839 List<ResolutionResult> argumentResults = <ResolutionResult>[]; |
| 736 bool oldSendIsMemberAccess = sendIsMemberAccess; | 840 bool oldSendIsMemberAccess = sendIsMemberAccess; |
| 737 sendIsMemberAccess = false; | 841 sendIsMemberAccess = false; |
| 738 Map<String, Node> seenNamedArguments = new Map<String, Node>(); | 842 Map<String, Node> seenNamedArguments = new Map<String, Node>(); |
| 739 int argumentCount = 0; | 843 int argumentCount = 0; |
| 740 List<String> namedArguments = <String>[]; | 844 List<String> namedArguments = <String>[]; |
| 741 for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) { | 845 for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) { |
| 742 Expression argument = link.head; | 846 Expression argument = link.head; |
| 743 ResolutionResult result = visit(argument); | 847 ResolutionResult result = visit(argument); |
| 848 assert(checkConstantInvariant(argument, result)); |
| 744 if (!result.isConstant) { | 849 if (!result.isConstant) { |
| 745 isValidAsConstant = false; | 850 isValidAsConstant = false; |
| 746 } | 851 } |
| 747 argumentResults.add(result); | 852 argumentResults.add(result); |
| 748 | 853 |
| 749 NamedArgument namedArgument = argument.asNamedArgument(); | 854 NamedArgument namedArgument = argument.asNamedArgument(); |
| 750 if (namedArgument != null) { | 855 if (namedArgument != null) { |
| 751 String source = namedArgument.name.source; | 856 String source = namedArgument.name.source; |
| 752 namedArguments.add(source); | 857 namedArguments.add(source); |
| 753 if (seenNamedArguments.containsKey(source)) { | 858 if (seenNamedArguments.containsKey(source)) { |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1220 // whether it is erroneous. | 1325 // whether it is erroneous. |
| 1221 if (semantics.kind == AccessKind.SUPER_METHOD) { | 1326 if (semantics.kind == AccessKind.SUPER_METHOD) { |
| 1222 registry.registerStaticUse(semantics.element.declaration); | 1327 registry.registerStaticUse(semantics.element.declaration); |
| 1223 } | 1328 } |
| 1224 // TODO(23998): Remove this when all information goes through | 1329 // TODO(23998): Remove this when all information goes through |
| 1225 // the [SendStructure]. | 1330 // the [SendStructure]. |
| 1226 registry.useElement(node, semantics.element); | 1331 registry.useElement(node, semantics.element); |
| 1227 } | 1332 } |
| 1228 } else { | 1333 } else { |
| 1229 ResolutionResult expressionResult = visitExpression(expression); | 1334 ResolutionResult expressionResult = visitExpression(expression); |
| 1335 assert(checkConstantInvariant(expression, expressionResult)); |
| 1230 semantics = const DynamicAccess.expression(); | 1336 semantics = const DynamicAccess.expression(); |
| 1231 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); | 1337 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); |
| 1232 | 1338 |
| 1339 ConstantExpression constant; |
| 1233 if (expressionResult.isConstant) { | 1340 if (expressionResult.isConstant) { |
| 1234 bool isValidConstant; | 1341 bool isValidAsConstant = |
| 1235 ConstantExpression expressionConstant = expressionResult.constant; | 1342 !expressionResult.constant.isErroneous && |
| 1236 DartType knownExpressionType = | 1343 constantChecker.checkUnary( |
| 1237 expressionConstant.getKnownType(coreTypes); | 1344 operator, |
| 1238 switch (operator.kind) { | 1345 constantChecker.createInfo(expressionResult)); |
| 1239 case UnaryOperatorKind.COMPLEMENT: | 1346 if (isValidAsConstant) { |
| 1240 isValidConstant = | 1347 constant = |
| 1241 knownExpressionType == coreTypes.intType; | 1348 new UnaryConstantExpression(operator, expressionResult.constant); |
| 1242 break; | |
| 1243 case UnaryOperatorKind.NEGATE: | |
| 1244 isValidConstant = | |
| 1245 knownExpressionType == coreTypes.intType || | |
| 1246 knownExpressionType == coreTypes.doubleType; | |
| 1247 break; | |
| 1248 case UnaryOperatorKind.NOT: | |
| 1249 reporter.internalError(node, | |
| 1250 "Unexpected user definable unary operator: $operator"); | |
| 1251 } | 1349 } |
| 1252 if (isValidConstant) { | 1350 } |
| 1253 // TODO(johnniwinther): Handle potentially invalid constant | 1351 if (constant == null && constantState.requiresConstant) { |
| 1254 // expressions. | 1352 constant = new ErroneousConstantExpression(); |
| 1255 ConstantExpression constant = | 1353 } |
| 1256 new UnaryConstantExpression(operator, expressionConstant); | 1354 if (constant != null) { |
| 1257 registry.setConstant(node, constant); | 1355 registry.setConstant(node, constant); |
| 1258 result = new ConstantResult(node, constant); | 1356 result = new ConstantResult(node, constant); |
| 1259 } | |
| 1260 } | 1357 } |
| 1261 } | 1358 } |
| 1262 if (semantics != null) { | 1359 if (semantics != null) { |
| 1263 registry.registerSendStructure(node, | 1360 registry.registerSendStructure(node, |
| 1264 new UnaryStructure(semantics, operator)); | 1361 new UnaryStructure(semantics, operator)); |
| 1265 } | 1362 } |
| 1266 return result; | 1363 return result; |
| 1267 } | 1364 } |
| 1268 | 1365 |
| 1269 /// Handle a not expression, like `!a`. | 1366 /// Handle a not expression, like `!a`. |
| 1270 ResolutionResult handleNot(Send node, UnaryOperator operator) { | 1367 ResolutionResult handleNot(Send node, UnaryOperator operator) { |
| 1271 assert(invariant(node, operator.kind == UnaryOperatorKind.NOT)); | 1368 assert(invariant(node, operator.kind == UnaryOperatorKind.NOT)); |
| 1272 | 1369 |
| 1273 Node expression = node.receiver; | 1370 Node expression = node.receiver; |
| 1274 ResolutionResult result = visitExpression(expression); | 1371 ResolutionResult expressionResult = visitExpression(expression); |
| 1275 registry.registerSendStructure(node, const NotStructure()); | 1372 registry.registerSendStructure(node, const NotStructure()); |
| 1276 | 1373 |
| 1277 if (result.isConstant) { | 1374 ConstantExpression constant; |
| 1278 ConstantExpression expressionConstant = result.constant; | 1375 if (expressionResult.isConstant) { |
| 1279 if (expressionConstant.getKnownType(coreTypes) == coreTypes.boolType) { | 1376 bool isValidAsConstant = constantChecker.checkUnary( |
| 1280 // TODO(johnniwinther): Handle potentially invalid constant expressions. | 1377 operator, |
| 1281 ConstantExpression constant = | 1378 constantChecker.createInfo(expressionResult)); |
| 1282 new UnaryConstantExpression(operator, expressionConstant); | 1379 if (isValidAsConstant) { |
| 1283 registry.setConstant(node, constant); | 1380 constant = |
| 1284 return new ConstantResult(node, constant); | 1381 new UnaryConstantExpression(operator, expressionResult.constant); |
| 1285 } | 1382 } |
| 1286 } | 1383 } |
| 1287 | 1384 if (constant == null && constantState.requiresConstant) { |
| 1385 constant = new ErroneousConstantExpression(); |
| 1386 } |
| 1387 if (constant != null) { |
| 1388 registry.setConstant(node, constant); |
| 1389 return new ConstantResult(node, constant); |
| 1390 } |
| 1288 return const NoneResult(); | 1391 return const NoneResult(); |
| 1289 } | 1392 } |
| 1290 | 1393 |
| 1291 /// Handle a logical and expression, like `a && b`. | 1394 /// Handle a logical and expression, like `a && b`. |
| 1292 ResolutionResult handleLogicalAnd(Send node) { | 1395 ResolutionResult handleLogicalAnd(Send node) { |
| 1293 Node left = node.receiver; | 1396 Node left = node.receiver; |
| 1294 Node right = node.arguments.head; | 1397 Node right = node.arguments.head; |
| 1295 ResolutionResult leftResult = | 1398 ResolutionResult leftResult = |
| 1296 doInPromotionScope(left, () => visitExpression(left)); | 1399 doInPromotionScope(left, () => visitExpression(left)); |
| 1297 ResolutionResult rightResult = | 1400 ResolutionResult rightResult = |
| 1298 doInPromotionScope(right, () => visitExpression(right)); | 1401 doInPromotionScope(right, () => visitExpression(right)); |
| 1299 registry.registerSendStructure(node, const LogicalAndStructure()); | 1402 registry.registerSendStructure(node, const LogicalAndStructure()); |
| 1300 | 1403 |
| 1404 ConstantExpression constant; |
| 1301 if (leftResult.isConstant && rightResult.isConstant) { | 1405 if (leftResult.isConstant && rightResult.isConstant) { |
| 1302 ConstantExpression leftConstant = leftResult.constant; | 1406 bool isValidAsConstant = constantChecker.checkBinaryExpression( |
| 1303 ConstantExpression rightConstant = rightResult.constant; | 1407 node, |
| 1304 if (leftConstant.getKnownType(coreTypes) == coreTypes.boolType && | 1408 constantChecker.createInfo(leftResult), |
| 1305 rightConstant.getKnownType(coreTypes) == coreTypes.boolType) { | 1409 BinaryOperator.LOGICAL_AND, |
| 1306 // TODO(johnniwinther): Handle potentially invalid constant expressions. | 1410 constantChecker.createInfo(rightResult)); |
| 1307 ConstantExpression constant = new BinaryConstantExpression( | 1411 if (isValidAsConstant) { |
| 1308 leftConstant, | 1412 constant = new BinaryConstantExpression( |
| 1413 leftResult.constant, |
| 1309 BinaryOperator.LOGICAL_AND, | 1414 BinaryOperator.LOGICAL_AND, |
| 1310 rightConstant); | 1415 rightResult.constant); |
| 1311 registry.setConstant(node, constant); | |
| 1312 return new ConstantResult(node, constant); | |
| 1313 } | 1416 } |
| 1314 } | 1417 } |
| 1315 | 1418 if (constant == null && constantState.requiresConstant) { |
| 1419 constant = new ErroneousConstantExpression(); |
| 1420 } |
| 1421 if (constant != null) { |
| 1422 registry.setConstant(node, constant); |
| 1423 return new ConstantResult(node, constant); |
| 1424 } |
| 1316 return const NoneResult(); | 1425 return const NoneResult(); |
| 1317 } | 1426 } |
| 1318 | 1427 |
| 1319 /// Handle a logical or expression, like `a || b`. | 1428 /// Handle a logical or expression, like `a || b`. |
| 1320 ResolutionResult handleLogicalOr(Send node) { | 1429 ResolutionResult handleLogicalOr(Send node) { |
| 1321 Node left = node.receiver; | 1430 Node left = node.receiver; |
| 1322 Node right = node.arguments.head; | 1431 Node right = node.arguments.head; |
| 1323 ResolutionResult leftResult = visitExpression(left); | 1432 ResolutionResult leftResult = visitExpression(left); |
| 1324 ResolutionResult rightResult = visitExpression(right); | 1433 ResolutionResult rightResult = visitExpression(right); |
| 1325 registry.registerSendStructure(node, const LogicalOrStructure()); | 1434 registry.registerSendStructure(node, const LogicalOrStructure()); |
| 1326 | 1435 |
| 1436 ConstantExpression constant; |
| 1327 if (leftResult.isConstant && rightResult.isConstant) { | 1437 if (leftResult.isConstant && rightResult.isConstant) { |
| 1328 ConstantExpression leftConstant = leftResult.constant; | 1438 bool isValidAsConstant = constantChecker.checkBinaryExpression( |
| 1329 ConstantExpression rightConstant = rightResult.constant; | 1439 node, |
| 1330 if (leftConstant.getKnownType(coreTypes) == coreTypes.boolType && | 1440 constantChecker.createInfo(leftResult), |
| 1331 rightConstant.getKnownType(coreTypes) == coreTypes.boolType) { | 1441 BinaryOperator.LOGICAL_OR, |
| 1332 // TODO(johnniwinther): Handle potentially invalid constant expressions. | 1442 constantChecker.createInfo(rightResult)); |
| 1333 ConstantExpression constant = new BinaryConstantExpression( | 1443 if (isValidAsConstant) { |
| 1334 leftConstant, | 1444 constant = new BinaryConstantExpression( |
| 1445 leftResult.constant, |
| 1335 BinaryOperator.LOGICAL_OR, | 1446 BinaryOperator.LOGICAL_OR, |
| 1336 rightConstant); | 1447 rightResult.constant); |
| 1337 registry.setConstant(node, constant); | |
| 1338 return new ConstantResult(node, constant); | |
| 1339 } | 1448 } |
| 1340 } | 1449 } |
| 1450 if (constant == null && constantState.requiresConstant) { |
| 1451 constant = new ErroneousConstantExpression(); |
| 1452 } |
| 1453 if (constant != null) { |
| 1454 registry.setConstant(node, constant); |
| 1455 return new ConstantResult(node, constant); |
| 1456 } |
| 1341 return const NoneResult(); | 1457 return const NoneResult(); |
| 1342 } | 1458 } |
| 1343 | 1459 |
| 1344 /// Handle an if-null expression, like `a ?? b`. | 1460 /// Handle an if-null expression, like `a ?? b`. |
| 1345 ResolutionResult handleIfNull(Send node) { | 1461 ResolutionResult handleIfNull(Send node) { |
| 1346 Node left = node.receiver; | 1462 Node left = node.receiver; |
| 1347 Node right = node.arguments.head; | 1463 Node right = node.arguments.head; |
| 1348 visitExpression(left); | 1464 visitExpression(left); |
| 1349 visitExpression(right); | 1465 visitExpression(right); |
| 1350 registry.registerSendStructure(node, const IfNullStructure()); | 1466 registry.registerSendStructure(node, const IfNullStructure()); |
| 1351 return const NoneResult(); | 1467 ResolutionResult result = const NoneResult(); |
| 1468 if (constantState.requiresConstant) { |
| 1469 ConstantExpression constant = new ErroneousConstantExpression(); |
| 1470 reporter.reportErrorMessage(node, MessageKind.INVALID_CONSTANT_IF_NULL); |
| 1471 registry.setConstant(node, constant); |
| 1472 result = new ConstantResult(node, constant); |
| 1473 } |
| 1474 return result; |
| 1352 } | 1475 } |
| 1353 | 1476 |
| 1354 /// Handle the binary expression of an unresolved binary operator [text], like | 1477 /// Handle the binary expression of an unresolved binary operator [text], like |
| 1355 /// the no longer supported `a === b`. | 1478 /// the no longer supported `a === b`. |
| 1356 ResolutionResult handleUnresolvedBinary(Send node, String text) { | 1479 ResolutionResult handleUnresolvedBinary(Send node, String text) { |
| 1357 Node left = node.receiver; | 1480 Node left = node.receiver; |
| 1358 Node right = node.arguments.head; | 1481 Node right = node.arguments.head; |
| 1359 if (node.isSuperCall) { | 1482 if (node.isSuperCall) { |
| 1360 checkSuperAccess(node); | 1483 checkSuperAccess(node); |
| 1361 } else { | 1484 } else { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1397 // the [SendStructure]. | 1520 // the [SendStructure]. |
| 1398 registry.useElement(node, semantics.element); | 1521 registry.useElement(node, semantics.element); |
| 1399 } | 1522 } |
| 1400 visitExpression(right); | 1523 visitExpression(right); |
| 1401 } else { | 1524 } else { |
| 1402 ResolutionResult leftResult = visitExpression(left); | 1525 ResolutionResult leftResult = visitExpression(left); |
| 1403 ResolutionResult rightResult = visitExpression(right); | 1526 ResolutionResult rightResult = visitExpression(right); |
| 1404 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); | 1527 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); |
| 1405 semantics = const DynamicAccess.expression(); | 1528 semantics = const DynamicAccess.expression(); |
| 1406 | 1529 |
| 1530 ConstantExpression constant; |
| 1407 if (leftResult.isConstant && rightResult.isConstant) { | 1531 if (leftResult.isConstant && rightResult.isConstant) { |
| 1408 bool isValidConstant; | 1532 //reportHere(compiler, node, 'left=${leftResult.constant.getText()},righ
t=${rightResult.constant.getText()}'); |
| 1409 ConstantExpression leftConstant = leftResult.constant; | 1533 bool isValidAsConstant = constantChecker.checkBinaryExpression( |
| 1410 ConstantExpression rightConstant = rightResult.constant; | 1534 node, |
| 1411 DartType knownLeftType = leftConstant.getKnownType(coreTypes); | 1535 constantChecker.createInfo(leftResult), |
| 1412 DartType knownRightType = rightConstant.getKnownType(coreTypes); | 1536 operator, |
| 1413 switch (operator.kind) { | 1537 constantChecker.createInfo(rightResult)); |
| 1414 case BinaryOperatorKind.EQ: | 1538 if (isValidAsConstant) { |
| 1415 case BinaryOperatorKind.NOT_EQ: | 1539 constant = new BinaryConstantExpression( |
| 1416 isValidConstant = | |
| 1417 (knownLeftType == coreTypes.intType || | |
| 1418 knownLeftType == coreTypes.doubleType || | |
| 1419 knownLeftType == coreTypes.stringType || | |
| 1420 knownLeftType == coreTypes.boolType || | |
| 1421 knownLeftType == coreTypes.nullType) && | |
| 1422 (knownRightType == coreTypes.intType || | |
| 1423 knownRightType == coreTypes.doubleType || | |
| 1424 knownRightType == coreTypes.stringType || | |
| 1425 knownRightType == coreTypes.boolType || | |
| 1426 knownRightType == coreTypes.nullType); | |
| 1427 break; | |
| 1428 case BinaryOperatorKind.ADD: | |
| 1429 isValidConstant = | |
| 1430 (knownLeftType == coreTypes.intType || | |
| 1431 knownLeftType == coreTypes.doubleType || | |
| 1432 knownLeftType == coreTypes.stringType) && | |
| 1433 (knownRightType == coreTypes.intType || | |
| 1434 knownRightType == coreTypes.doubleType || | |
| 1435 knownRightType == coreTypes.stringType); | |
| 1436 break; | |
| 1437 case BinaryOperatorKind.SUB: | |
| 1438 case BinaryOperatorKind.MUL: | |
| 1439 case BinaryOperatorKind.DIV: | |
| 1440 case BinaryOperatorKind.IDIV: | |
| 1441 case BinaryOperatorKind.MOD: | |
| 1442 case BinaryOperatorKind.GTEQ: | |
| 1443 case BinaryOperatorKind.GT: | |
| 1444 case BinaryOperatorKind.LTEQ: | |
| 1445 case BinaryOperatorKind.LT: | |
| 1446 isValidConstant = | |
| 1447 (knownLeftType == coreTypes.intType || | |
| 1448 knownLeftType == coreTypes.doubleType) && | |
| 1449 (knownRightType == coreTypes.intType || | |
| 1450 knownRightType == coreTypes.doubleType); | |
| 1451 break; | |
| 1452 case BinaryOperatorKind.SHL: | |
| 1453 case BinaryOperatorKind.SHR: | |
| 1454 case BinaryOperatorKind.AND: | |
| 1455 case BinaryOperatorKind.OR: | |
| 1456 case BinaryOperatorKind.XOR: | |
| 1457 isValidConstant = | |
| 1458 knownLeftType == coreTypes.intType && | |
| 1459 knownRightType == coreTypes.intType; | |
| 1460 break; | |
| 1461 case BinaryOperatorKind.INDEX: | |
| 1462 isValidConstant = false; | |
| 1463 break; | |
| 1464 case BinaryOperatorKind.LOGICAL_AND: | |
| 1465 case BinaryOperatorKind.LOGICAL_OR: | |
| 1466 case BinaryOperatorKind.IF_NULL: | |
| 1467 reporter.internalError( | |
| 1468 node, "Unexpected binary operator '${operator}'."); | |
| 1469 break; | |
| 1470 } | |
| 1471 if (isValidConstant) { | |
| 1472 // TODO(johnniwinther): Handle potentially invalid constant | |
| 1473 // expressions. | |
| 1474 ConstantExpression constant = new BinaryConstantExpression( | |
| 1475 leftResult.constant, | 1540 leftResult.constant, |
| 1476 operator, | 1541 operator, |
| 1477 rightResult.constant); | 1542 rightResult.constant); |
| 1478 registry.setConstant(node, constant); | |
| 1479 result = new ConstantResult(node, constant); | |
| 1480 } | 1543 } |
| 1481 } | 1544 } |
| 1545 if (constant == null && constantState.requiresConstant) { |
| 1546 constant = new ErroneousConstantExpression(); |
| 1547 } |
| 1548 if (constant != null) { |
| 1549 registry.setConstant(node, constant); |
| 1550 result = new ConstantResult(node, constant); |
| 1551 } |
| 1482 } | 1552 } |
| 1483 | 1553 |
| 1484 if (semantics != null) { | 1554 if (semantics != null) { |
| 1485 // TODO(johnniwinther): Support invalid super access as an | 1555 // TODO(johnniwinther): Support invalid super access as an |
| 1486 // [AccessSemantics]. | 1556 // [AccessSemantics]. |
| 1487 SendStructure sendStructure; | 1557 SendStructure sendStructure; |
| 1488 switch (operator.kind) { | 1558 switch (operator.kind) { |
| 1489 case BinaryOperatorKind.EQ: | 1559 case BinaryOperatorKind.EQ: |
| 1490 sendStructure = new EqualsStructure(semantics); | 1560 sendStructure = new EqualsStructure(semantics); |
| 1491 break; | 1561 break; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); | 1609 registry.registerDynamicInvocation(new UniverseSelector(selector, null)); |
| 1540 registry.registerSendStructure(node, | 1610 registry.registerSendStructure(node, |
| 1541 new InvokeStructure(const DynamicAccess.expression(), selector)); | 1611 new InvokeStructure(const DynamicAccess.expression(), selector)); |
| 1542 return const NoneResult(); | 1612 return const NoneResult(); |
| 1543 } | 1613 } |
| 1544 | 1614 |
| 1545 /// Handle access of a property of [name] on `this`, like `this.name` and | 1615 /// Handle access of a property of [name] on `this`, like `this.name` and |
| 1546 /// `this.name()`, or `name` and `name()` in instance context. | 1616 /// `this.name()`, or `name` and `name()` in instance context. |
| 1547 ResolutionResult handleThisPropertyAccess(Send node, Name name) { | 1617 ResolutionResult handleThisPropertyAccess(Send node, Name name) { |
| 1548 AccessSemantics semantics = new DynamicAccess.thisProperty(name); | 1618 AccessSemantics semantics = new DynamicAccess.thisProperty(name); |
| 1549 return handleDynamicAccessSemantics(node, name, semantics); | 1619 return handleDynamicAccessSemantics( |
| 1620 node, const NoneResult(), name, semantics); |
| 1550 } | 1621 } |
| 1551 | 1622 |
| 1552 /// Handle update of a property of [name] on `this`, like `this.name = b` and | 1623 /// Handle update of a property of [name] on `this`, like `this.name = b` and |
| 1553 /// `this.name++`, or `name = b` and `name++` in instance context. | 1624 /// `this.name++`, or `name = b` and `name++` in instance context. |
| 1554 ResolutionResult handleThisPropertyUpdate( | 1625 ResolutionResult handleThisPropertyUpdate( |
| 1555 SendSet node, Name name, Element element) { | 1626 SendSet node, Name name, Element element) { |
| 1556 AccessSemantics semantics = new DynamicAccess.thisProperty(name); | 1627 AccessSemantics semantics = new DynamicAccess.thisProperty(name); |
| 1557 return handleDynamicUpdateSemantics(node, name, element, semantics); | 1628 return handleDynamicUpdateSemantics(node, name, element, semantics); |
| 1558 } | 1629 } |
| 1559 | 1630 |
| (...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 // TODO(johnniwinther): Remove [element] when it is no longer needed for | 2123 // TODO(johnniwinther): Remove [element] when it is no longer needed for |
| 2053 // evaluating constants. | 2124 // evaluating constants. |
| 2054 ResolutionResult handleConstantTypeLiteralUpdate( | 2125 ResolutionResult handleConstantTypeLiteralUpdate( |
| 2055 SendSet node, | 2126 SendSet node, |
| 2056 Name name, | 2127 Name name, |
| 2057 TypeDeclarationElement element, | 2128 TypeDeclarationElement element, |
| 2058 DartType type, | 2129 DartType type, |
| 2059 ConstantAccess semantics) { | 2130 ConstantAccess semantics) { |
| 2060 | 2131 |
| 2061 // TODO(johnniwinther): Remove this when all constants are evaluated. | 2132 // TODO(johnniwinther): Remove this when all constants are evaluated. |
| 2062 compiler.resolver.constantCompiler.evaluate(semantics.constant); | 2133 compiler.resolver.constantCompiler.evaluate(node, semantics.constant); |
| 2063 | 2134 |
| 2064 ErroneousElement error; | 2135 ErroneousElement error; |
| 2065 if (node.isIfNullAssignment) { | 2136 if (node.isIfNullAssignment) { |
| 2066 error = reportAndCreateErroneousElement( | 2137 error = reportAndCreateErroneousElement( |
| 2067 node.selector, name.text, | 2138 node.selector, name.text, |
| 2068 MessageKind.IF_NULL_ASSIGNING_TYPE, const {}); | 2139 MessageKind.IF_NULL_ASSIGNING_TYPE, const {}); |
| 2069 // TODO(23998): Remove these when all information goes through | 2140 // TODO(23998): Remove these when all information goes through |
| 2070 // the [SendStructure]. | 2141 // the [SendStructure]. |
| 2071 registry.setConstant(node.selector, semantics.constant); | 2142 registry.setConstant(node.selector, semantics.constant); |
| 2072 registry.useElement(node.selector, element); | 2143 registry.useElement(node.selector, element); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2124 node, const PublicName('dynamic'), compiler.typeClass, type, semantics); | 2195 node, const PublicName('dynamic'), compiler.typeClass, type, semantics); |
| 2125 } | 2196 } |
| 2126 | 2197 |
| 2127 /// Handle update to a type literal of the type 'dynamic'. Like `dynamic++` or | 2198 /// Handle update to a type literal of the type 'dynamic'. Like `dynamic++` or |
| 2128 /// `dynamic = 0`. | 2199 /// `dynamic = 0`. |
| 2129 ResolutionResult handleDynamicTypeLiteralUpdate(SendSet node) { | 2200 ResolutionResult handleDynamicTypeLiteralUpdate(SendSet node) { |
| 2130 DartType type = const DynamicType(); | 2201 DartType type = const DynamicType(); |
| 2131 ConstantExpression constant = | 2202 ConstantExpression constant = |
| 2132 new TypeConstantExpression(const DynamicType()); | 2203 new TypeConstantExpression(const DynamicType()); |
| 2133 AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant); | 2204 AccessSemantics semantics = new ConstantAccess.dynamicTypeLiteral(constant); |
| 2205 // TODO(johnniwinther): Remove this when all constants are evaluated. |
| 2206 compiler.resolver.constantCompiler.evaluate(node, constant); |
| 2134 return handleConstantTypeLiteralUpdate( | 2207 return handleConstantTypeLiteralUpdate( |
| 2135 node, const PublicName('dynamic'), compiler.typeClass, type, semantics); | 2208 node, const PublicName('dynamic'), compiler.typeClass, type, semantics); |
| 2136 } | 2209 } |
| 2137 | 2210 |
| 2138 /// Handle access to a type literal of a class. Like `C` or | 2211 /// Handle access to a type literal of a class. Like `C` or |
| 2139 /// `C()` where 'C' is class. | 2212 /// `C()` where 'C' is class. |
| 2140 ResolutionResult handleClassTypeLiteralAccess( | 2213 ResolutionResult handleClassTypeLiteralAccess( |
| 2141 Send node, | 2214 Send node, |
| 2142 Name name, | 2215 Name name, |
| 2143 ClassElement cls) { | 2216 ClassElement cls) { |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2319 ResolutionResult result = handleStaticMemberUpdate(node, name, element); | 2392 ResolutionResult result = handleStaticMemberUpdate(node, name, element); |
| 2320 if (prefixResult.isDeferred) { | 2393 if (prefixResult.isDeferred) { |
| 2321 result = handleDeferredAccess(node, prefixResult.prefix, result); | 2394 result = handleDeferredAccess(node, prefixResult.prefix, result); |
| 2322 } | 2395 } |
| 2323 return result; | 2396 return result; |
| 2324 } | 2397 } |
| 2325 } | 2398 } |
| 2326 | 2399 |
| 2327 /// Handle dynamic access of [semantics]. | 2400 /// Handle dynamic access of [semantics]. |
| 2328 ResolutionResult handleDynamicAccessSemantics( | 2401 ResolutionResult handleDynamicAccessSemantics( |
| 2329 Send node, Name name, AccessSemantics semantics) { | 2402 Send node, |
| 2403 ResolutionResult receiverResult, |
| 2404 Name name, |
| 2405 AccessSemantics semantics) { |
| 2406 ResolutionResult result = const NoneResult(); |
| 2330 SendStructure sendStructure; | 2407 SendStructure sendStructure; |
| 2331 Selector selector; | 2408 Selector selector; |
| 2332 if (node.isCall) { | 2409 if (node.isCall) { |
| 2333 CallStructure callStructure = | 2410 CallStructure callStructure = |
| 2334 resolveArguments(node.argumentsNode).callStructure; | 2411 resolveArguments(node.argumentsNode).callStructure; |
| 2335 selector = new Selector.call(name, callStructure); | 2412 selector = new Selector.call(name, callStructure); |
| 2336 registry.registerDynamicInvocation( | 2413 registry.registerDynamicInvocation( |
| 2337 new UniverseSelector(selector, null)); | 2414 new UniverseSelector(selector, null)); |
| 2338 sendStructure = new InvokeStructure(semantics, selector); | 2415 sendStructure = new InvokeStructure(semantics, selector); |
| 2339 } else { | 2416 } else { |
| 2340 assert(invariant(node, node.isPropertyAccess)); | 2417 assert(invariant(node, node.isPropertyAccess)); |
| 2341 selector = new Selector.getter(name); | 2418 selector = new Selector.getter(name); |
| 2342 registry.registerDynamicGetter( | 2419 registry.registerDynamicGetter( |
| 2343 new UniverseSelector(selector, null)); | 2420 new UniverseSelector(selector, null)); |
| 2421 if (receiverResult.isConstant && name == const PublicName("length")) { |
| 2422 if (constantChecker.isStringOrNull( |
| 2423 receiverResult.constant.getKnownType(coreTypes))) { |
| 2424 ConstantExpression constant = |
| 2425 new StringLengthConstantExpression(receiverResult.constant); |
| 2426 registry.setConstant(node, constant); |
| 2427 result = new ConstantResult(node, constant); |
| 2428 } |
| 2429 } |
| 2344 sendStructure = new GetStructure(semantics); | 2430 sendStructure = new GetStructure(semantics); |
| 2345 } | 2431 } |
| 2346 registry.registerSendStructure(node, sendStructure); | 2432 registry.registerSendStructure(node, sendStructure); |
| 2347 // TODO(23998): Remove this when all information goes through | 2433 // TODO(23998): Remove this when all information goes through |
| 2348 // the [SendStructure]. | 2434 // the [SendStructure]. |
| 2349 registry.setSelector(node, selector); | 2435 registry.setSelector(node, selector); |
| 2350 return const NoneResult(); | 2436 return result; |
| 2351 } | 2437 } |
| 2352 | 2438 |
| 2353 /// Handle dynamic update of [semantics]. | 2439 /// Handle dynamic update of [semantics]. |
| 2354 ResolutionResult handleDynamicUpdateSemantics( | 2440 ResolutionResult handleDynamicUpdateSemantics( |
| 2355 SendSet node, Name name, Element element, AccessSemantics semantics) { | 2441 SendSet node, Name name, Element element, AccessSemantics semantics) { |
| 2356 Selector getterSelector = new Selector.getter(name); | 2442 Selector getterSelector = new Selector.getter(name); |
| 2357 Selector setterSelector = new Selector.setter(name.setter); | 2443 Selector setterSelector = new Selector.setter(name.setter); |
| 2358 registry.registerDynamicSetter( | 2444 registry.registerDynamicSetter( |
| 2359 new UniverseSelector(setterSelector, null)); | 2445 new UniverseSelector(setterSelector, null)); |
| 2360 if (node.isComplex) { | 2446 if (node.isComplex) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2411 // TODO(johnniwinther): Handle invalid this access as an | 2497 // TODO(johnniwinther): Handle invalid this access as an |
| 2412 // [AccessSemantics]. | 2498 // [AccessSemantics]. |
| 2413 return handleErroneousAccess(node, name, semantics); | 2499 return handleErroneousAccess(node, name, semantics); |
| 2414 } | 2500 } |
| 2415 } | 2501 } |
| 2416 ResolutionResult result = visitExpressionPrefix(node.receiver); | 2502 ResolutionResult result = visitExpressionPrefix(node.receiver); |
| 2417 if (result.kind == ResultKind.PREFIX) { | 2503 if (result.kind == ResultKind.PREFIX) { |
| 2418 return handlePrefixSend(node, name, result); | 2504 return handlePrefixSend(node, name, result); |
| 2419 } else if (node.isConditional) { | 2505 } else if (node.isConditional) { |
| 2420 return handleDynamicAccessSemantics( | 2506 return handleDynamicAccessSemantics( |
| 2421 node, name, new DynamicAccess.ifNotNullProperty(name)); | 2507 node, result, |
| 2508 name, new DynamicAccess.ifNotNullProperty(name)); |
| 2422 } else { | 2509 } else { |
| 2423 // Handle dynamic property access, like `a.b` or `a.b()` where `a` is not | 2510 // Handle dynamic property access, like `a.b` or `a.b()` where `a` is not |
| 2424 // a prefix or class. | 2511 // a prefix or class. |
| 2425 // TODO(johnniwinther): Use the `element` of [result]. | 2512 // TODO(johnniwinther): Use the `element` of [result]. |
| 2426 return handleDynamicAccessSemantics( | 2513 return handleDynamicAccessSemantics( |
| 2427 node, name, new DynamicAccess.dynamicProperty(name)); | 2514 node, result, |
| 2515 name, new DynamicAccess.dynamicProperty(name)); |
| 2428 } | 2516 } |
| 2429 } | 2517 } |
| 2430 | 2518 |
| 2431 /// Handle a qualified [SendSet], that is where the receiver is non-null, like | 2519 /// Handle a qualified [SendSet], that is where the receiver is non-null, like |
| 2432 /// `a.b = c`, `a.b++`, and `a.b += c`. | 2520 /// `a.b = c`, `a.b++`, and `a.b += c`. |
| 2433 ResolutionResult handleQualifiedSendSet(SendSet node) { | 2521 ResolutionResult handleQualifiedSendSet(SendSet node) { |
| 2434 Identifier selector = node.selector.asIdentifier(); | 2522 Identifier selector = node.selector.asIdentifier(); |
| 2435 String text = selector.source; | 2523 String text = selector.source; |
| 2436 Name name = new Name(text, enclosingElement.library); | 2524 Name name = new Name(text, enclosingElement.library); |
| 2437 if (text == 'this') { | 2525 if (text == 'this') { |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2584 ? new IncompatibleInvokeStructure(semantics, selector) | 2672 ? new IncompatibleInvokeStructure(semantics, selector) |
| 2585 : new InvokeStructure(semantics, selector)); | 2673 : new InvokeStructure(semantics, selector)); |
| 2586 } else { | 2674 } else { |
| 2587 switch (semantics.kind) { | 2675 switch (semantics.kind) { |
| 2588 case AccessKind.LOCAL_VARIABLE: | 2676 case AccessKind.LOCAL_VARIABLE: |
| 2589 case AccessKind.LOCAL_FUNCTION: | 2677 case AccessKind.LOCAL_FUNCTION: |
| 2590 result = new ElementResult(element); | 2678 result = new ElementResult(element); |
| 2591 break; | 2679 break; |
| 2592 case AccessKind.PARAMETER: | 2680 case AccessKind.PARAMETER: |
| 2593 case AccessKind.FINAL_PARAMETER: | 2681 case AccessKind.FINAL_PARAMETER: |
| 2594 if (constantState == ConstantState.CONSTANT_INITIALIZER) { | 2682 if (constantState.parameterReferenceIsConstant) { |
| 2595 ParameterElement parameter = element; | 2683 ParameterElement parameter = element; |
| 2596 if (parameter.isNamed) { | 2684 if (parameter.isNamed) { |
| 2597 result = new ConstantResult( | 2685 result = new ConstantResult( |
| 2598 node, | 2686 node, |
| 2599 new NamedArgumentReference(parameter.name), | 2687 new NamedArgumentReference(parameter.name), |
| 2600 element: element); | 2688 element: element); |
| 2601 } else { | 2689 } else { |
| 2602 result = new ConstantResult( | 2690 result = new ConstantResult( |
| 2603 node, | 2691 node, |
| 2604 new PositionalArgumentReference( | 2692 new PositionalArgumentReference( |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2775 } | 2863 } |
| 2776 registry.registerSendStructure(node, | 2864 registry.registerSendStructure(node, |
| 2777 isIncompatibleInvoke | 2865 isIncompatibleInvoke |
| 2778 ? new IncompatibleInvokeStructure(semantics, selector) | 2866 ? new IncompatibleInvokeStructure(semantics, selector) |
| 2779 : new InvokeStructure(semantics, selector)); | 2867 : new InvokeStructure(semantics, selector)); |
| 2780 } else { | 2868 } else { |
| 2781 selector = new Selector.getter(name); | 2869 selector = new Selector.getter(name); |
| 2782 switch (semantics.kind) { | 2870 switch (semantics.kind) { |
| 2783 case AccessKind.STATIC_METHOD: | 2871 case AccessKind.STATIC_METHOD: |
| 2784 case AccessKind.TOPLEVEL_METHOD: | 2872 case AccessKind.TOPLEVEL_METHOD: |
| 2873 MethodElement method = member; |
| 2785 // TODO(johnniwinther): Method this should be registered as a | 2874 // TODO(johnniwinther): Method this should be registered as a |
| 2786 // closurization. | 2875 // closurization. |
| 2787 registry.registerStaticUse(semantics.element); | 2876 registry.registerStaticUse(semantics.element); |
| 2788 registry.registerGetOfStaticFunction(semantics.element); | 2877 registry.registerGetOfStaticFunction(semantics.element); |
| 2878 result = new ConstantResult( |
| 2879 node, |
| 2880 new FunctionConstantExpression(method), |
| 2881 element: method); |
| 2789 break; | 2882 break; |
| 2790 case AccessKind.STATIC_FIELD: | 2883 case AccessKind.STATIC_FIELD: |
| 2791 case AccessKind.FINAL_STATIC_FIELD: | 2884 case AccessKind.FINAL_STATIC_FIELD: |
| 2792 case AccessKind.STATIC_GETTER: | |
| 2793 case AccessKind.TOPLEVEL_FIELD: | 2885 case AccessKind.TOPLEVEL_FIELD: |
| 2794 case AccessKind.FINAL_TOPLEVEL_FIELD: | 2886 case AccessKind.FINAL_TOPLEVEL_FIELD: |
| 2887 FieldElement field = member; |
| 2888 if (field.isConst) { |
| 2889 result = new ConstantResult( |
| 2890 node, new VariableConstantExpression(field), element: field); |
| 2891 } else { |
| 2892 result = new ElementResult(field); |
| 2893 } |
| 2894 registry.registerStaticUse(semantics.element); |
| 2895 break; |
| 2896 case AccessKind.STATIC_GETTER: |
| 2795 case AccessKind.TOPLEVEL_GETTER: | 2897 case AccessKind.TOPLEVEL_GETTER: |
| 2796 registry.registerStaticUse(semantics.element); | 2898 registry.registerStaticUse(semantics.element); |
| 2899 result = new ElementResult(member); |
| 2797 break; | 2900 break; |
| 2798 case AccessKind.STATIC_SETTER: | 2901 case AccessKind.STATIC_SETTER: |
| 2799 case AccessKind.TOPLEVEL_SETTER: | 2902 case AccessKind.TOPLEVEL_SETTER: |
| 2800 case AccessKind.UNRESOLVED: | 2903 case AccessKind.UNRESOLVED: |
| 2801 registry.registerThrowNoSuchMethod(); | 2904 registry.registerThrowNoSuchMethod(); |
| 2802 member = reportAndCreateErroneousElement( | 2905 member = reportAndCreateErroneousElement( |
| 2803 node.selector, name.text, | 2906 node.selector, name.text, |
| 2804 MessageKind.CANNOT_RESOLVE_GETTER, const {}); | 2907 MessageKind.CANNOT_RESOLVE_GETTER, const {}); |
| 2908 result = new ElementResult(member); |
| 2805 break; | 2909 break; |
| 2806 default: | 2910 default: |
| 2807 reporter.internalError(node, | 2911 reporter.internalError(node, |
| 2808 "Unexpected statically resolved access $semantics."); | 2912 "Unexpected statically resolved access $semantics."); |
| 2809 break; | 2913 break; |
| 2810 } | 2914 } |
| 2811 registry.registerSendStructure(node, new GetStructure(semantics)); | 2915 registry.registerSendStructure(node, new GetStructure(semantics)); |
| 2812 if (member.isConst) { | 2916 if (member.isConst) { |
| 2813 FieldElement field = member; | 2917 FieldElement field = member; |
| 2814 result = new ConstantResult( | 2918 result = new ConstantResult( |
| 2815 node, new VariableConstantExpression(field), element: field); | 2919 node, new VariableConstantExpression(field), element: field); |
| 2920 } else if (member.isFunction) { |
| 2921 MethodElement function = member; |
| 2922 result = new ConstantResult( |
| 2923 node, new FunctionConstantExpression(function), element: function); |
| 2816 } else { | 2924 } else { |
| 2817 result = new ElementResult(member); | 2925 result = new ElementResult(member); |
| 2818 } | 2926 } |
| 2819 } | 2927 } |
| 2820 | 2928 |
| 2821 // TODO(23998): Remove these when all information goes through | 2929 // TODO(23998): Remove these when all information goes through |
| 2822 // the [SendStructure]. | 2930 // the [SendStructure]. |
| 2823 registry.useElement(node, member); | 2931 registry.useElement(node, member); |
| 2824 registry.setSelector(node, selector); | 2932 registry.setSelector(node, selector); |
| 2825 | 2933 |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3061 // Create [ErroneousElement] for unresolved access. | 3169 // Create [ErroneousElement] for unresolved access. |
| 3062 ErroneousElement error = reportCannotResolve(node, text); | 3170 ErroneousElement error = reportCannotResolve(node, text); |
| 3063 return handleUpdate(node, name, new StaticAccess.unresolved(error)); | 3171 return handleUpdate(node, name, new StaticAccess.unresolved(error)); |
| 3064 } | 3172 } |
| 3065 } else { | 3173 } else { |
| 3066 return handleResolvedSendSet(node, name, element); | 3174 return handleResolvedSendSet(node, name, element); |
| 3067 } | 3175 } |
| 3068 } | 3176 } |
| 3069 | 3177 |
| 3070 ResolutionResult visitSend(Send node) { | 3178 ResolutionResult visitSend(Send node) { |
| 3179 ResolutionResult result; |
| 3071 if (node.isOperator) { | 3180 if (node.isOperator) { |
| 3072 // `a && b`, `a + b`, `-a`, or `a is T`. | 3181 // `a && b`, `a + b`, `-a`, or `a is T`. |
| 3073 return handleOperatorSend(node); | 3182 result = handleOperatorSend(node); |
| 3074 } else if (node.receiver != null) { | 3183 } else if (node.receiver != null) { |
| 3075 // `a.b`. | 3184 // `a.b`. |
| 3076 return handleQualifiedSend(node); | 3185 result = handleQualifiedSend(node); |
| 3077 } else { | 3186 } else { |
| 3078 // `a`. | 3187 // `a`. |
| 3079 return handleUnqualifiedSend(node); | 3188 result = handleUnqualifiedSend(node); |
| 3080 } | 3189 } |
| 3190 if (result.kind == ResultKind.PREFIX) { |
| 3191 return result; |
| 3192 } |
| 3193 return ensureConstantResult(node, result); |
| 3081 } | 3194 } |
| 3082 | 3195 |
| 3083 /// Register read access of [target] inside a closure. | 3196 /// Register read access of [target] inside a closure. |
| 3084 void registerPotentialAccessInClosure(Send node, Element target) { | 3197 void registerPotentialAccessInClosure(Send node, Element target) { |
| 3085 if (isPotentiallyMutableTarget(target)) { | 3198 if (isPotentiallyMutableTarget(target)) { |
| 3086 if (enclosingElement != target.enclosingElement) { | 3199 if (enclosingElement != target.enclosingElement) { |
| 3087 for (Node scope in promotionScope) { | 3200 for (Node scope in promotionScope) { |
| 3088 registry.setAccessedByClosureIn(scope, target, node); | 3201 registry.setAccessedByClosureIn(scope, target, node); |
| 3089 } | 3202 } |
| 3090 } | 3203 } |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3622 Node constructorReference = node.constructorReference; | 3735 Node constructorReference = node.constructorReference; |
| 3623 if (constructorReference is Send) { | 3736 if (constructorReference is Send) { |
| 3624 constructor.redirectionDeferredPrefix = | 3737 constructor.redirectionDeferredPrefix = |
| 3625 compiler.deferredLoadTask.deferredPrefixElement(constructorReference, | 3738 compiler.deferredLoadTask.deferredPrefixElement(constructorReference, |
| 3626 registry.mapping); | 3739 registry.mapping); |
| 3627 } | 3740 } |
| 3628 | 3741 |
| 3629 registry.setRedirectingTargetConstructor(node, redirectionTarget); | 3742 registry.setRedirectingTargetConstructor(node, redirectionTarget); |
| 3630 if (Elements.isUnresolved(redirectionTarget)) { | 3743 if (Elements.isUnresolved(redirectionTarget)) { |
| 3631 registry.registerThrowNoSuchMethod(); | 3744 registry.registerThrowNoSuchMethod(); |
| 3745 if (isConstConstructor) { |
| 3746 constructor.constantConstructor = const ErroneousConstantConstructor(); |
| 3747 } |
| 3632 return const NoneResult(); | 3748 return const NoneResult(); |
| 3633 } else { | 3749 } else { |
| 3634 if (isConstConstructor && | 3750 if (isConstConstructor && |
| 3635 !redirectionTarget.isConst) { | 3751 !redirectionTarget.isConst) { |
| 3636 reporter.reportErrorMessage( | 3752 reporter.reportErrorMessage( |
| 3637 node, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | 3753 node, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |
| 3638 isValidAsConstant = false; | 3754 isValidAsConstant = false; |
| 3639 } | 3755 } |
| 3640 if (redirectionTarget == constructor) { | 3756 if (redirectionTarget == constructor) { |
| 3641 reporter.reportErrorMessage( | 3757 reporter.reportErrorMessage( |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3702 }); | 3818 }); |
| 3703 CallStructure callStructure = | 3819 CallStructure callStructure = |
| 3704 new CallStructure(constructorSignature.parameterCount, names); | 3820 new CallStructure(constructorSignature.parameterCount, names); |
| 3705 constructor.constantConstructor = | 3821 constructor.constantConstructor = |
| 3706 new RedirectingFactoryConstantConstructor( | 3822 new RedirectingFactoryConstantConstructor( |
| 3707 new ConstructedConstantExpression( | 3823 new ConstructedConstantExpression( |
| 3708 type, | 3824 type, |
| 3709 redirectionTarget, | 3825 redirectionTarget, |
| 3710 callStructure, | 3826 callStructure, |
| 3711 arguments)); | 3827 arguments)); |
| 3828 } else if (isConstConstructor) { |
| 3829 constructor.constantConstructor = const ErroneousConstantConstructor(); |
| 3712 } | 3830 } |
| 3713 return const NoneResult(); | 3831 return const NoneResult(); |
| 3714 } | 3832 } |
| 3715 | 3833 |
| 3716 ResolutionResult visitThrow(Throw node) { | 3834 ResolutionResult visitThrow(Throw node) { |
| 3717 registry.registerThrowExpression(); | 3835 registry.registerThrowExpression(); |
| 3718 visit(node.expression); | 3836 visit(node.expression); |
| 3719 return const NoneResult(); | 3837 return ensureConstantResult(node, const NoneResult()); |
| 3720 } | 3838 } |
| 3721 | 3839 |
| 3722 ResolutionResult visitAwait(Await node) { | 3840 ResolutionResult visitAwait(Await node) { |
| 3723 compiler.futureClass.ensureResolved(resolution); | 3841 compiler.futureClass.ensureResolved(resolution); |
| 3724 visit(node.expression); | 3842 visit(node.expression); |
| 3725 return const NoneResult(); | 3843 return const NoneResult(); |
| 3726 } | 3844 } |
| 3727 | 3845 |
| 3728 ResolutionResult visitVariableDefinitions(VariableDefinitions node) { | 3846 ResolutionResult visitVariableDefinitions(VariableDefinitions node) { |
| 3729 DartType type; | 3847 DartType type; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3792 allowedCategory = oldCategory; | 3910 allowedCategory = oldCategory; |
| 3793 sendIsMemberAccess = oldSendIsMemberAccess; | 3911 sendIsMemberAccess = oldSendIsMemberAccess; |
| 3794 if (result.kind == ResultKind.CONSTANT) { | 3912 if (result.kind == ResultKind.CONSTANT) { |
| 3795 return result; | 3913 return result; |
| 3796 } | 3914 } |
| 3797 return const NoneResult(); | 3915 return const NoneResult(); |
| 3798 } | 3916 } |
| 3799 | 3917 |
| 3800 ResolutionResult visitNewExpression(NewExpression node) { | 3918 ResolutionResult visitNewExpression(NewExpression node) { |
| 3801 bool isValidAsConstant = true; | 3919 bool isValidAsConstant = true; |
| 3802 ConstructorElement constructor = resolveConstructor(node).element; | 3920 ConstructorResult result = resolveConstructor(node); |
| 3921 //reportHere(reporter, node, '$result'); |
| 3922 ConstructorElement constructor = result.element; |
| 3803 final bool isSymbolConstructor = constructor == compiler.symbolConstructor; | 3923 final bool isSymbolConstructor = constructor == compiler.symbolConstructor; |
| 3804 final bool isMirrorsUsedConstant = | 3924 final bool isMirrorsUsedConstant = |
| 3805 node.isConst && (constructor == compiler.mirrorsUsedConstructor); | 3925 node.isConst && (constructor == compiler.mirrorsUsedConstructor); |
| 3806 Selector callSelector = resolveSelector(node.send, constructor); | 3926 Selector callSelector = resolveSelector(node.send, constructor); |
| 3807 ArgumentsResult argumentsResult; | 3927 ArgumentsResult argumentsResult; |
| 3808 if (node.isConst) { | 3928 if (node.isConst) { |
| 3809 argumentsResult = | 3929 argumentsResult = |
| 3810 inConstantContext(() => resolveArguments(node.send.argumentsNode)); | 3930 inConstantContext(() => resolveArguments(node.send.argumentsNode)); |
| 3811 } else { | 3931 } else { |
| 3812 argumentsResult = resolveArguments(node.send.argumentsNode); | 3932 argumentsResult = resolveArguments(node.send.argumentsNode); |
| 3813 } | 3933 } |
| 3934 |
| 3814 registry.useElement(node.send, constructor); | 3935 registry.useElement(node.send, constructor); |
| 3815 if (Elements.isUnresolved(constructor)) { | 3936 if (Elements.isUnresolved(constructor)) { |
| 3816 return new ResolutionResult.forElement(constructor); | 3937 if (node.isConst) { |
| 3938 ConstantExpression constant = new ErroneousConstantExpression(); |
| 3939 registry.setConstant(node, constant); |
| 3940 return new ConstantResult(node, constant, element: constructor); |
| 3941 } |
| 3942 return ensureConstantResult(node, |
| 3943 new ResolutionResult.forElement(constructor)); |
| 3817 } | 3944 } |
| 3818 constructor.computeType(resolution); | 3945 constructor.computeType(resolution); |
| 3819 if (!callSelector.applies(constructor, compiler.world)) { | 3946 if (!callSelector.applies(constructor, compiler.world)) { |
| 3820 registry.registerThrowNoSuchMethod(); | 3947 registry.registerThrowNoSuchMethod(); |
| 3948 if (node.isConst) { |
| 3949 // TODO(johnniwinther): Provide a better message. |
| 3950 reporter.reportErrorMessage( |
| 3951 node, MessageKind.NOT_A_COMPILE_TIME_CONSTANT); |
| 3952 } |
| 3953 isValidAsConstant = false; |
| 3821 } | 3954 } |
| 3822 | 3955 |
| 3823 // [constructor] might be the implementation element | 3956 // [constructor] might be the implementation element |
| 3824 // and only declaration elements may be registered. | 3957 // and only declaration elements may be registered. |
| 3825 registry.registerStaticUse(constructor.declaration); | 3958 registry.registerStaticUse(constructor.declaration); |
| 3826 ClassElement cls = constructor.enclosingClass; | 3959 ClassElement cls = constructor.enclosingClass; |
| 3827 if (cls.isEnumClass && currentClass != cls) { | 3960 if (cls.isEnumClass && currentClass != cls) { |
| 3828 reporter.reportErrorMessage( | 3961 reporter.reportErrorMessage( |
| 3829 node, | 3962 node, |
| 3830 MessageKind.CANNOT_INSTANTIATE_ENUM, | 3963 MessageKind.CANNOT_INSTANTIATE_ENUM, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3870 if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage( | 4003 if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage( |
| 3871 enclosingElement)) { | 4004 enclosingElement)) { |
| 3872 reporter.reportHintMessage( | 4005 reporter.reportHintMessage( |
| 3873 node.newToken, MessageKind.NON_CONST_BLOAT, | 4006 node.newToken, MessageKind.NON_CONST_BLOAT, |
| 3874 {'name': compiler.symbolClass.name}); | 4007 {'name': compiler.symbolClass.name}); |
| 3875 } | 4008 } |
| 3876 } | 4009 } |
| 3877 } else if (isMirrorsUsedConstant) { | 4010 } else if (isMirrorsUsedConstant) { |
| 3878 compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping); | 4011 compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping); |
| 3879 } | 4012 } |
| 4013 |
| 4014 ConstantExpression constant; |
| 3880 if (node.isConst) { | 4015 if (node.isConst) { |
| 3881 analyzeConstantDeferred(node); | 4016 analyzeConstantDeferred(node); |
| 3882 | 4017 |
| 3883 // TODO(johnniwinther): Compute this in the [ConstructorResolver]. | 4018 // TODO(johnniwinther): Compute this in the [ConstructorResolver]. |
| 3884 // Check that the constructor is not deferred. | 4019 // Check that the constructor is not deferred. |
| 3885 Send send = node.send.selector.asSend(); | 4020 Send send = node.send.selector.asSend(); |
| 3886 if (send != null) { | 4021 if (send != null) { |
| 3887 // Of the form `const a.b(...)`. | 4022 // Of the form `const a.b(...)`. |
| 3888 if (compiler.deferredLoadTask.deferredPrefixElement( | 4023 if (compiler.deferredLoadTask.deferredPrefixElement( |
| 3889 send, registry.mapping) != null) { | 4024 send, registry.mapping) != null) { |
| 3890 // `a` is a deferred prefix. | 4025 // `a` is a deferred prefix. |
| 3891 isValidAsConstant = false; | 4026 isValidAsConstant = false; |
| 3892 // TODO(johnniwinther): Create an [ErroneousConstantExpression] here | 4027 // TODO(johnniwinther): Create an [ErroneousConstantExpression] here |
| 3893 // when constants are only created during resolution. | 4028 // when constants are only created during resolution. |
| 3894 } | 4029 } |
| 3895 } | 4030 } |
| 3896 | 4031 |
| 3897 if (isValidAsConstant && | 4032 if (isValidAsConstant && |
| 3898 constructor.isConst && | 4033 constructor.isConst && |
| 3899 argumentsResult.isValidAsConstant) { | 4034 argumentsResult.isValidAsConstant) { |
| 3900 CallStructure callStructure = argumentsResult.callStructure; | 4035 CallStructure callStructure = argumentsResult.callStructure; |
| 3901 List<ConstantExpression> arguments = argumentsResult.constantArguments; | 4036 List<ConstantExpression> arguments = |
| 3902 ConstructedConstantExpression constant = | 4037 argumentsResult.constantArguments; |
| 3903 new ConstructedConstantExpression( | 4038 if (constructor.isFromEnvironmentConstructor) { |
| 3904 type, | 4039 ConstantResult nameResult = argumentsResult.argumentResults[0]; |
| 3905 constructor, | 4040 ConstantResult defaultValueResult; |
| 3906 callStructure, | 4041 ConstantExpression defaultValueConstant; |
| 3907 arguments); | 4042 if (arguments.length > 1) { |
| 3908 return new ConstantResult(node, constant); | 4043 defaultValueResult = argumentsResult.argumentResults[1]; |
| 4044 defaultValueConstant = defaultValueResult.constant; |
| 4045 } |
| 4046 if (type == coreTypes.boolType) { |
| 4047 isValidAsConstant = constantChecker.checkBoolFromEnvironment( |
| 4048 constantChecker.createInfo(nameResult), |
| 4049 constantChecker.createInfo(defaultValueResult)); |
| 4050 if (isValidAsConstant) { |
| 4051 constant = new BoolFromEnvironmentConstantExpression( |
| 4052 nameResult.constant, defaultValueConstant); |
| 4053 } |
| 4054 } else if (type == coreTypes.intType) { |
| 4055 isValidAsConstant = constantChecker.checkIntFromEnvironment( |
| 4056 constantChecker.createInfo(nameResult), |
| 4057 constantChecker.createInfo(defaultValueResult)); |
| 4058 if (isValidAsConstant) { |
| 4059 constant = new IntFromEnvironmentConstantExpression( |
| 4060 nameResult.constant, defaultValueConstant); |
| 4061 } |
| 4062 } else { |
| 4063 assert(type == coreTypes.stringType); |
| 4064 isValidAsConstant = constantChecker.checkStringFromEnvironment( |
| 4065 constantChecker.createInfo(nameResult), |
| 4066 constantChecker.createInfo(defaultValueResult)); |
| 4067 if (isValidAsConstant) { |
| 4068 constant = new StringFromEnvironmentConstantExpression( |
| 4069 nameResult.constant, defaultValueConstant); |
| 4070 } |
| 4071 } |
| 4072 } else { |
| 4073 constant = new ConstructedConstantExpression( |
| 4074 type, constructor, callStructure, arguments); |
| 4075 } |
| 4076 } |
| 4077 if (constant == null) { |
| 4078 constant = new ErroneousConstantExpression(); |
| 3909 } | 4079 } |
| 3910 } | 4080 } |
| 3911 | 4081 if (constant != null) { |
| 3912 return const NoneResult(); | 4082 registry.setConstant(node, constant); |
| 4083 return new ConstantResult(node, constant); |
| 4084 } else { |
| 4085 return ensureConstantResult(node, const NoneResult()); |
| 4086 } |
| 3913 } | 4087 } |
| 3914 | 4088 |
| 3915 void checkConstMapKeysDontOverrideEquals(Spannable spannable, | 4089 void checkConstMapKeysDontOverrideEquals(Spannable spannable, |
| 3916 MapConstantValue map) { | 4090 MapConstantValue map) { |
| 3917 for (ConstantValue key in map.keys) { | 4091 for (ConstantValue key in map.keys) { |
| 3918 if (!key.isObject) continue; | 4092 if (!key.isObject) continue; |
| 3919 ObjectConstantValue objectConstant = key; | 4093 ObjectConstantValue objectConstant = key; |
| 3920 DartType keyType = objectConstant.type; | 4094 DartType keyType = objectConstant.type; |
| 3921 ClassElement cls = keyType.element; | 4095 ClassElement cls = keyType.element; |
| 3922 if (cls == compiler.stringClass) continue; | 4096 if (cls == compiler.stringClass) continue; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4047 ResolutionResult elementResult = visit(element); | 4221 ResolutionResult elementResult = visit(element); |
| 4048 if (isValidAsConstant && elementResult.isConstant) { | 4222 if (isValidAsConstant && elementResult.isConstant) { |
| 4049 constantExpressions.add(elementResult.constant); | 4223 constantExpressions.add(elementResult.constant); |
| 4050 } else { | 4224 } else { |
| 4051 isValidAsConstant = false; | 4225 isValidAsConstant = false; |
| 4052 } | 4226 } |
| 4053 } | 4227 } |
| 4054 }); | 4228 }); |
| 4055 analyzeConstantDeferred(node); | 4229 analyzeConstantDeferred(node); |
| 4056 sendIsMemberAccess = false; | 4230 sendIsMemberAccess = false; |
| 4231 ConstantExpression constant; |
| 4057 if (isValidAsConstant) { | 4232 if (isValidAsConstant) { |
| 4058 ConstantExpression constant = | 4233 constant = new ListConstantExpression(listType, constantExpressions); |
| 4059 new ListConstantExpression(listType, constantExpressions); | 4234 } else { |
| 4060 registry.setConstant(node, constant); | 4235 constant = new ErroneousConstantExpression(); |
| 4061 return new ConstantResult(node, constant); | |
| 4062 } | 4236 } |
| 4237 registry.setConstant(node, constant); |
| 4238 return new ConstantResult(node, constant); |
| 4063 } else { | 4239 } else { |
| 4064 visit(node.elements); | 4240 visit(node.elements); |
| 4065 sendIsMemberAccess = false; | 4241 sendIsMemberAccess = false; |
| 4066 } | 4242 } |
| 4067 return const NoneResult(); | 4243 return const NoneResult(); |
| 4068 | 4244 |
| 4069 } | 4245 } |
| 4070 | 4246 |
| 4071 ResolutionResult visitConditional(Conditional node) { | 4247 ResolutionResult visitConditional(Conditional node) { |
| 4072 ResolutionResult conditionResult = | 4248 ResolutionResult conditionResult = |
| 4073 doInPromotionScope(node.condition, () => visit(node.condition)); | 4249 doInPromotionScope(node.condition, () => visit(node.condition)); |
| 4250 assert(checkConstantInvariant(node.condition, conditionResult)); |
| 4251 |
| 4074 ResolutionResult thenResult = | 4252 ResolutionResult thenResult = |
| 4075 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression)
); | 4253 doInPromotionScope(node.thenExpression, |
| 4254 () => visit(node.thenExpression)); |
| 4255 assert(checkConstantInvariant(node.thenExpression, thenResult)); |
| 4256 |
| 4076 ResolutionResult elseResult = visit(node.elseExpression); | 4257 ResolutionResult elseResult = visit(node.elseExpression); |
| 4258 assert(checkConstantInvariant(node.elseExpression, elseResult)); |
| 4259 |
| 4260 ConstantExpression constant; |
| 4077 if (conditionResult.isConstant && | 4261 if (conditionResult.isConstant && |
| 4078 thenResult.isConstant && | 4262 thenResult.isConstant && |
| 4079 elseResult.isConstant) { | 4263 elseResult.isConstant) { |
| 4080 ConstantExpression constant = new ConditionalConstantExpression( | 4264 bool isValidAsConstant = constantChecker.checkConditional( |
| 4081 conditionResult.constant, | 4265 constantChecker.createInfo(conditionResult)); |
| 4082 thenResult.constant, | 4266 if (isValidAsConstant) { |
| 4083 elseResult.constant); | 4267 constant = new ConditionalConstantExpression( |
| 4268 conditionResult.constant, |
| 4269 thenResult.constant, |
| 4270 elseResult.constant); |
| 4271 } |
| 4272 } |
| 4273 if (constant == null && constantState.requiresConstant) { |
| 4274 constant = new ErroneousConstantExpression(); |
| 4275 } |
| 4276 if (constant != null) { |
| 4084 registry.setConstant(node, constant); | 4277 registry.setConstant(node, constant); |
| 4085 return new ConstantResult(node, constant); | 4278 return new ConstantResult(node, constant); |
| 4086 } | 4279 } |
| 4087 return const NoneResult(); | 4280 return const NoneResult(); |
| 4088 } | 4281 } |
| 4089 | 4282 |
| 4090 ResolutionResult visitStringInterpolation(StringInterpolation node) { | 4283 ResolutionResult visitStringInterpolation(StringInterpolation node) { |
| 4091 registry.registerInstantiatedType(coreTypes.stringType); | 4284 registry.registerInstantiatedType(coreTypes.stringType); |
| 4092 registry.registerStringInterpolation(); | 4285 registry.registerStringInterpolation(); |
| 4093 registerImplicitInvocation(Selectors.toString_); | 4286 registerImplicitInvocation(Selectors.toString_); |
| 4094 | 4287 |
| 4095 bool isValidAsConstant = true; | 4288 bool isValidAsConstant = true; |
| 4096 List<ConstantExpression> parts = <ConstantExpression>[]; | 4289 List<ConstantExpression> parts = <ConstantExpression>[]; |
| 4097 | 4290 |
| 4291 ConstantExpression constant; |
| 4098 void resolvePart(Node subnode) { | 4292 void resolvePart(Node subnode) { |
| 4099 ResolutionResult result = visit(subnode); | 4293 ResolutionResult result = visit(subnode); |
| 4100 if (isValidAsConstant && result.isConstant) { | 4294 if (result.isConstant) { |
| 4101 parts.add(result.constant); | 4295 bool isPartTypeValid = constantChecker.checkConcatenate( |
| 4102 } else { | 4296 constantChecker.createInfo(result)); |
| 4103 isValidAsConstant = false; | 4297 if (isPartTypeValid) { |
| 4298 parts.add(result.constant); |
| 4299 } else { |
| 4300 isValidAsConstant = false; |
| 4301 } |
| 4104 } | 4302 } |
| 4105 } | 4303 } |
| 4106 | 4304 |
| 4107 resolvePart(node.string); | 4305 resolvePart(node.string); |
| 4108 for (StringInterpolationPart part in node.parts) { | 4306 for (StringInterpolationPart part in node.parts) { |
| 4109 resolvePart(part.expression); | 4307 resolvePart(part.expression); |
| 4110 resolvePart(part.string); | 4308 resolvePart(part.string); |
| 4111 } | 4309 } |
| 4112 | |
| 4113 if (isValidAsConstant) { | 4310 if (isValidAsConstant) { |
| 4114 ConstantExpression constant = new ConcatenateConstantExpression(parts); | 4311 constant = new ConcatenateConstantExpression(parts); |
| 4312 } else if (constantState.requiresConstant) { |
| 4313 constant = new ErroneousConstantExpression(); |
| 4314 } |
| 4315 if (constant != null) { |
| 4115 registry.setConstant(node, constant); | 4316 registry.setConstant(node, constant); |
| 4116 return new ConstantResult(node, constant); | 4317 return new ConstantResult(node, constant); |
| 4117 } | 4318 } |
| 4118 return const NoneResult(); | 4319 return const NoneResult(); |
| 4119 } | 4320 } |
| 4120 | 4321 |
| 4121 ResolutionResult visitBreakStatement(BreakStatement node) { | 4322 ResolutionResult visitBreakStatement(BreakStatement node) { |
| 4122 JumpTarget target; | 4323 JumpTarget target; |
| 4123 if (node.target == null) { | 4324 if (node.target == null) { |
| 4124 target = statementScope.currentBreakTarget(); | 4325 target = statementScope.currentBreakTarget(); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4364 isConstant: node.isConst, | 4565 isConstant: node.isConst, |
| 4365 isEmpty: node.entries.isEmpty); | 4566 isEmpty: node.entries.isEmpty); |
| 4366 registry.registerRequiredType(mapType, enclosingElement); | 4567 registry.registerRequiredType(mapType, enclosingElement); |
| 4367 if (node.isConst) { | 4568 if (node.isConst) { |
| 4368 | 4569 |
| 4369 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; | 4570 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; |
| 4370 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; | 4571 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; |
| 4371 inConstantContext(() { | 4572 inConstantContext(() { |
| 4372 for (LiteralMapEntry entry in node.entries) { | 4573 for (LiteralMapEntry entry in node.entries) { |
| 4373 ResolutionResult keyResult = visit(entry.key); | 4574 ResolutionResult keyResult = visit(entry.key); |
| 4575 assert(checkConstantInvariant(entry.key, keyResult)); |
| 4374 ResolutionResult valueResult = visit(entry.value); | 4576 ResolutionResult valueResult = visit(entry.value); |
| 4577 assert(checkConstantInvariant(entry.value, valueResult)); |
| 4375 if (isValidAsConstant && | 4578 if (isValidAsConstant && |
| 4376 keyResult.isConstant && | 4579 keyResult.isConstant && |
| 4377 valueResult.isConstant) { | 4580 valueResult.isConstant) { |
| 4378 keyExpressions.add(keyResult.constant); | 4581 keyExpressions.add(keyResult.constant); |
| 4379 valueExpressions.add(valueResult.constant); | 4582 valueExpressions.add(valueResult.constant); |
| 4380 } else { | 4583 } else { |
| 4381 isValidAsConstant = false; | 4584 isValidAsConstant = false; |
| 4382 } | 4585 } |
| 4383 } | 4586 } |
| 4384 }); | 4587 }); |
| 4385 analyzeConstantDeferred(node); | 4588 analyzeConstantDeferred(node); |
| 4386 sendIsMemberAccess = false; | 4589 sendIsMemberAccess = false; |
| 4590 ConstantExpression constant; |
| 4387 if (isValidAsConstant) { | 4591 if (isValidAsConstant) { |
| 4388 ConstantExpression constant = new MapConstantExpression( | 4592 constant = new MapConstantExpression( |
| 4389 mapType, keyExpressions, valueExpressions); | 4593 mapType, keyExpressions, valueExpressions); |
| 4390 registry.setConstant(node, constant); | 4594 } else { |
| 4391 return new ConstantResult(node, constant); | 4595 constant = new ErroneousConstantExpression(); |
| 4392 } | 4596 } |
| 4597 registry.setConstant(node, constant); |
| 4598 return new ConstantResult(node, constant); |
| 4393 } else { | 4599 } else { |
| 4394 node.visitChildren(this); | 4600 node.visitChildren(this); |
| 4395 sendIsMemberAccess = false; | 4601 sendIsMemberAccess = false; |
| 4396 } | 4602 } |
| 4397 return const NoneResult(); | 4603 return const NoneResult(); |
| 4398 } | 4604 } |
| 4399 | 4605 |
| 4400 ResolutionResult visitLiteralMapEntry(LiteralMapEntry node) { | 4606 ResolutionResult visitLiteralMapEntry(LiteralMapEntry node) { |
| 4401 node.visitChildren(this); | 4607 node.visitChildren(this); |
| 4402 return const NoneResult(); | 4608 return const NoneResult(); |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4682 } | 4888 } |
| 4683 return const NoneResult(); | 4889 return const NoneResult(); |
| 4684 } | 4890 } |
| 4685 } | 4891 } |
| 4686 | 4892 |
| 4687 /// Looks up [name] in [scope] and unwraps the result. | 4893 /// Looks up [name] in [scope] and unwraps the result. |
| 4688 Element lookupInScope(DiagnosticReporter reporter, Node node, | 4894 Element lookupInScope(DiagnosticReporter reporter, Node node, |
| 4689 Scope scope, String name) { | 4895 Scope scope, String name) { |
| 4690 return Elements.unwrap(scope.lookup(name), reporter, node); | 4896 return Elements.unwrap(scope.lookup(name), reporter, node); |
| 4691 } | 4897 } |
| 4898 |
| 4899 class ConstantNodeChecker extends ConstantTypeChecker<Spannable> { |
| 4900 final Compiler compiler; |
| 4901 final bool constantIsRequired; |
| 4902 |
| 4903 ConstantNodeChecker(this.compiler, {this.constantIsRequired}); |
| 4904 |
| 4905 @override |
| 4906 bool get allowUnknown => constantIsRequired; |
| 4907 |
| 4908 @override |
| 4909 CoreTypes get coreTypes => compiler.coreTypes; |
| 4910 |
| 4911 @override |
| 4912 bool get isRequired => constantIsRequired; |
| 4913 |
| 4914 @override |
| 4915 void reportError(Spannable position, MessageKind messageKind, Map arguments) { |
| 4916 if (constantIsRequired) { |
| 4917 compiler.reporter.reportErrorMessage(position, messageKind, arguments); |
| 4918 } |
| 4919 } |
| 4920 |
| 4921 ConstantTypeInfo createInfo(ResolutionResult result) { |
| 4922 if (result == null) return null; |
| 4923 return new NodeConstantTypeInfo( |
| 4924 result.node, result.constant, result.constant.getKnownType(coreTypes)); |
| 4925 } |
| 4926 } |
| 4927 |
| 4928 class NodeConstantTypeInfo implements ConstantTypeInfo<Spannable> { |
| 4929 final Spannable position; |
| 4930 final ConstantExpression constant; |
| 4931 final DartType type; |
| 4932 |
| 4933 NodeConstantTypeInfo(this.position, this.constant, this.type); |
| 4934 |
| 4935 String toString() { |
| 4936 return 'NodeConstantTypeInfo[' |
| 4937 'position=$position,constant=${constant.getText()},type=$type]'; |
| 4938 } |
| 4939 } |
| OLD | NEW |