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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/compile_time_constants.dart

Issue 574683002: Use ConstExp for storing constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes and further implementation. Created 6 years, 2 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 | Annotate | Revision Log
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 part of dart2js; 5 part of dart2js;
6 6
7 /// A [ConstantEnvironment] provides access for constants compiled for variable 7 /// A [ConstantEnvironment] provides access for constants compiled for variable
8 /// initializers. 8 /// initializers.
9 abstract class ConstantEnvironment { 9 abstract class ConstantEnvironment {
10 /// Returns the constant for the initializer of [element]. 10 /// Returns the constant for the initializer of [element].
11 Constant getConstantForVariable(VariableElement element); 11 ConstExp getConstantForVariable(VariableElement element);
12 } 12 }
13 13
14 /// A class that can compile and provide constants for variables, nodes and 14 /// A class that can compile and provide constants for variables, nodes and
15 /// metadata. 15 /// metadata.
16 abstract class ConstantCompiler extends ConstantEnvironment { 16 abstract class ConstantCompiler extends ConstantEnvironment {
17 /// Compiles the compile-time constant for the initializer of [element], or 17 /// Compiles the compile-time constant for the initializer of [element], or
18 /// reports an error if the initializer is not a compile-time constant. 18 /// reports an error if the initializer is not a compile-time constant.
19 /// 19 ///
20 /// Depending on implementation, the constant compiler might also compute 20 /// Depending on implementation, the constant compiler might also compute
21 /// the compile-time constant for the backend interpretation of constants. 21 /// the compile-time constant for the backend interpretation of constants.
22 /// 22 ///
23 /// The returned constant is always of the frontend interpretation. 23 /// The returned constant is always of the frontend interpretation.
24 Constant compileConstant(VariableElement element); 24 ConstExp compileConstant(VariableElement element);
25 25
26 /// Computes the compile-time constant for the variable initializer, 26 /// Computes the compile-time constant for the variable initializer,
27 /// if possible. 27 /// if possible.
28 void compileVariable(VariableElement element); 28 void compileVariable(VariableElement element);
29 29
30 /// Compiles the compile-time constant for [node], or reports an error if 30 /// Compiles the compile-time constant for [node], or reports an error if
31 /// [node] is not a compile-time constant. 31 /// [node] is not a compile-time constant.
32 /// 32 ///
33 /// Depending on implementation, the constant compiler might also compute 33 /// Depending on implementation, the constant compiler might also compute
34 /// the compile-time constant for the backend interpretation of constants. 34 /// the compile-time constant for the backend interpretation of constants.
35 /// 35 ///
36 /// The returned constant is always of the frontend interpretation. 36 /// The returned constant is always of the frontend interpretation.
37 Constant compileNode(Node node, TreeElements elements); 37 ConstExp compileNode(Node node, TreeElements elements);
38 38
39 /// Compiles the compile-time constant for the value [metadata], or reports an 39 /// Compiles the compile-time constant for the value [metadata], or reports an
40 /// error if the value is not a compile-time constant. 40 /// error if the value is not a compile-time constant.
41 /// 41 ///
42 /// Depending on implementation, the constant compiler might also compute 42 /// Depending on implementation, the constant compiler might also compute
43 /// the compile-time constant for the backend interpretation of constants. 43 /// the compile-time constant for the backend interpretation of constants.
44 /// 44 ///
45 /// The returned constant is always of the frontend interpretation. 45 /// The returned constant is always of the frontend interpretation.
46 Constant compileMetadata(MetadataAnnotation metadata, 46 ConstExp compileMetadata(MetadataAnnotation metadata,
47 Node node, TreeElements elements); 47 Node node, TreeElements elements);
48 } 48 }
49 49
50 /// A [BackendConstantEnvironment] provides access to constants needed for 50 /// A [BackendConstantEnvironment] provides access to constants needed for
51 /// backend implementation. 51 /// backend implementation.
52 abstract class BackendConstantEnvironment extends ConstantEnvironment { 52 abstract class BackendConstantEnvironment extends ConstantEnvironment {
53 /// Returns the compile-time constant associated with [node]. 53 /// Returns the compile-time constant associated with [node].
54 /// 54 ///
55 /// Depending on implementation, the constant might be stored in [elements]. 55 /// Depending on implementation, the constant might be stored in [elements].
56 Constant getConstantForNode(Node node, TreeElements elements); 56 ConstExp getConstantForNode(Node node, TreeElements elements);
57 57
58 /// Returns the compile-time constant value of [metadata]. 58 /// Returns the compile-time constant value of [metadata].
59 Constant getConstantForMetadata(MetadataAnnotation metadata); 59 ConstExp getConstantForMetadata(MetadataAnnotation metadata);
60 } 60 }
61 61
62 /// Interface for the task that compiles the constant environments for the 62 /// Interface for the task that compiles the constant environments for the
63 /// frontend and backend interpretation of compile-time constants. 63 /// frontend and backend interpretation of compile-time constants.
64 abstract class ConstantCompilerTask extends CompilerTask 64 abstract class ConstantCompilerTask extends CompilerTask
65 implements ConstantCompiler { 65 implements ConstantCompiler {
66 ConstantCompilerTask(Compiler compiler) : super(compiler); 66 ConstantCompilerTask(Compiler compiler) : super(compiler);
67 } 67 }
68 68
69 /** 69 /**
70 * The [ConstantCompilerBase] is provides base implementation for compilation of 70 * The [ConstantCompilerBase] is provides base implementation for compilation of
71 * compile-time constants for both the Dart and JavaScript interpretation of 71 * compile-time constants for both the Dart and JavaScript interpretation of
72 * constants. It keeps track of compile-time constants for initializations of 72 * constants. It keeps track of compile-time constants for initializations of
73 * global and static fields, and default values of optional parameters. 73 * global and static fields, and default values of optional parameters.
74 */ 74 */
75 abstract class ConstantCompilerBase implements ConstantCompiler { 75 abstract class ConstantCompilerBase implements ConstantCompiler {
76 final Compiler compiler; 76 final Compiler compiler;
77 final ConstantSystem constantSystem; 77 final ConstantSystem constantSystem;
78 78
79 /** 79 /**
80 * Contains the initial value of fields. Must contain all static and global 80 * Contains the initial value of fields. Must contain all static and global
81 * initializations of const fields. May contain eagerly compiled values for 81 * initializations of const fields. May contain eagerly compiled values for
82 * statics and instance fields. 82 * statics and instance fields.
83 * 83 *
84 * Invariant: The keys in this map are declarations. 84 * Invariant: The keys in this map are declarations.
85 */ 85 */
86 final Map<VariableElement, Constant> initialVariableValues = 86 final Map<VariableElement, ConstExp> initialVariableValues =
87 new Map<VariableElement, Constant>(); 87 new Map<VariableElement, ConstExp>();
88 88
89 /** The set of variable elements that are in the process of being computed. */ 89 /** The set of variable elements that are in the process of being computed. */
90 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); 90 final Set<VariableElement> pendingVariables = new Set<VariableElement>();
91 91
92 ConstantCompilerBase(this.compiler, this.constantSystem); 92 ConstantCompilerBase(this.compiler, this.constantSystem);
93 93
94 Constant getConstantForVariable(VariableElement element) { 94 ConstExp getConstantForVariable(VariableElement element) {
95 return initialVariableValues[element.declaration]; 95 return initialVariableValues[element.declaration];
96 } 96 }
97 97
98 Constant compileConstant(VariableElement element) { 98 ConstExp compileConstant(VariableElement element) {
99 return compileVariable(element, isConst: true); 99 return compileVariable(element, isConst: true);
100 } 100 }
101 101
102 Constant compileVariable(VariableElement element, {bool isConst: false}) { 102 ConstExp compileVariable(VariableElement element, {bool isConst: false}) {
103 103
104 if (initialVariableValues.containsKey(element.declaration)) { 104 if (initialVariableValues.containsKey(element.declaration)) {
105 Constant result = initialVariableValues[element.declaration]; 105 ConstExp result = initialVariableValues[element.declaration];
106 return result; 106 return result;
107 } 107 }
108 AstElement currentElement = element.analyzableElement; 108 AstElement currentElement = element.analyzableElement;
109 return compiler.withCurrentElement(currentElement, () { 109 return compiler.withCurrentElement(currentElement, () {
110 compiler.analyzeElement(currentElement.declaration); 110 compiler.analyzeElement(currentElement.declaration);
111 Constant constant = compileVariableWithDefinitions( 111 ConstExp constant = compileVariableWithDefinitions(
112 element, currentElement.resolvedAst.elements, isConst: isConst); 112 element, currentElement.resolvedAst.elements, isConst: isConst);
113 return constant; 113 return constant;
114 }); 114 });
115 } 115 }
116 116
117 /** 117 /**
118 * Returns the a compile-time constant if the variable could be compiled 118 * Returns the a compile-time constant if the variable could be compiled
119 * eagerly. If the variable needs to be initialized lazily returns `null`. 119 * eagerly. If the variable needs to be initialized lazily returns `null`.
120 * If the variable is `const` but cannot be compiled eagerly reports an 120 * If the variable is `const` but cannot be compiled eagerly reports an
121 * error. 121 * error.
122 */ 122 */
123 Constant compileVariableWithDefinitions(VariableElement element, 123 ConstExp compileVariableWithDefinitions(VariableElement element,
124 TreeElements definitions, 124 TreeElements definitions,
125 {bool isConst: false}) { 125 {bool isConst: false}) {
126 Node node = element.node; 126 Node node = element.node;
127 if (pendingVariables.contains(element)) { 127 if (pendingVariables.contains(element)) {
128 if (isConst) { 128 if (isConst) {
129 compiler.reportFatalError( 129 compiler.reportFatalError(
130 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); 130 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
131 } 131 }
132 return null; 132 return null;
133 } 133 }
134 pendingVariables.add(element); 134 pendingVariables.add(element);
135 135
136 Expression initializer = element.initializer; 136 Expression initializer = element.initializer;
137 Constant value; 137 ConstExp value;
138 if (initializer == null) { 138 if (initializer == null) {
139 // No initial value. 139 // No initial value.
140 value = new NullConstant(); 140 value = new PrimitiveConstExp(new NullConstant());
141 } else { 141 } else {
142 value = compileNodeWithDefinitions( 142 value = compileNodeWithDefinitions(
143 initializer, definitions, isConst: isConst); 143 initializer, definitions, isConst: isConst);
144 if (compiler.enableTypeAssertions && 144 if (compiler.enableTypeAssertions &&
145 value != null && 145 value != null &&
146 element.isField) { 146 element.isField) {
147 DartType elementType = element.type; 147 DartType elementType = element.type;
148 if (elementType.isMalformed && !value.isNull) { 148 if (elementType.isMalformed && !value.value.isNull) {
149 if (isConst) { 149 if (isConst) {
150 ErroneousElement element = elementType.element; 150 ErroneousElement element = elementType.element;
151 compiler.reportFatalError( 151 compiler.reportFatalError(
152 node, element.messageKind, element.messageArguments); 152 node, element.messageKind, element.messageArguments);
153 } else { 153 } else {
154 // We need to throw an exception at runtime. 154 // We need to throw an exception at runtime.
155 value = null; 155 value = null;
156 } 156 }
157 } else { 157 } else {
158 DartType constantType = value.computeType(compiler); 158 DartType constantType = value.value.computeType(compiler);
159 if (!constantSystem.isSubtype(compiler, 159 if (!constantSystem.isSubtype(compiler,
160 constantType, elementType)) { 160 constantType, elementType)) {
161 if (isConst) { 161 if (isConst) {
162 compiler.reportFatalError( 162 compiler.reportFatalError(
163 node, MessageKind.NOT_ASSIGNABLE, 163 node, MessageKind.NOT_ASSIGNABLE,
164 {'fromType': constantType, 'toType': elementType}); 164 {'fromType': constantType, 'toType': elementType});
165 } else { 165 } else {
166 // If the field cannot be lazily initialized, we will throw 166 // If the field cannot be lazily initialized, we will throw
167 // the exception at runtime. 167 // the exception at runtime.
168 value = null; 168 value = null;
169 } 169 }
170 } 170 }
171 } 171 }
172 } 172 }
173 } 173 }
174 if (value != null) { 174 if (value != null) {
175 initialVariableValues[element.declaration] = value; 175 initialVariableValues[element.declaration] = value;
176 } else { 176 } else {
177 assert(!isConst); 177 assert(invariant(element, !isConst,
178 message: "Variable $element does not compile to a constant."));
178 } 179 }
179 pendingVariables.remove(element); 180 pendingVariables.remove(element);
180 return value; 181 return value;
181 } 182 }
182 183
183 Constant compileNodeWithDefinitions(Node node, 184 ConstExp compileNodeWithDefinitions(Node node,
184 TreeElements definitions, 185 TreeElements definitions,
185 {bool isConst: true}) { 186 {bool isConst: true}) {
186 assert(node != null); 187 assert(node != null);
187 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( 188 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator(
188 this, definitions, compiler, isConst: isConst); 189 this, definitions, compiler, isConst: isConst);
189 return evaluator.evaluate(node); 190 AstConstant constant = evaluator.evaluate(node);
191 return constant != null ? constant.expression : null;
190 } 192 }
191 193
192 Constant compileNode(Node node, TreeElements elements) { 194 ConstExp compileNode(Node node, TreeElements elements) {
193 return compileNodeWithDefinitions(node, elements); 195 return compileNodeWithDefinitions(node, elements);
194 } 196 }
195 197
196 Constant compileMetadata(MetadataAnnotation metadata, 198 ConstExp compileMetadata(MetadataAnnotation metadata,
197 Node node, 199 Node node,
198 TreeElements elements) { 200 TreeElements elements) {
199 return compileNodeWithDefinitions(node, elements); 201 return compileNodeWithDefinitions(node, elements);
200 } 202 }
201 } 203 }
202 204
203 /// [ConstantCompiler] that uses the Dart semantics for the compile-time 205 /// [ConstantCompiler] that uses the Dart semantics for the compile-time
204 /// constant evaluation. 206 /// constant evaluation.
205 class DartConstantCompiler extends ConstantCompilerBase { 207 class DartConstantCompiler extends ConstantCompilerBase {
206 DartConstantCompiler(Compiler compiler) 208 DartConstantCompiler(Compiler compiler)
207 : super(compiler, const DartConstantSystem()); 209 : super(compiler, const DartConstantSystem());
208 210
209 Constant getConstantForNode(Node node, TreeElements definitions) { 211 ConstExp getConstantForNode(Node node, TreeElements definitions) {
210 return definitions.getConstant(node); 212 return definitions.getConstant(node);
211 } 213 }
212 214
213 Constant getConstantForMetadata(MetadataAnnotation metadata) { 215 ConstExp getConstantForMetadata(MetadataAnnotation metadata) {
214 return metadata.value; 216 return metadata.constant;
215 } 217 }
216 218
217 Constant compileNodeWithDefinitions(Node node, 219 ConstExp compileNodeWithDefinitions(Node node,
218 TreeElements definitions, 220 TreeElements definitions,
219 {bool isConst: true}) { 221 {bool isConst: true}) {
220 Constant constant = definitions.getConstant(node); 222 ConstExp constant = definitions.getConstant(node);
221 if (constant != null) { 223 if (constant != null) {
222 return constant; 224 return constant;
223 } 225 }
224 constant = 226 constant =
225 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); 227 super.compileNodeWithDefinitions(node, definitions, isConst: isConst);
226 if (constant != null) { 228 if (constant != null) {
227 definitions.setConstant(node, constant); 229 definitions.setConstant(node, constant);
228 } 230 }
229 return constant; 231 return constant;
230 } 232 }
231 } 233 }
232 234
233 // TODO(johnniwinther): Change to create [ConstExp] instead of [Constant]. 235 // TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from
234 class CompileTimeConstantEvaluator extends Visitor { 236 // front-end AST in order to reuse the evaluation for the shared front-end.
237 class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
235 bool isEvaluatingConstant; 238 bool isEvaluatingConstant;
236 final ConstantCompilerBase handler; 239 final ConstantCompilerBase handler;
237 final TreeElements elements; 240 final TreeElements elements;
238 final Compiler compiler; 241 final Compiler compiler;
239 242
243 Element get context => elements.analyzedElement;
244
240 CompileTimeConstantEvaluator(this.handler, 245 CompileTimeConstantEvaluator(this.handler,
241 this.elements, 246 this.elements,
242 this.compiler, 247 this.compiler,
243 {bool isConst: false}) 248 {bool isConst: false})
244 : this.isEvaluatingConstant = isConst; 249 : this.isEvaluatingConstant = isConst;
245 250
246 ConstantSystem get constantSystem => handler.constantSystem; 251 ConstantSystem get constantSystem => handler.constantSystem;
247 252
248 Constant evaluate(Node node) { 253 AstConstant evaluate(Node node) {
249 return node.accept(this); 254 return node.accept(this);
250 } 255 }
251 256
252 Constant evaluateConstant(Node node) { 257 AstConstant evaluateConstant(Node node) {
253 bool oldIsEvaluatingConstant = isEvaluatingConstant; 258 bool oldIsEvaluatingConstant = isEvaluatingConstant;
254 isEvaluatingConstant = true; 259 isEvaluatingConstant = true;
255 Constant result = node.accept(this); 260 AstConstant result = node.accept(this);
256 isEvaluatingConstant = oldIsEvaluatingConstant; 261 isEvaluatingConstant = oldIsEvaluatingConstant;
257 assert(result != null); 262 assert(result != null);
258 return result; 263 return result;
259 } 264 }
260 265
261 Constant visitNode(Node node) { 266 AstConstant visitNode(Node node) {
262 return signalNotCompileTimeConstant(node); 267 return signalNotCompileTimeConstant(node);
263 } 268 }
264 269
265 Constant visitLiteralBool(LiteralBool node) { 270 AstConstant visitLiteralBool(LiteralBool node) {
266 return constantSystem.createBool(node.value); 271 return new AstConstant(
272 context, node, new PrimitiveConstExp(
273 constantSystem.createBool(node.value)));
267 } 274 }
268 275
269 Constant visitLiteralDouble(LiteralDouble node) { 276 AstConstant visitLiteralDouble(LiteralDouble node) {
270 return constantSystem.createDouble(node.value); 277 return new AstConstant(
278 context, node, new PrimitiveConstExp(
279 constantSystem.createDouble(node.value)));
271 } 280 }
272 281
273 Constant visitLiteralInt(LiteralInt node) { 282 AstConstant visitLiteralInt(LiteralInt node) {
274 return constantSystem.createInt(node.value); 283 return new AstConstant(
284 context, node, new PrimitiveConstExp(
285 constantSystem.createInt(node.value)));
275 } 286 }
276 287
277 Constant visitLiteralList(LiteralList node) { 288 AstConstant visitLiteralList(LiteralList node) {
278 if (!node.isConst) { 289 if (!node.isConst) {
279 return signalNotCompileTimeConstant(node); 290 return signalNotCompileTimeConstant(node);
280 } 291 }
281 List<Constant> arguments = <Constant>[]; 292 List<ConstExp> argumentExpressions = <ConstExp>[];
293 List<Constant> argumentValues = <Constant>[];
282 for (Link<Node> link = node.elements.nodes; 294 for (Link<Node> link = node.elements.nodes;
283 !link.isEmpty; 295 !link.isEmpty;
284 link = link.tail) { 296 link = link.tail) {
285 arguments.add(evaluateConstant(link.head)); 297 AstConstant argument = evaluateConstant(link.head);
298 if (argument == null) {
299 return null;
300 }
301 argumentExpressions.add(argument.expression);
302 argumentValues.add(argument.value);
286 } 303 }
287 DartType type = elements.getType(node); 304 DartType type = elements.getType(node);
288 return new ListConstant(type, arguments); 305 return new AstConstant(
306 context, node, new ListConstExp(
307 new ListConstant(type, argumentValues),
308 type,
309 argumentExpressions));
289 } 310 }
290 311
291 Constant visitLiteralMap(LiteralMap node) { 312 AstConstant visitLiteralMap(LiteralMap node) {
292 if (!node.isConst) { 313 if (!node.isConst) {
293 return signalNotCompileTimeConstant(node); 314 return signalNotCompileTimeConstant(node);
294 } 315 }
295 List<Constant> keys = <Constant>[]; 316 List<ConstExp> keyExpressions = <ConstExp>[];
296 Map<Constant, Constant> map = new Map<Constant, Constant>(); 317 List<Constant> keyValues = <Constant>[];
318 Map<Constant, ConstExp> map = new Map<Constant, ConstExp>();
297 for (Link<Node> link = node.entries.nodes; 319 for (Link<Node> link = node.entries.nodes;
298 !link.isEmpty; 320 !link.isEmpty;
299 link = link.tail) { 321 link = link.tail) {
300 LiteralMapEntry entry = link.head; 322 LiteralMapEntry entry = link.head;
301 Constant key = evaluateConstant(entry.key); 323 AstConstant key = evaluateConstant(entry.key);
302 if (!map.containsKey(key)) { 324 if (key == null) {
303 keys.add(key); 325 return null;
326 }
327 if (!map.containsKey(key.value)) {
328 keyExpressions.add(key.expression);
329 keyValues.add(key.value);
304 } else { 330 } else {
305 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); 331 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
306 } 332 }
307 map[key] = evaluateConstant(entry.value); 333 AstConstant value = evaluateConstant(entry.value);
334 if (value == null) {
335 return null;
336 }
337 map[key.value] = value.expression;
308 } 338 }
309 List<Constant> values = map.values.toList(); 339 List<ConstExp> valueExpressions = map.values.toList();
310 InterfaceType sourceType = elements.getType(node); 340 InterfaceType type = elements.getType(node);
311 return constantSystem.createMap(compiler, sourceType, keys, values); 341 return new AstConstant(
342 context, node, new MapConstExp(
343 constantSystem.createMap(compiler, type, keyValues,
344 valueExpressions.map((e) => e.value).toList()),
345 type,
346 keyExpressions,
347 valueExpressions));
312 } 348 }
313 349
314 Constant visitLiteralNull(LiteralNull node) { 350 AstConstant visitLiteralNull(LiteralNull node) {
315 return constantSystem.createNull(); 351 return new AstConstant(
352 context, node, new PrimitiveConstExp(
353 constantSystem.createNull()));
316 } 354 }
317 355
318 Constant visitLiteralString(LiteralString node) { 356 AstConstant visitLiteralString(LiteralString node) {
319 return constantSystem.createString(node.dartString); 357 return new AstConstant(
358 context, node, new PrimitiveConstExp(
359 constantSystem.createString(node.dartString)));
320 } 360 }
321 361
322 Constant visitStringJuxtaposition(StringJuxtaposition node) { 362 AstConstant visitStringJuxtaposition(StringJuxtaposition node) {
323 StringConstant left = evaluate(node.first); 363 AstConstant left = evaluate(node.first);
324 StringConstant right = evaluate(node.second); 364 AstConstant right = evaluate(node.second);
325 if (left == null || right == null) return null; 365 if (left == null || right == null) return null;
326 return constantSystem.createString( 366 StringConstant leftValue = left.value;
327 new DartString.concat(left.value, right.value)); 367 StringConstant rightValue = right.value;
368 return new AstConstant(
369 context, node, new ConcatenateConstExp(
370 constantSystem.createString(
371 new DartString.concat(leftValue.value, rightValue.value)),
372 [left.expression, right.expression]));
328 } 373 }
329 374
330 Constant visitStringInterpolation(StringInterpolation node) { 375 AstConstant visitStringInterpolation(StringInterpolation node) {
331 StringConstant initialString = evaluate(node.string); 376 List<ConstExp> subexpressions = <ConstExp>[];
332 if (initialString == null) return null; 377 AstConstant initialString = evaluate(node.string);
333 DartString accumulator = initialString.value; 378 if (initialString == null) {
379 return null;
380 }
381 subexpressions.add(initialString.expression);
382 StringConstant initialStringValue = initialString.value;
383 DartString accumulator = initialStringValue.value;
334 for (StringInterpolationPart part in node.parts) { 384 for (StringInterpolationPart part in node.parts) {
335 Constant expression = evaluate(part.expression); 385 AstConstant subexpression = evaluate(part.expression);
386 if (subexpression == null) {
387 return null;
388 }
389 subexpressions.add(subexpression.expression);
390 Constant expression = subexpression.value;
336 DartString expressionString; 391 DartString expressionString;
337 if (expression == null) { 392 if (expression.isNum || expression.isBool) {
338 return signalNotCompileTimeConstant(part.expression);
339 } else if (expression.isNum || expression.isBool) {
340 PrimitiveConstant primitive = expression; 393 PrimitiveConstant primitive = expression;
341 expressionString = new DartString.literal(primitive.value.toString()); 394 expressionString = new DartString.literal(primitive.value.toString());
342 } else if (expression.isString) { 395 } else if (expression.isString) {
343 PrimitiveConstant primitive = expression; 396 PrimitiveConstant primitive = expression;
344 expressionString = primitive.value; 397 expressionString = primitive.value;
345 } else { 398 } else {
399 // TODO(johnniwinther): Specialize message to indicated that the problem
400 // is not constness but the types of the const expressions.
346 return signalNotCompileTimeConstant(part.expression); 401 return signalNotCompileTimeConstant(part.expression);
347 } 402 }
348 accumulator = new DartString.concat(accumulator, expressionString); 403 accumulator = new DartString.concat(accumulator, expressionString);
349 StringConstant partString = evaluate(part.string); 404 AstConstant partString = evaluate(part.string);
350 if (partString == null) return null; 405 if (partString == null) return null;
351 accumulator = new DartString.concat(accumulator, partString.value); 406 subexpressions.add(partString.expression);
407 StringConstant partStringValue = partString.value;
408 accumulator = new DartString.concat(accumulator, partStringValue.value);
352 }; 409 };
353 return constantSystem.createString(accumulator); 410 return new AstConstant(
411 context, node, new ConcatenateConstExp(
412 constantSystem.createString(accumulator),
413 subexpressions));
354 } 414 }
355 415
356 Constant visitLiteralSymbol(LiteralSymbol node) { 416 AstConstant visitLiteralSymbol(LiteralSymbol node) {
357 InterfaceType type = compiler.symbolClass.rawType; 417 InterfaceType type = compiler.symbolClass.rawType;
358 List<Constant> createArguments(_) { 418 String text = node.slowNameString;
359 return [constantSystem.createString( 419 List<AstConstant> arguments =
360 new DartString.literal(node.slowNameString))]; 420 <AstConstant>[new AstConstant(context, node,
361 } 421 new PrimitiveConstExp(constantSystem.createString(
362 return makeConstructedConstant( 422 new DartString.literal(text))))];
363 compiler, handler, node, type, compiler.symbolConstructor, 423 AstConstant constant = makeConstructedConstant(
364 createArguments, isLiteralSymbol: true); 424 compiler, handler, context, node, type, compiler.symbolConstructor,
425 new Selector.callConstructor('', null, 1),
426 arguments, arguments);
427 return new AstConstant(
428 context, node, new SymbolConstExp(constant.value, text));
365 } 429 }
366 430
367 Constant makeTypeConstant(DartType elementType) { 431 AstConstant makeTypeConstant(Node node, DartType elementType) {
368 DartType constantType = 432 DartType constantType =
369 compiler.backend.typeImplementation.computeType(compiler); 433 compiler.backend.typeImplementation.computeType(compiler);
370 return new TypeConstant(elementType, constantType); 434 return new AstConstant(
435 context, node, new TypeConstExp(
436 new TypeConstant(elementType, constantType),
437 elementType));
371 } 438 }
372 439
373 /// Returns true if the prefix of the send resolves to a deferred import 440 /// Returns true if the prefix of the send resolves to a deferred import
374 /// prefix. 441 /// prefix.
375 bool isDeferredUse(Send send) { 442 bool isDeferredUse(Send send) {
376 if (send == null) return false; 443 if (send == null) return false;
377 return compiler.deferredLoadTask 444 return compiler.deferredLoadTask
378 .deferredPrefixElement(send, elements) != null; 445 .deferredPrefixElement(send, elements) != null;
379 } 446 }
380 447
381 Constant visitIdentifier(Identifier node) { 448 AstConstant visitIdentifier(Identifier node) {
382 Element element = elements[node]; 449 Element element = elements[node];
383 if (Elements.isClass(element) || Elements.isTypedef(element)) { 450 if (Elements.isClass(element) || Elements.isTypedef(element)) {
384 TypeDeclarationElement typeDeclarationElement = element; 451 TypeDeclarationElement typeDeclarationElement = element;
385 return makeTypeConstant(typeDeclarationElement.rawType); 452 DartType type = typeDeclarationElement.rawType;
453 return makeTypeConstant(node, type);
386 } 454 }
387 return signalNotCompileTimeConstant(node); 455 return signalNotCompileTimeConstant(node);
388 } 456 }
389 457
390 // TODO(floitsch): provide better error-messages. 458 // TODO(floitsch): provide better error-messages.
391 Constant visitSend(Send send) { 459 AstConstant visitSend(Send send) {
392 Element element = elements[send]; 460 Element element = elements[send];
393 if (send.isPropertyAccess) { 461 if (send.isPropertyAccess) {
394 if (isDeferredUse(send)) { 462 if (isDeferredUse(send)) {
395 return signalNotCompileTimeConstant(send, 463 return signalNotCompileTimeConstant(send,
396 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); 464 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
397 } 465 }
398 if (Elements.isStaticOrTopLevelFunction(element)) { 466 if (Elements.isStaticOrTopLevelFunction(element)) {
399 return new FunctionConstant(element); 467 return new AstConstant(
468 context, send, new FunctionConstExp(
469 new FunctionConstant(element),
470 element));
400 } else if (Elements.isStaticOrTopLevelField(element)) { 471 } else if (Elements.isStaticOrTopLevelField(element)) {
401 Constant result; 472 ConstExp result;
402 if (element.isConst) { 473 if (element.isConst) {
403 result = handler.compileConstant(element); 474 result = handler.compileConstant(element);
404 } else if (element.isFinal && !isEvaluatingConstant) { 475 } else if (element.isFinal && !isEvaluatingConstant) {
405 result = handler.compileVariable(element); 476 result = handler.compileVariable(element);
406 } 477 }
407 if (result != null) return result; 478 if (result != null) {
479 return new AstConstant(
480 context, send, new VariableConstExp(result.value, element));
481 }
408 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { 482 } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
409 assert(elements.isTypeLiteral(send)); 483 assert(elements.isTypeLiteral(send));
410 return makeTypeConstant(elements.getTypeLiteralType(send)); 484 return makeTypeConstant(send, elements.getTypeLiteralType(send));
411 } else if (send.receiver != null) { 485 } else if (send.receiver != null) {
412 // Fall through to error handling. 486 // Fall through to error handling.
413 } else if (!Elements.isUnresolved(element) 487 } else if (!Elements.isUnresolved(element)
414 && element.isVariable 488 && element.isVariable
415 && element.isConst) { 489 && element.isConst) {
416 Constant result = handler.compileConstant(element); 490 ConstExp result = handler.compileConstant(element);
417 if (result != null) return result; 491 if (result != null) {
492 return new AstConstant(
493 context, send, new VariableConstExp(result.value, element));
494 }
418 } 495 }
419 return signalNotCompileTimeConstant(send); 496 return signalNotCompileTimeConstant(send);
420 } else if (send.isCall) { 497 } else if (send.isCall) {
421 if (identical(element, compiler.identicalFunction) 498 if (identical(element, compiler.identicalFunction)
422 && send.argumentCount() == 2) { 499 && send.argumentCount() == 2) {
423 Constant left = evaluate(send.argumentsNode.nodes.head); 500 AstConstant left = evaluate(send.argumentsNode.nodes.head);
424 Constant right = evaluate(send.argumentsNode.nodes.tail.head); 501 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head);
425 Constant result = constantSystem.identity.fold(left, right); 502 if (left == null || right == null) {
426 if (result != null) return result; 503 return null;
504 }
505 Constant result = constantSystem.identity.fold(left.value, right.value);
506 if (result != null) {
507 return new AstConstant(
508 context, send, new BinaryConstExp(result,
509 left.expression, 'identical', right.expression));
510 }
427 } 511 }
428 return signalNotCompileTimeConstant(send); 512 return signalNotCompileTimeConstant(send);
429 } else if (send.isPrefix) { 513 } else if (send.isPrefix) {
430 assert(send.isOperator); 514 assert(send.isOperator);
431 Constant receiverConstant = evaluate(send.receiver); 515 AstConstant receiverConstant = evaluate(send.receiver);
432 if (receiverConstant == null) return null; 516 if (receiverConstant == null) {
517 return null;
518 }
433 Operator op = send.selector; 519 Operator op = send.selector;
434 UnaryOperation operation = constantSystem.lookupUnary(op.source); 520 UnaryOperation operation = constantSystem.lookupUnary(op.source);
435 if (operation == null) { 521 if (operation == null) {
436 compiler.internalError(op, "Unexpected operator."); 522 compiler.internalError(op, "Unexpected operator.");
437 } 523 }
438 Constant folded = operation.fold(receiverConstant); 524 Constant folded = operation.fold(receiverConstant.value);
439 if (folded == null) return signalNotCompileTimeConstant(send); 525 if (folded == null) {
440 return folded; 526 return signalNotCompileTimeConstant(send);
527 }
528 return new AstConstant(
529 context, send, new UnaryConstExp(folded,
530 op.source, receiverConstant.expression));
441 } else if (send.isOperator && !send.isPostfix) { 531 } else if (send.isOperator && !send.isPostfix) {
442 assert(send.argumentCount() == 1); 532 assert(send.argumentCount() == 1);
443 Constant left = evaluate(send.receiver); 533 AstConstant left = evaluate(send.receiver);
444 Constant right = evaluate(send.argumentsNode.nodes.head); 534 AstConstant right = evaluate(send.argumentsNode.nodes.head);
445 if (left == null || right == null) return null; 535 if (left == null || right == null) {
536 return null;
537 }
538 Constant leftValue = left.value;
539 Constant rightValue = right.value;
446 Operator op = send.selector.asOperator(); 540 Operator op = send.selector.asOperator();
447 Constant folded = null; 541 Constant folded = null;
448 switch (op.source) { 542 switch (op.source) {
449 case "==": 543 case "==":
450 if (left.isPrimitive && right.isPrimitive) { 544 if (leftValue.isPrimitive && rightValue.isPrimitive) {
451 folded = constantSystem.equal.fold(left, right); 545 folded = constantSystem.equal.fold(leftValue, rightValue);
452 } 546 }
453 break; 547 break;
454 case "!=": 548 case "!=":
455 if (left.isPrimitive && right.isPrimitive) { 549 if (leftValue.isPrimitive && rightValue.isPrimitive) {
456 BoolConstant areEquals = constantSystem.equal.fold(left, right); 550 BoolConstant areEquals =
551 constantSystem.equal.fold(leftValue, rightValue);
457 if (areEquals == null) { 552 if (areEquals == null) {
458 folded = null; 553 folded = null;
459 } else { 554 } else {
460 folded = areEquals.negate(); 555 folded = areEquals.negate();
461 } 556 }
462 } 557 }
463 break; 558 break;
464 default: 559 default:
465 BinaryOperation operation = constantSystem.lookupBinary(op.source); 560 BinaryOperation operation = constantSystem.lookupBinary(op.source);
466 if (operation != null) { 561 if (operation != null) {
467 folded = operation.fold(left, right); 562 folded = operation.fold(leftValue, rightValue);
468 } 563 }
469 } 564 }
470 if (folded == null) return signalNotCompileTimeConstant(send); 565 if (folded == null) {
471 return folded; 566 return signalNotCompileTimeConstant(send);
567 }
568 return new AstConstant(
569 context, send, new BinaryConstExp(folded,
570 left.expression, op.source, right.expression));
472 } 571 }
473 return signalNotCompileTimeConstant(send); 572 return signalNotCompileTimeConstant(send);
474 } 573 }
475 574
476 Constant visitConditional(Conditional node) { 575 AstConstant visitConditional(Conditional node) {
477 Constant condition = evaluate(node.condition); 576 AstConstant condition = evaluate(node.condition);
478 if (condition == null) { 577 if (condition == null) {
479 return null; 578 return null;
480 } else if (!condition.isBool) { 579 } else if (!condition.value.isBool) {
481 DartType conditionType = condition.computeType(compiler); 580 DartType conditionType = condition.value.computeType(compiler);
482 if (isEvaluatingConstant) { 581 if (isEvaluatingConstant) {
483 compiler.reportFatalError( 582 compiler.reportFatalError(
484 node.condition, MessageKind.NOT_ASSIGNABLE, 583 node.condition, MessageKind.NOT_ASSIGNABLE,
485 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); 584 {'fromType': conditionType, 'toType': compiler.boolClass.rawType});
486 } 585 }
487 return null; 586 return null;
488 } 587 }
489 Constant thenExpression = evaluate(node.thenExpression); 588 AstConstant thenExpression = evaluate(node.thenExpression);
490 Constant elseExpression = evaluate(node.elseExpression); 589 AstConstant elseExpression = evaluate(node.elseExpression);
491 BoolConstant boolCondition = condition; 590 if (thenExpression == null || elseExpression == null) {
492 return boolCondition.value ? thenExpression : elseExpression; 591 return null;
592 }
593 BoolConstant boolCondition = condition.value;
594 return new AstConstant(
595 context, node, new ConditionalConstExp(
596 boolCondition.value ? thenExpression.value : elseExpression.value,
597 condition.expression,
598 thenExpression.expression,
599 elseExpression.expression));
493 } 600 }
494 601
495 Constant visitSendSet(SendSet node) { 602 AstConstant visitSendSet(SendSet node) {
496 return signalNotCompileTimeConstant(node); 603 return signalNotCompileTimeConstant(node);
497 } 604 }
498 605
499 /** 606 /**
500 * Returns the list of constants that are passed to the static function. 607 * Returns the normalized list of constant arguments that are passed to the
608 * constructor including both the concrete arguments and default values for
609 * omitted optional arguments.
501 * 610 *
502 * Invariant: [target] must be an implementation element. 611 * Invariant: [target] must be an implementation element.
503 */ 612 */
504 List<Constant> evaluateArgumentsToConstructor(Node node, 613 List<AstConstant> evaluateArgumentsToConstructor(
505 Selector selector, 614 Node node,
506 Link<Node> arguments, 615 Selector selector,
507 FunctionElement target) { 616 Link<Node> arguments,
617 FunctionElement target,
618 {AstConstant compileArgument(Node node)}) {
508 assert(invariant(node, target.isImplementation)); 619 assert(invariant(node, target.isImplementation));
509 List<Constant> compiledArguments = <Constant>[]; 620 List<AstConstant> compiledArguments = <AstConstant>[];
510 621
511 Function compileArgument = evaluateConstant; 622 AstConstant compileDefaultValue(VariableElement element) {
512 Function compileConstant = handler.compileConstant; 623 ConstExp constant = handler.compileConstant(element);
624 return new AstConstant.fromDefaultValue(element, constant);
625 }
513 target.computeSignature(compiler); 626 target.computeSignature(compiler);
514 bool succeeded = selector.addArgumentsToList(arguments, 627 bool succeeded = selector.addArgumentsToList(arguments,
515 compiledArguments, 628 compiledArguments,
516 target, 629 target,
517 compileArgument, 630 compileArgument,
518 compileConstant, 631 compileDefaultValue,
519 compiler.world); 632 compiler.world);
520 if (!succeeded) { 633 if (!succeeded) {
521 String name = Elements.constructorNameForDiagnostics( 634 String name = Elements.constructorNameForDiagnostics(
522 target.enclosingClass.name, target.name); 635 target.enclosingClass.name, target.name);
523 compiler.reportFatalError( 636 compiler.reportFatalError(
524 node, 637 node,
525 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, 638 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
526 {'constructorName': name}); 639 {'constructorName': name});
527 } 640 }
528 return compiledArguments; 641 return compiledArguments;
529 } 642 }
530 643
531 Constant visitNewExpression(NewExpression node) { 644 AstConstant visitNewExpression(NewExpression node) {
532 if (!node.isConst) { 645 if (!node.isConst) {
533 return signalNotCompileTimeConstant(node); 646 return signalNotCompileTimeConstant(node);
534 } 647 }
535 648
536 Send send = node.send; 649 Send send = node.send;
537 FunctionElement constructor = elements[send]; 650 FunctionElement constructor = elements[send];
538 if (Elements.isUnresolved(constructor)) { 651 if (Elements.isUnresolved(constructor)) {
539 return signalNotCompileTimeConstant(node); 652 return signalNotCompileTimeConstant(node);
540 } 653 }
541 654
542 // Deferred types can not be used in const instance creation expressions. 655 // Deferred types can not be used in const instance creation expressions.
543 // Check if the constructor comes from a deferred library. 656 // Check if the constructor comes from a deferred library.
544 if (isDeferredUse(node.send.selector.asSend())) { 657 if (isDeferredUse(node.send.selector.asSend())) {
545 return signalNotCompileTimeConstant(node, 658 return signalNotCompileTimeConstant(node,
546 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); 659 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION);
547 } 660 }
548 661
549 // TODO(ahe): This is nasty: we must eagerly analyze the 662 // TODO(ahe): This is nasty: we must eagerly analyze the
550 // constructor to ensure the redirectionTarget has been computed 663 // constructor to ensure the redirectionTarget has been computed
551 // correctly. Find a way to avoid this. 664 // correctly. Find a way to avoid this.
552 compiler.analyzeElement(constructor.declaration); 665 compiler.analyzeElement(constructor.declaration);
553 666
554 InterfaceType type = elements.getType(node); 667 InterfaceType type = elements.getType(node);
555 List<Constant> evaluateArguments(FunctionElement constructor) { 668 Selector selector = elements.getSelector(send);
556 Selector selector = elements.getSelector(send); 669
557 return evaluateArgumentsToConstructor( 670 Map<Node, AstConstant> concreteArgumentMap =
558 node, selector, send.arguments, constructor); 671 <Node, AstConstant>{};
672 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) {
673 Node argument = link.head;
674 NamedArgument namedArgument = argument.asNamedArgument();
675 if (namedArgument != null) {
676 argument = namedArgument.expression;
677 }
678 concreteArgumentMap[argument] = evaluateConstant(argument);
559 } 679 }
560 680
561 if (constructor == compiler.intEnvironment 681 List<AstConstant> normalizedArguments =
562 || constructor == compiler.boolEnvironment 682 evaluateArgumentsToConstructor(
563 || constructor == compiler.stringEnvironment) { 683 node, selector, send.arguments, constructor.implementation,
564 List<Constant> arguments = evaluateArguments(constructor.implementation); 684 compileArgument: (node) => concreteArgumentMap[node]);
565 var firstArgument = arguments[0]; 685 List<AstConstant> concreteArguments =
566 Constant defaultValue = arguments[1]; 686 concreteArgumentMap.values.toList();
687
688 if (constructor == compiler.intEnvironment ||
689 constructor == compiler.boolEnvironment ||
690 constructor == compiler.stringEnvironment) {
691
692 AstConstant createEvaluatedConstant(Constant value) {
693 return new AstConstant(
694 context, node, new ConstructorConstExp(
695 value,
696 type,
697 constructor,
698 elements.getSelector(send),
699 concreteArguments.map((e) => e.expression).toList()));
700 }
701
702 var firstArgument = normalizedArguments[0].value;
703 Constant defaultValue = normalizedArguments[1].value;
567 704
568 if (firstArgument is NullConstant) { 705 if (firstArgument is NullConstant) {
569 compiler.reportFatalError( 706 compiler.reportFatalError(
570 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); 707 send.arguments.head, MessageKind.NULL_NOT_ALLOWED);
708 return null;
571 } 709 }
572 710
573 if (firstArgument is! StringConstant) { 711 if (firstArgument is! StringConstant) {
574 DartType type = defaultValue.computeType(compiler); 712 DartType type = defaultValue.computeType(compiler);
575 compiler.reportFatalError( 713 compiler.reportFatalError(
576 send.arguments.head, MessageKind.NOT_ASSIGNABLE, 714 send.arguments.head, MessageKind.NOT_ASSIGNABLE,
577 {'fromType': type, 'toType': compiler.stringClass.rawType}); 715 {'fromType': type, 'toType': compiler.stringClass.rawType});
716 return null;
578 } 717 }
579 718
580 if (constructor == compiler.intEnvironment 719 if (constructor == compiler.intEnvironment
581 && !(defaultValue is NullConstant || defaultValue is IntConstant)) { 720 && !(defaultValue is NullConstant || defaultValue is IntConstant)) {
582 DartType type = defaultValue.computeType(compiler); 721 DartType type = defaultValue.computeType(compiler);
583 compiler.reportFatalError( 722 compiler.reportFatalError(
584 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 723 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
585 {'fromType': type, 'toType': compiler.intClass.rawType}); 724 {'fromType': type, 'toType': compiler.intClass.rawType});
725 return null;
586 } 726 }
587 727
588 if (constructor == compiler.boolEnvironment 728 if (constructor == compiler.boolEnvironment
589 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) { 729 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) {
590 DartType type = defaultValue.computeType(compiler); 730 DartType type = defaultValue.computeType(compiler);
591 compiler.reportFatalError( 731 compiler.reportFatalError(
592 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 732 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
593 {'fromType': type, 'toType': compiler.boolClass.rawType}); 733 {'fromType': type, 'toType': compiler.boolClass.rawType});
734 return null;
594 } 735 }
595 736
596 if (constructor == compiler.stringEnvironment 737 if (constructor == compiler.stringEnvironment
597 && !(defaultValue is NullConstant 738 && !(defaultValue is NullConstant
598 || defaultValue is StringConstant)) { 739 || defaultValue is StringConstant)) {
599 DartType type = defaultValue.computeType(compiler); 740 DartType type = defaultValue.computeType(compiler);
600 compiler.reportFatalError( 741 compiler.reportFatalError(
601 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 742 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
602 {'fromType': type, 'toType': compiler.stringClass.rawType}); 743 {'fromType': type, 'toType': compiler.stringClass.rawType});
744 return null;
603 } 745 }
604 746
605 String value = 747 String value =
606 compiler.fromEnvironment(firstArgument.value.slowToString()); 748 compiler.fromEnvironment(firstArgument.value.slowToString());
607 749
608 if (value == null) { 750 if (value == null) {
609 return defaultValue; 751 return createEvaluatedConstant(defaultValue);
610 } else if (constructor == compiler.intEnvironment) { 752 } else if (constructor == compiler.intEnvironment) {
611 int number = int.parse(value, onError: (_) => null); 753 int number = int.parse(value, onError: (_) => null);
612 return (number == null) 754 return createEvaluatedConstant(
613 ? defaultValue 755 (number == null)
614 : constantSystem.createInt(number); 756 ? defaultValue
757 : constantSystem.createInt(number));
615 } else if (constructor == compiler.boolEnvironment) { 758 } else if (constructor == compiler.boolEnvironment) {
616 if (value == 'true') { 759 if (value == 'true') {
617 return constantSystem.createBool(true); 760 return createEvaluatedConstant(constantSystem.createBool(true));
618 } else if (value == 'false') { 761 } else if (value == 'false') {
619 return constantSystem.createBool(false); 762 return createEvaluatedConstant(constantSystem.createBool(false));
620 } else { 763 } else {
621 return defaultValue; 764 return createEvaluatedConstant(defaultValue);
622 } 765 }
623 } else { 766 } else {
624 assert(constructor == compiler.stringEnvironment); 767 assert(constructor == compiler.stringEnvironment);
625 return constantSystem.createString(new DartString.literal(value)); 768 return createEvaluatedConstant(
769 constantSystem.createString(new DartString.literal(value)));
626 } 770 }
627 } else { 771 } else {
628 return makeConstructedConstant( 772 return makeConstructedConstant(
629 compiler, handler, node, type, constructor, evaluateArguments); 773 compiler, handler, context,
774 node, type, constructor, selector,
775 concreteArguments, normalizedArguments);
630 } 776 }
631 } 777 }
632 778
633 static Constant makeConstructedConstant( 779 static AstConstant makeConstructedConstant(
634 Compiler compiler, 780 Compiler compiler,
635 ConstantCompilerBase handler, 781 ConstantCompilerBase handler,
636 Spannable node, 782 Element context,
783 Node node,
637 InterfaceType type, 784 InterfaceType type,
638 ConstructorElement constructor, 785 ConstructorElement constructor,
639 List<Constant> getArguments(ConstructorElement constructor), 786 Selector selector,
640 {bool isLiteralSymbol: false}) { 787 List<AstConstant> concreteArguments,
788 List<AstConstant> normalizedArguments) {
789 assert(invariant(node, selector.applies(constructor, compiler.world),
790 message: "Selector $selector does not apply to constructor "
791 "$constructor."));
641 792
642 // The redirection chain of this element may not have been resolved through 793 // The redirection chain of this element may not have been resolved through
643 // a post-process action, so we have to make sure it is done here. 794 // a post-process action, so we have to make sure it is done here.
644 compiler.resolver.resolveRedirectionChain(constructor, node); 795 compiler.resolver.resolveRedirectionChain(constructor, node);
645 InterfaceType constructedType = 796 InterfaceType constructedType =
646 constructor.computeEffectiveTargetType(type); 797 constructor.computeEffectiveTargetType(type);
647 constructor = constructor.effectiveTarget; 798 ConstructorElement target = constructor.effectiveTarget;
648 ClassElement classElement = constructor.enclosingClass; 799 ClassElement classElement = target.enclosingClass;
649 // The constructor must be an implementation to ensure that field 800 // The constructor must be an implementation to ensure that field
650 // initializers are handled correctly. 801 // initializers are handled correctly.
651 constructor = constructor.implementation; 802 target = target.implementation;
652 assert(invariant(node, constructor.isImplementation)); 803 assert(invariant(node, target.isImplementation));
653 804
654 List<Constant> arguments = getArguments(constructor);
655 ConstructorEvaluator evaluator = new ConstructorEvaluator( 805 ConstructorEvaluator evaluator = new ConstructorEvaluator(
656 constructedType, constructor, handler, compiler); 806 constructedType, target, handler, compiler);
657 evaluator.evaluateConstructorFieldValues(arguments); 807 evaluator.evaluateConstructorFieldValues(normalizedArguments);
658 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); 808 List<AstConstant> fieldConstants =
809 evaluator.buildFieldConstants(classElement);
659 810
660 return new ConstructedConstant(constructedType, jsNewArguments, 811 return new AstConstant(
661 isLiteralSymbol: isLiteralSymbol); 812 context, node, new ConstructorConstExp(
813 new ConstructedConstant(
814 constructedType,
815 fieldConstants.map((e) => e.value).toList()),
816 type,
817 constructor,
818 selector,
819 concreteArguments.map((e) => e.expression).toList()));
662 } 820 }
663 821
664 Constant visitParenthesizedExpression(ParenthesizedExpression node) { 822 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) {
665 return node.expression.accept(this); 823 return node.expression.accept(this);
666 } 824 }
667 825
668 error(Node node, MessageKind message) { 826 error(Node node, MessageKind message) {
669 // TODO(floitsch): get the list of constants that are currently compiled 827 // TODO(floitsch): get the list of constants that are currently compiled
670 // and present some kind of stack-trace. 828 // and present some kind of stack-trace.
671 compiler.reportFatalError(node, message); 829 compiler.reportFatalError(node, message);
672 } 830 }
673 831
674 Constant signalNotCompileTimeConstant(Node node, 832 AstConstant signalNotCompileTimeConstant(Node node,
675 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { 833 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
676 if (isEvaluatingConstant) { 834 if (isEvaluatingConstant) {
677 error(node, message); 835 error(node, message);
678 } 836 }
679 // Else we don't need to do anything. The final handler is only 837 // Else we don't need to do anything. The final handler is only
680 // optimistically trying to compile constants. So it is normal that we 838 // optimistically trying to compile constants. So it is normal that we
681 // sometimes see non-compile time constants. 839 // sometimes see non-compile time constants.
682 // Simply return [:null:] which is used to propagate a failing 840 // Simply return [:null:] which is used to propagate a failing
683 // compile-time compilation. 841 // compile-time compilation.
684 return null; 842 return null;
685 } 843 }
686 } 844 }
687 845
688 class ConstructorEvaluator extends CompileTimeConstantEvaluator { 846 class ConstructorEvaluator extends CompileTimeConstantEvaluator {
689 final InterfaceType constructedType; 847 final InterfaceType constructedType;
690 final ConstructorElement constructor; 848 final ConstructorElement constructor;
691 final Map<Element, Constant> definitions; 849 final Map<Element, AstConstant> definitions;
692 final Map<Element, Constant> fieldValues; 850 final Map<Element, AstConstant> fieldValues;
693 851
694 /** 852 /**
695 * Documentation wanted -- johnniwinther 853 * Documentation wanted -- johnniwinther
696 * 854 *
697 * Invariant: [constructor] must be an implementation element. 855 * Invariant: [constructor] must be an implementation element.
698 */ 856 */
699 ConstructorEvaluator(InterfaceType this.constructedType, 857 ConstructorEvaluator(InterfaceType this.constructedType,
700 FunctionElement constructor, 858 FunctionElement constructor,
701 ConstantCompiler handler, 859 ConstantCompiler handler,
702 Compiler compiler) 860 Compiler compiler)
703 : this.constructor = constructor, 861 : this.constructor = constructor,
704 this.definitions = new Map<Element, Constant>(), 862 this.definitions = new Map<Element, AstConstant>(),
705 this.fieldValues = new Map<Element, Constant>(), 863 this.fieldValues = new Map<Element, AstConstant>(),
706 super(handler, 864 super(handler,
707 compiler.resolver.resolveMethodElement(constructor.declaration), 865 compiler.resolver.resolveMethodElement(constructor.declaration),
708 compiler, 866 compiler,
709 isConst: true) { 867 isConst: true) {
710 assert(invariant(constructor, constructor.isImplementation)); 868 assert(invariant(constructor, constructor.isImplementation));
711 } 869 }
712 870
713 Constant visitSend(Send send) { 871 AstConstant visitSend(Send send) {
714 Element element = elements[send]; 872 Element element = elements[send];
715 if (Elements.isLocal(element)) { 873 if (Elements.isLocal(element)) {
716 Constant constant = definitions[element]; 874 AstConstant constant = definitions[element];
717 if (constant == null) { 875 if (constant == null) {
718 compiler.internalError(send, "Local variable without value."); 876 compiler.internalError(send, "Local variable without value.");
719 } 877 }
720 return constant; 878 return constant;
721 } 879 }
722 return super.visitSend(send); 880 return super.visitSend(send);
723 } 881 }
724 882
725 void potentiallyCheckType(Node node, 883 void potentiallyCheckType(Node node,
726 TypedElement element, 884 TypedElement element,
727 Constant constant) { 885 AstConstant constant) {
728 if (compiler.enableTypeAssertions) { 886 if (compiler.enableTypeAssertions) {
729 DartType elementType = element.type.substByContext(constructedType); 887 DartType elementType = element.type.substByContext(constructedType);
730 DartType constantType = constant.computeType(compiler); 888 DartType constantType = constant.value.computeType(compiler);
731 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { 889 if (!constantSystem.isSubtype(compiler, constantType, elementType)) {
732 compiler.reportFatalError( 890 compiler.withCurrentElement(constant.element, () {
733 node, MessageKind.NOT_ASSIGNABLE, 891 compiler.reportFatalError(
734 {'fromType': constantType, 'toType': elementType}); 892 constant.node, MessageKind.NOT_ASSIGNABLE,
893 {'fromType': constantType, 'toType': elementType});
894 });
735 } 895 }
736 } 896 }
737 } 897 }
738 898
739 void updateFieldValue(Node node, TypedElement element, Constant constant) { 899 void updateFieldValue(Node node,
900 TypedElement element,
901 AstConstant constant) {
740 potentiallyCheckType(node, element, constant); 902 potentiallyCheckType(node, element, constant);
741 fieldValues[element] = constant; 903 fieldValues[element] = constant;
742 } 904 }
743 905
744 /** 906 /**
745 * Given the arguments (a list of constants) assigns them to the parameters, 907 * Given the arguments (a list of constants) assigns them to the parameters,
746 * updating the definitions map. If the constructor has field-initializer 908 * updating the definitions map. If the constructor has field-initializer
747 * parameters (like [:this.x:]), also updates the [fieldValues] map. 909 * parameters (like [:this.x:]), also updates the [fieldValues] map.
748 */ 910 */
749 void assignArgumentsToParameters(List<Constant> arguments) { 911 void assignArgumentsToParameters(List<AstConstant> arguments) {
750 // Assign arguments to parameters. 912 // Assign arguments to parameters.
751 FunctionSignature signature = constructor.functionSignature; 913 FunctionSignature signature = constructor.functionSignature;
752 int index = 0; 914 int index = 0;
753 signature.orderedForEachParameter((ParameterElement parameter) { 915 signature.orderedForEachParameter((ParameterElement parameter) {
754 Constant argument = arguments[index++]; 916 AstConstant argument = arguments[index++];
755 Node node = parameter.node; 917 Node node = parameter.node;
756 potentiallyCheckType(node, parameter, argument);
757 definitions[parameter] = argument;
758 if (parameter.isInitializingFormal) { 918 if (parameter.isInitializingFormal) {
759 InitializingFormalElement initializingFormal = parameter; 919 InitializingFormalElement initializingFormal = parameter;
760 updateFieldValue(node, initializingFormal.fieldElement, argument); 920 updateFieldValue(node, initializingFormal.fieldElement, argument);
921 } else {
922 potentiallyCheckType(node, parameter, argument);
923 definitions[parameter] = argument;
761 } 924 }
762 }); 925 });
763 } 926 }
764 927
765 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, 928 void evaluateSuperOrRedirectSend(List<AstConstant> compiledArguments,
766 FunctionElement targetConstructor) { 929 FunctionElement targetConstructor) {
767 ConstructorEvaluator evaluator = new ConstructorEvaluator( 930 ConstructorEvaluator evaluator = new ConstructorEvaluator(
768 constructedType.asInstanceOf(targetConstructor.enclosingClass), 931 constructedType.asInstanceOf(targetConstructor.enclosingClass),
769 targetConstructor, handler, compiler); 932 targetConstructor, handler, compiler);
770 evaluator.evaluateConstructorFieldValues(compiledArguments); 933 evaluator.evaluateConstructorFieldValues(compiledArguments);
771 // Copy over the fieldValues from the super/redirect-constructor. 934 // Copy over the fieldValues from the super/redirect-constructor.
772 // No need to go through [updateFieldValue] because the 935 // No need to go through [updateFieldValue] because the
773 // assignments have already been checked in checked mode. 936 // assignments have already been checked in checked mode.
774 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); 937 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value);
775 } 938 }
776 939
777 /** 940 /**
778 * Runs through the initializers of the given [constructor] and updates 941 * Runs through the initializers of the given [constructor] and updates
779 * the [fieldValues] map. 942 * the [fieldValues] map.
780 */ 943 */
781 void evaluateConstructorInitializers() { 944 void evaluateConstructorInitializers() {
782 if (constructor.isSynthesized) { 945 if (constructor.isSynthesized) {
783 List<Constant> compiledArguments = <Constant>[]; 946 List<AstConstant> compiledArguments = <AstConstant>[];
784 947
785 Function compileArgument = (element) => definitions[element]; 948 Function compileArgument = (element) => definitions[element];
786 Function compileConstant = handler.compileConstant; 949 Function compileConstant = handler.compileConstant;
787 FunctionElement target = constructor.definingConstructor.implementation; 950 FunctionElement target = constructor.definingConstructor.implementation;
788 Selector.addForwardingElementArgumentsToList(constructor, 951 Selector.addForwardingElementArgumentsToList(constructor,
789 compiledArguments, 952 compiledArguments,
790 target, 953 target,
791 compileArgument, 954 compileArgument,
792 compileConstant, 955 compileConstant,
793 compiler.world); 956 compiler.world);
794 evaluateSuperOrRedirectSend(compiledArguments, target); 957 evaluateSuperOrRedirectSend(compiledArguments, target);
795 return; 958 return;
796 } 959 }
797 FunctionExpression functionNode = constructor.node; 960 FunctionExpression functionNode = constructor.node;
798 NodeList initializerList = functionNode.initializers; 961 NodeList initializerList = functionNode.initializers;
799 962
800 bool foundSuperOrRedirect = false; 963 bool foundSuperOrRedirect = false;
801 964
802 if (initializerList != null) { 965 if (initializerList != null) {
803 for (Link<Node> link = initializerList.nodes; 966 for (Link<Node> link = initializerList.nodes;
804 !link.isEmpty; 967 !link.isEmpty;
805 link = link.tail) { 968 link = link.tail) {
806 assert(link.head is Send); 969 assert(link.head is Send);
807 if (link.head is !SendSet) { 970 if (link.head is !SendSet) {
808 // A super initializer or constructor redirection. 971 // A super initializer or constructor redirection.
809 Send call = link.head; 972 Send call = link.head;
810 FunctionElement target = elements[call]; 973 FunctionElement target = elements[call];
811 List<Constant> compiledArguments = evaluateArgumentsToConstructor( 974 List<AstConstant> compiledArguments =
812 call, elements.getSelector(call), call.arguments, target); 975 evaluateArgumentsToConstructor(
976 call, elements.getSelector(call), call.arguments, target,
977 compileArgument: evaluateConstant);
813 evaluateSuperOrRedirectSend(compiledArguments, target); 978 evaluateSuperOrRedirectSend(compiledArguments, target);
814 foundSuperOrRedirect = true; 979 foundSuperOrRedirect = true;
815 } else { 980 } else {
816 // A field initializer. 981 // A field initializer.
817 SendSet init = link.head; 982 SendSet init = link.head;
818 Link<Node> initArguments = init.arguments; 983 Link<Node> initArguments = init.arguments;
819 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); 984 assert(!initArguments.isEmpty && initArguments.tail.isEmpty);
820 Constant fieldValue = evaluate(initArguments.head); 985 AstConstant fieldValue = evaluate(initArguments.head);
821 updateFieldValue(init, elements[init], fieldValue); 986 updateFieldValue(init, elements[init], fieldValue);
822 } 987 }
823 } 988 }
824 } 989 }
825 990
826 if (!foundSuperOrRedirect) { 991 if (!foundSuperOrRedirect) {
827 // No super initializer found. Try to find the default constructor if 992 // No super initializer found. Try to find the default constructor if
828 // the class is not Object. 993 // the class is not Object.
829 ClassElement enclosingClass = constructor.enclosingClass; 994 ClassElement enclosingClass = constructor.enclosingClass;
830 ClassElement superClass = enclosingClass.superclass; 995 ClassElement superClass = enclosingClass.superclass;
831 if (enclosingClass != compiler.objectClass) { 996 if (enclosingClass != compiler.objectClass) {
832 assert(superClass != null); 997 assert(superClass != null);
833 assert(superClass.resolutionState == STATE_DONE); 998 assert(superClass.resolutionState == STATE_DONE);
834 999
835 Selector selector = 1000 Selector selector =
836 new Selector.callDefaultConstructor(enclosingClass.library); 1001 new Selector.callDefaultConstructor(enclosingClass.library);
837 1002
838 FunctionElement targetConstructor = 1003 FunctionElement targetConstructor =
839 superClass.lookupConstructor(selector); 1004 superClass.lookupConstructor(selector);
840 if (targetConstructor == null) { 1005 if (targetConstructor == null) {
841 compiler.internalError(functionNode, 1006 compiler.internalError(functionNode,
842 "No default constructor available."); 1007 "No default constructor available.");
843 } 1008 }
844 List<Constant> compiledArguments = evaluateArgumentsToConstructor( 1009 List<AstConstant> compiledArguments =
845 functionNode, selector, const Link<Node>(), targetConstructor); 1010 evaluateArgumentsToConstructor(
1011 functionNode, selector, const Link<Node>(), targetConstructor);
846 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); 1012 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor);
847 } 1013 }
848 } 1014 }
849 } 1015 }
850 1016
851 /** 1017 /**
852 * Simulates the execution of the [constructor] with the given 1018 * Simulates the execution of the [constructor] with the given
853 * [arguments] to obtain the field values that need to be passed to the 1019 * [arguments] to obtain the field values that need to be passed to the
854 * native JavaScript constructor. 1020 * native JavaScript constructor.
855 */ 1021 */
856 void evaluateConstructorFieldValues(List<Constant> arguments) { 1022 void evaluateConstructorFieldValues(List<AstConstant> arguments) {
857 compiler.withCurrentElement(constructor, () { 1023 compiler.withCurrentElement(constructor, () {
858 assignArgumentsToParameters(arguments); 1024 assignArgumentsToParameters(arguments);
859 evaluateConstructorInitializers(); 1025 evaluateConstructorInitializers();
860 }); 1026 });
861 } 1027 }
862 1028
863 List<Constant> buildJsNewArguments(ClassElement classElement) { 1029 /// Builds a normalized list of the constant values for each field in the
864 List<Constant> jsNewArguments = <Constant>[]; 1030 /// inheritance chain of [classElement].
1031 List<AstConstant> buildFieldConstants(ClassElement classElement) {
1032 List<AstConstant> fieldConstants = <AstConstant>[];
865 classElement.implementation.forEachInstanceField( 1033 classElement.implementation.forEachInstanceField(
866 (ClassElement enclosing, Element field) { 1034 (ClassElement enclosing, FieldElement field) {
867 Constant fieldValue = fieldValues[field]; 1035 AstConstant fieldValue = fieldValues[field];
868 if (fieldValue == null) { 1036 if (fieldValue == null) {
869 // Use the default value. 1037 // Use the default value.
870 fieldValue = handler.compileConstant(field); 1038 fieldValue = new AstConstant.fromDefaultValue(
1039 field, handler.compileConstant(field));
871 } 1040 }
872 jsNewArguments.add(fieldValue); 1041 fieldConstants.add(fieldValue);
873 }, 1042 },
874 includeSuperAndInjectedMembers: true); 1043 includeSuperAndInjectedMembers: true);
875 return jsNewArguments; 1044 return fieldConstants;
876 } 1045 }
877 } 1046 }
1047
1048 /// A constant created from the front-end AST.
1049 ///
1050 /// [element] and [node] point to the source location of the constant.
1051 /// [expression] holds the symbolic constant expression and [value] its constant
1052 /// value.
1053 ///
1054 /// This class differs from [ConstExp] in that it is coupled to the front-end
1055 /// AST whereas [ConstExp] is only coupled to the element model.
1056 class AstConstant {
1057 final Element element;
1058 final Node node;
1059 final ConstExp expression;
1060
1061 AstConstant(this.element, this.node, this.expression);
1062
1063 factory AstConstant.fromDefaultValue(
1064 VariableElement element,
1065 ConstExp constant) {
1066 return new AstConstant(
1067 element,
1068 element.initializer != null ? element.initializer : element.node,
1069 constant);
1070 }
1071
1072 Constant get value => expression.value;
1073
1074 String toString() => expression.toString();
1075 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698