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

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: Remove ConstExpBuilder. Created 6 years, 3 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 EvaluatedConstant 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): Change to create [ConstExp] instead of [Constant].
sigurdm 2014/09/17 10:29:40 I think this TODO is solved now?
Johnni Winther 2014/09/17 12:20:39 Done.
234 class CompileTimeConstantEvaluator extends Visitor { 236 class CompileTimeConstantEvaluator extends Visitor<EvaluatedConstant> {
sigurdm 2014/09/17 10:29:40 We might want to consider evaluating the constants
Johnni Winther 2014/09/17 12:20:39 Added a TODO.
235 bool isEvaluatingConstant; 237 bool isEvaluatingConstant;
236 final ConstantCompilerBase handler; 238 final ConstantCompilerBase handler;
237 final TreeElements elements; 239 final TreeElements elements;
238 final Compiler compiler; 240 final Compiler compiler;
239 241
242 Element get context => elements.analyzedElement;
243
240 CompileTimeConstantEvaluator(this.handler, 244 CompileTimeConstantEvaluator(this.handler,
241 this.elements, 245 this.elements,
242 this.compiler, 246 this.compiler,
243 {bool isConst: false}) 247 {bool isConst: false})
244 : this.isEvaluatingConstant = isConst; 248 : this.isEvaluatingConstant = isConst;
245 249
246 ConstantSystem get constantSystem => handler.constantSystem; 250 ConstantSystem get constantSystem => handler.constantSystem;
247 251
248 Constant evaluate(Node node) { 252 EvaluatedConstant evaluate(Node node) {
249 return node.accept(this); 253 return node.accept(this);
250 } 254 }
251 255
252 Constant evaluateConstant(Node node) { 256 EvaluatedConstant evaluateConstant(Node node) {
253 bool oldIsEvaluatingConstant = isEvaluatingConstant; 257 bool oldIsEvaluatingConstant = isEvaluatingConstant;
254 isEvaluatingConstant = true; 258 isEvaluatingConstant = true;
255 Constant result = node.accept(this); 259 EvaluatedConstant result = node.accept(this);
256 isEvaluatingConstant = oldIsEvaluatingConstant; 260 isEvaluatingConstant = oldIsEvaluatingConstant;
257 assert(result != null); 261 assert(result != null);
258 return result; 262 return result;
259 } 263 }
260 264
261 Constant visitNode(Node node) { 265 EvaluatedConstant visitNode(Node node) {
262 return signalNotCompileTimeConstant(node); 266 return signalNotCompileTimeConstant(node);
263 } 267 }
264 268
265 Constant visitLiteralBool(LiteralBool node) { 269 EvaluatedConstant visitLiteralBool(LiteralBool node) {
266 return constantSystem.createBool(node.value); 270 return new EvaluatedConstant(
271 context, node, new PrimitiveConstExp(
272 constantSystem.createBool(node.value)));
267 } 273 }
268 274
269 Constant visitLiteralDouble(LiteralDouble node) { 275 EvaluatedConstant visitLiteralDouble(LiteralDouble node) {
270 return constantSystem.createDouble(node.value); 276 return new EvaluatedConstant(
277 context, node, new PrimitiveConstExp(
278 constantSystem.createDouble(node.value)));
271 } 279 }
272 280
273 Constant visitLiteralInt(LiteralInt node) { 281 EvaluatedConstant visitLiteralInt(LiteralInt node) {
274 return constantSystem.createInt(node.value); 282 return new EvaluatedConstant(
283 context, node, new PrimitiveConstExp(
284 constantSystem.createInt(node.value)));
275 } 285 }
276 286
277 Constant visitLiteralList(LiteralList node) { 287 EvaluatedConstant visitLiteralList(LiteralList node) {
278 if (!node.isConst) { 288 if (!node.isConst) {
279 return signalNotCompileTimeConstant(node); 289 return signalNotCompileTimeConstant(node);
280 } 290 }
281 List<Constant> arguments = <Constant>[]; 291 List<ConstExp> argumentExpressions = <ConstExp>[];
292 List<Constant> argumentValues = <Constant>[];
282 for (Link<Node> link = node.elements.nodes; 293 for (Link<Node> link = node.elements.nodes;
283 !link.isEmpty; 294 !link.isEmpty;
284 link = link.tail) { 295 link = link.tail) {
285 arguments.add(evaluateConstant(link.head)); 296 EvaluatedConstant argument = evaluateConstant(link.head);
297 if (argument == null) {
298 return null;
299 }
300 argumentExpressions.add(argument.expression);
301 argumentValues.add(argument.value);
286 } 302 }
287 DartType type = elements.getType(node); 303 DartType type = elements.getType(node);
288 return new ListConstant(type, arguments); 304 return new EvaluatedConstant(
305 context, node, new ListConstExp(
306 new ListConstant(type, argumentValues),
307 type,
308 argumentExpressions));
289 } 309 }
290 310
291 Constant visitLiteralMap(LiteralMap node) { 311 EvaluatedConstant visitLiteralMap(LiteralMap node) {
292 if (!node.isConst) { 312 if (!node.isConst) {
293 return signalNotCompileTimeConstant(node); 313 return signalNotCompileTimeConstant(node);
294 } 314 }
295 List<Constant> keys = <Constant>[]; 315 List<ConstExp> keyExpressions = <ConstExp>[];
296 Map<Constant, Constant> map = new Map<Constant, Constant>(); 316 List<Constant> keyValues = <Constant>[];
317 Map<Constant, ConstExp> map = new Map<Constant, ConstExp>();
297 for (Link<Node> link = node.entries.nodes; 318 for (Link<Node> link = node.entries.nodes;
298 !link.isEmpty; 319 !link.isEmpty;
299 link = link.tail) { 320 link = link.tail) {
300 LiteralMapEntry entry = link.head; 321 LiteralMapEntry entry = link.head;
301 Constant key = evaluateConstant(entry.key); 322 EvaluatedConstant key = evaluateConstant(entry.key);
302 if (!map.containsKey(key)) { 323 if (key == null) {
303 keys.add(key); 324 return null;
325 }
326 if (!map.containsKey(key.value)) {
327 keyExpressions.add(key.expression);
328 keyValues.add(key.value);
304 } else { 329 } else {
305 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); 330 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
306 } 331 }
307 map[key] = evaluateConstant(entry.value); 332 EvaluatedConstant value = evaluateConstant(entry.value);
333 if (value == null) {
334 return null;
335 }
336 map[key.value] = value.expression;
308 } 337 }
309 List<Constant> values = map.values.toList(); 338 List<ConstExp> valueExpressions = map.values.toList();
310 InterfaceType sourceType = elements.getType(node); 339 InterfaceType type = elements.getType(node);
311 return constantSystem.createMap(compiler, sourceType, keys, values); 340 return new EvaluatedConstant(
341 context, node, new MapConstExp(
342 constantSystem.createMap(compiler, type, keyValues,
343 valueExpressions.map((e) => e.value).toList()),
344 type,
345 keyExpressions,
346 valueExpressions));
312 } 347 }
313 348
314 Constant visitLiteralNull(LiteralNull node) { 349 EvaluatedConstant visitLiteralNull(LiteralNull node) {
315 return constantSystem.createNull(); 350 return new EvaluatedConstant(
351 context, node, new PrimitiveConstExp(
352 constantSystem.createNull()));
316 } 353 }
317 354
318 Constant visitLiteralString(LiteralString node) { 355 EvaluatedConstant visitLiteralString(LiteralString node) {
319 return constantSystem.createString(node.dartString); 356 return new EvaluatedConstant(
357 context, node, new PrimitiveConstExp(
358 constantSystem.createString(node.dartString)));
320 } 359 }
321 360
322 Constant visitStringJuxtaposition(StringJuxtaposition node) { 361 EvaluatedConstant visitStringJuxtaposition(StringJuxtaposition node) {
323 StringConstant left = evaluate(node.first); 362 EvaluatedConstant left = evaluate(node.first);
324 StringConstant right = evaluate(node.second); 363 EvaluatedConstant right = evaluate(node.second);
325 if (left == null || right == null) return null; 364 if (left == null || right == null) return null;
326 return constantSystem.createString( 365 StringConstant leftValue = left.value;
327 new DartString.concat(left.value, right.value)); 366 StringConstant rightValue = right.value;
367 return new EvaluatedConstant(
368 context, node, new ConcatenateConstExp(
369 constantSystem.createString(
370 new DartString.concat(leftValue.value, rightValue.value)),
371 [left.expression, right.expression]));
328 } 372 }
329 373
330 Constant visitStringInterpolation(StringInterpolation node) { 374 EvaluatedConstant visitStringInterpolation(StringInterpolation node) {
331 StringConstant initialString = evaluate(node.string); 375 List<ConstExp> subexpressions = <ConstExp>[];
332 if (initialString == null) return null; 376 EvaluatedConstant initialString = evaluate(node.string);
333 DartString accumulator = initialString.value; 377 if (initialString == null) {
378 return null;
379 }
380 subexpressions.add(initialString.expression);
381 StringConstant initialStringValue = initialString.value;
382 DartString accumulator = initialStringValue.value;
334 for (StringInterpolationPart part in node.parts) { 383 for (StringInterpolationPart part in node.parts) {
335 Constant expression = evaluate(part.expression); 384 EvaluatedConstant subexpression = evaluate(part.expression);
385 if (subexpression == null) {
386 return null;
387 }
388 subexpressions.add(subexpression.expression);
389 Constant expression = subexpression.value;
336 DartString expressionString; 390 DartString expressionString;
337 if (expression == null) { 391 if (expression.isNum || expression.isBool) {
338 return signalNotCompileTimeConstant(part.expression);
339 } else if (expression.isNum || expression.isBool) {
340 PrimitiveConstant primitive = expression; 392 PrimitiveConstant primitive = expression;
341 expressionString = new DartString.literal(primitive.value.toString()); 393 expressionString = new DartString.literal(primitive.value.toString());
342 } else if (expression.isString) { 394 } else if (expression.isString) {
343 PrimitiveConstant primitive = expression; 395 PrimitiveConstant primitive = expression;
344 expressionString = primitive.value; 396 expressionString = primitive.value;
345 } else { 397 } else {
398 // TODO(johnniwinther): Specialize message to indicated that the problem
399 // is not constness but the types of the const expressions.
346 return signalNotCompileTimeConstant(part.expression); 400 return signalNotCompileTimeConstant(part.expression);
347 } 401 }
348 accumulator = new DartString.concat(accumulator, expressionString); 402 accumulator = new DartString.concat(accumulator, expressionString);
349 StringConstant partString = evaluate(part.string); 403 EvaluatedConstant partString = evaluate(part.string);
350 if (partString == null) return null; 404 if (partString == null) return null;
351 accumulator = new DartString.concat(accumulator, partString.value); 405 subexpressions.add(partString.expression);
406 StringConstant partStringValue = partString.value;
407 accumulator = new DartString.concat(accumulator, partStringValue.value);
352 }; 408 };
353 return constantSystem.createString(accumulator); 409 return new EvaluatedConstant(
410 context, node, new ConcatenateConstExp(
411 constantSystem.createString(accumulator),
412 subexpressions));
354 } 413 }
355 414
356 Constant visitLiteralSymbol(LiteralSymbol node) { 415 EvaluatedConstant visitLiteralSymbol(LiteralSymbol node) {
357 InterfaceType type = compiler.symbolClass.rawType; 416 InterfaceType type = compiler.symbolClass.rawType;
358 List<Constant> createArguments(_) { 417 String text = node.slowNameString;
359 return [constantSystem.createString( 418 List<EvaluatedConstant> arguments =
360 new DartString.literal(node.slowNameString))]; 419 <EvaluatedConstant>[new EvaluatedConstant(context, node,
361 } 420 new PrimitiveConstExp(constantSystem.createString(
362 return makeConstructedConstant( 421 new DartString.literal(text))))];
363 compiler, handler, node, type, compiler.symbolConstructor, 422 EvaluatedConstant constant = makeConstructedConstant(
364 createArguments, isLiteralSymbol: true); 423 compiler, handler, context, node, type, compiler.symbolConstructor,
424 new Selector.callConstructor('', null, 1),
425 arguments, arguments);
426 return new EvaluatedConstant(
427 context, node, new SymbolConstExp(constant.value, text));
365 } 428 }
366 429
367 Constant makeTypeConstant(DartType elementType) { 430 EvaluatedConstant makeTypeConstant(Node node, DartType elementType) {
368 DartType constantType = 431 DartType constantType =
369 compiler.backend.typeImplementation.computeType(compiler); 432 compiler.backend.typeImplementation.computeType(compiler);
370 return new TypeConstant(elementType, constantType); 433 return new EvaluatedConstant(
434 context, node, new TypeConstExp(
435 new TypeConstant(elementType, constantType),
436 elementType));
371 } 437 }
372 438
373 /// Returns true if the prefix of the send resolves to a deferred import 439 /// Returns true if the prefix of the send resolves to a deferred import
374 /// prefix. 440 /// prefix.
375 bool isDeferredUse(Send send) { 441 bool isDeferredUse(Send send) {
376 if (send == null) return false; 442 if (send == null) return false;
377 return compiler.deferredLoadTask 443 return compiler.deferredLoadTask
378 .deferredPrefixElement(send, elements) != null; 444 .deferredPrefixElement(send, elements) != null;
379 } 445 }
380 446
381 Constant visitIdentifier(Identifier node) { 447 EvaluatedConstant visitIdentifier(Identifier node) {
382 Element element = elements[node]; 448 Element element = elements[node];
383 if (Elements.isClass(element) || Elements.isTypedef(element)) { 449 if (Elements.isClass(element) || Elements.isTypedef(element)) {
384 TypeDeclarationElement typeDeclarationElement = element; 450 TypeDeclarationElement typeDeclarationElement = element;
385 return makeTypeConstant(typeDeclarationElement.rawType); 451 DartType type = typeDeclarationElement.rawType;
452 return makeTypeConstant(node, type);
386 } 453 }
387 return signalNotCompileTimeConstant(node); 454 return signalNotCompileTimeConstant(node);
388 } 455 }
389 456
390 // TODO(floitsch): provide better error-messages. 457 // TODO(floitsch): provide better error-messages.
391 Constant visitSend(Send send) { 458 EvaluatedConstant visitSend(Send send) {
392 Element element = elements[send]; 459 Element element = elements[send];
393 if (send.isPropertyAccess) { 460 if (send.isPropertyAccess) {
394 if (isDeferredUse(send)) { 461 if (isDeferredUse(send)) {
395 return signalNotCompileTimeConstant(send, 462 return signalNotCompileTimeConstant(send,
396 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); 463 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
397 } 464 }
398 if (Elements.isStaticOrTopLevelFunction(element)) { 465 if (Elements.isStaticOrTopLevelFunction(element)) {
399 return new FunctionConstant(element); 466 return new EvaluatedConstant(
467 context, send, new FunctionConstExp(
468 new FunctionConstant(element),
469 element));
400 } else if (Elements.isStaticOrTopLevelField(element)) { 470 } else if (Elements.isStaticOrTopLevelField(element)) {
401 Constant result; 471 ConstExp result;
402 if (element.isConst) { 472 if (element.isConst) {
403 result = handler.compileConstant(element); 473 result = handler.compileConstant(element);
404 } else if (element.isFinal && !isEvaluatingConstant) { 474 } else if (element.isFinal && !isEvaluatingConstant) {
405 result = handler.compileVariable(element); 475 result = handler.compileVariable(element);
406 } 476 }
407 if (result != null) return result; 477 if (result != null) {
478 return new EvaluatedConstant(
479 context, send, new VariableConstExp(result.value, element));
480 }
408 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { 481 } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
409 assert(elements.isTypeLiteral(send)); 482 assert(elements.isTypeLiteral(send));
410 return makeTypeConstant(elements.getTypeLiteralType(send)); 483 return makeTypeConstant(send, elements.getTypeLiteralType(send));
411 } else if (send.receiver != null) { 484 } else if (send.receiver != null) {
412 // Fall through to error handling. 485 // Fall through to error handling.
413 } else if (!Elements.isUnresolved(element) 486 } else if (!Elements.isUnresolved(element)
414 && element.isVariable 487 && element.isVariable
415 && element.isConst) { 488 && element.isConst) {
416 Constant result = handler.compileConstant(element); 489 ConstExp result = handler.compileConstant(element);
417 if (result != null) return result; 490 if (result != null) {
491 return new EvaluatedConstant(
492 context, send, new VariableConstExp(result.value, element));
493 }
418 } 494 }
419 return signalNotCompileTimeConstant(send); 495 return signalNotCompileTimeConstant(send);
420 } else if (send.isCall) { 496 } else if (send.isCall) {
421 if (identical(element, compiler.identicalFunction) 497 if (identical(element, compiler.identicalFunction)
422 && send.argumentCount() == 2) { 498 && send.argumentCount() == 2) {
423 Constant left = evaluate(send.argumentsNode.nodes.head); 499 EvaluatedConstant left = evaluate(send.argumentsNode.nodes.head);
424 Constant right = evaluate(send.argumentsNode.nodes.tail.head); 500 EvaluatedConstant right = evaluate(send.argumentsNode.nodes.tail.head);
425 Constant result = constantSystem.identity.fold(left, right); 501 if (left == null || right == null) {
426 if (result != null) return result; 502 return null;
503 }
504 Constant result = constantSystem.identity.fold(left.value, right.value);
505 if (result != null) {
506 return new EvaluatedConstant(
507 context, send, new BinaryConstExp(result,
508 left.expression, 'identical', right.expression));
509 }
427 } 510 }
428 return signalNotCompileTimeConstant(send); 511 return signalNotCompileTimeConstant(send);
429 } else if (send.isPrefix) { 512 } else if (send.isPrefix) {
430 assert(send.isOperator); 513 assert(send.isOperator);
431 Constant receiverConstant = evaluate(send.receiver); 514 EvaluatedConstant receiverConstant = evaluate(send.receiver);
432 if (receiverConstant == null) return null; 515 if (receiverConstant == null) {
516 return null;
517 }
433 Operator op = send.selector; 518 Operator op = send.selector;
434 UnaryOperation operation = constantSystem.lookupUnary(op.source); 519 UnaryOperation operation = constantSystem.lookupUnary(op.source);
435 if (operation == null) { 520 if (operation == null) {
436 compiler.internalError(op, "Unexpected operator."); 521 compiler.internalError(op, "Unexpected operator.");
437 } 522 }
438 Constant folded = operation.fold(receiverConstant); 523 Constant folded = operation.fold(receiverConstant.value);
439 if (folded == null) return signalNotCompileTimeConstant(send); 524 if (folded == null) {
440 return folded; 525 return signalNotCompileTimeConstant(send);
526 }
527 return new EvaluatedConstant(
528 context, send, new UnaryConstExp(folded,
529 op.source, receiverConstant.expression));
441 } else if (send.isOperator && !send.isPostfix) { 530 } else if (send.isOperator && !send.isPostfix) {
442 assert(send.argumentCount() == 1); 531 assert(send.argumentCount() == 1);
443 Constant left = evaluate(send.receiver); 532 EvaluatedConstant left = evaluate(send.receiver);
444 Constant right = evaluate(send.argumentsNode.nodes.head); 533 EvaluatedConstant right = evaluate(send.argumentsNode.nodes.head);
445 if (left == null || right == null) return null; 534 if (left == null || right == null) {
535 return null;
536 }
537 Constant leftValue = left.value;
538 Constant rightValue = right.value;
446 Operator op = send.selector.asOperator(); 539 Operator op = send.selector.asOperator();
447 Constant folded = null; 540 Constant folded = null;
448 switch (op.source) { 541 switch (op.source) {
449 case "==": 542 case "==":
450 if (left.isPrimitive && right.isPrimitive) { 543 if (leftValue.isPrimitive && rightValue.isPrimitive) {
451 folded = constantSystem.equal.fold(left, right); 544 folded = constantSystem.equal.fold(leftValue, rightValue);
452 } 545 }
453 break; 546 break;
454 case "!=": 547 case "!=":
455 if (left.isPrimitive && right.isPrimitive) { 548 if (leftValue.isPrimitive && rightValue.isPrimitive) {
456 BoolConstant areEquals = constantSystem.equal.fold(left, right); 549 BoolConstant areEquals =
550 constantSystem.equal.fold(leftValue, rightValue);
457 if (areEquals == null) { 551 if (areEquals == null) {
458 folded = null; 552 folded = null;
459 } else { 553 } else {
460 folded = areEquals.negate(); 554 folded = areEquals.negate();
461 } 555 }
462 } 556 }
463 break; 557 break;
464 default: 558 default:
465 BinaryOperation operation = constantSystem.lookupBinary(op.source); 559 BinaryOperation operation = constantSystem.lookupBinary(op.source);
466 if (operation != null) { 560 if (operation != null) {
467 folded = operation.fold(left, right); 561 folded = operation.fold(leftValue, rightValue);
468 } 562 }
469 } 563 }
470 if (folded == null) return signalNotCompileTimeConstant(send); 564 if (folded == null) {
471 return folded; 565 return signalNotCompileTimeConstant(send);
566 }
567 return new EvaluatedConstant(
568 context, send, new BinaryConstExp(folded,
569 left.expression, op.source, right.expression));
472 } 570 }
473 return signalNotCompileTimeConstant(send); 571 return signalNotCompileTimeConstant(send);
474 } 572 }
475 573
476 Constant visitConditional(Conditional node) { 574 EvaluatedConstant visitConditional(Conditional node) {
477 Constant condition = evaluate(node.condition); 575 EvaluatedConstant condition = evaluate(node.condition);
478 if (condition == null) { 576 if (condition == null) {
479 return null; 577 return null;
480 } else if (!condition.isBool) { 578 } else if (!condition.value.isBool) {
481 DartType conditionType = condition.computeType(compiler); 579 DartType conditionType = condition.value.computeType(compiler);
482 if (isEvaluatingConstant) { 580 if (isEvaluatingConstant) {
483 compiler.reportFatalError( 581 compiler.reportFatalError(
484 node.condition, MessageKind.NOT_ASSIGNABLE, 582 node.condition, MessageKind.NOT_ASSIGNABLE,
485 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); 583 {'fromType': conditionType, 'toType': compiler.boolClass.rawType});
486 } 584 }
487 return null; 585 return null;
488 } 586 }
489 Constant thenExpression = evaluate(node.thenExpression); 587 EvaluatedConstant thenExpression = evaluate(node.thenExpression);
490 Constant elseExpression = evaluate(node.elseExpression); 588 EvaluatedConstant elseExpression = evaluate(node.elseExpression);
491 BoolConstant boolCondition = condition; 589 if (thenExpression == null || elseExpression == null) {
492 return boolCondition.value ? thenExpression : elseExpression; 590 return null;
591 }
592 BoolConstant boolCondition = condition.value;
593 return new EvaluatedConstant(
594 context, node, new ConditionalConstExp(
595 boolCondition.value ? thenExpression.value : elseExpression.value,
596 condition.expression,
597 thenExpression.expression,
598 elseExpression.expression));
493 } 599 }
494 600
495 Constant visitSendSet(SendSet node) { 601 EvaluatedConstant visitSendSet(SendSet node) {
496 return signalNotCompileTimeConstant(node); 602 return signalNotCompileTimeConstant(node);
497 } 603 }
498 604
499 /** 605 /**
500 * Returns the list of constants that are passed to the static function. 606 * Returns the normalized list of constant arguments that are passed to the
607 * constructor including both the concrete arguments and default values for
608 * omitted optional arguments.
501 * 609 *
502 * Invariant: [target] must be an implementation element. 610 * Invariant: [target] must be an implementation element.
503 */ 611 */
504 List<Constant> evaluateArgumentsToConstructor(Node node, 612 List<EvaluatedConstant> evaluateArgumentsToConstructor(
505 Selector selector, 613 Node node,
506 Link<Node> arguments, 614 Selector selector,
507 FunctionElement target) { 615 Link<Node> arguments,
616 FunctionElement target,
617 {EvaluatedConstant compileArgument(Node node)}) {
508 assert(invariant(node, target.isImplementation)); 618 assert(invariant(node, target.isImplementation));
509 List<Constant> compiledArguments = <Constant>[]; 619 List<EvaluatedConstant> compiledArguments = <EvaluatedConstant>[];
510 620
511 Function compileArgument = evaluateConstant; 621 EvaluatedConstant compileDefaultValue(VariableElement element) {
512 Function compileConstant = handler.compileConstant; 622 ConstExp constant = handler.compileConstant(element);
623 return new EvaluatedConstant.fromDefaultValue(element, constant);
624 }
513 target.computeSignature(compiler); 625 target.computeSignature(compiler);
514 bool succeeded = selector.addArgumentsToList(arguments, 626 bool succeeded = selector.addArgumentsToList(arguments,
515 compiledArguments, 627 compiledArguments,
516 target, 628 target,
517 compileArgument, 629 compileArgument,
518 compileConstant, 630 compileDefaultValue,
519 compiler.world); 631 compiler.world);
520 if (!succeeded) { 632 if (!succeeded) {
521 String name = Elements.constructorNameForDiagnostics( 633 String name = Elements.constructorNameForDiagnostics(
522 target.enclosingClass.name, target.name); 634 target.enclosingClass.name, target.name);
523 compiler.reportFatalError( 635 compiler.reportFatalError(
524 node, 636 node,
525 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, 637 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
526 {'constructorName': name}); 638 {'constructorName': name});
527 } 639 }
528 return compiledArguments; 640 return compiledArguments;
529 } 641 }
530 642
531 Constant visitNewExpression(NewExpression node) { 643 EvaluatedConstant visitNewExpression(NewExpression node) {
532 if (!node.isConst) { 644 if (!node.isConst) {
533 return signalNotCompileTimeConstant(node); 645 return signalNotCompileTimeConstant(node);
534 } 646 }
535 647
536 Send send = node.send; 648 Send send = node.send;
537 FunctionElement constructor = elements[send]; 649 FunctionElement constructor = elements[send];
538 if (Elements.isUnresolved(constructor)) { 650 if (Elements.isUnresolved(constructor)) {
539 return signalNotCompileTimeConstant(node); 651 return signalNotCompileTimeConstant(node);
540 } 652 }
541 653
542 // Deferred types can not be used in const instance creation expressions. 654 // Deferred types can not be used in const instance creation expressions.
543 // Check if the constructor comes from a deferred library. 655 // Check if the constructor comes from a deferred library.
544 if (isDeferredUse(node.send.selector.asSend())) { 656 if (isDeferredUse(node.send.selector.asSend())) {
545 return signalNotCompileTimeConstant(node, 657 return signalNotCompileTimeConstant(node,
546 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); 658 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION);
547 } 659 }
548 660
549 // TODO(ahe): This is nasty: we must eagerly analyze the 661 // TODO(ahe): This is nasty: we must eagerly analyze the
550 // constructor to ensure the redirectionTarget has been computed 662 // constructor to ensure the redirectionTarget has been computed
551 // correctly. Find a way to avoid this. 663 // correctly. Find a way to avoid this.
552 compiler.analyzeElement(constructor.declaration); 664 compiler.analyzeElement(constructor.declaration);
553 665
554 InterfaceType type = elements.getType(node); 666 InterfaceType type = elements.getType(node);
555 List<Constant> evaluateArguments(FunctionElement constructor) { 667 Selector selector = elements.getSelector(send);
556 Selector selector = elements.getSelector(send); 668
557 return evaluateArgumentsToConstructor( 669 Map<Node, EvaluatedConstant> concreteArgumentMap =
558 node, selector, send.arguments, constructor); 670 <Node, EvaluatedConstant>{};
671 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) {
672 Node argument = link.head;
673 NamedArgument namedArgument = argument.asNamedArgument();
674 if (namedArgument != null) {
675 argument = namedArgument.expression;
676 }
677 concreteArgumentMap[argument] = evaluateConstant(argument);
559 } 678 }
560 679
561 if (constructor == compiler.intEnvironment 680 List<EvaluatedConstant> normalizedArguments =
562 || constructor == compiler.boolEnvironment 681 evaluateArgumentsToConstructor(
563 || constructor == compiler.stringEnvironment) { 682 node, selector, send.arguments, constructor.implementation,
564 List<Constant> arguments = evaluateArguments(constructor.implementation); 683 compileArgument: (node) => concreteArgumentMap[node]);
565 var firstArgument = arguments[0]; 684 List<EvaluatedConstant> concreteArguments =
566 Constant defaultValue = arguments[1]; 685 concreteArgumentMap.values.toList();
686
687 if (constructor == compiler.intEnvironment ||
688 constructor == compiler.boolEnvironment ||
689 constructor == compiler.stringEnvironment) {
690
691 EvaluatedConstant createEvaluatedConstant(Constant value) {
692 return new EvaluatedConstant(
693 context, node, new ConstructorConstExp(
694 value,
695 type,
696 constructor,
697 elements.getSelector(send),
698 concreteArguments.map((e) => e.expression).toList()));
699 }
700
701 var firstArgument = normalizedArguments[0].value;
702 Constant defaultValue = normalizedArguments[1].value;
567 703
568 if (firstArgument is NullConstant) { 704 if (firstArgument is NullConstant) {
569 compiler.reportFatalError( 705 compiler.reportFatalError(
570 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); 706 send.arguments.head, MessageKind.NULL_NOT_ALLOWED);
707 return null;
571 } 708 }
572 709
573 if (firstArgument is! StringConstant) { 710 if (firstArgument is! StringConstant) {
574 DartType type = defaultValue.computeType(compiler); 711 DartType type = defaultValue.computeType(compiler);
575 compiler.reportFatalError( 712 compiler.reportFatalError(
576 send.arguments.head, MessageKind.NOT_ASSIGNABLE, 713 send.arguments.head, MessageKind.NOT_ASSIGNABLE,
577 {'fromType': type, 'toType': compiler.stringClass.rawType}); 714 {'fromType': type, 'toType': compiler.stringClass.rawType});
715 return null;
578 } 716 }
579 717
580 if (constructor == compiler.intEnvironment 718 if (constructor == compiler.intEnvironment
581 && !(defaultValue is NullConstant || defaultValue is IntConstant)) { 719 && !(defaultValue is NullConstant || defaultValue is IntConstant)) {
582 DartType type = defaultValue.computeType(compiler); 720 DartType type = defaultValue.computeType(compiler);
583 compiler.reportFatalError( 721 compiler.reportFatalError(
584 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 722 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
585 {'fromType': type, 'toType': compiler.intClass.rawType}); 723 {'fromType': type, 'toType': compiler.intClass.rawType});
724 return null;
586 } 725 }
587 726
588 if (constructor == compiler.boolEnvironment 727 if (constructor == compiler.boolEnvironment
589 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) { 728 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) {
590 DartType type = defaultValue.computeType(compiler); 729 DartType type = defaultValue.computeType(compiler);
591 compiler.reportFatalError( 730 compiler.reportFatalError(
592 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 731 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
593 {'fromType': type, 'toType': compiler.boolClass.rawType}); 732 {'fromType': type, 'toType': compiler.boolClass.rawType});
733 return null;
594 } 734 }
595 735
596 if (constructor == compiler.stringEnvironment 736 if (constructor == compiler.stringEnvironment
597 && !(defaultValue is NullConstant 737 && !(defaultValue is NullConstant
598 || defaultValue is StringConstant)) { 738 || defaultValue is StringConstant)) {
599 DartType type = defaultValue.computeType(compiler); 739 DartType type = defaultValue.computeType(compiler);
600 compiler.reportFatalError( 740 compiler.reportFatalError(
601 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, 741 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
602 {'fromType': type, 'toType': compiler.stringClass.rawType}); 742 {'fromType': type, 'toType': compiler.stringClass.rawType});
743 return null;
603 } 744 }
604 745
605 String value = 746 String value =
606 compiler.fromEnvironment(firstArgument.value.slowToString()); 747 compiler.fromEnvironment(firstArgument.value.slowToString());
607 748
608 if (value == null) { 749 if (value == null) {
609 return defaultValue; 750 return createEvaluatedConstant(defaultValue);
610 } else if (constructor == compiler.intEnvironment) { 751 } else if (constructor == compiler.intEnvironment) {
611 int number = int.parse(value, onError: (_) => null); 752 int number = int.parse(value, onError: (_) => null);
612 return (number == null) 753 return createEvaluatedConstant(
613 ? defaultValue 754 (number == null)
614 : constantSystem.createInt(number); 755 ? defaultValue
756 : constantSystem.createInt(number));
615 } else if (constructor == compiler.boolEnvironment) { 757 } else if (constructor == compiler.boolEnvironment) {
616 if (value == 'true') { 758 if (value == 'true') {
617 return constantSystem.createBool(true); 759 return createEvaluatedConstant(constantSystem.createBool(true));
618 } else if (value == 'false') { 760 } else if (value == 'false') {
619 return constantSystem.createBool(false); 761 return createEvaluatedConstant(constantSystem.createBool(false));
620 } else { 762 } else {
621 return defaultValue; 763 return createEvaluatedConstant(defaultValue);
622 } 764 }
623 } else { 765 } else {
624 assert(constructor == compiler.stringEnvironment); 766 assert(constructor == compiler.stringEnvironment);
625 return constantSystem.createString(new DartString.literal(value)); 767 return createEvaluatedConstant(
768 constantSystem.createString(new DartString.literal(value)));
626 } 769 }
627 } else { 770 } else {
628 return makeConstructedConstant( 771 return makeConstructedConstant(
629 compiler, handler, node, type, constructor, evaluateArguments); 772 compiler, handler, context,
773 node, type, constructor, selector,
774 concreteArguments, normalizedArguments);
630 } 775 }
631 } 776 }
632 777
633 static Constant makeConstructedConstant( 778 static EvaluatedConstant makeConstructedConstant(
634 Compiler compiler, 779 Compiler compiler,
635 ConstantCompilerBase handler, 780 ConstantCompilerBase handler,
636 Spannable node, 781 Element context,
782 Node node,
637 InterfaceType type, 783 InterfaceType type,
638 ConstructorElement constructor, 784 ConstructorElement constructor,
639 List<Constant> getArguments(ConstructorElement constructor), 785 Selector selector,
640 {bool isLiteralSymbol: false}) { 786 List<EvaluatedConstant> concreteArguments,
787 List<EvaluatedConstant> normalizedArguments) {
788 assert(invariant(node, selector.applies(constructor, compiler.world),
789 message: "Selector $selector does not apply to constructor "
790 "$constructor."));
641 791
642 // The redirection chain of this element may not have been resolved through 792 // 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. 793 // a post-process action, so we have to make sure it is done here.
644 compiler.resolver.resolveRedirectionChain(constructor, node); 794 compiler.resolver.resolveRedirectionChain(constructor, node);
645 InterfaceType constructedType = 795 InterfaceType constructedType =
646 constructor.computeEffectiveTargetType(type); 796 constructor.computeEffectiveTargetType(type);
647 constructor = constructor.effectiveTarget; 797 ConstructorElement target = constructor.effectiveTarget;
648 ClassElement classElement = constructor.enclosingClass; 798 ClassElement classElement = target.enclosingClass;
649 // The constructor must be an implementation to ensure that field 799 // The constructor must be an implementation to ensure that field
650 // initializers are handled correctly. 800 // initializers are handled correctly.
651 constructor = constructor.implementation; 801 target = target.implementation;
652 assert(invariant(node, constructor.isImplementation)); 802 assert(invariant(node, target.isImplementation));
653 803
654 List<Constant> arguments = getArguments(constructor);
655 ConstructorEvaluator evaluator = new ConstructorEvaluator( 804 ConstructorEvaluator evaluator = new ConstructorEvaluator(
656 constructedType, constructor, handler, compiler); 805 constructedType, target, handler, compiler);
657 evaluator.evaluateConstructorFieldValues(arguments); 806 evaluator.evaluateConstructorFieldValues(normalizedArguments);
658 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); 807 List<EvaluatedConstant> fieldConstants =
808 evaluator.buildFieldConstants(classElement);
659 809
660 return new ConstructedConstant(constructedType, jsNewArguments, 810 return new EvaluatedConstant(
661 isLiteralSymbol: isLiteralSymbol); 811 context, node, new ConstructorConstExp(
812 new ConstructedConstant(
813 constructedType,
814 fieldConstants.map((e) => e.value).toList()),
815 type,
816 constructor,
817 selector,
818 concreteArguments.map((e) => e.expression).toList()));
662 } 819 }
663 820
664 Constant visitParenthesizedExpression(ParenthesizedExpression node) { 821 EvaluatedConstant visitParenthesizedExpression(ParenthesizedExpression node) {
665 return node.expression.accept(this); 822 return node.expression.accept(this);
666 } 823 }
667 824
668 error(Node node, MessageKind message) { 825 error(Node node, MessageKind message) {
669 // TODO(floitsch): get the list of constants that are currently compiled 826 // TODO(floitsch): get the list of constants that are currently compiled
670 // and present some kind of stack-trace. 827 // and present some kind of stack-trace.
671 compiler.reportFatalError(node, message); 828 compiler.reportFatalError(node, message);
672 } 829 }
673 830
674 Constant signalNotCompileTimeConstant(Node node, 831 EvaluatedConstant signalNotCompileTimeConstant(Node node,
675 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { 832 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
676 if (isEvaluatingConstant) { 833 if (isEvaluatingConstant) {
677 error(node, message); 834 error(node, message);
678 } 835 }
679 // Else we don't need to do anything. The final handler is only 836 // 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 837 // optimistically trying to compile constants. So it is normal that we
681 // sometimes see non-compile time constants. 838 // sometimes see non-compile time constants.
682 // Simply return [:null:] which is used to propagate a failing 839 // Simply return [:null:] which is used to propagate a failing
683 // compile-time compilation. 840 // compile-time compilation.
684 return null; 841 return null;
685 } 842 }
686 } 843 }
687 844
688 class ConstructorEvaluator extends CompileTimeConstantEvaluator { 845 class ConstructorEvaluator extends CompileTimeConstantEvaluator {
689 final InterfaceType constructedType; 846 final InterfaceType constructedType;
690 final ConstructorElement constructor; 847 final ConstructorElement constructor;
691 final Map<Element, Constant> definitions; 848 final Map<Element, EvaluatedConstant> definitions;
692 final Map<Element, Constant> fieldValues; 849 final Map<Element, EvaluatedConstant> fieldValues;
693 850
694 /** 851 /**
695 * Documentation wanted -- johnniwinther 852 * Documentation wanted -- johnniwinther
696 * 853 *
697 * Invariant: [constructor] must be an implementation element. 854 * Invariant: [constructor] must be an implementation element.
698 */ 855 */
699 ConstructorEvaluator(InterfaceType this.constructedType, 856 ConstructorEvaluator(InterfaceType this.constructedType,
700 FunctionElement constructor, 857 FunctionElement constructor,
701 ConstantCompiler handler, 858 ConstantCompiler handler,
702 Compiler compiler) 859 Compiler compiler)
703 : this.constructor = constructor, 860 : this.constructor = constructor,
704 this.definitions = new Map<Element, Constant>(), 861 this.definitions = new Map<Element, EvaluatedConstant>(),
705 this.fieldValues = new Map<Element, Constant>(), 862 this.fieldValues = new Map<Element, EvaluatedConstant>(),
706 super(handler, 863 super(handler,
707 compiler.resolver.resolveMethodElement(constructor.declaration), 864 compiler.resolver.resolveMethodElement(constructor.declaration),
708 compiler, 865 compiler,
709 isConst: true) { 866 isConst: true) {
710 assert(invariant(constructor, constructor.isImplementation)); 867 assert(invariant(constructor, constructor.isImplementation));
711 } 868 }
712 869
713 Constant visitSend(Send send) { 870 EvaluatedConstant visitSend(Send send) {
714 Element element = elements[send]; 871 Element element = elements[send];
715 if (Elements.isLocal(element)) { 872 if (Elements.isLocal(element)) {
716 Constant constant = definitions[element]; 873 EvaluatedConstant constant = definitions[element];
717 if (constant == null) { 874 if (constant == null) {
718 compiler.internalError(send, "Local variable without value."); 875 compiler.internalError(send, "Local variable without value.");
719 } 876 }
720 return constant; 877 return constant;
721 } 878 }
722 return super.visitSend(send); 879 return super.visitSend(send);
723 } 880 }
724 881
725 void potentiallyCheckType(Node node, 882 void potentiallyCheckType(Node node,
726 TypedElement element, 883 TypedElement element,
727 Constant constant) { 884 EvaluatedConstant constant) {
728 if (compiler.enableTypeAssertions) { 885 if (compiler.enableTypeAssertions) {
729 DartType elementType = element.type.substByContext(constructedType); 886 DartType elementType = element.type.substByContext(constructedType);
730 DartType constantType = constant.computeType(compiler); 887 DartType constantType = constant.value.computeType(compiler);
731 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { 888 if (!constantSystem.isSubtype(compiler, constantType, elementType)) {
732 compiler.reportFatalError( 889 compiler.withCurrentElement(constant.element, () {
733 node, MessageKind.NOT_ASSIGNABLE, 890 compiler.reportFatalError(
734 {'fromType': constantType, 'toType': elementType}); 891 constant.node, MessageKind.NOT_ASSIGNABLE,
892 {'fromType': constantType, 'toType': elementType});
893 });
735 } 894 }
736 } 895 }
737 } 896 }
738 897
739 void updateFieldValue(Node node, TypedElement element, Constant constant) { 898 void updateFieldValue(Node node,
899 TypedElement element,
900 EvaluatedConstant constant) {
740 potentiallyCheckType(node, element, constant); 901 potentiallyCheckType(node, element, constant);
741 fieldValues[element] = constant; 902 fieldValues[element] = constant;
742 } 903 }
743 904
744 /** 905 /**
745 * Given the arguments (a list of constants) assigns them to the parameters, 906 * Given the arguments (a list of constants) assigns them to the parameters,
746 * updating the definitions map. If the constructor has field-initializer 907 * updating the definitions map. If the constructor has field-initializer
747 * parameters (like [:this.x:]), also updates the [fieldValues] map. 908 * parameters (like [:this.x:]), also updates the [fieldValues] map.
748 */ 909 */
749 void assignArgumentsToParameters(List<Constant> arguments) { 910 void assignArgumentsToParameters(List<EvaluatedConstant> arguments) {
750 // Assign arguments to parameters. 911 // Assign arguments to parameters.
751 FunctionSignature signature = constructor.functionSignature; 912 FunctionSignature signature = constructor.functionSignature;
752 int index = 0; 913 int index = 0;
753 signature.orderedForEachParameter((ParameterElement parameter) { 914 signature.orderedForEachParameter((ParameterElement parameter) {
754 Constant argument = arguments[index++]; 915 EvaluatedConstant argument = arguments[index++];
755 Node node = parameter.node; 916 Node node = parameter.node;
756 potentiallyCheckType(node, parameter, argument);
757 definitions[parameter] = argument;
758 if (parameter.isInitializingFormal) { 917 if (parameter.isInitializingFormal) {
759 InitializingFormalElement initializingFormal = parameter; 918 InitializingFormalElement initializingFormal = parameter;
760 updateFieldValue(node, initializingFormal.fieldElement, argument); 919 updateFieldValue(node, initializingFormal.fieldElement, argument);
920 } else {
921 potentiallyCheckType(node, parameter, argument);
922 definitions[parameter] = argument;
761 } 923 }
762 }); 924 });
763 } 925 }
764 926
765 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, 927 void evaluateSuperOrRedirectSend(List<EvaluatedConstant> compiledArguments,
766 FunctionElement targetConstructor) { 928 FunctionElement targetConstructor) {
767 ConstructorEvaluator evaluator = new ConstructorEvaluator( 929 ConstructorEvaluator evaluator = new ConstructorEvaluator(
768 constructedType.asInstanceOf(targetConstructor.enclosingClass), 930 constructedType.asInstanceOf(targetConstructor.enclosingClass),
769 targetConstructor, handler, compiler); 931 targetConstructor, handler, compiler);
770 evaluator.evaluateConstructorFieldValues(compiledArguments); 932 evaluator.evaluateConstructorFieldValues(compiledArguments);
771 // Copy over the fieldValues from the super/redirect-constructor. 933 // Copy over the fieldValues from the super/redirect-constructor.
772 // No need to go through [updateFieldValue] because the 934 // No need to go through [updateFieldValue] because the
773 // assignments have already been checked in checked mode. 935 // assignments have already been checked in checked mode.
774 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); 936 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value);
775 } 937 }
776 938
777 /** 939 /**
778 * Runs through the initializers of the given [constructor] and updates 940 * Runs through the initializers of the given [constructor] and updates
779 * the [fieldValues] map. 941 * the [fieldValues] map.
780 */ 942 */
781 void evaluateConstructorInitializers() { 943 void evaluateConstructorInitializers() {
782 if (constructor.isSynthesized) { 944 if (constructor.isSynthesized) {
783 List<Constant> compiledArguments = <Constant>[]; 945 List<EvaluatedConstant> compiledArguments = <EvaluatedConstant>[];
784 946
785 Function compileArgument = (element) => definitions[element]; 947 Function compileArgument = (element) => definitions[element];
786 Function compileConstant = handler.compileConstant; 948 Function compileConstant = handler.compileConstant;
787 FunctionElement target = constructor.definingConstructor.implementation; 949 FunctionElement target = constructor.definingConstructor.implementation;
788 Selector.addForwardingElementArgumentsToList(constructor, 950 Selector.addForwardingElementArgumentsToList(constructor,
789 compiledArguments, 951 compiledArguments,
790 target, 952 target,
791 compileArgument, 953 compileArgument,
792 compileConstant, 954 compileConstant,
793 compiler.world); 955 compiler.world);
794 evaluateSuperOrRedirectSend(compiledArguments, target); 956 evaluateSuperOrRedirectSend(compiledArguments, target);
795 return; 957 return;
796 } 958 }
797 FunctionExpression functionNode = constructor.node; 959 FunctionExpression functionNode = constructor.node;
798 NodeList initializerList = functionNode.initializers; 960 NodeList initializerList = functionNode.initializers;
799 961
800 bool foundSuperOrRedirect = false; 962 bool foundSuperOrRedirect = false;
801 963
802 if (initializerList != null) { 964 if (initializerList != null) {
803 for (Link<Node> link = initializerList.nodes; 965 for (Link<Node> link = initializerList.nodes;
804 !link.isEmpty; 966 !link.isEmpty;
805 link = link.tail) { 967 link = link.tail) {
806 assert(link.head is Send); 968 assert(link.head is Send);
807 if (link.head is !SendSet) { 969 if (link.head is !SendSet) {
808 // A super initializer or constructor redirection. 970 // A super initializer or constructor redirection.
809 Send call = link.head; 971 Send call = link.head;
810 FunctionElement target = elements[call]; 972 FunctionElement target = elements[call];
811 List<Constant> compiledArguments = evaluateArgumentsToConstructor( 973 List<EvaluatedConstant> compiledArguments =
812 call, elements.getSelector(call), call.arguments, target); 974 evaluateArgumentsToConstructor(
975 call, elements.getSelector(call), call.arguments, target,
976 compileArgument: evaluateConstant);
813 evaluateSuperOrRedirectSend(compiledArguments, target); 977 evaluateSuperOrRedirectSend(compiledArguments, target);
814 foundSuperOrRedirect = true; 978 foundSuperOrRedirect = true;
815 } else { 979 } else {
816 // A field initializer. 980 // A field initializer.
817 SendSet init = link.head; 981 SendSet init = link.head;
818 Link<Node> initArguments = init.arguments; 982 Link<Node> initArguments = init.arguments;
819 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); 983 assert(!initArguments.isEmpty && initArguments.tail.isEmpty);
820 Constant fieldValue = evaluate(initArguments.head); 984 EvaluatedConstant fieldValue = evaluate(initArguments.head);
821 updateFieldValue(init, elements[init], fieldValue); 985 updateFieldValue(init, elements[init], fieldValue);
822 } 986 }
823 } 987 }
824 } 988 }
825 989
826 if (!foundSuperOrRedirect) { 990 if (!foundSuperOrRedirect) {
827 // No super initializer found. Try to find the default constructor if 991 // No super initializer found. Try to find the default constructor if
828 // the class is not Object. 992 // the class is not Object.
829 ClassElement enclosingClass = constructor.enclosingClass; 993 ClassElement enclosingClass = constructor.enclosingClass;
830 ClassElement superClass = enclosingClass.superclass; 994 ClassElement superClass = enclosingClass.superclass;
831 if (enclosingClass != compiler.objectClass) { 995 if (enclosingClass != compiler.objectClass) {
832 assert(superClass != null); 996 assert(superClass != null);
833 assert(superClass.resolutionState == STATE_DONE); 997 assert(superClass.resolutionState == STATE_DONE);
834 998
835 Selector selector = 999 Selector selector =
836 new Selector.callDefaultConstructor(enclosingClass.library); 1000 new Selector.callDefaultConstructor(enclosingClass.library);
837 1001
838 FunctionElement targetConstructor = 1002 FunctionElement targetConstructor =
839 superClass.lookupConstructor(selector); 1003 superClass.lookupConstructor(selector);
840 if (targetConstructor == null) { 1004 if (targetConstructor == null) {
841 compiler.internalError(functionNode, 1005 compiler.internalError(functionNode,
842 "No default constructor available."); 1006 "No default constructor available.");
843 } 1007 }
844 List<Constant> compiledArguments = evaluateArgumentsToConstructor( 1008 List<EvaluatedConstant> compiledArguments =
845 functionNode, selector, const Link<Node>(), targetConstructor); 1009 evaluateArgumentsToConstructor(
1010 functionNode, selector, const Link<Node>(), targetConstructor);
846 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); 1011 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor);
847 } 1012 }
848 } 1013 }
849 } 1014 }
850 1015
851 /** 1016 /**
852 * Simulates the execution of the [constructor] with the given 1017 * Simulates the execution of the [constructor] with the given
853 * [arguments] to obtain the field values that need to be passed to the 1018 * [arguments] to obtain the field values that need to be passed to the
854 * native JavaScript constructor. 1019 * native JavaScript constructor.
855 */ 1020 */
856 void evaluateConstructorFieldValues(List<Constant> arguments) { 1021 void evaluateConstructorFieldValues(List<EvaluatedConstant> arguments) {
857 compiler.withCurrentElement(constructor, () { 1022 compiler.withCurrentElement(constructor, () {
858 assignArgumentsToParameters(arguments); 1023 assignArgumentsToParameters(arguments);
859 evaluateConstructorInitializers(); 1024 evaluateConstructorInitializers();
860 }); 1025 });
861 } 1026 }
862 1027
863 List<Constant> buildJsNewArguments(ClassElement classElement) { 1028 /// Builds a normalized list of the constant values for each field in the
864 List<Constant> jsNewArguments = <Constant>[]; 1029 /// inheritance chain of [classElement].
1030 List<EvaluatedConstant> buildFieldConstants(ClassElement classElement) {
1031 List<EvaluatedConstant> fieldConstants = <EvaluatedConstant>[];
865 classElement.implementation.forEachInstanceField( 1032 classElement.implementation.forEachInstanceField(
866 (ClassElement enclosing, Element field) { 1033 (ClassElement enclosing, FieldElement field) {
867 Constant fieldValue = fieldValues[field]; 1034 EvaluatedConstant fieldValue = fieldValues[field];
868 if (fieldValue == null) { 1035 if (fieldValue == null) {
869 // Use the default value. 1036 // Use the default value.
870 fieldValue = handler.compileConstant(field); 1037 fieldValue = new EvaluatedConstant.fromDefaultValue(
1038 field, handler.compileConstant(field));
871 } 1039 }
872 jsNewArguments.add(fieldValue); 1040 fieldConstants.add(fieldValue);
873 }, 1041 },
874 includeSuperAndInjectedMembers: true); 1042 includeSuperAndInjectedMembers: true);
875 return jsNewArguments; 1043 return fieldConstants;
876 } 1044 }
877 } 1045 }
1046
1047 class EvaluatedConstant {
sigurdm 2014/09/17 10:29:40 Document this class esp. why we need it. Maybe it
Johnni Winther 2014/09/17 12:20:39 Done.
1048 final Element element;
1049 final Node node;
1050 final ConstExp expression;
1051
1052 EvaluatedConstant(this.element, this.node, this.expression);
1053
1054 factory EvaluatedConstant.fromDefaultValue(
1055 VariableElement element,
1056 ConstExp constant) {
1057 return new EvaluatedConstant(
1058 element,
1059 element.initializer != null ? element.initializer : element.node,
1060 constant);
1061 }
1062
1063 Constant get value => expression.value;
1064
1065 String toString() => expression.toString();
1066 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698