OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.compile_time_constant_evaluator; | 5 library dart2js.compile_time_constant_evaluator; |
6 | 6 |
7 import 'constant_system_dart.dart'; | 7 import 'constant_system_dart.dart'; |
8 import 'constants/constant_system.dart'; | 8 import 'constants/constant_system.dart'; |
9 import 'constants/expressions.dart'; | 9 import 'constants/expressions.dart'; |
10 import 'constants/values.dart'; | 10 import 'constants/values.dart'; |
(...skipping 30 matching lines...) Expand all Loading... | |
41 /// if possible. | 41 /// if possible. |
42 void compileVariable(VariableElement element); | 42 void compileVariable(VariableElement element); |
43 | 43 |
44 /// Compiles the compile-time constant for [node], or reports an error if | 44 /// Compiles the compile-time constant for [node], or reports an error if |
45 /// [node] is not a compile-time constant. | 45 /// [node] is not a compile-time constant. |
46 /// | 46 /// |
47 /// Depending on implementation, the constant compiler might also compute | 47 /// Depending on implementation, the constant compiler might also compute |
48 /// the compile-time constant for the backend interpretation of constants. | 48 /// the compile-time constant for the backend interpretation of constants. |
49 /// | 49 /// |
50 /// The returned constant is always of the frontend interpretation. | 50 /// The returned constant is always of the frontend interpretation. |
51 ConstantExpression compileNode(Node node, TreeElements elements); | 51 ConstantExpression compileNode(Node node, TreeElements elements, |
52 {bool enforceConst: true}); | |
Johnni Winther
2015/04/30 09:15:03
Document [enforceConst].
sigurdm
2015/04/30 11:21:44
Done.
| |
52 | 53 |
53 /// Compiles the compile-time constant for the value [metadata], or reports an | 54 /// Compiles the compile-time constant for the value [metadata], or reports an |
54 /// error if the value is not a compile-time constant. | 55 /// error if the value is not a compile-time constant. |
55 /// | 56 /// |
56 /// Depending on implementation, the constant compiler might also compute | 57 /// Depending on implementation, the constant compiler might also compute |
57 /// the compile-time constant for the backend interpretation of constants. | 58 /// the compile-time constant for the backend interpretation of constants. |
58 /// | 59 /// |
59 /// The returned constant is always of the frontend interpretation. | 60 /// The returned constant is always of the frontend interpretation. |
60 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 61 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
61 Node node, | 62 Node node, |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 ConstantExpression compileNodeWithDefinitions(Node node, | 207 ConstantExpression compileNodeWithDefinitions(Node node, |
207 TreeElements definitions, | 208 TreeElements definitions, |
208 {bool isConst: true}) { | 209 {bool isConst: true}) { |
209 assert(node != null); | 210 assert(node != null); |
210 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 211 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
211 this, definitions, compiler, isConst: isConst); | 212 this, definitions, compiler, isConst: isConst); |
212 AstConstant constant = evaluator.evaluate(node); | 213 AstConstant constant = evaluator.evaluate(node); |
213 return constant != null ? constant.expression : null; | 214 return constant != null ? constant.expression : null; |
214 } | 215 } |
215 | 216 |
216 ConstantExpression compileNode(Node node, TreeElements elements) { | 217 ConstantExpression compileNode(Node node, TreeElements elements, |
217 return compileNodeWithDefinitions(node, elements); | 218 {bool enforceConst: true}) { |
219 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); | |
218 } | 220 } |
219 | 221 |
220 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 222 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
221 Node node, | 223 Node node, |
222 TreeElements elements) { | 224 TreeElements elements) { |
223 return compileNodeWithDefinitions(node, elements); | 225 return compileNodeWithDefinitions(node, elements); |
224 } | 226 } |
225 | 227 |
226 void forgetElement(Element element) { | 228 void forgetElement(Element element) { |
227 initialVariableValues.remove(element); | 229 initialVariableValues.remove(element); |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 text, | 464 text, |
463 constantSystem.createString(new LiteralDartString(text))))]; | 465 constantSystem.createString(new LiteralDartString(text))))]; |
464 AstConstant constant = makeConstructedConstant( | 466 AstConstant constant = makeConstructedConstant( |
465 compiler, handler, context, node, type, compiler.symbolConstructor, | 467 compiler, handler, context, node, type, compiler.symbolConstructor, |
466 CallStructure.ONE_ARG, | 468 CallStructure.ONE_ARG, |
467 arguments, arguments); | 469 arguments, arguments); |
468 return new AstConstant( | 470 return new AstConstant( |
469 context, node, new SymbolConstantExpression(constant.value, text)); | 471 context, node, new SymbolConstantExpression(constant.value, text)); |
470 } | 472 } |
471 | 473 |
472 AstConstant makeTypeConstant(Node node, DartType elementType) { | 474 ConstantExpression makeTypeConstant(DartType elementType) { |
473 DartType constantType = | 475 DartType constantType = |
474 compiler.backend.typeImplementation.computeType(compiler); | 476 compiler.backend.typeImplementation.computeType(compiler); |
475 return new AstConstant( | 477 return new TypeConstantExpression( |
476 context, node, new TypeConstantExpression( | 478 new TypeConstantValue(elementType, constantType), elementType); |
477 new TypeConstantValue(elementType, constantType), | |
478 elementType)); | |
479 } | 479 } |
480 | 480 |
481 /// Returns true if the prefix of the send resolves to a deferred import | 481 /// Returns true if the prefix of the send resolves to a deferred import |
482 /// prefix. | 482 /// prefix. |
483 bool isDeferredUse(Send send) { | 483 bool isDeferredUse(Send send) { |
484 if (send == null) return false; | 484 if (send == null) return false; |
485 return compiler.deferredLoadTask | 485 return compiler.deferredLoadTask |
486 .deferredPrefixElement(send, elements) != null; | 486 .deferredPrefixElement(send, elements) != null; |
487 } | 487 } |
488 | 488 |
489 AstConstant visitIdentifier(Identifier node) { | 489 AstConstant visitIdentifier(Identifier node) { |
490 Element element = elements[node]; | 490 Element element = elements[node]; |
491 if (Elements.isClass(element) || Elements.isTypedef(element)) { | 491 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
492 TypeDeclarationElement typeDeclarationElement = element; | 492 TypeDeclarationElement typeDeclarationElement = element; |
493 DartType type = typeDeclarationElement.rawType; | 493 DartType type = typeDeclarationElement.rawType; |
494 return makeTypeConstant(node, type); | 494 return new AstConstant(element, node, makeTypeConstant(type)); |
495 } | 495 } |
496 return signalNotCompileTimeConstant(node); | 496 return signalNotCompileTimeConstant(node); |
497 } | 497 } |
498 | 498 |
499 // TODO(floitsch): provide better error-messages. | 499 // TODO(floitsch): provide better error-messages. |
500 AstConstant visitSend(Send send) { | 500 AstConstant visitSend(Send send) { |
501 Element element = elements[send]; | 501 Element element = elements[send]; |
502 if (send.isPropertyAccess) { | 502 if (send.isPropertyAccess) { |
503 if (isDeferredUse(send)) { | 503 ConstantExpression result; |
504 return signalNotCompileTimeConstant(send, | 504 |
505 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | |
506 } | |
507 if (Elements.isStaticOrTopLevelFunction(element)) { | 505 if (Elements.isStaticOrTopLevelFunction(element)) { |
508 FunctionElementX function = element; | 506 FunctionElementX function = element; |
509 function.computeType(compiler); | 507 function.computeType(compiler); |
510 return new AstConstant( | 508 result = new FunctionConstantExpression( |
511 context, send, new FunctionConstantExpression( | 509 new FunctionConstantValue(function), function); |
512 new FunctionConstantValue(function), | |
513 function)); | |
514 } else if (Elements.isStaticOrTopLevelField(element)) { | 510 } else if (Elements.isStaticOrTopLevelField(element)) { |
515 ConstantExpression result; | 511 ConstantExpression elementExpression; |
516 if (element.isConst) { | 512 if (element.isConst) { |
517 result = handler.compileConstant(element); | 513 elementExpression = handler.compileConstant(element); |
518 } else if (element.isFinal && !isEvaluatingConstant) { | 514 } else if (element.isFinal && !isEvaluatingConstant) { |
519 result = handler.compileVariable(element); | 515 elementExpression = handler.compileVariable(element); |
520 } | 516 } |
521 if (result != null) { | 517 if (elementExpression != null) { |
522 return new AstConstant( | 518 result = |
523 context, send, | 519 new VariableConstantExpression(elementExpression.value, element); |
524 new VariableConstantExpression(result.value, element)); | |
525 } | 520 } |
526 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 521 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
527 assert(elements.isTypeLiteral(send)); | 522 assert(elements.isTypeLiteral(send)); |
528 return makeTypeConstant(send, elements.getTypeLiteralType(send)); | 523 result = makeTypeConstant(elements.getTypeLiteralType(send)); |
529 } else if (send.receiver != null) { | 524 } else if (send.receiver != null) { |
530 if (send.selector.asIdentifier().source == "length") { | 525 if (send.selector.asIdentifier().source == "length") { |
531 AstConstant left = evaluate(send.receiver); | 526 AstConstant left = evaluate(send.receiver); |
532 if (left != null && left.value.isString) { | 527 if (left != null && left.value.isString) { |
533 StringConstantValue stringConstantValue = left.value; | 528 StringConstantValue stringConstantValue = left.value; |
534 DartString string = stringConstantValue.primitiveValue; | 529 DartString string = stringConstantValue.primitiveValue; |
535 IntConstantValue length = constantSystem.createInt(string.length); | 530 IntConstantValue length = constantSystem.createInt(string.length); |
536 return new AstConstant( | 531 result = new VariableConstantExpression(length, element); |
537 context, send, new VariableConstantExpression(length, element)); | |
538 } | 532 } |
539 } | 533 } |
540 // Fall through to error handling. | 534 // Fall through to error handling. |
541 } else if (!Elements.isUnresolved(element) | 535 } else if (!Elements.isUnresolved(element) |
542 && element.isVariable | 536 && element.isVariable |
543 && element.isConst) { | 537 && element.isConst) { |
544 ConstantExpression result = handler.compileConstant(element); | 538 ConstantExpression variableExpression = |
545 if (result != null) { | 539 handler.compileConstant(element); |
546 return new AstConstant( | 540 if (variableExpression != null) { |
547 context, send, | 541 result = new VariableConstantExpression(variableExpression.value, |
548 new VariableConstantExpression(result.value, element)); | 542 element); |
549 } | 543 } |
550 } | 544 } |
551 return signalNotCompileTimeConstant(send); | 545 if (result == null) { |
546 return signalNotCompileTimeConstant(send); | |
547 } | |
548 if (isDeferredUse(send)) { | |
549 if (isEvaluatingConstant) { | |
550 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | |
551 } | |
552 PrefixElement prefix = compiler.deferredLoadTask | |
553 .deferredPrefixElement(send, elements); | |
554 result = new DeferredConstantExpression( | |
555 new DeferredConstantValue(result.value, prefix), | |
556 result, | |
557 prefix); | |
558 compiler.deferredLoadTask | |
559 .registerConstantDeferredUse(result.value, prefix); | |
560 } | |
561 return new AstConstant(context, send, result); | |
552 } else if (send.isCall) { | 562 } else if (send.isCall) { |
553 if (element == compiler.identicalFunction | 563 if (element == compiler.identicalFunction |
554 && send.argumentCount() == 2) { | 564 && send.argumentCount() == 2) { |
555 AstConstant left = evaluate(send.argumentsNode.nodes.head); | 565 AstConstant left = evaluate(send.argumentsNode.nodes.head); |
556 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); | 566 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); |
557 if (left == null || right == null) { | 567 if (left == null || right == null) { |
558 return null; | 568 return null; |
559 } | 569 } |
560 ConstantValue result = | 570 ConstantValue result = |
561 constantSystem.identity.fold(left.value, right.value); | 571 constantSystem.identity.fold(left.value, right.value); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 Map<Node, AstConstant> concreteArgumentMap = | 746 Map<Node, AstConstant> concreteArgumentMap = |
737 <Node, AstConstant>{}; | 747 <Node, AstConstant>{}; |
738 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) { | 748 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) { |
739 Node argument = link.head; | 749 Node argument = link.head; |
740 NamedArgument namedArgument = argument.asNamedArgument(); | 750 NamedArgument namedArgument = argument.asNamedArgument(); |
741 if (namedArgument != null) { | 751 if (namedArgument != null) { |
742 argument = namedArgument.expression; | 752 argument = namedArgument.expression; |
743 } | 753 } |
744 concreteArgumentMap[argument] = evaluateConstant(argument); | 754 concreteArgumentMap[argument] = evaluateConstant(argument); |
745 } | 755 } |
746 | |
747 List<AstConstant> normalizedArguments = | 756 List<AstConstant> normalizedArguments = |
748 evaluateArgumentsToConstructor( | 757 evaluateArgumentsToConstructor( |
749 node, callStructure, send.arguments, constructor.implementation, | 758 node, callStructure, send.arguments, constructor.implementation, |
750 compileArgument: (node) => concreteArgumentMap[node]); | 759 compileArgument: (node) => concreteArgumentMap[node]); |
751 List<AstConstant> concreteArguments = | 760 List<AstConstant> concreteArguments = |
752 concreteArgumentMap.values.toList(); | 761 concreteArgumentMap.values.toList(); |
753 | 762 |
754 if (constructor == compiler.intEnvironment || | 763 if (constructor == compiler.intEnvironment || |
755 constructor == compiler.boolEnvironment || | 764 constructor == compiler.boolEnvironment || |
756 constructor == compiler.stringEnvironment) { | 765 constructor == compiler.stringEnvironment) { |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1147 ConstantValue get value => expression.value; | 1156 ConstantValue get value => expression.value; |
1148 | 1157 |
1149 String toString() => expression.toString(); | 1158 String toString() => expression.toString(); |
1150 } | 1159 } |
1151 | 1160 |
1152 /// A synthetic constant used to recover from errors. | 1161 /// A synthetic constant used to recover from errors. |
1153 class ErroneousAstConstant extends AstConstant { | 1162 class ErroneousAstConstant extends AstConstant { |
1154 ErroneousAstConstant(Element element, Node node) | 1163 ErroneousAstConstant(Element element, Node node) |
1155 : super(element, node, new ErroneousConstantExpression()); | 1164 : super(element, node, new ErroneousConstantExpression()); |
1156 } | 1165 } |
OLD | NEW |