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

Side by Side Diff: pkg/compiler/lib/src/resolution/members.dart

Issue 1559233002: WIP: Compute constant expressions in resolution. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/resolution/constructors.dart ('k') | pkg/compiler/lib/src/resolution/resolution.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698