| 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 part of dart2js; | 5 part of dart2js; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * The [ConstantHandler] keeps track of compile-time constants, | 8 * The [ConstantHandler] keeps track of compile-time constants, |
| 9 * initializations of global and static fields, and default values of | 9 * initializations of global and static fields, and default values of |
| 10 * optional parameters. | 10 * optional parameters. |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 {bool isConst: false}) { | 169 {bool isConst: false}) { |
| 170 return measure(() { | 170 return measure(() { |
| 171 // Initializers for parameters must be const. | 171 // Initializers for parameters must be const. |
| 172 isConst = isConst || element.modifiers.isConst() | 172 isConst = isConst || element.modifiers.isConst() |
| 173 || !Elements.isStaticOrTopLevel(element); | 173 || !Elements.isStaticOrTopLevel(element); |
| 174 if (!isConst && lazyStatics.contains(element)) return null; | 174 if (!isConst && lazyStatics.contains(element)) return null; |
| 175 | 175 |
| 176 Node node = element.parseNode(compiler); | 176 Node node = element.parseNode(compiler); |
| 177 if (pendingVariables.contains(element)) { | 177 if (pendingVariables.contains(element)) { |
| 178 if (isConst) { | 178 if (isConst) { |
| 179 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; | 179 compiler.reportFatalError( |
| 180 compiler.reportError(node, | 180 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 181 new CompileTimeConstantError(kind)); | |
| 182 } else { | 181 } else { |
| 183 lazyStatics.add(element); | 182 lazyStatics.add(element); |
| 184 return null; | 183 return null; |
| 185 } | 184 } |
| 186 } | 185 } |
| 187 pendingVariables.add(element); | 186 pendingVariables.add(element); |
| 188 | 187 |
| 189 SendSet assignment = node.asSendSet(); | 188 SendSet assignment = node.asSendSet(); |
| 190 Constant value; | 189 Constant value; |
| 191 if (assignment == null) { | 190 if (assignment == null) { |
| 192 // No initial value. | 191 // No initial value. |
| 193 value = new NullConstant(); | 192 value = new NullConstant(); |
| 194 } else { | 193 } else { |
| 195 Node right = assignment.arguments.head; | 194 Node right = assignment.arguments.head; |
| 196 value = | 195 value = |
| 197 compileNodeWithDefinitions(right, definitions, isConst: isConst); | 196 compileNodeWithDefinitions(right, definitions, isConst: isConst); |
| 198 if (compiler.enableTypeAssertions | 197 if (compiler.enableTypeAssertions |
| 199 && value != null | 198 && value != null |
| 200 && element.isField()) { | 199 && element.isField()) { |
| 201 DartType elementType = element.computeType(compiler); | 200 DartType elementType = element.computeType(compiler); |
| 202 DartType constantType = value.computeType(compiler); | 201 DartType constantType = value.computeType(compiler); |
| 203 if (elementType.isMalformed || constantType.isMalformed || | 202 if (elementType.isMalformed || constantType.isMalformed || |
| 204 !constantSystem.isSubtype(compiler, constantType, elementType)) { | 203 !constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 205 if (isConst) { | 204 if (isConst) { |
| 206 compiler.reportError(node, new CompileTimeConstantError( | 205 compiler.reportFatalError( |
| 207 MessageKind.NOT_ASSIGNABLE, | 206 node, MessageKind.NOT_ASSIGNABLE.error, |
| 208 {'fromType': constantType, 'toType': elementType})); | 207 {'fromType': constantType, 'toType': elementType}); |
| 209 } else { | 208 } else { |
| 210 // If the field can be lazily initialized, we will throw | 209 // If the field can be lazily initialized, we will throw |
| 211 // the exception at runtime. | 210 // the exception at runtime. |
| 212 value = null; | 211 value = null; |
| 213 } | 212 } |
| 214 } | 213 } |
| 215 } | 214 } |
| 216 } | 215 } |
| 217 if (value != null) { | 216 if (value != null) { |
| 218 initialVariableValues[element] = value; | 217 initialVariableValues[element] = value; |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 return signalNotCompileTimeConstant(node); | 388 return signalNotCompileTimeConstant(node); |
| 390 } | 389 } |
| 391 List<StringConstant> keys = <StringConstant>[]; | 390 List<StringConstant> keys = <StringConstant>[]; |
| 392 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); | 391 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 393 for (Link<Node> link = node.entries.nodes; | 392 for (Link<Node> link = node.entries.nodes; |
| 394 !link.isEmpty; | 393 !link.isEmpty; |
| 395 link = link.tail) { | 394 link = link.tail) { |
| 396 LiteralMapEntry entry = link.head; | 395 LiteralMapEntry entry = link.head; |
| 397 Constant key = evaluateConstant(entry.key); | 396 Constant key = evaluateConstant(entry.key); |
| 398 if (!key.isString() || entry.key.asStringNode() == null) { | 397 if (!key.isString() || entry.key.asStringNode() == null) { |
| 399 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 398 compiler.reportFatalError( |
| 400 compiler.reportError(entry.key, new ResolutionError(kind)); | 399 entry.key, MessageKind.KEY_NOT_A_STRING_LITERAL); |
| 401 } | 400 } |
| 402 StringConstant keyConstant = key; | 401 StringConstant keyConstant = key; |
| 403 if (!map.containsKey(key)) keys.add(key); | 402 if (!map.containsKey(key)) keys.add(key); |
| 404 map[key] = evaluateConstant(entry.value); | 403 map[key] = evaluateConstant(entry.value); |
| 405 } | 404 } |
| 406 List<Constant> values = <Constant>[]; | 405 List<Constant> values = <Constant>[]; |
| 407 Constant protoValue = null; | 406 Constant protoValue = null; |
| 408 for (StringConstant key in keys) { | 407 for (StringConstant key in keys) { |
| 409 if (key.value == MapConstant.PROTO_PROPERTY) { | 408 if (key.value == MapConstant.PROTO_PROPERTY) { |
| 410 protoValue = map[key]; | 409 protoValue = map[key]; |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 | 661 |
| 663 Function compileArgument = evaluateConstant; | 662 Function compileArgument = evaluateConstant; |
| 664 Function compileConstant = handler.compileConstant; | 663 Function compileConstant = handler.compileConstant; |
| 665 bool succeeded = selector.addArgumentsToList(arguments, | 664 bool succeeded = selector.addArgumentsToList(arguments, |
| 666 compiledArguments, | 665 compiledArguments, |
| 667 target, | 666 target, |
| 668 compileArgument, | 667 compileArgument, |
| 669 compileConstant, | 668 compileConstant, |
| 670 compiler); | 669 compiler); |
| 671 if (!succeeded) { | 670 if (!succeeded) { |
| 672 MessageKind kind = MessageKind.INVALID_ARGUMENTS; | 671 compiler.reportFatalError( |
| 673 compiler.reportError(node, | 672 node, |
| 674 new CompileTimeConstantError(kind, {'methodName': target.name})); | 673 MessageKind.INVALID_ARGUMENTS.error, {'methodName': target.name}); |
| 675 } | 674 } |
| 676 return compiledArguments; | 675 return compiledArguments; |
| 677 } | 676 } |
| 678 | 677 |
| 679 Constant visitNewExpression(NewExpression node) { | 678 Constant visitNewExpression(NewExpression node) { |
| 680 if (!node.isConst()) { | 679 if (!node.isConst()) { |
| 681 return signalNotCompileTimeConstant(node); | 680 return signalNotCompileTimeConstant(node); |
| 682 } | 681 } |
| 683 | 682 |
| 684 Send send = node.send; | 683 Send send = node.send; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 714 return constant; | 713 return constant; |
| 715 } | 714 } |
| 716 | 715 |
| 717 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 716 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 718 return node.expression.accept(this); | 717 return node.expression.accept(this); |
| 719 } | 718 } |
| 720 | 719 |
| 721 error(Node node) { | 720 error(Node node) { |
| 722 // TODO(floitsch): get the list of constants that are currently compiled | 721 // TODO(floitsch): get the list of constants that are currently compiled |
| 723 // and present some kind of stack-trace. | 722 // and present some kind of stack-trace. |
| 724 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 723 compiler.reportFatalError( |
| 725 compiler.reportError(node, new CompileTimeConstantError(kind)); | 724 node, MessageKind.NOT_A_COMPILE_TIME_CONSTANT); |
| 726 } | 725 } |
| 727 | 726 |
| 728 Constant signalNotCompileTimeConstant(Node node) { | 727 Constant signalNotCompileTimeConstant(Node node) { |
| 729 if (isEvaluatingConstant) { | 728 if (isEvaluatingConstant) { |
| 730 error(node); | 729 error(node); |
| 731 } | 730 } |
| 732 // Else we don't need to do anything. The final handler is only | 731 // Else we don't need to do anything. The final handler is only |
| 733 // optimistically trying to compile constants. So it is normal that we | 732 // optimistically trying to compile constants. So it is normal that we |
| 734 // sometimes see non-compile time constants. | 733 // sometimes see non-compile time constants. |
| 735 // Simply return [:null:] which is used to propagate a failing | 734 // Simply return [:null:] which is used to propagate a failing |
| 736 // compile-time compilation. | 735 // compile-time compilation. |
| 737 return null; | 736 return null; |
| 738 } | 737 } |
| 739 } | 738 } |
| 740 | 739 |
| 741 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 740 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 742 TryCompileTimeConstantEvaluator(ConstantHandler handler, | 741 TryCompileTimeConstantEvaluator(ConstantHandler handler, |
| 743 TreeElements elements, | 742 TreeElements elements, |
| 744 Compiler compiler) | 743 Compiler compiler) |
| 745 : super(handler, elements, compiler, isConst: true); | 744 : super(handler, elements, compiler, isConst: true); |
| 746 | 745 |
| 747 error(Node node) { | 746 error(Node node) { |
| 748 // Just fail without reporting it anywhere. | 747 // Just fail without reporting it anywhere. |
| 749 throw new CompileTimeConstantError( | 748 throw new CompileTimeConstantError(MessageKind.NOT_A_COMPILE_TIME_CONSTANT); |
| 750 MessageKind.NOT_A_COMPILE_TIME_CONSTANT); | |
| 751 } | 749 } |
| 752 } | 750 } |
| 753 | 751 |
| 754 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 752 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 755 final FunctionElement constructor; | 753 final FunctionElement constructor; |
| 756 final Map<Element, Constant> definitions; | 754 final Map<Element, Constant> definitions; |
| 757 final Map<Element, Constant> fieldValues; | 755 final Map<Element, Constant> fieldValues; |
| 758 | 756 |
| 759 /** | 757 /** |
| 760 * Documentation wanted -- johnniwinther | 758 * Documentation wanted -- johnniwinther |
| (...skipping 26 matching lines...) Expand all Loading... |
| 787 } | 785 } |
| 788 | 786 |
| 789 void potentiallyCheckType(Node node, Element element, Constant constant) { | 787 void potentiallyCheckType(Node node, Element element, Constant constant) { |
| 790 if (compiler.enableTypeAssertions) { | 788 if (compiler.enableTypeAssertions) { |
| 791 DartType elementType = element.computeType(compiler); | 789 DartType elementType = element.computeType(compiler); |
| 792 DartType constantType = constant.computeType(compiler); | 790 DartType constantType = constant.computeType(compiler); |
| 793 // TODO(ngeoffray): Handle type parameters. | 791 // TODO(ngeoffray): Handle type parameters. |
| 794 if (elementType.element.isTypeVariable()) return; | 792 if (elementType.element.isTypeVariable()) return; |
| 795 if (elementType.isMalformed || constantType.isMalformed || | 793 if (elementType.isMalformed || constantType.isMalformed || |
| 796 !constantSystem.isSubtype(compiler, constantType, elementType)) { | 794 !constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 797 compiler.reportError(node, new CompileTimeConstantError( | 795 compiler.reportFatalError( |
| 798 MessageKind.NOT_ASSIGNABLE, | 796 node, MessageKind.NOT_ASSIGNABLE.error, |
| 799 {'fromType': elementType, 'toType': constantType})); | 797 {'fromType': elementType, 'toType': constantType}); |
| 800 } | 798 } |
| 801 } | 799 } |
| 802 } | 800 } |
| 803 | 801 |
| 804 void updateFieldValue(Node node, Element element, Constant constant) { | 802 void updateFieldValue(Node node, Element element, Constant constant) { |
| 805 potentiallyCheckType(node, element, constant); | 803 potentiallyCheckType(node, element, constant); |
| 806 fieldValues[element] = constant; | 804 fieldValues[element] = constant; |
| 807 } | 805 } |
| 808 | 806 |
| 809 /** | 807 /** |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 if (fieldValue == null) { | 930 if (fieldValue == null) { |
| 933 // Use the default value. | 931 // Use the default value. |
| 934 fieldValue = handler.compileConstant(field); | 932 fieldValue = handler.compileConstant(field); |
| 935 } | 933 } |
| 936 jsNewArguments.add(fieldValue); | 934 jsNewArguments.add(fieldValue); |
| 937 }, | 935 }, |
| 938 includeSuperAndInjectedMembers: true); | 936 includeSuperAndInjectedMembers: true); |
| 939 return jsNewArguments; | 937 return jsNewArguments; |
| 940 } | 938 } |
| 941 } | 939 } |
| OLD | NEW |