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 |