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.compile_time_constant_evaluator; | 5 library dart2js.compile_time_constant_evaluator; |
6 | 6 |
7 import 'constant_system_dart.dart'; | 7 import 'constant_system_dart.dart'; |
8 import 'constants/constant_system.dart'; | 8 import 'constants/constant_system.dart'; |
9 import 'constants/expressions.dart'; | 9 import 'constants/expressions.dart'; |
10 import 'constants/values.dart'; | 10 import 'constants/values.dart'; |
11 import 'dart_types.dart'; | 11 import 'dart_types.dart'; |
12 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact,
invariant; | 12 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact,
invariant; |
13 import 'elements/elements.dart'; | 13 import 'elements/elements.dart'; |
14 import 'elements/modelx.dart' show FunctionElementX; | 14 import 'elements/modelx.dart' show FunctionElementX; |
15 import 'helpers/helpers.dart'; | 15 import 'helpers/helpers.dart'; |
16 import 'resolution/resolution.dart'; | 16 import 'resolution/resolution.dart'; |
17 import 'resolution/operators.dart'; | 17 import 'resolution/operators.dart'; |
18 import 'tree/tree.dart'; | 18 import 'tree/tree.dart'; |
19 import 'util/util.dart' show Link; | 19 import 'util/util.dart' show Link; |
20 import 'universe/universe.dart' show CallStructure; | 20 import 'universe/universe.dart' show CallStructure; |
21 | 21 |
22 /// A [ConstantEnvironment] provides access for constants compiled for variable | 22 /// A [ConstantEnvironment] provides access for constants compiled for variable |
23 /// initializers. | 23 /// initializers. |
24 abstract class ConstantEnvironment { | 24 abstract class ConstantEnvironment { |
| 25 /// The [ConstantSystem] used by this environment. |
| 26 ConstantSystem get constantSystem; |
| 27 |
| 28 /// Returns the constant value computed for [expression]. |
| 29 // TODO(johnniwinther): Support directly evaluation of [expression]. |
| 30 ConstantValue getConstantValue(ConstantExpression expression); |
| 31 |
| 32 /// Returns the constant value for the initializer of [element]. |
| 33 ConstantValue getConstantValueForVariable(VariableElement element); |
| 34 |
25 /// Returns the constant for the initializer of [element]. | 35 /// Returns the constant for the initializer of [element]. |
26 ConstantExpression getConstantForVariable(VariableElement element); | 36 ConstantExpression getConstantForVariable(VariableElement element); |
27 } | 37 } |
28 | 38 |
29 /// A class that can compile and provide constants for variables, nodes and | 39 /// A class that can compile and provide constants for variables, nodes and |
30 /// metadata. | 40 /// metadata. |
31 abstract class ConstantCompiler extends ConstantEnvironment { | 41 abstract class ConstantCompiler extends ConstantEnvironment { |
32 /// Compiles the compile-time constant for the initializer of [element], or | 42 /// Compiles the compile-time constant for the initializer of [element], or |
33 /// reports an error if the initializer is not a compile-time constant. | 43 /// reports an error if the initializer is not a compile-time constant. |
34 /// | 44 /// |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 /// | 76 /// |
67 /// The returned constant is always of the frontend interpretation. | 77 /// The returned constant is always of the frontend interpretation. |
68 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 78 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
69 Node node, | 79 Node node, |
70 TreeElements elements); | 80 TreeElements elements); |
71 } | 81 } |
72 | 82 |
73 /// A [BackendConstantEnvironment] provides access to constants needed for | 83 /// A [BackendConstantEnvironment] provides access to constants needed for |
74 /// backend implementation. | 84 /// backend implementation. |
75 abstract class BackendConstantEnvironment extends ConstantEnvironment { | 85 abstract class BackendConstantEnvironment extends ConstantEnvironment { |
| 86 /// Returns the compile-time constant value associated with [node]. |
| 87 /// |
| 88 /// Depending on implementation, the constant might be stored in [elements]. |
| 89 ConstantValue getConstantValueForNode(Node node, TreeElements elements); |
| 90 |
76 /// Returns the compile-time constant associated with [node]. | 91 /// Returns the compile-time constant associated with [node]. |
77 /// | 92 /// |
78 /// Depending on implementation, the constant might be stored in [elements]. | 93 /// Depending on implementation, the constant might be stored in [elements]. |
79 ConstantExpression getConstantForNode(Node node, TreeElements elements); | 94 ConstantExpression getConstantForNode(Node node, TreeElements elements); |
80 | 95 |
81 /// Returns the compile-time constant value of [metadata]. | 96 /// Returns the compile-time constant value of [metadata]. |
82 ConstantExpression getConstantForMetadata(MetadataAnnotation metadata); | 97 ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata); |
83 } | 98 } |
84 | 99 |
85 /// Interface for the task that compiles the constant environments for the | 100 /// Interface for the task that compiles the constant environments for the |
86 /// frontend and backend interpretation of compile-time constants. | 101 /// frontend and backend interpretation of compile-time constants. |
87 abstract class ConstantCompilerTask extends CompilerTask | 102 abstract class ConstantCompilerTask extends CompilerTask |
88 implements ConstantCompiler { | 103 implements ConstantCompiler { |
89 ConstantCompilerTask(Compiler compiler) : super(compiler); | 104 ConstantCompilerTask(Compiler compiler) : super(compiler); |
| 105 |
| 106 /// Copy all cached constant values from [task]. |
| 107 /// |
| 108 /// This is a hack to support reuse cached compilers in memory_compiler. |
| 109 // TODO(johnniwinther): Remove this when values are computed from the |
| 110 // expressions. |
| 111 void copyConstantValues(ConstantCompilerTask task); |
90 } | 112 } |
91 | 113 |
92 /** | 114 /** |
93 * The [ConstantCompilerBase] is provides base implementation for compilation of | 115 * The [ConstantCompilerBase] is provides base implementation for compilation of |
94 * compile-time constants for both the Dart and JavaScript interpretation of | 116 * compile-time constants for both the Dart and JavaScript interpretation of |
95 * constants. It keeps track of compile-time constants for initializations of | 117 * constants. It keeps track of compile-time constants for initializations of |
96 * global and static fields, and default values of optional parameters. | 118 * global and static fields, and default values of optional parameters. |
97 */ | 119 */ |
98 abstract class ConstantCompilerBase implements ConstantCompiler { | 120 abstract class ConstantCompilerBase implements ConstantCompiler { |
99 final Compiler compiler; | 121 final Compiler compiler; |
(...skipping 10 matching lines...) Expand all Loading... |
110 * May contain default parameter values of optional arguments. | 132 * May contain default parameter values of optional arguments. |
111 * | 133 * |
112 * Invariant: The keys in this map are declarations. | 134 * Invariant: The keys in this map are declarations. |
113 */ | 135 */ |
114 final Map<VariableElement, ConstantExpression> initialVariableValues = | 136 final Map<VariableElement, ConstantExpression> initialVariableValues = |
115 new Map<VariableElement, ConstantExpression>(); | 137 new Map<VariableElement, ConstantExpression>(); |
116 | 138 |
117 /** The set of variable elements that are in the process of being computed. */ | 139 /** The set of variable elements that are in the process of being computed. */ |
118 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); | 140 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); |
119 | 141 |
| 142 final Map<ConstantExpression, ConstantValue> constantValueMap = |
| 143 <ConstantExpression, ConstantValue>{}; |
| 144 |
120 ConstantCompilerBase(this.compiler, this.constantSystem); | 145 ConstantCompilerBase(this.compiler, this.constantSystem); |
121 | 146 |
| 147 @override |
| 148 ConstantValue getConstantValueForVariable(VariableElement element) { |
| 149 return getConstantValue(initialVariableValues[element.declaration]); |
| 150 } |
| 151 |
| 152 @override |
122 ConstantExpression getConstantForVariable(VariableElement element) { | 153 ConstantExpression getConstantForVariable(VariableElement element) { |
123 return initialVariableValues[element.declaration]; | 154 return initialVariableValues[element.declaration]; |
124 } | 155 } |
125 | 156 |
126 ConstantExpression compileConstant(VariableElement element) { | 157 ConstantExpression compileConstant(VariableElement element) { |
127 return compileVariable(element, isConst: true); | 158 return compileVariable(element, isConst: true); |
128 } | 159 } |
129 | 160 |
130 ConstantExpression compileVariable(VariableElement element, | 161 ConstantExpression compileVariable(VariableElement element, |
131 {bool isConst: false}) { | 162 {bool isConst: false}) { |
(...skipping 20 matching lines...) Expand all Loading... |
152 * error. | 183 * error. |
153 */ | 184 */ |
154 ConstantExpression compileVariableWithDefinitions(VariableElement element, | 185 ConstantExpression compileVariableWithDefinitions(VariableElement element, |
155 TreeElements definitions, | 186 TreeElements definitions, |
156 {bool isConst: false}) { | 187 {bool isConst: false}) { |
157 Node node = element.node; | 188 Node node = element.node; |
158 if (pendingVariables.contains(element)) { | 189 if (pendingVariables.contains(element)) { |
159 if (isConst) { | 190 if (isConst) { |
160 compiler.reportError( | 191 compiler.reportError( |
161 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | 192 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
162 return new ErroneousConstantExpression(); | 193 ConstantExpression expression = new ErroneousConstantExpression(); |
| 194 constantValueMap[expression] = constantSystem.createNull(); |
| 195 return expression; |
163 } | 196 } |
164 return null; | 197 return null; |
165 } | 198 } |
166 pendingVariables.add(element); | 199 pendingVariables.add(element); |
167 | 200 |
168 Expression initializer = element.initializer; | 201 Expression initializer = element.initializer; |
169 ConstantExpression value; | 202 ConstantExpression expression; |
170 if (initializer == null) { | 203 if (initializer == null) { |
171 // No initial value. | 204 // No initial value. |
172 value = new NullConstantExpression(new NullConstantValue()); | 205 expression = new NullConstantExpression(); |
| 206 constantValueMap[expression] = constantSystem.createNull(); |
173 } else { | 207 } else { |
174 value = compileNodeWithDefinitions( | 208 expression = compileNodeWithDefinitions( |
175 initializer, definitions, isConst: isConst); | 209 initializer, definitions, isConst: isConst); |
176 if (compiler.enableTypeAssertions && | 210 if (compiler.enableTypeAssertions && |
177 value != null && | 211 expression != null && |
178 element.isField) { | 212 element.isField) { |
179 DartType elementType = element.type; | 213 DartType elementType = element.type; |
180 if (elementType.isMalformed && !value.value.isNull) { | 214 ConstantValue value = getConstantValue(expression); |
| 215 if (elementType.isMalformed && !value.isNull) { |
181 if (isConst) { | 216 if (isConst) { |
182 ErroneousElement element = elementType.element; | 217 ErroneousElement element = elementType.element; |
183 compiler.reportError( | 218 compiler.reportError( |
184 node, element.messageKind, element.messageArguments); | 219 node, element.messageKind, element.messageArguments); |
185 } else { | 220 } else { |
186 // We need to throw an exception at runtime. | 221 // We need to throw an exception at runtime. |
187 value = null; | 222 expression = null; |
188 } | 223 } |
189 } else { | 224 } else { |
190 DartType constantType = value.value.getType(compiler.coreTypes); | 225 DartType constantType = value.getType(compiler.coreTypes); |
191 if (!constantSystem.isSubtype(compiler.types, | 226 if (!constantSystem.isSubtype(compiler.types, |
192 constantType, elementType)) { | 227 constantType, elementType)) { |
193 if (isConst) { | 228 if (isConst) { |
194 compiler.reportError( | 229 compiler.reportError( |
195 node, MessageKind.NOT_ASSIGNABLE, | 230 node, MessageKind.NOT_ASSIGNABLE, |
196 {'fromType': constantType, 'toType': elementType}); | 231 {'fromType': constantType, 'toType': elementType}); |
197 } else { | 232 } else { |
198 // If the field cannot be lazily initialized, we will throw | 233 // If the field cannot be lazily initialized, we will throw |
199 // the exception at runtime. | 234 // the exception at runtime. |
200 value = null; | 235 expression = null; |
201 } | 236 } |
202 } | 237 } |
203 } | 238 } |
204 } | 239 } |
205 } | 240 } |
206 if (value != null) { | 241 if (expression != null) { |
207 initialVariableValues[element.declaration] = value; | 242 initialVariableValues[element.declaration] = expression; |
208 } else { | 243 } else { |
209 assert(invariant(element, !isConst, | 244 assert(invariant(element, !isConst, |
210 message: "Variable $element does not compile to a constant.")); | 245 message: "Variable $element does not compile to a constant.")); |
211 } | 246 } |
212 pendingVariables.remove(element); | 247 pendingVariables.remove(element); |
213 return value; | 248 return expression; |
214 } | 249 } |
215 | 250 |
216 ConstantExpression compileNodeWithDefinitions(Node node, | 251 ConstantExpression compileNodeWithDefinitions(Node node, |
217 TreeElements definitions, | 252 TreeElements definitions, |
218 {bool isConst: true}) { | 253 {bool isConst: true}) { |
219 assert(node != null); | 254 assert(node != null); |
220 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 255 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
221 this, definitions, compiler, isConst: isConst); | 256 this, definitions, compiler, isConst: isConst); |
222 AstConstant constant = evaluator.evaluate(node); | 257 AstConstant constant = evaluator.evaluate(node); |
223 return constant != null ? constant.expression : null; | 258 if (constant != null) { |
| 259 constantValueMap[constant.expression] = constant.value; |
| 260 return constant.expression; |
| 261 } |
| 262 return null; |
| 263 } |
| 264 |
| 265 ConstantValue getConstantValue(ConstantExpression expression) { |
| 266 return constantValueMap[expression]; |
224 } | 267 } |
225 | 268 |
226 ConstantExpression compileNode(Node node, TreeElements elements, | 269 ConstantExpression compileNode(Node node, TreeElements elements, |
227 {bool enforceConst: true}) { | 270 {bool enforceConst: true}) { |
228 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); | 271 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); |
229 } | 272 } |
230 | 273 |
231 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 274 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
232 Node node, | 275 Node node, |
233 TreeElements elements) { | 276 TreeElements elements) { |
(...skipping 14 matching lines...) Expand all Loading... |
248 /// [ConstantCompiler] that uses the Dart semantics for the compile-time | 291 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
249 /// constant evaluation. | 292 /// constant evaluation. |
250 class DartConstantCompiler extends ConstantCompilerBase { | 293 class DartConstantCompiler extends ConstantCompilerBase { |
251 DartConstantCompiler(Compiler compiler) | 294 DartConstantCompiler(Compiler compiler) |
252 : super(compiler, const DartConstantSystem()); | 295 : super(compiler, const DartConstantSystem()); |
253 | 296 |
254 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { | 297 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { |
255 return definitions.getConstant(node); | 298 return definitions.getConstant(node); |
256 } | 299 } |
257 | 300 |
258 ConstantExpression getConstantForMetadata(MetadataAnnotation metadata) { | |
259 return metadata.constant; | |
260 } | |
261 | |
262 ConstantExpression compileNodeWithDefinitions(Node node, | 301 ConstantExpression compileNodeWithDefinitions(Node node, |
263 TreeElements definitions, | 302 TreeElements definitions, |
264 {bool isConst: true}) { | 303 {bool isConst: true}) { |
265 ConstantExpression constant = definitions.getConstant(node); | 304 ConstantExpression constant = definitions.getConstant(node); |
266 if (constant != null) { | 305 if (constant != null) { |
267 return constant; | 306 return constant; |
268 } | 307 } |
269 constant = | 308 constant = |
270 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); | 309 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
271 if (constant != null) { | 310 if (constant != null) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 assert(result != null); | 344 assert(result != null); |
306 return result; | 345 return result; |
307 } | 346 } |
308 | 347 |
309 AstConstant visitNode(Node node) { | 348 AstConstant visitNode(Node node) { |
310 return signalNotCompileTimeConstant(node); | 349 return signalNotCompileTimeConstant(node); |
311 } | 350 } |
312 | 351 |
313 AstConstant visitLiteralBool(LiteralBool node) { | 352 AstConstant visitLiteralBool(LiteralBool node) { |
314 return new AstConstant( | 353 return new AstConstant( |
315 context, node, new BoolConstantExpression( | 354 context, |
316 node.value, | 355 node, |
317 constantSystem.createBool(node.value))); | 356 new BoolConstantExpression(node.value), |
| 357 constantSystem.createBool(node.value)); |
318 } | 358 } |
319 | 359 |
320 AstConstant visitLiteralDouble(LiteralDouble node) { | 360 AstConstant visitLiteralDouble(LiteralDouble node) { |
321 return new AstConstant( | 361 return new AstConstant( |
322 context, node, new DoubleConstantExpression( | 362 context, |
323 node.value, | 363 node, |
324 constantSystem.createDouble(node.value))); | 364 new DoubleConstantExpression(node.value), |
| 365 constantSystem.createDouble(node.value)); |
325 } | 366 } |
326 | 367 |
327 AstConstant visitLiteralInt(LiteralInt node) { | 368 AstConstant visitLiteralInt(LiteralInt node) { |
328 return new AstConstant( | 369 return new AstConstant( |
329 context, node, new IntConstantExpression( | 370 context, |
330 node.value, | 371 node, |
331 constantSystem.createInt(node.value))); | 372 new IntConstantExpression(node.value), |
| 373 constantSystem.createInt(node.value)); |
332 } | 374 } |
333 | 375 |
334 AstConstant visitLiteralList(LiteralList node) { | 376 AstConstant visitLiteralList(LiteralList node) { |
335 if (!node.isConst) { | 377 if (!node.isConst) { |
336 return signalNotCompileTimeConstant(node); | 378 return signalNotCompileTimeConstant(node); |
337 } | 379 } |
338 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; | 380 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; |
339 List<ConstantValue> argumentValues = <ConstantValue>[]; | 381 List<ConstantValue> argumentValues = <ConstantValue>[]; |
340 for (Link<Node> link = node.elements.nodes; | 382 for (Link<Node> link = node.elements.nodes; |
341 !link.isEmpty; | 383 !link.isEmpty; |
342 link = link.tail) { | 384 link = link.tail) { |
343 AstConstant argument = evaluateConstant(link.head); | 385 AstConstant argument = evaluateConstant(link.head); |
344 if (argument == null) { | 386 if (argument == null) { |
345 return null; | 387 return null; |
346 } | 388 } |
347 argumentExpressions.add(argument.expression); | 389 argumentExpressions.add(argument.expression); |
348 argumentValues.add(argument.value); | 390 argumentValues.add(argument.value); |
349 } | 391 } |
350 DartType type = elements.getType(node); | 392 DartType type = elements.getType(node); |
351 return new AstConstant( | 393 return new AstConstant( |
352 context, node, new ListConstantExpression( | 394 context, |
353 constantSystem.createList(type, argumentValues), | 395 node, |
354 type, | 396 new ListConstantExpression(type, argumentExpressions), |
355 argumentExpressions)); | 397 constantSystem.createList(type, argumentValues)); |
356 } | 398 } |
357 | 399 |
358 AstConstant visitLiteralMap(LiteralMap node) { | 400 AstConstant visitLiteralMap(LiteralMap node) { |
359 if (!node.isConst) { | 401 if (!node.isConst) { |
360 return signalNotCompileTimeConstant(node); | 402 return signalNotCompileTimeConstant(node); |
361 } | 403 } |
362 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; | 404 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; |
| 405 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; |
363 List<ConstantValue> keyValues = <ConstantValue>[]; | 406 List<ConstantValue> keyValues = <ConstantValue>[]; |
364 Map<ConstantValue, ConstantExpression> map = | 407 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; |
365 new Map<ConstantValue, ConstantExpression>(); | |
366 for (Link<Node> link = node.entries.nodes; | 408 for (Link<Node> link = node.entries.nodes; |
367 !link.isEmpty; | 409 !link.isEmpty; |
368 link = link.tail) { | 410 link = link.tail) { |
369 LiteralMapEntry entry = link.head; | 411 LiteralMapEntry entry = link.head; |
370 AstConstant key = evaluateConstant(entry.key); | 412 AstConstant key = evaluateConstant(entry.key); |
371 if (key == null) { | 413 if (key == null) { |
372 return null; | 414 return null; |
373 } | 415 } |
374 if (!map.containsKey(key.value)) { | |
375 keyExpressions.add(key.expression); | |
376 keyValues.add(key.value); | |
377 } else { | |
378 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); | |
379 } | |
380 AstConstant value = evaluateConstant(entry.value); | 416 AstConstant value = evaluateConstant(entry.value); |
381 if (value == null) { | 417 if (value == null) { |
382 return null; | 418 return null; |
383 } | 419 } |
384 map[key.value] = value.expression; | 420 if (!map.containsKey(key.value)) { |
| 421 keyValues.add(key.value); |
| 422 } else { |
| 423 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); |
| 424 } |
| 425 keyExpressions.add(key.expression); |
| 426 valueExpressions.add(value.expression); |
| 427 map[key.value] = value.value; |
385 } | 428 } |
386 List<ConstantExpression> valueExpressions = map.values.toList(); | |
387 InterfaceType type = elements.getType(node); | 429 InterfaceType type = elements.getType(node); |
388 return new AstConstant( | 430 return new AstConstant( |
389 context, node, new MapConstantExpression( | 431 context, |
390 constantSystem.createMap(compiler, type, keyValues, | 432 node, |
391 valueExpressions.map((e) => e.value).toList()), | 433 new MapConstantExpression( |
392 type, | 434 type, |
393 keyExpressions, | 435 keyExpressions, |
394 valueExpressions)); | 436 valueExpressions), |
| 437 constantSystem.createMap( |
| 438 compiler, type, keyValues, map.values.toList())); |
395 } | 439 } |
396 | 440 |
397 AstConstant visitLiteralNull(LiteralNull node) { | 441 AstConstant visitLiteralNull(LiteralNull node) { |
398 return new AstConstant( | 442 return new AstConstant( |
399 context, node, new NullConstantExpression( | 443 context, |
400 constantSystem.createNull())); | 444 node, |
| 445 new NullConstantExpression(), |
| 446 constantSystem.createNull()); |
401 } | 447 } |
402 | 448 |
403 AstConstant visitLiteralString(LiteralString node) { | 449 AstConstant visitLiteralString(LiteralString node) { |
404 return new AstConstant( | 450 return new AstConstant( |
405 context, node, new StringConstantExpression( | 451 context, |
406 node.dartString.slowToString(), | 452 node, |
407 constantSystem.createString(node.dartString))); | 453 new StringConstantExpression(node.dartString.slowToString()), |
| 454 constantSystem.createString(node.dartString)); |
408 } | 455 } |
409 | 456 |
410 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { | 457 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { |
411 AstConstant left = evaluate(node.first); | 458 AstConstant left = evaluate(node.first); |
412 AstConstant right = evaluate(node.second); | 459 AstConstant right = evaluate(node.second); |
413 if (left == null || right == null) return null; | 460 if (left == null || right == null) return null; |
414 StringConstantValue leftValue = left.value; | 461 StringConstantValue leftValue = left.value; |
415 StringConstantValue rightValue = right.value; | 462 StringConstantValue rightValue = right.value; |
416 return new AstConstant( | 463 return new AstConstant( |
417 context, node, new ConcatenateConstantExpression( | 464 context, |
418 constantSystem.createString( | 465 node, |
419 new DartString.concat( | 466 new ConcatenateConstantExpression([left.expression, right.expression]), |
420 leftValue.primitiveValue, rightValue.primitiveValue)), | 467 constantSystem.createString( |
421 [left.expression, right.expression])); | 468 new DartString.concat( |
| 469 leftValue.primitiveValue, rightValue.primitiveValue))); |
422 } | 470 } |
423 | 471 |
424 AstConstant visitStringInterpolation(StringInterpolation node) { | 472 AstConstant visitStringInterpolation(StringInterpolation node) { |
425 List<ConstantExpression> subexpressions = <ConstantExpression>[]; | 473 List<ConstantExpression> subexpressions = <ConstantExpression>[]; |
426 AstConstant initialString = evaluate(node.string); | 474 AstConstant initialString = evaluate(node.string); |
427 if (initialString == null) { | 475 if (initialString == null) { |
428 return null; | 476 return null; |
429 } | 477 } |
430 subexpressions.add(initialString.expression); | 478 subexpressions.add(initialString.expression); |
431 StringConstantValue initialStringValue = initialString.value; | 479 StringConstantValue initialStringValue = initialString.value; |
(...skipping 20 matching lines...) Expand all Loading... |
452 } | 500 } |
453 accumulator = new DartString.concat(accumulator, expressionString); | 501 accumulator = new DartString.concat(accumulator, expressionString); |
454 AstConstant partString = evaluate(part.string); | 502 AstConstant partString = evaluate(part.string); |
455 if (partString == null) return null; | 503 if (partString == null) return null; |
456 subexpressions.add(partString.expression); | 504 subexpressions.add(partString.expression); |
457 StringConstantValue partStringValue = partString.value; | 505 StringConstantValue partStringValue = partString.value; |
458 accumulator = | 506 accumulator = |
459 new DartString.concat(accumulator, partStringValue.primitiveValue); | 507 new DartString.concat(accumulator, partStringValue.primitiveValue); |
460 }; | 508 }; |
461 return new AstConstant( | 509 return new AstConstant( |
462 context, node, new ConcatenateConstantExpression( | 510 context, |
463 constantSystem.createString(accumulator), | 511 node, |
464 subexpressions)); | 512 new ConcatenateConstantExpression(subexpressions), |
| 513 constantSystem.createString(accumulator)); |
465 } | 514 } |
466 | 515 |
467 AstConstant visitLiteralSymbol(LiteralSymbol node) { | 516 AstConstant visitLiteralSymbol(LiteralSymbol node) { |
468 InterfaceType type = compiler.symbolClass.rawType; | 517 InterfaceType type = compiler.symbolClass.rawType; |
469 String text = node.slowNameString; | 518 String text = node.slowNameString; |
470 List<AstConstant> arguments = | 519 List<AstConstant> arguments = |
471 <AstConstant>[new AstConstant(context, node, | 520 <AstConstant>[new AstConstant( |
472 new StringConstantExpression( | 521 context, |
473 text, | 522 node, |
474 constantSystem.createString(new LiteralDartString(text))))]; | 523 new StringConstantExpression(text), |
| 524 constantSystem.createString(new LiteralDartString(text)))]; |
475 ConstructorElement constructor = compiler.symbolConstructor; | 525 ConstructorElement constructor = compiler.symbolConstructor; |
476 AstConstant constant = createConstructorInvocation( | 526 AstConstant constant = createConstructorInvocation( |
477 node, type, constructor, CallStructure.ONE_ARG, | 527 node, type, constructor, CallStructure.ONE_ARG, |
478 normalizedArguments: arguments); | 528 normalizedArguments: arguments); |
479 return new AstConstant( | 529 return new AstConstant( |
480 context, node, new SymbolConstantExpression(constant.value, text)); | 530 context, node, new SymbolConstantExpression(text), constant.value); |
481 } | 531 } |
482 | 532 |
483 ConstantExpression makeTypeConstant(DartType elementType) { | 533 ConstantValue makeTypeConstant(DartType elementType) { |
484 return new TypeConstantExpression( | 534 return constantSystem.createType(compiler, elementType); |
485 constantSystem.createType(compiler, elementType), elementType); | |
486 } | 535 } |
487 | 536 |
488 /// Returns true if the prefix of the send resolves to a deferred import | 537 /// Returns true if the prefix of the send resolves to a deferred import |
489 /// prefix. | 538 /// prefix. |
490 bool isDeferredUse(Send send) { | 539 bool isDeferredUse(Send send) { |
491 if (send == null) return false; | 540 if (send == null) return false; |
492 return compiler.deferredLoadTask | 541 return compiler.deferredLoadTask |
493 .deferredPrefixElement(send, elements) != null; | 542 .deferredPrefixElement(send, elements) != null; |
494 } | 543 } |
495 | 544 |
496 AstConstant visitIdentifier(Identifier node) { | 545 AstConstant visitIdentifier(Identifier node) { |
497 Element element = elements[node]; | 546 Element element = elements[node]; |
498 if (Elements.isClass(element) || Elements.isTypedef(element)) { | 547 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
499 TypeDeclarationElement typeDeclarationElement = element; | 548 TypeDeclarationElement typeDeclarationElement = element; |
500 DartType type = typeDeclarationElement.rawType; | 549 DartType type = typeDeclarationElement.rawType; |
501 return new AstConstant(element, node, makeTypeConstant(type)); | 550 return new AstConstant(element, node, |
| 551 new TypeConstantExpression(type), makeTypeConstant(type)); |
502 } | 552 } |
503 return signalNotCompileTimeConstant(node); | 553 return signalNotCompileTimeConstant(node); |
504 } | 554 } |
505 | 555 |
506 // TODO(floitsch): provide better error-messages. | 556 // TODO(floitsch): provide better error-messages. |
507 AstConstant visitSend(Send send) { | 557 AstConstant visitSend(Send send) { |
508 Element element = elements[send]; | 558 Element element = elements[send]; |
509 if (send.isPropertyAccess) { | 559 if (send.isPropertyAccess) { |
510 ConstantExpression result; | 560 AstConstant result; |
511 | |
512 if (Elements.isStaticOrTopLevelFunction(element)) { | 561 if (Elements.isStaticOrTopLevelFunction(element)) { |
513 FunctionElementX function = element; | 562 FunctionElementX function = element; |
514 function.computeType(compiler); | 563 function.computeType(compiler); |
515 result = new FunctionConstantExpression( | 564 result = new AstConstant( |
516 new FunctionConstantValue(function), function); | 565 context, |
| 566 send, |
| 567 new FunctionConstantExpression(function), |
| 568 new FunctionConstantValue(function)); |
517 } else if (Elements.isStaticOrTopLevelField(element)) { | 569 } else if (Elements.isStaticOrTopLevelField(element)) { |
518 ConstantExpression elementExpression; | 570 ConstantExpression elementExpression; |
519 if (element.isConst) { | 571 if (element.isConst) { |
520 elementExpression = handler.compileConstant(element); | 572 elementExpression = handler.compileConstant(element); |
521 } else if (element.isFinal && !isEvaluatingConstant) { | 573 } else if (element.isFinal && !isEvaluatingConstant) { |
522 elementExpression = handler.compileVariable(element); | 574 elementExpression = handler.compileVariable(element); |
523 } | 575 } |
524 if (elementExpression != null) { | 576 if (elementExpression != null) { |
525 result = | 577 result = new AstConstant( |
526 new VariableConstantExpression(elementExpression.value, element); | 578 context, |
| 579 send, |
| 580 new VariableConstantExpression(element), |
| 581 handler.getConstantValue(elementExpression)); |
527 } | 582 } |
528 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 583 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
529 assert(elements.isTypeLiteral(send)); | 584 assert(elements.isTypeLiteral(send)); |
530 result = makeTypeConstant(elements.getTypeLiteralType(send)); | 585 DartType elementType = elements.getTypeLiteralType(send); |
| 586 result = new AstConstant( |
| 587 context, |
| 588 send, |
| 589 new TypeConstantExpression(elementType), |
| 590 makeTypeConstant(elementType)); |
531 } else if (send.receiver != null) { | 591 } else if (send.receiver != null) { |
532 if (send.selector.asIdentifier().source == "length") { | 592 if (send.selector.asIdentifier().source == "length") { |
533 AstConstant left = evaluate(send.receiver); | 593 AstConstant left = evaluate(send.receiver); |
534 if (left != null && left.value.isString) { | 594 if (left != null && left.value.isString) { |
535 StringConstantValue stringConstantValue = left.value; | 595 StringConstantValue stringConstantValue = left.value; |
536 DartString string = stringConstantValue.primitiveValue; | 596 DartString string = stringConstantValue.primitiveValue; |
537 IntConstantValue length = constantSystem.createInt(string.length); | 597 IntConstantValue length = constantSystem.createInt(string.length); |
538 result = | 598 result = new AstConstant( |
539 new StringLengthConstantExpression(length, left.expression); | 599 context, |
| 600 send, |
| 601 new StringLengthConstantExpression(left.expression), |
| 602 length); |
540 } | 603 } |
541 } | 604 } |
542 // Fall through to error handling. | 605 // Fall through to error handling. |
543 } else if (!Elements.isUnresolved(element) | 606 } else if (!Elements.isUnresolved(element) |
544 && element.isVariable | 607 && element.isVariable |
545 && element.isConst) { | 608 && element.isConst) { |
546 ConstantExpression variableExpression = | 609 ConstantExpression variableExpression = |
547 handler.compileConstant(element); | 610 handler.compileConstant(element); |
548 if (variableExpression != null) { | 611 if (variableExpression != null) { |
549 result = new VariableConstantExpression(variableExpression.value, | 612 result = new AstConstant( |
550 element); | 613 context, |
| 614 send, |
| 615 new VariableConstantExpression(element), |
| 616 handler.getConstantValue(variableExpression)); |
551 } | 617 } |
552 } | 618 } |
553 if (result == null) { | 619 if (result == null) { |
554 return signalNotCompileTimeConstant(send); | 620 return signalNotCompileTimeConstant(send); |
555 } | 621 } |
556 if (isDeferredUse(send)) { | 622 if (isDeferredUse(send)) { |
557 if (isEvaluatingConstant) { | 623 if (isEvaluatingConstant) { |
558 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 624 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
559 } | 625 } |
560 PrefixElement prefix = compiler.deferredLoadTask | 626 PrefixElement prefix = compiler.deferredLoadTask |
561 .deferredPrefixElement(send, elements); | 627 .deferredPrefixElement(send, elements); |
562 result = new DeferredConstantExpression( | 628 result = new AstConstant( |
563 new DeferredConstantValue(result.value, prefix), | 629 context, |
564 result, | 630 send, |
565 prefix); | 631 new DeferredConstantExpression( |
| 632 result.expression, |
| 633 prefix), |
| 634 new DeferredConstantValue(result.value, prefix)); |
566 compiler.deferredLoadTask | 635 compiler.deferredLoadTask |
567 .registerConstantDeferredUse(result.value, prefix); | 636 .registerConstantDeferredUse(result.value, prefix); |
568 } | 637 } |
569 return new AstConstant(context, send, result); | 638 return result; |
570 } else if (send.isCall) { | 639 } else if (send.isCall) { |
571 if (element == compiler.identicalFunction | 640 if (element == compiler.identicalFunction |
572 && send.argumentCount() == 2) { | 641 && send.argumentCount() == 2) { |
573 AstConstant left = evaluate(send.argumentsNode.nodes.head); | 642 AstConstant left = evaluate(send.argumentsNode.nodes.head); |
574 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); | 643 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); |
575 if (left == null || right == null) { | 644 if (left == null || right == null) { |
576 return null; | 645 return null; |
577 } | 646 } |
578 ConstantValue result = | 647 ConstantValue result = |
579 constantSystem.identity.fold(left.value, right.value); | 648 constantSystem.identity.fold(left.value, right.value); |
580 if (result != null) { | 649 if (result != null) { |
581 return new AstConstant( | 650 return new AstConstant( |
582 context, send, new IdenticalConstantExpression(result, | 651 context, |
583 left.expression, right.expression)); | 652 send, |
| 653 new IdenticalConstantExpression( |
| 654 left.expression, right.expression), |
| 655 result); |
584 } | 656 } |
585 } | 657 } |
586 return signalNotCompileTimeConstant(send); | 658 return signalNotCompileTimeConstant(send); |
587 } else if (send.isPrefix) { | 659 } else if (send.isPrefix) { |
588 assert(send.isOperator); | 660 assert(send.isOperator); |
589 AstConstant receiverConstant = evaluate(send.receiver); | 661 AstConstant receiverConstant = evaluate(send.receiver); |
590 if (receiverConstant == null) { | 662 if (receiverConstant == null) { |
591 return null; | 663 return null; |
592 } | 664 } |
593 Operator node = send.selector; | 665 Operator node = send.selector; |
594 UnaryOperator operator = UnaryOperator.parse(node.source); | 666 UnaryOperator operator = UnaryOperator.parse(node.source); |
595 UnaryOperation operation = constantSystem.lookupUnary(operator); | 667 UnaryOperation operation = constantSystem.lookupUnary(operator); |
596 if (operation == null) { | 668 if (operation == null) { |
597 compiler.internalError(send.selector, "Unexpected operator."); | 669 compiler.internalError(send.selector, "Unexpected operator."); |
598 } | 670 } |
599 ConstantValue folded = operation.fold(receiverConstant.value); | 671 ConstantValue folded = operation.fold(receiverConstant.value); |
600 if (folded == null) { | 672 if (folded == null) { |
601 return signalNotCompileTimeConstant(send); | 673 return signalNotCompileTimeConstant(send); |
602 } | 674 } |
603 return new AstConstant( | 675 return new AstConstant( |
604 context, send, new UnaryConstantExpression(folded, | 676 context, |
605 operator, receiverConstant.expression)); | 677 send, |
| 678 new UnaryConstantExpression( |
| 679 operator, receiverConstant.expression), |
| 680 folded); |
606 } else if (send.isOperator && !send.isPostfix) { | 681 } else if (send.isOperator && !send.isPostfix) { |
607 assert(send.argumentCount() == 1); | 682 assert(send.argumentCount() == 1); |
608 AstConstant left = evaluate(send.receiver); | 683 AstConstant left = evaluate(send.receiver); |
609 AstConstant right = evaluate(send.argumentsNode.nodes.head); | 684 AstConstant right = evaluate(send.argumentsNode.nodes.head); |
610 if (left == null || right == null) { | 685 if (left == null || right == null) { |
611 return null; | 686 return null; |
612 } | 687 } |
613 ConstantValue leftValue = left.value; | 688 ConstantValue leftValue = left.value; |
614 ConstantValue rightValue = right.value; | 689 ConstantValue rightValue = right.value; |
615 Operator node = send.selector.asOperator(); | 690 Operator node = send.selector.asOperator(); |
(...skipping 22 matching lines...) Expand all Loading... |
638 BinaryOperation operation = constantSystem.lookupBinary(operator); | 713 BinaryOperation operation = constantSystem.lookupBinary(operator); |
639 if (operation != null) { | 714 if (operation != null) { |
640 folded = operation.fold(leftValue, rightValue); | 715 folded = operation.fold(leftValue, rightValue); |
641 } | 716 } |
642 } | 717 } |
643 } | 718 } |
644 if (folded == null) { | 719 if (folded == null) { |
645 return signalNotCompileTimeConstant(send); | 720 return signalNotCompileTimeConstant(send); |
646 } | 721 } |
647 return new AstConstant( | 722 return new AstConstant( |
648 context, send, new BinaryConstantExpression(folded, | 723 context, |
649 left.expression, operator, right.expression)); | 724 send, |
| 725 new BinaryConstantExpression( |
| 726 left.expression, operator, right.expression), |
| 727 folded); |
650 } | 728 } |
651 return signalNotCompileTimeConstant(send); | 729 return signalNotCompileTimeConstant(send); |
652 } | 730 } |
653 | 731 |
654 AstConstant visitConditional(Conditional node) { | 732 AstConstant visitConditional(Conditional node) { |
655 AstConstant condition = evaluate(node.condition); | 733 AstConstant condition = evaluate(node.condition); |
656 if (condition == null) { | 734 if (condition == null) { |
657 return null; | 735 return null; |
658 } else if (!condition.value.isBool) { | 736 } else if (!condition.value.isBool) { |
659 DartType conditionType = condition.value.getType(compiler.coreTypes); | 737 DartType conditionType = condition.value.getType(compiler.coreTypes); |
660 if (isEvaluatingConstant) { | 738 if (isEvaluatingConstant) { |
661 compiler.reportError( | 739 compiler.reportError( |
662 node.condition, MessageKind.NOT_ASSIGNABLE, | 740 node.condition, MessageKind.NOT_ASSIGNABLE, |
663 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); | 741 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); |
664 return new ErroneousAstConstant(context, node); | 742 return new ErroneousAstConstant(context, node); |
665 } | 743 } |
666 return null; | 744 return null; |
667 } | 745 } |
668 AstConstant thenExpression = evaluate(node.thenExpression); | 746 AstConstant thenExpression = evaluate(node.thenExpression); |
669 AstConstant elseExpression = evaluate(node.elseExpression); | 747 AstConstant elseExpression = evaluate(node.elseExpression); |
670 if (thenExpression == null || elseExpression == null) { | 748 if (thenExpression == null || elseExpression == null) { |
671 return null; | 749 return null; |
672 } | 750 } |
673 BoolConstantValue boolCondition = condition.value; | 751 BoolConstantValue boolCondition = condition.value; |
674 return new AstConstant( | 752 return new AstConstant( |
675 context, node, new ConditionalConstantExpression( | 753 context, |
676 boolCondition.primitiveValue | 754 node, |
677 ? thenExpression.value | 755 new ConditionalConstantExpression( |
678 : elseExpression.value, | |
679 condition.expression, | 756 condition.expression, |
680 thenExpression.expression, | 757 thenExpression.expression, |
681 elseExpression.expression)); | 758 elseExpression.expression), |
| 759 boolCondition.primitiveValue |
| 760 ? thenExpression.value |
| 761 : elseExpression.value); |
682 } | 762 } |
683 | 763 |
684 AstConstant visitSendSet(SendSet node) { | 764 AstConstant visitSendSet(SendSet node) { |
685 return signalNotCompileTimeConstant(node); | 765 return signalNotCompileTimeConstant(node); |
686 } | 766 } |
687 | 767 |
688 /** | 768 /** |
689 * Returns the normalized list of constant arguments that are passed to the | 769 * Returns the normalized list of constant arguments that are passed to the |
690 * constructor including both the concrete arguments and default values for | 770 * constructor including both the concrete arguments and default values for |
691 * omitted optional arguments. | 771 * omitted optional arguments. |
692 * | 772 * |
693 * Invariant: [target] must be an implementation element. | 773 * Invariant: [target] must be an implementation element. |
694 */ | 774 */ |
695 List<AstConstant> evaluateArgumentsToConstructor( | 775 List<AstConstant> evaluateArgumentsToConstructor( |
696 Node node, | 776 Node node, |
697 CallStructure callStructure, | 777 CallStructure callStructure, |
698 Link<Node> arguments, | 778 Link<Node> arguments, |
699 FunctionElement target, | 779 FunctionElement target, |
700 {AstConstant compileArgument(Node node)}) { | 780 {AstConstant compileArgument(Node node)}) { |
701 assert(invariant(node, target.isImplementation)); | 781 assert(invariant(node, target.isImplementation)); |
702 | 782 |
703 AstConstant compileDefaultValue(VariableElement element) { | 783 AstConstant compileDefaultValue(VariableElement element) { |
704 ConstantExpression constant = handler.compileConstant(element); | 784 ConstantExpression constant = handler.compileConstant(element); |
705 return new AstConstant.fromDefaultValue(element, constant); | 785 return new AstConstant.fromDefaultValue( |
| 786 element, constant, handler.getConstantValue(constant)); |
706 } | 787 } |
707 target.computeSignature(compiler); | 788 target.computeSignature(compiler); |
708 | 789 |
709 if (!callStructure.signatureApplies(target)) { | 790 if (!callStructure.signatureApplies(target)) { |
710 String name = Elements.constructorNameForDiagnostics( | 791 String name = Elements.constructorNameForDiagnostics( |
711 target.enclosingClass.name, target.name); | 792 target.enclosingClass.name, target.name); |
712 compiler.reportError( | 793 compiler.reportError( |
713 node, | 794 node, |
714 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, | 795 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, |
715 {'constructorName': name}); | 796 {'constructorName': name}); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 // a post-process action, so we have to make sure it is done here. | 848 // a post-process action, so we have to make sure it is done here. |
768 compiler.resolver.resolveRedirectionChain(constructor, node); | 849 compiler.resolver.resolveRedirectionChain(constructor, node); |
769 InterfaceType constructedType = | 850 InterfaceType constructedType = |
770 constructor.computeEffectiveTargetType(type); | 851 constructor.computeEffectiveTargetType(type); |
771 ConstructorElement target = constructor.effectiveTarget; | 852 ConstructorElement target = constructor.effectiveTarget; |
772 // The constructor must be an implementation to ensure that field | 853 // The constructor must be an implementation to ensure that field |
773 // initializers are handled correctly. | 854 // initializers are handled correctly. |
774 ConstructorElement implementation = target.implementation; | 855 ConstructorElement implementation = target.implementation; |
775 | 856 |
776 if (implementation.isErroneous) { | 857 if (implementation.isErroneous) { |
| 858 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant]. |
777 return new AstConstant( | 859 return new AstConstant( |
778 context, node, new ConstructedConstantExpression( | 860 context, |
779 new ConstructedConstantValue( | 861 node, |
780 constructedType, const <FieldElement, ConstantValue>{}), | 862 new ConstructedConstantExpression( |
781 type, | 863 type, |
782 constructor, | 864 constructor, |
783 callStructure, | 865 callStructure, |
784 const <ConstantExpression>[])); | 866 const <ConstantExpression>[]), |
| 867 new ConstructedConstantValue( |
| 868 constructedType, const <FieldElement, ConstantValue>{})); |
785 } | 869 } |
786 | 870 |
787 List<AstConstant> concreteArguments; | 871 List<AstConstant> concreteArguments; |
788 if (arguments != null) { | 872 if (arguments != null) { |
789 Map<Node, AstConstant> concreteArgumentMap = | 873 Map<Node, AstConstant> concreteArgumentMap = |
790 <Node, AstConstant>{}; | 874 <Node, AstConstant>{}; |
791 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { | 875 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { |
792 Node argument = link.head; | 876 Node argument = link.head; |
793 NamedArgument namedArgument = argument.asNamedArgument(); | 877 NamedArgument namedArgument = argument.asNamedArgument(); |
794 if (namedArgument != null) { | 878 if (namedArgument != null) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
881 AstConstant createEvaluatedConstant(ConstantValue value) { | 965 AstConstant createEvaluatedConstant(ConstantValue value) { |
882 | 966 |
883 ConstantExpression expression; | 967 ConstantExpression expression; |
884 ConstantExpression name = concreteArguments[0].expression; | 968 ConstantExpression name = concreteArguments[0].expression; |
885 ConstantExpression defaultValue; | 969 ConstantExpression defaultValue; |
886 if (concreteArguments.length > 1) { | 970 if (concreteArguments.length > 1) { |
887 defaultValue = concreteArguments[1].expression; | 971 defaultValue = concreteArguments[1].expression; |
888 } | 972 } |
889 if (constructor == compiler.intEnvironment) { | 973 if (constructor == compiler.intEnvironment) { |
890 expression = new IntFromEnvironmentConstantExpression( | 974 expression = new IntFromEnvironmentConstantExpression( |
891 value, name, defaultValue); | 975 name, defaultValue); |
892 } else if (constructor == compiler.boolEnvironment) { | 976 } else if (constructor == compiler.boolEnvironment) { |
893 expression = new BoolFromEnvironmentConstantExpression( | 977 expression = new BoolFromEnvironmentConstantExpression( |
894 value, name, defaultValue); | 978 name, defaultValue); |
895 } else if (constructor == compiler.stringEnvironment) { | 979 } else if (constructor == compiler.stringEnvironment) { |
896 expression = new StringFromEnvironmentConstantExpression( | 980 expression = new StringFromEnvironmentConstantExpression( |
897 value, name, defaultValue); | 981 name, defaultValue); |
898 } | 982 } |
899 return new AstConstant(context, node, expression); | 983 return new AstConstant(context, node, expression, value); |
900 } | 984 } |
901 | 985 |
902 if (value == null) { | 986 if (value == null) { |
903 return createEvaluatedConstant(defaultValue); | 987 return createEvaluatedConstant(defaultValue); |
904 } else if (constructor == compiler.intEnvironment) { | 988 } else if (constructor == compiler.intEnvironment) { |
905 int number = int.parse(value, onError: (_) => null); | 989 int number = int.parse(value, onError: (_) => null); |
906 return createEvaluatedConstant( | 990 return createEvaluatedConstant( |
907 (number == null) | 991 (number == null) |
908 ? defaultValue | 992 ? defaultValue |
909 : constantSystem.createInt(number)); | 993 : constantSystem.createInt(number)); |
(...skipping 22 matching lines...) Expand all Loading... |
932 InterfaceType constructedType, | 1016 InterfaceType constructedType, |
933 ConstructorElement target, | 1017 ConstructorElement target, |
934 CallStructure callStructure, | 1018 CallStructure callStructure, |
935 List<AstConstant> concreteArguments, | 1019 List<AstConstant> concreteArguments, |
936 List<AstConstant> normalizedArguments) { | 1020 List<AstConstant> normalizedArguments) { |
937 if (target.isRedirectingFactory) { | 1021 if (target.isRedirectingFactory) { |
938 // This happens is case of cyclic redirection. | 1022 // This happens is case of cyclic redirection. |
939 assert(invariant(node, compiler.compilationFailed, | 1023 assert(invariant(node, compiler.compilationFailed, |
940 message: "makeConstructedConstant can only be called with the " | 1024 message: "makeConstructedConstant can only be called with the " |
941 "effective target: $constructor")); | 1025 "effective target: $constructor")); |
942 return new AstConstant( | 1026 return new ErroneousAstConstant(context, node); |
943 context, node, new ErroneousConstantExpression()); | |
944 } | 1027 } |
945 assert(invariant(node, callStructure.signatureApplies(constructor) || | 1028 assert(invariant(node, callStructure.signatureApplies(constructor) || |
946 compiler.compilationFailed, | 1029 compiler.compilationFailed, |
947 message: "Call structure $callStructure does not apply to constructor " | 1030 message: "Call structure $callStructure does not apply to constructor " |
948 "$constructor.")); | 1031 "$constructor.")); |
949 | 1032 |
950 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 1033 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
951 constructedType, target, handler, compiler); | 1034 constructedType, target, handler, compiler); |
952 evaluator.evaluateConstructorFieldValues(normalizedArguments); | 1035 evaluator.evaluateConstructorFieldValues(normalizedArguments); |
953 Map<FieldElement, AstConstant> fieldConstants = | 1036 Map<FieldElement, AstConstant> fieldConstants = |
954 evaluator.buildFieldConstants(target.enclosingClass); | 1037 evaluator.buildFieldConstants(target.enclosingClass); |
955 Map<FieldElement, ConstantValue> fieldValues = | 1038 Map<FieldElement, ConstantValue> fieldValues = |
956 <FieldElement, ConstantValue>{}; | 1039 <FieldElement, ConstantValue>{}; |
957 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { | 1040 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { |
958 fieldValues[field] = astConstant.value; | 1041 fieldValues[field] = astConstant.value; |
959 }); | 1042 }); |
960 return new AstConstant( | 1043 return new AstConstant( |
961 context, node, new ConstructedConstantExpression( | 1044 context, |
962 new ConstructedConstantValue(constructedType, fieldValues), | 1045 node, |
| 1046 new ConstructedConstantExpression( |
963 type, | 1047 type, |
964 constructor, | 1048 constructor, |
965 callStructure, | 1049 callStructure, |
966 concreteArguments.map((e) => e.expression).toList())); | 1050 concreteArguments.map((e) => e.expression).toList()), |
| 1051 new ConstructedConstantValue(constructedType, fieldValues)); |
967 } | 1052 } |
968 | 1053 |
969 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { | 1054 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
970 return node.expression.accept(this); | 1055 return node.expression.accept(this); |
971 } | 1056 } |
972 | 1057 |
973 error(Node node, MessageKind message) { | 1058 error(Node node, MessageKind message) { |
974 // TODO(floitsch): get the list of constants that are currently compiled | 1059 // TODO(floitsch): get the list of constants that are currently compiled |
975 // and present some kind of stack-trace. | 1060 // and present some kind of stack-trace. |
976 compiler.reportError(node, message); | 1061 compiler.reportError(node, message); |
977 } | 1062 } |
978 | 1063 |
979 AstConstant signalNotCompileTimeConstant(Node node, | 1064 AstConstant signalNotCompileTimeConstant(Node node, |
980 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { | 1065 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { |
981 if (isEvaluatingConstant) { | 1066 if (isEvaluatingConstant) { |
982 error(node, message); | 1067 error(node, message); |
983 | 1068 |
984 return new AstConstant( | 1069 return new AstConstant( |
985 null, node, new ErroneousConstantExpression()); | 1070 context, |
| 1071 node, |
| 1072 new ErroneousConstantExpression(), |
| 1073 new NullConstantValue()); |
986 } | 1074 } |
987 // Else we don't need to do anything. The final handler is only | 1075 // Else we don't need to do anything. The final handler is only |
988 // optimistically trying to compile constants. So it is normal that we | 1076 // optimistically trying to compile constants. So it is normal that we |
989 // sometimes see non-compile time constants. | 1077 // sometimes see non-compile time constants. |
990 // Simply return [:null:] which is used to propagate a failing | 1078 // Simply return [:null:] which is used to propagate a failing |
991 // compile-time compilation. | 1079 // compile-time compilation. |
992 return null; | 1080 return null; |
993 } | 1081 } |
994 } | 1082 } |
995 | 1083 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1181 /// inheritance chain of [classElement]. | 1269 /// inheritance chain of [classElement]. |
1182 Map<FieldElement, AstConstant> buildFieldConstants( | 1270 Map<FieldElement, AstConstant> buildFieldConstants( |
1183 ClassElement classElement) { | 1271 ClassElement classElement) { |
1184 Map<FieldElement, AstConstant> fieldConstants = | 1272 Map<FieldElement, AstConstant> fieldConstants = |
1185 <FieldElement, AstConstant>{}; | 1273 <FieldElement, AstConstant>{}; |
1186 classElement.implementation.forEachInstanceField( | 1274 classElement.implementation.forEachInstanceField( |
1187 (ClassElement enclosing, FieldElement field) { | 1275 (ClassElement enclosing, FieldElement field) { |
1188 AstConstant fieldValue = fieldValues[field]; | 1276 AstConstant fieldValue = fieldValues[field]; |
1189 if (fieldValue == null) { | 1277 if (fieldValue == null) { |
1190 // Use the default value. | 1278 // Use the default value. |
| 1279 ConstantExpression fieldExpression = handler.compileConstant(field); |
1191 fieldValue = new AstConstant.fromDefaultValue( | 1280 fieldValue = new AstConstant.fromDefaultValue( |
1192 field, handler.compileConstant(field)); | 1281 field, |
| 1282 fieldExpression, |
| 1283 handler.getConstantValue(fieldExpression)); |
1193 } | 1284 } |
1194 fieldConstants[field] = fieldValue; | 1285 fieldConstants[field] = fieldValue; |
1195 }, | 1286 }, |
1196 includeSuperAndInjectedMembers: true); | 1287 includeSuperAndInjectedMembers: true); |
1197 return fieldConstants; | 1288 return fieldConstants; |
1198 } | 1289 } |
1199 } | 1290 } |
1200 | 1291 |
1201 /// A constant created from the front-end AST. | 1292 /// A constant created from the front-end AST. |
1202 /// | 1293 /// |
1203 /// [element] and [node] point to the source location of the constant. | 1294 /// [element] and [node] point to the source location of the constant. |
1204 /// [expression] holds the symbolic constant expression and [value] its constant | 1295 /// [expression] holds the symbolic constant expression and [value] its constant |
1205 /// value. | 1296 /// value. |
1206 /// | 1297 /// |
1207 /// This class differs from [ConstantExpression] in that it is coupled to the | 1298 /// This class differs from [ConstantExpression] in that it is coupled to the |
1208 /// front-end AST whereas [ConstantExpression] is only coupled to the element | 1299 /// front-end AST whereas [ConstantExpression] is only coupled to the element |
1209 /// model. | 1300 /// model. |
1210 class AstConstant { | 1301 class AstConstant { |
1211 final Element element; | 1302 final Element element; |
1212 final Node node; | 1303 final Node node; |
1213 final ConstantExpression expression; | 1304 final ConstantExpression expression; |
| 1305 final ConstantValue value; |
1214 | 1306 |
1215 AstConstant(this.element, this.node, this.expression); | 1307 AstConstant(this.element, this.node, this.expression, this.value); |
1216 | 1308 |
1217 factory AstConstant.fromDefaultValue( | 1309 factory AstConstant.fromDefaultValue( |
1218 VariableElement element, | 1310 VariableElement element, |
1219 ConstantExpression constant) { | 1311 ConstantExpression constant, |
| 1312 ConstantValue value) { |
1220 return new AstConstant( | 1313 return new AstConstant( |
1221 element, | 1314 element, |
1222 element.initializer != null ? element.initializer : element.node, | 1315 element.initializer != null ? element.initializer : element.node, |
1223 constant); | 1316 constant, |
| 1317 value); |
1224 } | 1318 } |
1225 | 1319 |
1226 ConstantValue get value => expression.value; | |
1227 | |
1228 String toString() => expression.toString(); | 1320 String toString() => expression.toString(); |
1229 } | 1321 } |
1230 | 1322 |
1231 /// A synthetic constant used to recover from errors. | 1323 /// A synthetic constant used to recover from errors. |
1232 class ErroneousAstConstant extends AstConstant { | 1324 class ErroneousAstConstant extends AstConstant { |
1233 ErroneousAstConstant(Element element, Node node) | 1325 ErroneousAstConstant(Element element, Node node) |
1234 : super(element, node, new ErroneousConstantExpression()); | 1326 : super(element, node, |
| 1327 // TODO(johnniwinther): Return a [NonConstantValue] instead. |
| 1328 new ErroneousConstantExpression(), new NullConstantValue()); |
1235 } | 1329 } |
1236 | 1330 |
1237 // TODO(johnniwinther): Avoid the need for this hack. | 1331 // TODO(johnniwinther): Avoid the need for this hack. |
1238 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { | 1332 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { |
1239 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); | 1333 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); |
1240 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); | 1334 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); |
1241 return element.resolvedAst.elements; | 1335 return element.resolvedAst.elements; |
1242 } | 1336 } |
OLD | NEW |