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

Side by Side Diff: pkg/compiler/lib/src/compile_time_constants.dart

Issue 1182663008: Typecheck const classes in the context of the constructor call. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: address comments Created 5 years, 4 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.compile_time_constant_evaluator; 5 library dart2js.compile_time_constant_evaluator;
6 6
7 import 'constant_system_dart.dart'; 7 import 'constant_system_dart.dart';
8 import 'constants/constant_system.dart'; 8 import 'constants/constant_system.dart';
9 import 'constants/evaluation.dart'; 9 import 'constants/evaluation.dart';
10 import 'constants/expressions.dart'; 10 import 'constants/expressions.dart';
11 import 'constants/values.dart'; 11 import 'constants/values.dart';
12 import 'dart_types.dart'; 12 import 'dart_types.dart';
13 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact, invariant; 13 import 'dart2jslib.dart'
14 show Compiler, CompilerTask, MessageKind, WorldImpact, invariant;
14 import 'elements/elements.dart'; 15 import 'elements/elements.dart';
15 import 'elements/modelx.dart' show FunctionElementX; 16 import 'elements/modelx.dart' show FunctionElementX;
16 import 'resolution/resolution.dart'; 17 import 'resolution/resolution.dart';
17 import 'resolution/operators.dart'; 18 import 'resolution/operators.dart';
18 import 'tree/tree.dart'; 19 import 'tree/tree.dart';
19 import 'util/util.dart' show Link; 20 import 'util/util.dart' show Link;
20 import 'universe/universe.dart' show CallStructure; 21 import 'universe/universe.dart' show CallStructure;
21 22
22 /// A [ConstantEnvironment] provides access for constants compiled for variable 23 /// A [ConstantEnvironment] provides access for constants compiled for variable
23 /// initializers. 24 /// initializers.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 /// 60 ///
60 /// If `!enforceConst`, then if [node] is a "runtime constant" (for example 61 /// If `!enforceConst`, then if [node] is a "runtime constant" (for example
61 /// a reference to a deferred constant) it will be returned - otherwise null 62 /// a reference to a deferred constant) it will be returned - otherwise null
62 /// is returned. 63 /// is returned.
63 /// 64 ///
64 /// Depending on implementation, the constant compiler might also compute 65 /// Depending on implementation, the constant compiler might also compute
65 /// the constant for the backend interpretation of constants. 66 /// the constant for the backend interpretation of constants.
66 /// 67 ///
67 /// The returned constant is always of the frontend interpretation. 68 /// The returned constant is always of the frontend interpretation.
68 ConstantExpression compileNode(Node node, TreeElements elements, 69 ConstantExpression compileNode(Node node, TreeElements elements,
69 {bool enforceConst: true}); 70 {bool enforceConst: true});
70 71
71 /// Compiles the compile-time constant for the value [metadata], or reports an 72 /// Compiles the compile-time constant for the value [metadata], or reports an
72 /// error if the value is not a compile-time constant. 73 /// error if the value is not a compile-time constant.
73 /// 74 ///
74 /// Depending on implementation, the constant compiler might also compute 75 /// Depending on implementation, the constant compiler might also compute
75 /// the compile-time constant for the backend interpretation of constants. 76 /// the compile-time constant for the backend interpretation of constants.
76 /// 77 ///
77 /// The returned constant is always of the frontend interpretation. 78 /// The returned constant is always of the frontend interpretation.
78 ConstantExpression compileMetadata(MetadataAnnotation metadata, 79 ConstantExpression compileMetadata(MetadataAnnotation metadata,
79 Node node, 80 Node node,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 ConstantValue getConstantValueForVariable(VariableElement element) { 153 ConstantValue getConstantValueForVariable(VariableElement element) {
153 return getConstantValue(initialVariableValues[element.declaration]); 154 return getConstantValue(initialVariableValues[element.declaration]);
154 } 155 }
155 156
156 @override 157 @override
157 ConstantExpression getConstantForVariable(VariableElement element) { 158 ConstantExpression getConstantForVariable(VariableElement element) {
158 return initialVariableValues[element.declaration]; 159 return initialVariableValues[element.declaration];
159 } 160 }
160 161
161 ConstantExpression compileConstant(VariableElement element) { 162 ConstantExpression compileConstant(VariableElement element) {
162 return compileVariable(element, isConst: true); 163 return internalCompileVariable(element, true, true);
163 } 164 }
164 165
165 @override 166 @override
166 void evaluate(ConstantExpression constant) { 167 void evaluate(ConstantExpression constant) {
167 constantValueMap.putIfAbsent(constant, () { 168 constantValueMap.putIfAbsent(constant, () {
168 return constant.evaluate( 169 return constant.evaluate(
169 new _CompilerEnvironment(compiler), 170 new _CompilerEnvironment(compiler),
170 constantSystem); 171 constantSystem);
171 }); 172 });
172 } 173 }
173 174
174 ConstantExpression compileVariable(VariableElement element, 175 ConstantExpression compileVariable(VariableElement element) {
175 {bool isConst: false}) { 176 return internalCompileVariable(element, false, true);
177 }
176 178
179 /// Compile [element] into a constant expression. If [isConst] is true,
180 /// then [element] is a constant variable. If [checkType] is true, then
181 /// report an error if [element] does not typecheck.
182 ConstantExpression internalCompileVariable(
183 VariableElement element, bool isConst, bool checkType) {
177 if (initialVariableValues.containsKey(element.declaration)) { 184 if (initialVariableValues.containsKey(element.declaration)) {
178 ConstantExpression result = initialVariableValues[element.declaration]; 185 ConstantExpression result = initialVariableValues[element.declaration];
179 return result; 186 return result;
180 } 187 }
181 AstElement currentElement = element.analyzableElement; 188 AstElement currentElement = element.analyzableElement;
182 return compiler.withCurrentElement(currentElement, () { 189 return compiler.withCurrentElement(currentElement, () {
183 // TODO(johnniwinther): Avoid this eager analysis. 190 // TODO(johnniwinther): Avoid this eager analysis.
184 _analyzeElementEagerly(compiler, currentElement); 191 _analyzeElementEagerly(compiler, currentElement);
185 192
186 ConstantExpression constant = compileVariableWithDefinitions( 193 ConstantExpression constant = compileVariableWithDefinitions(
187 element, currentElement.resolvedAst.elements, isConst: isConst); 194 element, currentElement.resolvedAst.elements,
195 isConst: isConst, checkType: checkType);
188 return constant; 196 return constant;
189 }); 197 });
190 } 198 }
191 199
192 /** 200 /**
193 * Returns the a compile-time constant if the variable could be compiled 201 * Returns the a compile-time constant if the variable could be compiled
194 * eagerly. If the variable needs to be initialized lazily returns `null`. 202 * eagerly. If the variable needs to be initialized lazily returns `null`.
195 * If the variable is `const` but cannot be compiled eagerly reports an 203 * If the variable is `const` but cannot be compiled eagerly reports an
196 * error. 204 * error.
197 */ 205 */
198 ConstantExpression compileVariableWithDefinitions(VariableElement element, 206 ConstantExpression compileVariableWithDefinitions(
199 TreeElements definitions, 207 VariableElement element, TreeElements definitions,
200 {bool isConst: false}) { 208 {bool isConst: false, bool checkType: true}) {
201 Node node = element.node; 209 Node node = element.node;
202 if (pendingVariables.contains(element)) { 210 if (pendingVariables.contains(element)) {
203 if (isConst) { 211 if (isConst) {
204 compiler.reportError( 212 compiler.reportError(node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
205 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
206 ConstantExpression expression = new ErroneousConstantExpression(); 213 ConstantExpression expression = new ErroneousConstantExpression();
207 constantValueMap[expression] = constantSystem.createNull(); 214 constantValueMap[expression] = constantSystem.createNull();
208 return expression; 215 return expression;
209 } 216 }
210 return null; 217 return null;
211 } 218 }
212 pendingVariables.add(element); 219 pendingVariables.add(element);
213 220
214 Expression initializer = element.initializer; 221 Expression initializer = element.initializer;
215 ConstantExpression expression; 222 ConstantExpression expression;
216 if (initializer == null) { 223 if (initializer == null) {
217 // No initial value. 224 // No initial value.
218 expression = new NullConstantExpression(); 225 expression = new NullConstantExpression();
219 constantValueMap[expression] = constantSystem.createNull(); 226 constantValueMap[expression] = constantSystem.createNull();
220 } else { 227 } else {
221 expression = compileNodeWithDefinitions( 228 expression = compileNodeWithDefinitions(initializer, definitions,
222 initializer, definitions, isConst: isConst); 229 isConst: isConst);
223 if (compiler.enableTypeAssertions && 230 if (compiler.enableTypeAssertions &&
231 checkType &&
224 expression != null && 232 expression != null &&
225 element.isField) { 233 element.isField) {
226 DartType elementType = element.type; 234 DartType elementType = element.type;
227 ConstantValue value = getConstantValue(expression); 235 ConstantValue value = getConstantValue(expression);
228 if (elementType.isMalformed && !value.isNull) { 236 if (elementType.isMalformed && !value.isNull) {
229 if (isConst) { 237 if (isConst) {
230 ErroneousElement element = elementType.element; 238 ErroneousElement element = elementType.element;
231 compiler.reportError( 239 compiler.reportError(
232 node, element.messageKind, element.messageArguments); 240 node, element.messageKind, element.messageArguments);
233 } else { 241 } else {
234 // We need to throw an exception at runtime. 242 // We need to throw an exception at runtime.
235 expression = null; 243 expression = null;
236 } 244 }
237 } else { 245 } else {
238 DartType constantType = value.getType(compiler.coreTypes); 246 DartType constantType = value.getType(compiler.coreTypes);
239 if (!constantSystem.isSubtype(compiler.types, 247 if (!constantSystem.isSubtype(
240 constantType, elementType)) { 248 compiler.types, constantType, elementType)) {
241 if (isConst) { 249 if (isConst) {
242 compiler.reportError( 250 compiler.reportError(node, MessageKind.NOT_ASSIGNABLE, {
243 node, MessageKind.NOT_ASSIGNABLE, 251 'fromType': constantType,
244 {'fromType': constantType, 'toType': elementType}); 252 'toType': elementType
253 });
245 } else { 254 } else {
246 // If the field cannot be lazily initialized, we will throw 255 // If the field cannot be lazily initialized, we will throw
247 // the exception at runtime. 256 // the exception at runtime.
248 expression = null; 257 expression = null;
249 } 258 }
250 } 259 }
251 } 260 }
252 } 261 }
253 } 262 }
254 if (expression != null) { 263 if (expression != null) {
255 initialVariableValues[element.declaration] = expression; 264 initialVariableValues[element.declaration] = expression;
256 } else { 265 } else {
257 assert(invariant(element, !isConst, 266 assert(invariant(element, !isConst,
258 message: "Variable $element does not compile to a constant.")); 267 message: "Variable $element does not compile to a constant."));
259 } 268 }
260 pendingVariables.remove(element); 269 pendingVariables.remove(element);
261 return expression; 270 return expression;
262 } 271 }
263 272
264 void cacheConstantValue(ConstantExpression expression, ConstantValue value) { 273 void cacheConstantValue(ConstantExpression expression, ConstantValue value) {
265 constantValueMap[expression] = value; 274 constantValueMap[expression] = value;
266 } 275 }
267 276
268 ConstantExpression compileNodeWithDefinitions(Node node, 277 ConstantExpression compileNodeWithDefinitions(
269 TreeElements definitions, 278 Node node, TreeElements definitions, {bool isConst: true}) {
270 {bool isConst: true}) {
271 assert(node != null); 279 assert(node != null);
272 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( 280 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator(
273 this, definitions, compiler, isConst: isConst); 281 this, definitions, compiler, isConst: isConst);
274 AstConstant constant = evaluator.evaluate(node); 282 AstConstant constant = evaluator.evaluate(node);
275 if (constant != null) { 283 if (constant != null) {
276 cacheConstantValue(constant.expression, constant.value); 284 cacheConstantValue(constant.expression, constant.value);
277 return constant.expression; 285 return constant.expression;
278 } 286 }
279 return null; 287 return null;
280 } 288 }
281 289
282 ConstantValue getConstantValue(ConstantExpression expression) { 290 ConstantValue getConstantValue(ConstantExpression expression) {
283 return constantValueMap[expression]; 291 return constantValueMap[expression];
284 } 292 }
285 293
286 ConstantExpression compileNode(Node node, TreeElements elements, 294 ConstantExpression compileNode(Node node, TreeElements elements,
287 {bool enforceConst: true}) { 295 {bool enforceConst: true}) {
288 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); 296 return compileNodeWithDefinitions(node, elements, isConst: enforceConst);
289 } 297 }
290 298
291 ConstantExpression compileMetadata(MetadataAnnotation metadata, 299 ConstantExpression compileMetadata(
292 Node node, 300 MetadataAnnotation metadata, Node node, TreeElements elements) {
293 TreeElements elements) {
294 return compileNodeWithDefinitions(node, elements); 301 return compileNodeWithDefinitions(node, elements);
295 } 302 }
296 303
297 void forgetElement(Element element) { 304 void forgetElement(Element element) {
298 initialVariableValues.remove(element); 305 initialVariableValues.remove(element);
299 if (element is ScopeContainerElement) { 306 if (element is ScopeContainerElement) {
300 element.forEachLocalMember(initialVariableValues.remove); 307 element.forEachLocalMember(initialVariableValues.remove);
301 } 308 }
302 if (element is FunctionElement && element.hasFunctionSignature) { 309 if (element is FunctionElement && element.hasFunctionSignature) {
303 element.functionSignature.forEachParameter(this.forgetElement); 310 element.functionSignature.forEachParameter(this.forgetElement);
304 } 311 }
305 } 312 }
306 } 313 }
307 314
308 /// [ConstantCompiler] that uses the Dart semantics for the compile-time 315 /// [ConstantCompiler] that uses the Dart semantics for the compile-time
309 /// constant evaluation. 316 /// constant evaluation.
310 class DartConstantCompiler extends ConstantCompilerBase { 317 class DartConstantCompiler extends ConstantCompilerBase {
311 DartConstantCompiler(Compiler compiler) 318 DartConstantCompiler(Compiler compiler)
312 : super(compiler, const DartConstantSystem()); 319 : super(compiler, const DartConstantSystem());
313 320
314 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { 321 ConstantExpression getConstantForNode(Node node, TreeElements definitions) {
315 return definitions.getConstant(node); 322 return definitions.getConstant(node);
316 } 323 }
317 324
318 ConstantExpression compileNodeWithDefinitions(Node node, 325 ConstantExpression compileNodeWithDefinitions(
319 TreeElements definitions, 326 Node node, TreeElements definitions, {bool isConst: true}) {
320 {bool isConst: true}) {
321 ConstantExpression constant = definitions.getConstant(node); 327 ConstantExpression constant = definitions.getConstant(node);
322 if (constant != null && getConstantValue(constant) != null) { 328 if (constant != null && getConstantValue(constant) != null) {
323 return constant; 329 return constant;
324 } 330 }
325 constant = 331 constant =
326 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); 332 super.compileNodeWithDefinitions(node, definitions, isConst: isConst);
327 if (constant != null) { 333 if (constant != null) {
328 definitions.setConstant(node, constant); 334 definitions.setConstant(node, constant);
329 } 335 }
330 return constant; 336 return constant;
331 } 337 }
332 } 338 }
333 339
334 // TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from 340 // TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from
335 // front-end AST in order to reuse the evaluation for the shared front-end. 341 // front-end AST in order to reuse the evaluation for the shared front-end.
336 class CompileTimeConstantEvaluator extends Visitor<AstConstant> { 342 class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
337 bool isEvaluatingConstant; 343 bool isEvaluatingConstant;
338 final ConstantCompilerBase handler; 344 final ConstantCompilerBase handler;
339 final TreeElements elements; 345 final TreeElements elements;
340 final Compiler compiler; 346 final Compiler compiler;
341 347
342 Element get context => elements.analyzedElement; 348 Element get context => elements.analyzedElement;
343 349
344 CompileTimeConstantEvaluator(this.handler, 350 CompileTimeConstantEvaluator(this.handler, this.elements, this.compiler,
345 this.elements, 351 {bool isConst: false})
346 this.compiler,
347 {bool isConst: false})
348 : this.isEvaluatingConstant = isConst; 352 : this.isEvaluatingConstant = isConst;
349 353
350 ConstantSystem get constantSystem => handler.constantSystem; 354 ConstantSystem get constantSystem => handler.constantSystem;
351 355
352 AstConstant evaluate(Node node) { 356 AstConstant evaluate(Node node) {
353 // TODO(johnniwinther): should there be a visitErrorNode? 357 // TODO(johnniwinther): should there be a visitErrorNode?
354 if (node is ErrorNode) return new ErroneousAstConstant(context, node); 358 if (node is ErrorNode) return new ErroneousAstConstant(context, node);
355 return node.accept(this); 359 return node.accept(this);
356 } 360 }
357 361
358 AstConstant evaluateConstant(Node node) { 362 AstConstant evaluateConstant(Node node) {
359 bool oldIsEvaluatingConstant = isEvaluatingConstant; 363 bool oldIsEvaluatingConstant = isEvaluatingConstant;
360 isEvaluatingConstant = true; 364 isEvaluatingConstant = true;
361 AstConstant result = node.accept(this); 365 AstConstant result = node.accept(this);
362 isEvaluatingConstant = oldIsEvaluatingConstant; 366 isEvaluatingConstant = oldIsEvaluatingConstant;
363 assert(result != null); 367 assert(result != null);
364 return result; 368 return result;
365 } 369 }
366 370
367 AstConstant visitNode(Node node) { 371 AstConstant visitNode(Node node) {
368 return signalNotCompileTimeConstant(node); 372 return signalNotCompileTimeConstant(node);
369 } 373 }
370 374
371 AstConstant visitLiteralBool(LiteralBool node) { 375 AstConstant visitLiteralBool(LiteralBool node) {
372 return new AstConstant( 376 return new AstConstant(context, node,
373 context,
374 node,
375 new BoolConstantExpression(node.value), 377 new BoolConstantExpression(node.value),
376 constantSystem.createBool(node.value)); 378 constantSystem.createBool(node.value));
377 } 379 }
378 380
379 AstConstant visitLiteralDouble(LiteralDouble node) { 381 AstConstant visitLiteralDouble(LiteralDouble node) {
380 return new AstConstant( 382 return new AstConstant(context, node,
381 context,
382 node,
383 new DoubleConstantExpression(node.value), 383 new DoubleConstantExpression(node.value),
384 constantSystem.createDouble(node.value)); 384 constantSystem.createDouble(node.value));
385 } 385 }
386 386
387 AstConstant visitLiteralInt(LiteralInt node) { 387 AstConstant visitLiteralInt(LiteralInt node) {
388 return new AstConstant( 388 return new AstConstant(context, node, new IntConstantExpression(node.value),
389 context,
390 node,
391 new IntConstantExpression(node.value),
392 constantSystem.createInt(node.value)); 389 constantSystem.createInt(node.value));
393 } 390 }
394 391
395 AstConstant visitLiteralList(LiteralList node) { 392 AstConstant visitLiteralList(LiteralList node) {
396 if (!node.isConst) { 393 if (!node.isConst) {
397 return signalNotCompileTimeConstant(node); 394 return signalNotCompileTimeConstant(node);
398 } 395 }
399 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; 396 List<ConstantExpression> argumentExpressions = <ConstantExpression>[];
400 List<ConstantValue> argumentValues = <ConstantValue>[]; 397 List<ConstantValue> argumentValues = <ConstantValue>[];
401 for (Link<Node> link = node.elements.nodes; 398 for (Link<Node> link = node.elements.nodes;
402 !link.isEmpty; 399 !link.isEmpty;
403 link = link.tail) { 400 link = link.tail) {
404 AstConstant argument = evaluateConstant(link.head); 401 AstConstant argument = evaluateConstant(link.head);
405 if (argument == null) { 402 if (argument == null) {
406 return null; 403 return null;
407 } 404 }
408 argumentExpressions.add(argument.expression); 405 argumentExpressions.add(argument.expression);
409 argumentValues.add(argument.value); 406 argumentValues.add(argument.value);
410 } 407 }
411 DartType type = elements.getType(node); 408 DartType type = elements.getType(node);
412 return new AstConstant( 409 return new AstConstant(context, node,
413 context,
414 node,
415 new ListConstantExpression(type, argumentExpressions), 410 new ListConstantExpression(type, argumentExpressions),
416 constantSystem.createList(type, argumentValues)); 411 constantSystem.createList(type, argumentValues));
417 } 412 }
418 413
419 AstConstant visitLiteralMap(LiteralMap node) { 414 AstConstant visitLiteralMap(LiteralMap node) {
420 if (!node.isConst) { 415 if (!node.isConst) {
421 return signalNotCompileTimeConstant(node); 416 return signalNotCompileTimeConstant(node);
422 } 417 }
423 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; 418 List<ConstantExpression> keyExpressions = <ConstantExpression>[];
424 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; 419 List<ConstantExpression> valueExpressions = <ConstantExpression>[];
425 List<ConstantValue> keyValues = <ConstantValue>[]; 420 List<ConstantValue> keyValues = <ConstantValue>[];
426 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; 421 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{};
427 for (Link<Node> link = node.entries.nodes; 422 for (Link<Node> link = node.entries.nodes;
428 !link.isEmpty; 423 !link.isEmpty;
429 link = link.tail) { 424 link = link.tail) {
430 LiteralMapEntry entry = link.head; 425 LiteralMapEntry entry = link.head;
431 AstConstant key = evaluateConstant(entry.key); 426 AstConstant key = evaluateConstant(entry.key);
432 if (key == null) { 427 if (key == null) {
433 return null; 428 return null;
434 } 429 }
435 AstConstant value = evaluateConstant(entry.value); 430 AstConstant value = evaluateConstant(entry.value);
436 if (value == null) { 431 if (value == null) {
437 return null; 432 return null;
438 } 433 }
439 if (!map.containsKey(key.value)) { 434 if (!map.containsKey(key.value)) {
440 keyValues.add(key.value); 435 keyValues.add(key.value);
441 } else { 436 } else {
442 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); 437 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
443 } 438 }
444 keyExpressions.add(key.expression); 439 keyExpressions.add(key.expression);
445 valueExpressions.add(value.expression); 440 valueExpressions.add(value.expression);
446 map[key.value] = value.value; 441 map[key.value] = value.value;
447 } 442 }
448 InterfaceType type = elements.getType(node); 443 InterfaceType type = elements.getType(node);
449 return new AstConstant( 444 return new AstConstant(context, node,
450 context, 445 new MapConstantExpression(type, keyExpressions, valueExpressions),
451 node,
452 new MapConstantExpression(
453 type,
454 keyExpressions,
455 valueExpressions),
456 constantSystem.createMap( 446 constantSystem.createMap(
457 compiler, type, keyValues, map.values.toList())); 447 compiler, type, keyValues, map.values.toList()));
458 } 448 }
459 449
460 AstConstant visitLiteralNull(LiteralNull node) { 450 AstConstant visitLiteralNull(LiteralNull node) {
461 return new AstConstant( 451 return new AstConstant(context, node, new NullConstantExpression(),
462 context,
463 node,
464 new NullConstantExpression(),
465 constantSystem.createNull()); 452 constantSystem.createNull());
466 } 453 }
467 454
468 AstConstant visitLiteralString(LiteralString node) { 455 AstConstant visitLiteralString(LiteralString node) {
469 return new AstConstant( 456 return new AstConstant(context, node,
470 context,
471 node,
472 new StringConstantExpression(node.dartString.slowToString()), 457 new StringConstantExpression(node.dartString.slowToString()),
473 constantSystem.createString(node.dartString)); 458 constantSystem.createString(node.dartString));
474 } 459 }
475 460
476 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { 461 AstConstant visitStringJuxtaposition(StringJuxtaposition node) {
477 AstConstant left = evaluate(node.first); 462 AstConstant left = evaluate(node.first);
478 AstConstant right = evaluate(node.second); 463 AstConstant right = evaluate(node.second);
479 if (left == null || right == null) return null; 464 if (left == null || right == null) return null;
480 StringConstantValue leftValue = left.value; 465 StringConstantValue leftValue = left.value;
481 StringConstantValue rightValue = right.value; 466 StringConstantValue rightValue = right.value;
482 return new AstConstant( 467 return new AstConstant(context, node,
483 context,
484 node,
485 new ConcatenateConstantExpression([left.expression, right.expression]), 468 new ConcatenateConstantExpression([left.expression, right.expression]),
486 constantSystem.createString( 469 constantSystem.createString(new DartString.concat(
487 new DartString.concat( 470 leftValue.primitiveValue, rightValue.primitiveValue)));
488 leftValue.primitiveValue, rightValue.primitiveValue)));
489 } 471 }
490 472
491 AstConstant visitStringInterpolation(StringInterpolation node) { 473 AstConstant visitStringInterpolation(StringInterpolation node) {
492 List<ConstantExpression> subexpressions = <ConstantExpression>[]; 474 List<ConstantExpression> subexpressions = <ConstantExpression>[];
493 AstConstant initialString = evaluate(node.string); 475 AstConstant initialString = evaluate(node.string);
494 if (initialString == null) { 476 if (initialString == null) {
495 return null; 477 return null;
496 } 478 }
497 subexpressions.add(initialString.expression); 479 subexpressions.add(initialString.expression);
498 StringConstantValue initialStringValue = initialString.value; 480 StringConstantValue initialStringValue = initialString.value;
(...skipping 18 matching lines...) Expand all
517 // is not constness but the types of the const expressions. 499 // is not constness but the types of the const expressions.
518 return signalNotCompileTimeConstant(part.expression); 500 return signalNotCompileTimeConstant(part.expression);
519 } 501 }
520 accumulator = new DartString.concat(accumulator, expressionString); 502 accumulator = new DartString.concat(accumulator, expressionString);
521 AstConstant partString = evaluate(part.string); 503 AstConstant partString = evaluate(part.string);
522 if (partString == null) return null; 504 if (partString == null) return null;
523 subexpressions.add(partString.expression); 505 subexpressions.add(partString.expression);
524 StringConstantValue partStringValue = partString.value; 506 StringConstantValue partStringValue = partString.value;
525 accumulator = 507 accumulator =
526 new DartString.concat(accumulator, partStringValue.primitiveValue); 508 new DartString.concat(accumulator, partStringValue.primitiveValue);
527 }; 509 }
528 return new AstConstant( 510 ;
529 context, 511 return new AstConstant(context, node,
530 node,
531 new ConcatenateConstantExpression(subexpressions), 512 new ConcatenateConstantExpression(subexpressions),
532 constantSystem.createString(accumulator)); 513 constantSystem.createString(accumulator));
533 } 514 }
534 515
535 AstConstant visitLiteralSymbol(LiteralSymbol node) { 516 AstConstant visitLiteralSymbol(LiteralSymbol node) {
536 InterfaceType type = compiler.symbolClass.rawType; 517 InterfaceType type = compiler.symbolClass.rawType;
537 String text = node.slowNameString; 518 String text = node.slowNameString;
538 List<AstConstant> arguments = 519 List<AstConstant> arguments = <AstConstant>[
539 <AstConstant>[new AstConstant( 520 new AstConstant(context, node, new StringConstantExpression(text),
540 context, 521 constantSystem.createString(new LiteralDartString(text)))
541 node, 522 ];
542 new StringConstantExpression(text),
543 constantSystem.createString(new LiteralDartString(text)))];
544 ConstructorElement constructor = compiler.symbolConstructor; 523 ConstructorElement constructor = compiler.symbolConstructor;
545 AstConstant constant = createConstructorInvocation( 524 AstConstant constant = createConstructorInvocation(
546 node, type, constructor, CallStructure.ONE_ARG, 525 node, type, constructor, CallStructure.ONE_ARG,
547 normalizedArguments: arguments); 526 normalizedArguments: arguments);
548 return new AstConstant( 527 return new AstConstant(
549 context, node, new SymbolConstantExpression(text), constant.value); 528 context, node, new SymbolConstantExpression(text), constant.value);
550 } 529 }
551 530
552 ConstantValue makeTypeConstant(DartType elementType) { 531 ConstantValue makeTypeConstant(DartType elementType) {
553 return constantSystem.createType(compiler, elementType); 532 return constantSystem.createType(compiler, elementType);
554 } 533 }
555 534
556 /// Returns true if the prefix of the send resolves to a deferred import 535 /// Returns true if the prefix of the send resolves to a deferred import
557 /// prefix. 536 /// prefix.
558 bool isDeferredUse(Send send) { 537 bool isDeferredUse(Send send) {
559 if (send == null) return false; 538 if (send == null) return false;
560 return compiler.deferredLoadTask 539 return compiler.deferredLoadTask.deferredPrefixElement(send, elements) !=
561 .deferredPrefixElement(send, elements) != null; 540 null;
562 } 541 }
563 542
564 AstConstant visitIdentifier(Identifier node) { 543 AstConstant visitIdentifier(Identifier node) {
565 Element element = elements[node]; 544 Element element = elements[node];
566 if (Elements.isClass(element) || Elements.isTypedef(element)) { 545 if (Elements.isClass(element) || Elements.isTypedef(element)) {
567 TypeDeclarationElement typeDeclarationElement = element; 546 TypeDeclarationElement typeDeclarationElement = element;
568 DartType type = typeDeclarationElement.rawType; 547 DartType type = typeDeclarationElement.rawType;
569 return new AstConstant(element, node, 548 return new AstConstant(element, node, new TypeConstantExpression(type),
570 new TypeConstantExpression(type), makeTypeConstant(type)); 549 makeTypeConstant(type));
571 } 550 }
572 return signalNotCompileTimeConstant(node); 551 return signalNotCompileTimeConstant(node);
573 } 552 }
574 553
575 // TODO(floitsch): provide better error-messages. 554 // TODO(floitsch): provide better error-messages.
576 AstConstant visitSend(Send send) { 555 AstConstant visitSend(Send send) {
577 Element element = elements[send]; 556 Element element = elements[send];
578 if (send.isPropertyAccess) { 557 if (send.isPropertyAccess) {
579 AstConstant result; 558 AstConstant result;
580 if (Elements.isStaticOrTopLevelFunction(element)) { 559 if (Elements.isStaticOrTopLevelFunction(element)) {
581 FunctionElementX function = element; 560 FunctionElementX function = element;
582 function.computeType(compiler); 561 function.computeType(compiler);
583 result = new AstConstant( 562 result = new AstConstant(context, send,
584 context,
585 send,
586 new FunctionConstantExpression(function), 563 new FunctionConstantExpression(function),
587 new FunctionConstantValue(function)); 564 new FunctionConstantValue(function));
588 } else if (Elements.isStaticOrTopLevelField(element)) { 565 } else if (Elements.isStaticOrTopLevelField(element)) {
589 ConstantExpression elementExpression; 566 ConstantExpression elementExpression;
590 if (element.isConst) { 567 if (element.isConst) {
591 elementExpression = handler.compileConstant(element); 568 elementExpression = handler.compileConstant(element);
592 } else if (element.isFinal && !isEvaluatingConstant) { 569 } else if (element.isFinal && !isEvaluatingConstant) {
593 elementExpression = handler.compileVariable(element); 570 elementExpression = handler.compileVariable(element);
594 } 571 }
595 if (elementExpression != null) { 572 if (elementExpression != null) {
596 result = new AstConstant( 573 result = new AstConstant(context, send,
597 context,
598 send,
599 new VariableConstantExpression(element), 574 new VariableConstantExpression(element),
600 handler.getConstantValue(elementExpression)); 575 handler.getConstantValue(elementExpression));
601 } 576 }
602 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { 577 } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
603 assert(elements.isTypeLiteral(send)); 578 assert(elements.isTypeLiteral(send));
604 DartType elementType = elements.getTypeLiteralType(send); 579 DartType elementType = elements.getTypeLiteralType(send);
605 result = new AstConstant( 580 result = new AstConstant(context, send,
606 context,
607 send,
608 new TypeConstantExpression(elementType), 581 new TypeConstantExpression(elementType),
609 makeTypeConstant(elementType)); 582 makeTypeConstant(elementType));
610 } else if (send.receiver != null) { 583 } else if (send.receiver != null) {
611 if (send.selector.asIdentifier().source == "length") { 584 if (send.selector.asIdentifier().source == "length") {
612 AstConstant left = evaluate(send.receiver); 585 AstConstant left = evaluate(send.receiver);
613 if (left != null && left.value.isString) { 586 if (left != null && left.value.isString) {
614 StringConstantValue stringConstantValue = left.value; 587 StringConstantValue stringConstantValue = left.value;
615 DartString string = stringConstantValue.primitiveValue; 588 DartString string = stringConstantValue.primitiveValue;
616 IntConstantValue length = constantSystem.createInt(string.length); 589 IntConstantValue length = constantSystem.createInt(string.length);
617 result = new AstConstant( 590 result = new AstConstant(context, send,
618 context, 591 new StringLengthConstantExpression(left.expression), length);
619 send,
620 new StringLengthConstantExpression(left.expression),
621 length);
622 } 592 }
623 } 593 }
624 // Fall through to error handling. 594 // Fall through to error handling.
625 } else if (!Elements.isUnresolved(element) 595 } else if (!Elements.isUnresolved(element) &&
626 && element.isVariable 596 element.isVariable &&
627 && element.isConst) { 597 element.isConst) {
628 ConstantExpression variableExpression = 598 ConstantExpression variableExpression =
629 handler.compileConstant(element); 599 handler.compileConstant(element);
630 if (variableExpression != null) { 600 if (variableExpression != null) {
631 result = new AstConstant( 601 result = new AstConstant(context, send,
632 context,
633 send,
634 new VariableConstantExpression(element), 602 new VariableConstantExpression(element),
635 handler.getConstantValue(variableExpression)); 603 handler.getConstantValue(variableExpression));
636 } 604 }
637 } 605 }
638 if (result == null) { 606 if (result == null) {
639 return signalNotCompileTimeConstant(send); 607 return signalNotCompileTimeConstant(send);
640 } 608 }
641 if (isDeferredUse(send)) { 609 if (isDeferredUse(send)) {
642 if (isEvaluatingConstant) { 610 if (isEvaluatingConstant) {
643 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); 611 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
644 } 612 }
645 PrefixElement prefix = compiler.deferredLoadTask 613 PrefixElement prefix =
646 .deferredPrefixElement(send, elements); 614 compiler.deferredLoadTask.deferredPrefixElement(send, elements);
647 result = new AstConstant( 615 result = new AstConstant(context, send,
648 context, 616 new DeferredConstantExpression(result.expression, prefix),
649 send,
650 new DeferredConstantExpression(
651 result.expression,
652 prefix),
653 new DeferredConstantValue(result.value, prefix)); 617 new DeferredConstantValue(result.value, prefix));
654 compiler.deferredLoadTask 618 compiler.deferredLoadTask.registerConstantDeferredUse(
655 .registerConstantDeferredUse(result.value, prefix); 619 result.value, prefix);
656 } 620 }
657 return result; 621 return result;
658 } else if (send.isCall) { 622 } else if (send.isCall) {
659 if (element == compiler.identicalFunction 623 if (element == compiler.identicalFunction && send.argumentCount() == 2) {
660 && send.argumentCount() == 2) {
661 AstConstant left = evaluate(send.argumentsNode.nodes.head); 624 AstConstant left = evaluate(send.argumentsNode.nodes.head);
662 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); 625 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head);
663 if (left == null || right == null) { 626 if (left == null || right == null) {
664 return null; 627 return null;
665 } 628 }
666 ConstantValue result = 629 ConstantValue result =
667 constantSystem.identity.fold(left.value, right.value); 630 constantSystem.identity.fold(left.value, right.value);
668 if (result != null) { 631 if (result != null) {
669 return new AstConstant( 632 return new AstConstant(context, send, new IdenticalConstantExpression(
670 context, 633 left.expression, right.expression), result);
671 send,
672 new IdenticalConstantExpression(
673 left.expression, right.expression),
674 result);
675 } 634 }
676 } 635 }
677 return signalNotCompileTimeConstant(send); 636 return signalNotCompileTimeConstant(send);
678 } else if (send.isPrefix) { 637 } else if (send.isPrefix) {
679 assert(send.isOperator); 638 assert(send.isOperator);
680 AstConstant receiverConstant = evaluate(send.receiver); 639 AstConstant receiverConstant = evaluate(send.receiver);
681 if (receiverConstant == null) { 640 if (receiverConstant == null) {
682 return null; 641 return null;
683 } 642 }
684 Operator node = send.selector; 643 Operator node = send.selector;
685 UnaryOperator operator = UnaryOperator.parse(node.source); 644 UnaryOperator operator = UnaryOperator.parse(node.source);
686 UnaryOperation operation = constantSystem.lookupUnary(operator); 645 UnaryOperation operation = constantSystem.lookupUnary(operator);
687 if (operation == null) { 646 if (operation == null) {
688 compiler.internalError(send.selector, "Unexpected operator."); 647 compiler.internalError(send.selector, "Unexpected operator.");
689 } 648 }
690 ConstantValue folded = operation.fold(receiverConstant.value); 649 ConstantValue folded = operation.fold(receiverConstant.value);
691 if (folded == null) { 650 if (folded == null) {
692 return signalNotCompileTimeConstant(send); 651 return signalNotCompileTimeConstant(send);
693 } 652 }
694 return new AstConstant( 653 return new AstConstant(context, send,
695 context, 654 new UnaryConstantExpression(operator, receiverConstant.expression),
696 send,
697 new UnaryConstantExpression(
698 operator, receiverConstant.expression),
699 folded); 655 folded);
700 } else if (send.isOperator && !send.isPostfix) { 656 } else if (send.isOperator && !send.isPostfix) {
701 assert(send.argumentCount() == 1); 657 assert(send.argumentCount() == 1);
702 AstConstant left = evaluate(send.receiver); 658 AstConstant left = evaluate(send.receiver);
703 AstConstant right = evaluate(send.argumentsNode.nodes.head); 659 AstConstant right = evaluate(send.argumentsNode.nodes.head);
704 if (left == null || right == null) { 660 if (left == null || right == null) {
705 return null; 661 return null;
706 } 662 }
707 ConstantValue leftValue = left.value; 663 ConstantValue leftValue = left.value;
708 ConstantValue rightValue = right.value; 664 ConstantValue rightValue = right.value;
(...skipping 22 matching lines...) Expand all
731 default: 687 default:
732 BinaryOperation operation = constantSystem.lookupBinary(operator); 688 BinaryOperation operation = constantSystem.lookupBinary(operator);
733 if (operation != null) { 689 if (operation != null) {
734 folded = operation.fold(leftValue, rightValue); 690 folded = operation.fold(leftValue, rightValue);
735 } 691 }
736 } 692 }
737 } 693 }
738 if (folded == null) { 694 if (folded == null) {
739 return signalNotCompileTimeConstant(send); 695 return signalNotCompileTimeConstant(send);
740 } 696 }
741 return new AstConstant( 697 return new AstConstant(context, send, new BinaryConstantExpression(
742 context, 698 left.expression, operator, right.expression), folded);
743 send,
744 new BinaryConstantExpression(
745 left.expression, operator, right.expression),
746 folded);
747 } 699 }
748 return signalNotCompileTimeConstant(send); 700 return signalNotCompileTimeConstant(send);
749 } 701 }
750 702
751 AstConstant visitConditional(Conditional node) { 703 AstConstant visitConditional(Conditional node) {
752 AstConstant condition = evaluate(node.condition); 704 AstConstant condition = evaluate(node.condition);
753 if (condition == null) { 705 if (condition == null) {
754 return null; 706 return null;
755 } else if (!condition.value.isBool) { 707 } else if (!condition.value.isBool) {
756 DartType conditionType = condition.value.getType(compiler.coreTypes); 708 DartType conditionType = condition.value.getType(compiler.coreTypes);
757 if (isEvaluatingConstant) { 709 if (isEvaluatingConstant) {
758 compiler.reportError( 710 compiler.reportError(node.condition, MessageKind.NOT_ASSIGNABLE, {
759 node.condition, MessageKind.NOT_ASSIGNABLE, 711 'fromType': conditionType,
760 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); 712 'toType': compiler.boolClass.rawType
713 });
761 return new ErroneousAstConstant(context, node); 714 return new ErroneousAstConstant(context, node);
762 } 715 }
763 return null; 716 return null;
764 } 717 }
765 AstConstant thenExpression = evaluate(node.thenExpression); 718 AstConstant thenExpression = evaluate(node.thenExpression);
766 AstConstant elseExpression = evaluate(node.elseExpression); 719 AstConstant elseExpression = evaluate(node.elseExpression);
767 if (thenExpression == null || elseExpression == null) { 720 if (thenExpression == null || elseExpression == null) {
768 return null; 721 return null;
769 } 722 }
770 BoolConstantValue boolCondition = condition.value; 723 BoolConstantValue boolCondition = condition.value;
771 return new AstConstant( 724 return new AstConstant(context, node, new ConditionalConstantExpression(
772 context, 725 condition.expression, thenExpression.expression,
773 node, 726 elseExpression.expression), boolCondition.primitiveValue
774 new ConditionalConstantExpression( 727 ? thenExpression.value
775 condition.expression, 728 : elseExpression.value);
776 thenExpression.expression,
777 elseExpression.expression),
778 boolCondition.primitiveValue
779 ? thenExpression.value
780 : elseExpression.value);
781 } 729 }
782 730
783 AstConstant visitSendSet(SendSet node) { 731 AstConstant visitSendSet(SendSet node) {
784 return signalNotCompileTimeConstant(node); 732 return signalNotCompileTimeConstant(node);
785 } 733 }
786 734
787 /** 735 /**
788 * Returns the normalized list of constant arguments that are passed to the 736 * Returns the normalized list of constant arguments that are passed to the
789 * constructor including both the concrete arguments and default values for 737 * constructor including both the concrete arguments and default values for
790 * omitted optional arguments. 738 * omitted optional arguments.
791 * 739 *
792 * Invariant: [target] must be an implementation element. 740 * Invariant: [target] must be an implementation element.
793 */ 741 */
794 List<AstConstant> evaluateArgumentsToConstructor( 742 List<AstConstant> evaluateArgumentsToConstructor(Node node,
795 Node node, 743 CallStructure callStructure, Link<Node> arguments,
796 CallStructure callStructure, 744 ConstructorElement target, {AstConstant compileArgument(Node node)}) {
797 Link<Node> arguments,
798 ConstructorElement target,
799 {AstConstant compileArgument(Node node)}) {
800 assert(invariant(node, target.isImplementation)); 745 assert(invariant(node, target.isImplementation));
801 746
802 AstConstant compileDefaultValue(VariableElement element) { 747 AstConstant compileDefaultValue(VariableElement element) {
803 ConstantExpression constant = handler.compileConstant(element); 748 ConstantExpression constant = handler.compileConstant(element);
804 return new AstConstant.fromDefaultValue( 749 return new AstConstant.fromDefaultValue(
805 element, constant, handler.getConstantValue(constant)); 750 element, constant, handler.getConstantValue(constant));
806 } 751 }
807 target.computeType(compiler); 752 target.computeType(compiler);
808 753
809 FunctionSignature signature = target.functionSignature; 754 FunctionSignature signature = target.functionSignature;
810 if (!callStructure.signatureApplies(signature)) { 755 if (!callStructure.signatureApplies(signature)) {
811 String name = Elements.constructorNameForDiagnostics( 756 String name = Elements.constructorNameForDiagnostics(
812 target.enclosingClass.name, target.name); 757 target.enclosingClass.name, target.name);
813 compiler.reportError( 758 compiler.reportError(node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, {
814 node, 759 'constructorName': name
815 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, 760 });
816 {'constructorName': name});
817 761
818 return new List<AstConstant>.filled( 762 return new List<AstConstant>.filled(
819 target.functionSignature.parameterCount, 763 target.functionSignature.parameterCount,
820 new ErroneousAstConstant(context, node)); 764 new ErroneousAstConstant(context, node));
821 } 765 }
822 return callStructure.makeArgumentsList( 766 return callStructure.makeArgumentsList(
823 arguments, 767 arguments, target, compileArgument, compileDefaultValue);
824 target,
825 compileArgument,
826 compileDefaultValue);
827 } 768 }
828 769
829 AstConstant visitNewExpression(NewExpression node) { 770 AstConstant visitNewExpression(NewExpression node) {
830 if (!node.isConst) { 771 if (!node.isConst) {
831 return signalNotCompileTimeConstant(node); 772 return signalNotCompileTimeConstant(node);
832 } 773 }
833 774
834 Send send = node.send; 775 Send send = node.send;
835 ConstructorElement constructor = elements[send]; 776 ConstructorElement constructor = elements[send];
836 if (Elements.isUnresolved(constructor)) { 777 if (Elements.isUnresolved(constructor)) {
837 return signalNotCompileTimeConstant(node); 778 return signalNotCompileTimeConstant(node);
838 } 779 }
839 780
840 // Deferred types can not be used in const instance creation expressions. 781 // Deferred types can not be used in const instance creation expressions.
841 // Check if the constructor comes from a deferred library. 782 // Check if the constructor comes from a deferred library.
842 if (isDeferredUse(node.send.selector.asSend())) { 783 if (isDeferredUse(node.send.selector.asSend())) {
843 return signalNotCompileTimeConstant(node, 784 return signalNotCompileTimeConstant(node,
844 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); 785 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION);
845 } 786 }
846 787
847 InterfaceType type = elements.getType(node); 788 InterfaceType type = elements.getType(node);
848 CallStructure callStructure = elements.getSelector(send).callStructure; 789 CallStructure callStructure = elements.getSelector(send).callStructure;
849 790
850 return createConstructorInvocation( 791 return createConstructorInvocation(node, type, constructor, callStructure,
851 node, type, constructor, callStructure,
852 arguments: node.send.arguments); 792 arguments: node.send.arguments);
853 } 793 }
854 794
855 AstConstant createConstructorInvocation( 795 AstConstant createConstructorInvocation(Node node, InterfaceType type,
856 Node node, 796 ConstructorElement constructor, CallStructure callStructure,
857 InterfaceType type, 797 {Link<Node> arguments, List<AstConstant> normalizedArguments}) {
858 ConstructorElement constructor,
859 CallStructure callStructure,
860 {Link<Node> arguments,
861 List<AstConstant> normalizedArguments}) {
862 // TODO(ahe): This is nasty: we must eagerly analyze the 798 // TODO(ahe): This is nasty: we must eagerly analyze the
863 // constructor to ensure the redirectionTarget has been computed 799 // constructor to ensure the redirectionTarget has been computed
864 // correctly. Find a way to avoid this. 800 // correctly. Find a way to avoid this.
865 _analyzeElementEagerly(compiler, constructor); 801 _analyzeElementEagerly(compiler, constructor);
866 802
867 // The redirection chain of this element may not have been resolved through 803 // The redirection chain of this element may not have been resolved through
868 // a post-process action, so we have to make sure it is done here. 804 // a post-process action, so we have to make sure it is done here.
869 compiler.resolver.resolveRedirectionChain(constructor, node); 805 compiler.resolver.resolveRedirectionChain(constructor, node);
870 InterfaceType constructedType = 806 InterfaceType constructedType =
871 constructor.computeEffectiveTargetType(type); 807 constructor.computeEffectiveTargetType(type);
872 ConstructorElement target = constructor.effectiveTarget; 808 ConstructorElement target = constructor.effectiveTarget;
873 // The constructor must be an implementation to ensure that field 809 // The constructor must be an implementation to ensure that field
874 // initializers are handled correctly. 810 // initializers are handled correctly.
875 ConstructorElement implementation = target.implementation; 811 ConstructorElement implementation = target.implementation;
876 812
877 if (implementation.isErroneous) { 813 if (implementation.isErroneous) {
878 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant]. 814 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant].
879 return new AstConstant( 815 return new AstConstant(context, node, new ConstructedConstantExpression(
880 context, 816 type, constructor, callStructure, const <ConstantExpression>[]),
881 node,
882 new ConstructedConstantExpression(
883 type,
884 constructor,
885 callStructure,
886 const <ConstantExpression>[]),
887 new ConstructedConstantValue( 817 new ConstructedConstantValue(
888 constructedType, const <FieldElement, ConstantValue>{})); 818 constructedType, const <FieldElement, ConstantValue>{}));
889 } 819 }
890 820
891 List<AstConstant> concreteArguments; 821 List<AstConstant> concreteArguments;
892 if (arguments != null) { 822 if (arguments != null) {
893 Map<Node, AstConstant> concreteArgumentMap = 823 Map<Node, AstConstant> concreteArgumentMap = <Node, AstConstant>{};
894 <Node, AstConstant>{};
895 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { 824 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) {
896 Node argument = link.head; 825 Node argument = link.head;
897 NamedArgument namedArgument = argument.asNamedArgument(); 826 NamedArgument namedArgument = argument.asNamedArgument();
898 if (namedArgument != null) { 827 if (namedArgument != null) {
899 argument = namedArgument.expression; 828 argument = namedArgument.expression;
900 } 829 }
901 concreteArgumentMap[argument] = evaluateConstant(argument); 830 concreteArgumentMap[argument] = evaluateConstant(argument);
902 } 831 }
903 832
904 normalizedArguments = evaluateArgumentsToConstructor( 833 normalizedArguments = evaluateArgumentsToConstructor(
905 node, callStructure, arguments, implementation, 834 node, callStructure, arguments, implementation,
906 compileArgument: (node) => concreteArgumentMap[node]); 835 compileArgument: (node) => concreteArgumentMap[node]);
907 concreteArguments = concreteArgumentMap.values.toList(); 836 concreteArguments = concreteArgumentMap.values.toList();
908 } else { 837 } else {
909 assert(normalizedArguments != null); 838 assert(normalizedArguments != null);
910 concreteArguments = normalizedArguments; 839 concreteArguments = normalizedArguments;
911 } 840 }
912 841
913 if (target == compiler.intEnvironment || 842 if (target == compiler.intEnvironment ||
914 target == compiler.boolEnvironment || 843 target == compiler.boolEnvironment ||
915 target == compiler.stringEnvironment) { 844 target == compiler.stringEnvironment) {
916 return createFromEnvironmentConstant( 845 return createFromEnvironmentConstant(node, constructedType, target,
917 node, constructedType, target,
918 callStructure, normalizedArguments, concreteArguments); 846 callStructure, normalizedArguments, concreteArguments);
919 } else { 847 } else {
920 return makeConstructedConstant( 848 return makeConstructedConstant(compiler, handler, context, node, type,
921 compiler, handler, context, node, 849 constructor, constructedType, implementation, callStructure,
922 type, constructor, 850 concreteArguments, normalizedArguments);
923 constructedType, implementation,
924 callStructure, concreteArguments, normalizedArguments);
925 } 851 }
926 } 852 }
927 853
928 AstConstant createFromEnvironmentConstant( 854 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type,
929 Node node, 855 ConstructorElement constructor, CallStructure callStructure,
930 InterfaceType type,
931 ConstructorElement constructor,
932 CallStructure callStructure,
933 List<AstConstant> normalizedArguments, 856 List<AstConstant> normalizedArguments,
934 List<AstConstant> concreteArguments) { 857 List<AstConstant> concreteArguments) {
935
936 var firstArgument = normalizedArguments[0].value; 858 var firstArgument = normalizedArguments[0].value;
937 ConstantValue defaultValue = normalizedArguments[1].value; 859 ConstantValue defaultValue = normalizedArguments[1].value;
938 860
939 if (firstArgument.isNull) { 861 if (firstArgument.isNull) {
940 compiler.reportError( 862 compiler.reportError(
941 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); 863 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED);
942 return null; 864 return null;
943 } 865 }
944 866
945 if (!firstArgument.isString) { 867 if (!firstArgument.isString) {
946 DartType type = defaultValue.getType(compiler.coreTypes); 868 DartType type = defaultValue.getType(compiler.coreTypes);
947 compiler.reportError( 869 compiler.reportError(normalizedArguments[0].node,
948 normalizedArguments[0].node, MessageKind.NOT_ASSIGNABLE, 870 MessageKind.NOT_ASSIGNABLE, {
949 {'fromType': type, 'toType': compiler.stringClass.rawType}); 871 'fromType': type,
872 'toType': compiler.stringClass.rawType
873 });
950 return null; 874 return null;
951 } 875 }
952 876
953 if (constructor == compiler.intEnvironment && 877 if (constructor == compiler.intEnvironment &&
954 !(defaultValue.isNull || defaultValue.isInt)) { 878 !(defaultValue.isNull || defaultValue.isInt)) {
955 DartType type = defaultValue.getType(compiler.coreTypes); 879 DartType type = defaultValue.getType(compiler.coreTypes);
956 compiler.reportError( 880 compiler.reportError(normalizedArguments[1].node,
957 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, 881 MessageKind.NOT_ASSIGNABLE, {
958 {'fromType': type, 'toType': compiler.intClass.rawType}); 882 'fromType': type,
883 'toType': compiler.intClass.rawType
884 });
959 return null; 885 return null;
960 } 886 }
961 887
962 if (constructor == compiler.boolEnvironment && 888 if (constructor == compiler.boolEnvironment &&
963 !(defaultValue.isNull || defaultValue.isBool)) { 889 !(defaultValue.isNull || defaultValue.isBool)) {
964 DartType type = defaultValue.getType(compiler.coreTypes); 890 DartType type = defaultValue.getType(compiler.coreTypes);
965 compiler.reportError( 891 compiler.reportError(normalizedArguments[1].node,
966 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, 892 MessageKind.NOT_ASSIGNABLE, {
967 {'fromType': type, 'toType': compiler.boolClass.rawType}); 893 'fromType': type,
894 'toType': compiler.boolClass.rawType
895 });
968 return null; 896 return null;
969 } 897 }
970 898
971 if (constructor == compiler.stringEnvironment && 899 if (constructor == compiler.stringEnvironment &&
972 !(defaultValue.isNull || defaultValue.isString)) { 900 !(defaultValue.isNull || defaultValue.isString)) {
973 DartType type = defaultValue.getType(compiler.coreTypes); 901 DartType type = defaultValue.getType(compiler.coreTypes);
974 compiler.reportError( 902 compiler.reportError(normalizedArguments[1].node,
975 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, 903 MessageKind.NOT_ASSIGNABLE, {
976 {'fromType': type, 'toType': compiler.stringClass.rawType}); 904 'fromType': type,
905 'toType': compiler.stringClass.rawType
906 });
977 return null; 907 return null;
978 } 908 }
979 909
980 String name = 910 String name = firstArgument.primitiveValue.slowToString();
981 firstArgument.primitiveValue.slowToString(); 911 String value = compiler.fromEnvironment(name);
982 String value =
983 compiler.fromEnvironment(name);
984 912
985 AstConstant createEvaluatedConstant(ConstantValue value) { 913 AstConstant createEvaluatedConstant(ConstantValue value) {
986
987 ConstantExpression expression; 914 ConstantExpression expression;
988 ConstantExpression name = concreteArguments[0].expression; 915 ConstantExpression name = concreteArguments[0].expression;
989 ConstantExpression defaultValue; 916 ConstantExpression defaultValue;
990 if (concreteArguments.length > 1) { 917 if (concreteArguments.length > 1) {
991 defaultValue = concreteArguments[1].expression; 918 defaultValue = concreteArguments[1].expression;
992 } 919 }
993 if (constructor == compiler.intEnvironment) { 920 if (constructor == compiler.intEnvironment) {
994 expression = new IntFromEnvironmentConstantExpression( 921 expression =
995 name, defaultValue); 922 new IntFromEnvironmentConstantExpression(name, defaultValue);
996 } else if (constructor == compiler.boolEnvironment) { 923 } else if (constructor == compiler.boolEnvironment) {
997 expression = new BoolFromEnvironmentConstantExpression( 924 expression =
998 name, defaultValue); 925 new BoolFromEnvironmentConstantExpression(name, defaultValue);
999 } else if (constructor == compiler.stringEnvironment) { 926 } else if (constructor == compiler.stringEnvironment) {
1000 expression = new StringFromEnvironmentConstantExpression( 927 expression =
1001 name, defaultValue); 928 new StringFromEnvironmentConstantExpression(name, defaultValue);
1002 } 929 }
1003 return new AstConstant(context, node, expression, value); 930 return new AstConstant(context, node, expression, value);
1004 } 931 }
1005 932
1006 if (value == null) { 933 if (value == null) {
1007 return createEvaluatedConstant(defaultValue); 934 return createEvaluatedConstant(defaultValue);
1008 } else if (constructor == compiler.intEnvironment) { 935 } else if (constructor == compiler.intEnvironment) {
1009 int number = int.parse(value, onError: (_) => null); 936 int number = int.parse(value, onError: (_) => null);
1010 return createEvaluatedConstant( 937 return createEvaluatedConstant(
1011 (number == null) 938 (number == null) ? defaultValue : constantSystem.createInt(number));
1012 ? defaultValue
1013 : constantSystem.createInt(number));
1014 } else if (constructor == compiler.boolEnvironment) { 939 } else if (constructor == compiler.boolEnvironment) {
1015 if (value == 'true') { 940 if (value == 'true') {
1016 return createEvaluatedConstant(constantSystem.createBool(true)); 941 return createEvaluatedConstant(constantSystem.createBool(true));
1017 } else if (value == 'false') { 942 } else if (value == 'false') {
1018 return createEvaluatedConstant(constantSystem.createBool(false)); 943 return createEvaluatedConstant(constantSystem.createBool(false));
1019 } else { 944 } else {
1020 return createEvaluatedConstant(defaultValue); 945 return createEvaluatedConstant(defaultValue);
1021 } 946 }
1022 } else { 947 } else {
1023 assert(constructor == compiler.stringEnvironment); 948 assert(constructor == compiler.stringEnvironment);
1024 return createEvaluatedConstant( 949 return createEvaluatedConstant(
1025 constantSystem.createString(new DartString.literal(value))); 950 constantSystem.createString(new DartString.literal(value)));
1026 } 951 }
1027 } 952 }
1028 953
1029 static AstConstant makeConstructedConstant( 954 static AstConstant makeConstructedConstant(Compiler compiler,
1030 Compiler compiler, 955 ConstantCompilerBase handler, Element context, Node node,
1031 ConstantCompilerBase handler, 956 InterfaceType type, ConstructorElement constructor,
1032 Element context, 957 InterfaceType constructedType, ConstructorElement target,
1033 Node node, 958 CallStructure callStructure, List<AstConstant> concreteArguments,
1034 InterfaceType type,
1035 ConstructorElement constructor,
1036 InterfaceType constructedType,
1037 ConstructorElement target,
1038 CallStructure callStructure,
1039 List<AstConstant> concreteArguments,
1040 List<AstConstant> normalizedArguments) { 959 List<AstConstant> normalizedArguments) {
1041 if (target.isRedirectingFactory) { 960 if (target.isRedirectingFactory) {
1042 // This happens is case of cyclic redirection. 961 // This happens is case of cyclic redirection.
1043 assert(invariant(node, compiler.compilationFailed, 962 assert(invariant(node, compiler.compilationFailed,
1044 message: "makeConstructedConstant can only be called with the " 963 message: "makeConstructedConstant can only be called with the "
1045 "effective target: $constructor")); 964 "effective target: $constructor"));
1046 return new ErroneousAstConstant(context, node); 965 return new ErroneousAstConstant(context, node);
1047 } 966 }
1048 assert(invariant( 967 assert(invariant(node,
1049 node,
1050 callStructure.signatureApplies(constructor.functionSignature) || 968 callStructure.signatureApplies(constructor.functionSignature) ||
1051 compiler.compilationFailed, 969 compiler.compilationFailed,
1052 message: "Call structure $callStructure does not apply to constructor " 970 message: "Call structure $callStructure does not apply to constructor "
1053 "$constructor.")); 971 "$constructor."));
1054 972
1055 ConstructorEvaluator evaluator = new ConstructorEvaluator( 973 ConstructorEvaluator evaluator =
1056 constructedType, target, handler, compiler); 974 new ConstructorEvaluator(constructedType, target, handler, compiler);
1057 evaluator.evaluateConstructorFieldValues(normalizedArguments); 975 evaluator.evaluateConstructorFieldValues(normalizedArguments);
1058 Map<FieldElement, AstConstant> fieldConstants = 976 Map<FieldElement, AstConstant> fieldConstants =
1059 evaluator.buildFieldConstants(target.enclosingClass); 977 evaluator.buildFieldConstants(target.enclosingClass);
1060 Map<FieldElement, ConstantValue> fieldValues = 978 Map<FieldElement, ConstantValue> fieldValues =
1061 <FieldElement, ConstantValue>{}; 979 <FieldElement, ConstantValue>{};
1062 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { 980 fieldConstants.forEach((FieldElement field, AstConstant astConstant) {
1063 fieldValues[field] = astConstant.value; 981 fieldValues[field] = astConstant.value;
1064 }); 982 });
1065 return new AstConstant( 983 return new AstConstant(context, node, new ConstructedConstantExpression(
1066 context, 984 type, constructor, callStructure,
1067 node,
1068 new ConstructedConstantExpression(
1069 type,
1070 constructor,
1071 callStructure,
1072 concreteArguments.map((e) => e.expression).toList()), 985 concreteArguments.map((e) => e.expression).toList()),
1073 new ConstructedConstantValue(constructedType, fieldValues)); 986 new ConstructedConstantValue(constructedType, fieldValues));
1074 } 987 }
1075 988
1076 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { 989 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) {
1077 return node.expression.accept(this); 990 return node.expression.accept(this);
1078 } 991 }
1079 992
1080 error(Node node, MessageKind message) { 993 error(Node node, MessageKind message) {
1081 // TODO(floitsch): get the list of constants that are currently compiled 994 // TODO(floitsch): get the list of constants that are currently compiled
1082 // and present some kind of stack-trace. 995 // and present some kind of stack-trace.
1083 compiler.reportError(node, message); 996 compiler.reportError(node, message);
1084 } 997 }
1085 998
1086 AstConstant signalNotCompileTimeConstant(Node node, 999 AstConstant signalNotCompileTimeConstant(Node node,
1087 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { 1000 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
1088 if (isEvaluatingConstant) { 1001 if (isEvaluatingConstant) {
1089 error(node, message); 1002 error(node, message);
1090 1003
1091 return new AstConstant( 1004 return new AstConstant(context, node, new ErroneousConstantExpression(),
1092 context,
1093 node,
1094 new ErroneousConstantExpression(),
1095 new NullConstantValue()); 1005 new NullConstantValue());
1096 } 1006 }
1097 // Else we don't need to do anything. The final handler is only 1007 // Else we don't need to do anything. The final handler is only
1098 // optimistically trying to compile constants. So it is normal that we 1008 // optimistically trying to compile constants. So it is normal that we
1099 // sometimes see non-compile time constants. 1009 // sometimes see non-compile time constants.
1100 // Simply return [:null:] which is used to propagate a failing 1010 // Simply return [:null:] which is used to propagate a failing
1101 // compile-time compilation. 1011 // compile-time compilation.
1102 return null; 1012 return null;
1103 } 1013 }
1104 } 1014 }
1105 1015
1106 class ConstructorEvaluator extends CompileTimeConstantEvaluator { 1016 class ConstructorEvaluator extends CompileTimeConstantEvaluator {
1107 final InterfaceType constructedType; 1017 final InterfaceType constructedType;
1108 final ConstructorElement constructor; 1018 final ConstructorElement constructor;
1109 final Map<Element, AstConstant> definitions; 1019 final Map<Element, AstConstant> definitions;
1110 final Map<Element, AstConstant> fieldValues; 1020 final Map<Element, AstConstant> fieldValues;
1111 1021
1112 /** 1022 /**
1113 * Documentation wanted -- johnniwinther 1023 * Documentation wanted -- johnniwinther
1114 * 1024 *
1115 * Invariant: [constructor] must be an implementation element. 1025 * Invariant: [constructor] must be an implementation element.
1116 */ 1026 */
1117 ConstructorEvaluator(InterfaceType this.constructedType, 1027 ConstructorEvaluator(InterfaceType this.constructedType,
1118 FunctionElement constructor, 1028 FunctionElement constructor, ConstantCompiler handler, Compiler compiler)
1119 ConstantCompiler handler,
1120 Compiler compiler)
1121 : this.constructor = constructor, 1029 : this.constructor = constructor,
1122 this.definitions = new Map<Element, AstConstant>(), 1030 this.definitions = new Map<Element, AstConstant>(),
1123 this.fieldValues = new Map<Element, AstConstant>(), 1031 this.fieldValues = new Map<Element, AstConstant>(),
1124 super(handler, 1032 super(handler, _analyzeElementEagerly(compiler, constructor), compiler,
1125 _analyzeElementEagerly(compiler, constructor), 1033 isConst: true) {
1126 compiler,
1127 isConst: true) {
1128 assert(invariant(constructor, constructor.isImplementation)); 1034 assert(invariant(constructor, constructor.isImplementation));
1129 } 1035 }
1130 1036
1131 AstConstant visitSend(Send send) { 1037 AstConstant visitSend(Send send) {
1132 Element element = elements[send]; 1038 Element element = elements[send];
1133 if (Elements.isLocal(element)) { 1039 if (Elements.isLocal(element)) {
1134 AstConstant constant = definitions[element]; 1040 AstConstant constant = definitions[element];
1135 if (constant == null) { 1041 if (constant == null) {
1136 compiler.internalError(send, "Local variable without value."); 1042 compiler.internalError(send, "Local variable without value.");
1137 } 1043 }
1138 return constant; 1044 return constant;
1139 } 1045 }
1140 return super.visitSend(send); 1046 return super.visitSend(send);
1141 } 1047 }
1142 1048
1143 void potentiallyCheckType(Node node, 1049 void potentiallyCheckType(TypedElement element, AstConstant constant) {
1144 TypedElement element,
1145 AstConstant constant) {
1146 if (compiler.enableTypeAssertions) { 1050 if (compiler.enableTypeAssertions) {
1147 DartType elementType = element.type.substByContext(constructedType); 1051 DartType elementType = element.type.substByContext(constructedType);
1148 DartType constantType = constant.value.getType(compiler.coreTypes); 1052 DartType constantType = constant.value.getType(compiler.coreTypes);
1149 if (!constantSystem.isSubtype(compiler.types, 1053 if (!constantSystem.isSubtype(
1150 constantType, elementType)) { 1054 compiler.types, constantType, elementType)) {
1151 compiler.withCurrentElement(constant.element, () { 1055 compiler.withCurrentElement(constant.element, () {
1152 compiler.reportError( 1056 compiler.reportError(constant.node, MessageKind.NOT_ASSIGNABLE, {
1153 constant.node, MessageKind.NOT_ASSIGNABLE, 1057 'fromType': constantType,
1154 {'fromType': constantType, 'toType': elementType}); 1058 'toType': elementType
1059 });
1155 }); 1060 });
1156 } 1061 }
1157 } 1062 }
1158 } 1063 }
1159 1064
1160 void updateFieldValue(Node node, 1065 void updateFieldValue(Node node, TypedElement element, AstConstant constant) {
1161 TypedElement element, 1066 potentiallyCheckType(element, constant);
1162 AstConstant constant) {
1163 potentiallyCheckType(node, element, constant);
1164 fieldValues[element] = constant; 1067 fieldValues[element] = constant;
1165 } 1068 }
1166 1069
1167 /** 1070 /**
1168 * Given the arguments (a list of constants) assigns them to the parameters, 1071 * Given the arguments (a list of constants) assigns them to the parameters,
1169 * updating the definitions map. If the constructor has field-initializer 1072 * updating the definitions map. If the constructor has field-initializer
1170 * parameters (like [:this.x:]), also updates the [fieldValues] map. 1073 * parameters (like [:this.x:]), also updates the [fieldValues] map.
1171 */ 1074 */
1172 void assignArgumentsToParameters(List<AstConstant> arguments) { 1075 void assignArgumentsToParameters(List<AstConstant> arguments) {
1173 if (constructor.isErroneous) return; 1076 if (constructor.isErroneous) return;
1174 // Assign arguments to parameters. 1077 // Assign arguments to parameters.
1175 FunctionSignature signature = constructor.functionSignature; 1078 FunctionSignature signature = constructor.functionSignature;
1176 int index = 0; 1079 int index = 0;
1177 signature.orderedForEachParameter((ParameterElement parameter) { 1080 signature.orderedForEachParameter((ParameterElement parameter) {
1178 AstConstant argument = arguments[index++]; 1081 AstConstant argument = arguments[index++];
1179 Node node = parameter.node; 1082 Node node = parameter.node;
1180 if (parameter.isInitializingFormal) { 1083 if (parameter.isInitializingFormal) {
1181 InitializingFormalElement initializingFormal = parameter; 1084 InitializingFormalElement initializingFormal = parameter;
1182 updateFieldValue(node, initializingFormal.fieldElement, argument); 1085 updateFieldValue(node, initializingFormal.fieldElement, argument);
1183 } else { 1086 } else {
1184 potentiallyCheckType(node, parameter, argument); 1087 potentiallyCheckType(parameter, argument);
1185 definitions[parameter] = argument; 1088 definitions[parameter] = argument;
1186 } 1089 }
1187 }); 1090 });
1188 } 1091 }
1189 1092
1190 void evaluateSuperOrRedirectSend(List<AstConstant> compiledArguments, 1093 void evaluateSuperOrRedirectSend(
1191 FunctionElement targetConstructor) { 1094 List<AstConstant> compiledArguments, FunctionElement targetConstructor) {
1192 ConstructorEvaluator evaluator = new ConstructorEvaluator( 1095 ConstructorEvaluator evaluator = new ConstructorEvaluator(
1193 constructedType.asInstanceOf(targetConstructor.enclosingClass), 1096 constructedType.asInstanceOf(targetConstructor.enclosingClass),
1194 targetConstructor, handler, compiler); 1097 targetConstructor, handler, compiler);
1195 evaluator.evaluateConstructorFieldValues(compiledArguments); 1098 evaluator.evaluateConstructorFieldValues(compiledArguments);
1196 // Copy over the fieldValues from the super/redirect-constructor. 1099 // Copy over the fieldValues from the super/redirect-constructor.
1197 // No need to go through [updateFieldValue] because the 1100 // No need to go through [updateFieldValue] because the
1198 // assignments have already been checked in checked mode. 1101 // assignments have already been checked in checked mode.
1199 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); 1102 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value);
1200 } 1103 }
1201 1104
1202 /** 1105 /**
1203 * Runs through the initializers of the given [constructor] and updates 1106 * Runs through the initializers of the given [constructor] and updates
1204 * the [fieldValues] map. 1107 * the [fieldValues] map.
1205 */ 1108 */
1206 void evaluateConstructorInitializers() { 1109 void evaluateConstructorInitializers() {
1207 if (constructor.isSynthesized) { 1110 if (constructor.isSynthesized) {
1208 List<AstConstant> compiledArguments = <AstConstant>[]; 1111 List<AstConstant> compiledArguments = <AstConstant>[];
1209 1112
1210 Function compileArgument = (element) => definitions[element]; 1113 Function compileArgument = (element) => definitions[element];
1211 Function compileConstant = handler.compileConstant; 1114 Function compileConstant = handler.compileConstant;
1212 FunctionElement target = constructor.definingConstructor.implementation; 1115 FunctionElement target = constructor.definingConstructor.implementation;
1213 CallStructure.addForwardingElementArgumentsToList( 1116 CallStructure.addForwardingElementArgumentsToList(constructor,
1214 constructor, 1117 compiledArguments, target, compileArgument, compileConstant);
1215 compiledArguments,
1216 target,
1217 compileArgument,
1218 compileConstant);
1219 evaluateSuperOrRedirectSend(compiledArguments, target); 1118 evaluateSuperOrRedirectSend(compiledArguments, target);
1220 return; 1119 return;
1221 } 1120 }
1222 FunctionExpression functionNode = constructor.node; 1121 FunctionExpression functionNode = constructor.node;
1223 NodeList initializerList = functionNode.initializers; 1122 NodeList initializerList = functionNode.initializers;
1224 1123
1225 bool foundSuperOrRedirect = false; 1124 bool foundSuperOrRedirect = false;
1226 1125
1227 if (initializerList != null) { 1126 if (initializerList != null) {
1228 for (Link<Node> link = initializerList.nodes; 1127 for (Link<Node> link = initializerList.nodes;
1229 !link.isEmpty; 1128 !link.isEmpty;
1230 link = link.tail) { 1129 link = link.tail) {
1231 assert(link.head is Send); 1130 assert(link.head is Send);
1232 if (link.head is !SendSet) { 1131 if (link.head is! SendSet) {
1233 // A super initializer or constructor redirection. 1132 // A super initializer or constructor redirection.
1234 Send call = link.head; 1133 Send call = link.head;
1235 FunctionElement target = elements[call]; 1134 FunctionElement target = elements[call];
1236 List<AstConstant> compiledArguments = 1135 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor(
1237 evaluateArgumentsToConstructor( 1136 call, elements.getSelector(call).callStructure, call.arguments,
1238 call, elements.getSelector(call).callStructure, 1137 target, compileArgument: evaluateConstant);
1239 call.arguments, target,
1240 compileArgument: evaluateConstant);
1241 evaluateSuperOrRedirectSend(compiledArguments, target); 1138 evaluateSuperOrRedirectSend(compiledArguments, target);
1242 foundSuperOrRedirect = true; 1139 foundSuperOrRedirect = true;
1243 } else { 1140 } else {
1244 // A field initializer. 1141 // A field initializer.
1245 SendSet init = link.head; 1142 SendSet init = link.head;
1246 Link<Node> initArguments = init.arguments; 1143 Link<Node> initArguments = init.arguments;
1247 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); 1144 assert(!initArguments.isEmpty && initArguments.tail.isEmpty);
1248 AstConstant fieldValue = evaluate(initArguments.head); 1145 AstConstant fieldValue = evaluate(initArguments.head);
1249 updateFieldValue(init, elements[init], fieldValue); 1146 updateFieldValue(init, elements[init], fieldValue);
1250 } 1147 }
1251 } 1148 }
1252 } 1149 }
1253 1150
1254 if (!foundSuperOrRedirect) { 1151 if (!foundSuperOrRedirect) {
1255 // No super initializer found. Try to find the default constructor if 1152 // No super initializer found. Try to find the default constructor if
1256 // the class is not Object. 1153 // the class is not Object.
1257 ClassElement enclosingClass = constructor.enclosingClass; 1154 ClassElement enclosingClass = constructor.enclosingClass;
1258 ClassElement superClass = enclosingClass.superclass; 1155 ClassElement superClass = enclosingClass.superclass;
1259 if (enclosingClass != compiler.objectClass) { 1156 if (enclosingClass != compiler.objectClass) {
1260 assert(superClass != null); 1157 assert(superClass != null);
1261 assert(superClass.isResolved); 1158 assert(superClass.isResolved);
1262 1159
1263 FunctionElement targetConstructor = 1160 FunctionElement targetConstructor =
1264 superClass.lookupDefaultConstructor(); 1161 superClass.lookupDefaultConstructor();
1265 // If we do not find a default constructor, an error was reported 1162 // If we do not find a default constructor, an error was reported
1266 // already and compilation will fail anyway. So just ignore that case. 1163 // already and compilation will fail anyway. So just ignore that case.
1267 if (targetConstructor != null) { 1164 if (targetConstructor != null) {
1268 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( 1165 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor(
1269 functionNode, CallStructure.NO_ARGS, 1166 functionNode, CallStructure.NO_ARGS, const Link<Node>(),
1270 const Link<Node>(), targetConstructor); 1167 targetConstructor);
1271 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); 1168 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor);
1272 } 1169 }
1273 } 1170 }
1274 } 1171 }
1275 } 1172 }
1276 1173
1277 /** 1174 /**
1278 * Simulates the execution of the [constructor] with the given 1175 * Simulates the execution of the [constructor] with the given
1279 * [arguments] to obtain the field values that need to be passed to the 1176 * [arguments] to obtain the field values that need to be passed to the
1280 * native JavaScript constructor. 1177 * native JavaScript constructor.
1281 */ 1178 */
1282 void evaluateConstructorFieldValues(List<AstConstant> arguments) { 1179 void evaluateConstructorFieldValues(List<AstConstant> arguments) {
1283 if (constructor.isErroneous) return; 1180 if (constructor.isErroneous) return;
1284 compiler.withCurrentElement(constructor, () { 1181 compiler.withCurrentElement(constructor, () {
1285 assignArgumentsToParameters(arguments); 1182 assignArgumentsToParameters(arguments);
1286 evaluateConstructorInitializers(); 1183 evaluateConstructorInitializers();
1287 }); 1184 });
1288 } 1185 }
1289 1186
1290 /// Builds a normalized list of the constant values for each field in the 1187 /// Builds a normalized list of the constant values for each field in the
1291 /// inheritance chain of [classElement]. 1188 /// inheritance chain of [classElement].
1292 Map<FieldElement, AstConstant> buildFieldConstants( 1189 Map<FieldElement, AstConstant> buildFieldConstants(
1293 ClassElement classElement) { 1190 ClassElement classElement) {
1294 Map<FieldElement, AstConstant> fieldConstants = 1191 Map<FieldElement, AstConstant> fieldConstants = <FieldElement, AstConstant>{
1295 <FieldElement, AstConstant>{}; 1192 };
1296 classElement.implementation.forEachInstanceField( 1193 classElement.implementation
1297 (ClassElement enclosing, FieldElement field) { 1194 .forEachInstanceField((ClassElement enclosing, FieldElement field) {
1298 AstConstant fieldValue = fieldValues[field]; 1195 AstConstant fieldValue = fieldValues[field];
1299 if (fieldValue == null) { 1196 if (fieldValue == null) {
1300 // Use the default value. 1197 // Use the default value.
1301 ConstantExpression fieldExpression = handler.compileConstant(field); 1198 ConstantExpression fieldExpression =
1302 fieldValue = new AstConstant.fromDefaultValue( 1199 handler.internalCompileVariable(field, true, false);
1303 field, 1200 fieldValue = new AstConstant.fromDefaultValue(
1304 fieldExpression, 1201 field, fieldExpression, handler.getConstantValue(fieldExpression));
1305 handler.getConstantValue(fieldExpression)); 1202 // TODO(het): If the field value doesn't typecheck due to the type
1306 } 1203 // variable in the constructor invocation, then report the error on the
1307 fieldConstants[field] = fieldValue; 1204 // invocation rather than the field.
1308 }, 1205 potentiallyCheckType(field, fieldValue);
1309 includeSuperAndInjectedMembers: true); 1206 }
1207 fieldConstants[field] = fieldValue;
1208 }, includeSuperAndInjectedMembers: true);
1310 return fieldConstants; 1209 return fieldConstants;
1311 } 1210 }
1312 } 1211 }
1313 1212
1314 /// A constant created from the front-end AST. 1213 /// A constant created from the front-end AST.
1315 /// 1214 ///
1316 /// [element] and [node] point to the source location of the constant. 1215 /// [element] and [node] point to the source location of the constant.
1317 /// [expression] holds the symbolic constant expression and [value] its constant 1216 /// [expression] holds the symbolic constant expression and [value] its constant
1318 /// value. 1217 /// value.
1319 /// 1218 ///
1320 /// This class differs from [ConstantExpression] in that it is coupled to the 1219 /// This class differs from [ConstantExpression] in that it is coupled to the
1321 /// front-end AST whereas [ConstantExpression] is only coupled to the element 1220 /// front-end AST whereas [ConstantExpression] is only coupled to the element
1322 /// model. 1221 /// model.
1323 class AstConstant { 1222 class AstConstant {
1324 final Element element; 1223 final Element element;
1325 final Node node; 1224 final Node node;
1326 final ConstantExpression expression; 1225 final ConstantExpression expression;
1327 final ConstantValue value; 1226 final ConstantValue value;
1328 1227
1329 AstConstant(this.element, this.node, this.expression, this.value); 1228 AstConstant(this.element, this.node, this.expression, this.value);
1330 1229
1331 factory AstConstant.fromDefaultValue( 1230 factory AstConstant.fromDefaultValue(VariableElement element,
1332 VariableElement element, 1231 ConstantExpression constant, ConstantValue value) {
1333 ConstantExpression constant, 1232 return new AstConstant(element, element.initializer != null
1334 ConstantValue value) { 1233 ? element.initializer
1335 return new AstConstant( 1234 : element.node, constant, value);
1336 element,
1337 element.initializer != null ? element.initializer : element.node,
1338 constant,
1339 value);
1340 } 1235 }
1341 1236
1342 String toString() => expression.toString(); 1237 String toString() => expression.toString();
1343 } 1238 }
1344 1239
1345 /// A synthetic constant used to recover from errors. 1240 /// A synthetic constant used to recover from errors.
1346 class ErroneousAstConstant extends AstConstant { 1241 class ErroneousAstConstant extends AstConstant {
1347 ErroneousAstConstant(Element element, Node node) 1242 ErroneousAstConstant(Element element, Node node) : super(element, node,
1348 : super(element, node,
1349 // TODO(johnniwinther): Return a [NonConstantValue] instead. 1243 // TODO(johnniwinther): Return a [NonConstantValue] instead.
1350 new ErroneousConstantExpression(), new NullConstantValue()); 1244 new ErroneousConstantExpression(), new NullConstantValue());
1351 } 1245 }
1352 1246
1353 // TODO(johnniwinther): Avoid the need for this hack. 1247 // TODO(johnniwinther): Avoid the need for this hack.
1354 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { 1248 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
1355 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); 1249 WorldImpact worldImpact = compiler.analyzeElement(element.declaration);
1356 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); 1250 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact);
1357 return element.resolvedAst.elements; 1251 return element.resolvedAst.elements;
1358 } 1252 }
1359 1253
1360 class _CompilerEnvironment implements Environment { 1254 class _CompilerEnvironment implements Environment {
1361 final Compiler compiler; 1255 final Compiler compiler;
1362 1256
1363 _CompilerEnvironment(this.compiler); 1257 _CompilerEnvironment(this.compiler);
1364 1258
1365 @override 1259 @override
1366 String readFromEnvironment(String name) { 1260 String readFromEnvironment(String name) {
1367 return compiler.fromEnvironment(name); 1261 return compiler.fromEnvironment(name);
1368 } 1262 }
1369 } 1263 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/constant_handler_javascript.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698