| 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 // Initializers for parameters must be const. | 141 // Initializers for parameters must be const. |
| 142 isConst = isConst || element.modifiers.isConst() | 142 isConst = isConst || element.modifiers.isConst() |
| 143 || !Elements.isStaticOrTopLevel(element); | 143 || !Elements.isStaticOrTopLevel(element); |
| 144 if (!isConst && lazyStatics.contains(element)) return null; | 144 if (!isConst && lazyStatics.contains(element)) return null; |
| 145 | 145 |
| 146 Node node = element.parseNode(compiler); | 146 Node node = element.parseNode(compiler); |
| 147 if (pendingVariables.contains(element)) { | 147 if (pendingVariables.contains(element)) { |
| 148 if (isConst) { | 148 if (isConst) { |
| 149 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; | 149 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; |
| 150 compiler.reportError(node, | 150 compiler.reportError(node, |
| 151 new CompileTimeConstantError(kind, const [])); | 151 new CompileTimeConstantError(kind)); |
| 152 } else { | 152 } else { |
| 153 lazyStatics.add(element); | 153 lazyStatics.add(element); |
| 154 return null; | 154 return null; |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 pendingVariables.add(element); | 157 pendingVariables.add(element); |
| 158 | 158 |
| 159 SendSet assignment = node.asSendSet(); | 159 SendSet assignment = node.asSendSet(); |
| 160 Constant value; | 160 Constant value; |
| 161 if (assignment == null) { | 161 if (assignment == null) { |
| 162 // No initial value. | 162 // No initial value. |
| 163 value = new NullConstant(); | 163 value = new NullConstant(); |
| 164 } else { | 164 } else { |
| 165 Node right = assignment.arguments.head; | 165 Node right = assignment.arguments.head; |
| 166 value = | 166 value = |
| 167 compileNodeWithDefinitions(right, definitions, isConst: isConst); | 167 compileNodeWithDefinitions(right, definitions, isConst: isConst); |
| 168 if (compiler.enableTypeAssertions | 168 if (compiler.enableTypeAssertions |
| 169 && value != null | 169 && value != null |
| 170 && element.isField()) { | 170 && element.isField()) { |
| 171 DartType elementType = element.computeType(compiler); | 171 DartType elementType = element.computeType(compiler); |
| 172 DartType constantType = value.computeType(compiler); | 172 DartType constantType = value.computeType(compiler); |
| 173 if (elementType.isMalformed || constantType.isMalformed || | 173 if (elementType.isMalformed || constantType.isMalformed || |
| 174 !constantSystem.isSubtype(compiler, constantType, elementType)) { | 174 !constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 175 if (isConst) { | 175 if (isConst) { |
| 176 MessageKind kind = MessageKind.NOT_ASSIGNABLE; | |
| 177 compiler.reportError(node, new CompileTimeConstantError( | 176 compiler.reportError(node, new CompileTimeConstantError( |
| 178 kind, [elementType, constantType])); | 177 MessageKind.NOT_ASSIGNABLE, |
| 178 {'fromType': elementType, 'toType': constantType})); |
| 179 } else { | 179 } else { |
| 180 // If the field can be lazily initialized, we will throw | 180 // If the field can be lazily initialized, we will throw |
| 181 // the exception at runtime. | 181 // the exception at runtime. |
| 182 value = null; | 182 value = null; |
| 183 } | 183 } |
| 184 } | 184 } |
| 185 } | 185 } |
| 186 } | 186 } |
| 187 if (value != null) { | 187 if (value != null) { |
| 188 initialVariableValues[element] = value; | 188 initialVariableValues[element] = value; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 } | 347 } |
| 348 List<StringConstant> keys = <StringConstant>[]; | 348 List<StringConstant> keys = <StringConstant>[]; |
| 349 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); | 349 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 350 for (Link<Node> link = node.entries.nodes; | 350 for (Link<Node> link = node.entries.nodes; |
| 351 !link.isEmpty; | 351 !link.isEmpty; |
| 352 link = link.tail) { | 352 link = link.tail) { |
| 353 LiteralMapEntry entry = link.head; | 353 LiteralMapEntry entry = link.head; |
| 354 Constant key = evaluateConstant(entry.key); | 354 Constant key = evaluateConstant(entry.key); |
| 355 if (!key.isString() || entry.key.asStringNode() == null) { | 355 if (!key.isString() || entry.key.asStringNode() == null) { |
| 356 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 356 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
| 357 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 357 compiler.reportError(entry.key, new ResolutionError(kind)); |
| 358 } | 358 } |
| 359 StringConstant keyConstant = key; | 359 StringConstant keyConstant = key; |
| 360 if (!map.containsKey(key)) keys.add(key); | 360 if (!map.containsKey(key)) keys.add(key); |
| 361 map[key] = evaluateConstant(entry.value); | 361 map[key] = evaluateConstant(entry.value); |
| 362 } | 362 } |
| 363 List<Constant> values = <Constant>[]; | 363 List<Constant> values = <Constant>[]; |
| 364 Constant protoValue = null; | 364 Constant protoValue = null; |
| 365 for (StringConstant key in keys) { | 365 for (StringConstant key in keys) { |
| 366 if (key.value == MapConstant.PROTO_PROPERTY) { | 366 if (key.value == MapConstant.PROTO_PROPERTY) { |
| 367 protoValue = map[key]; | 367 protoValue = map[key]; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 } | 461 } |
| 462 if (result != null) return result; | 462 if (result != null) return result; |
| 463 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 463 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 464 return makeTypeConstant(element); | 464 return makeTypeConstant(element); |
| 465 } else if (send.receiver != null) { | 465 } else if (send.receiver != null) { |
| 466 // Fall through to error handling. | 466 // Fall through to error handling. |
| 467 } else if (!Elements.isUnresolved(element) | 467 } else if (!Elements.isUnresolved(element) |
| 468 && element.isVariable() | 468 && element.isVariable() |
| 469 && element.modifiers.isConst()) { | 469 && element.modifiers.isConst()) { |
| 470 Constant result = handler.compileConstant(element); | 470 Constant result = handler.compileConstant(element); |
| 471 if (result != null) return result; | 471 if (result != null) return result; |
| 472 } | 472 } |
| 473 return signalNotCompileTimeConstant(send); | 473 return signalNotCompileTimeConstant(send); |
| 474 } else if (send.isCall) { | 474 } else if (send.isCall) { |
| 475 if (identical(element, compiler.identicalFunction) | 475 if (identical(element, compiler.identicalFunction) |
| 476 && send.argumentCount() == 2) { | 476 && send.argumentCount() == 2) { |
| 477 Constant left = evaluate(send.argumentsNode.nodes.head); | 477 Constant left = evaluate(send.argumentsNode.nodes.head); |
| 478 Constant right = evaluate(send.argumentsNode.nodes.tail.head); | 478 Constant right = evaluate(send.argumentsNode.nodes.tail.head); |
| 479 Constant result = constantSystem.identity.fold(left, right); | 479 Constant result = constantSystem.identity.fold(left, right); |
| 480 if (result != null) return result; | 480 if (result != null) return result; |
| 481 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 481 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 Function compileConstant = handler.compileConstant; | 617 Function compileConstant = handler.compileConstant; |
| 618 bool succeeded = selector.addArgumentsToList(arguments, | 618 bool succeeded = selector.addArgumentsToList(arguments, |
| 619 compiledArguments, | 619 compiledArguments, |
| 620 target, | 620 target, |
| 621 compileArgument, | 621 compileArgument, |
| 622 compileConstant, | 622 compileConstant, |
| 623 compiler); | 623 compiler); |
| 624 if (!succeeded) { | 624 if (!succeeded) { |
| 625 MessageKind kind = MessageKind.INVALID_ARGUMENTS; | 625 MessageKind kind = MessageKind.INVALID_ARGUMENTS; |
| 626 compiler.reportError(node, | 626 compiler.reportError(node, |
| 627 new CompileTimeConstantError(kind, [target.name.slowToString()])); | 627 new CompileTimeConstantError(kind, {'methodName': target.name})); |
| 628 } | 628 } |
| 629 return compiledArguments; | 629 return compiledArguments; |
| 630 } | 630 } |
| 631 | 631 |
| 632 Constant visitNewExpression(NewExpression node) { | 632 Constant visitNewExpression(NewExpression node) { |
| 633 if (!node.isConst()) { | 633 if (!node.isConst()) { |
| 634 return signalNotCompileTimeConstant(node); | 634 return signalNotCompileTimeConstant(node); |
| 635 } | 635 } |
| 636 | 636 |
| 637 Send send = node.send; | 637 Send send = node.send; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 665 } | 665 } |
| 666 | 666 |
| 667 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 667 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 668 return node.expression.accept(this); | 668 return node.expression.accept(this); |
| 669 } | 669 } |
| 670 | 670 |
| 671 error(Node node) { | 671 error(Node node) { |
| 672 // TODO(floitsch): get the list of constants that are currently compiled | 672 // TODO(floitsch): get the list of constants that are currently compiled |
| 673 // and present some kind of stack-trace. | 673 // and present some kind of stack-trace. |
| 674 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 674 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 675 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 675 compiler.reportError(node, new CompileTimeConstantError(kind)); |
| 676 } | 676 } |
| 677 | 677 |
| 678 Constant signalNotCompileTimeConstant(Node node) { | 678 Constant signalNotCompileTimeConstant(Node node) { |
| 679 if (isEvaluatingConstant) { | 679 if (isEvaluatingConstant) { |
| 680 error(node); | 680 error(node); |
| 681 } | 681 } |
| 682 // Else we don't need to do anything. The final handler is only | 682 // Else we don't need to do anything. The final handler is only |
| 683 // optimistically trying to compile constants. So it is normal that we | 683 // optimistically trying to compile constants. So it is normal that we |
| 684 // sometimes see non-compile time constants. | 684 // sometimes see non-compile time constants. |
| 685 // Simply return [:null:] which is used to propagate a failing | 685 // Simply return [:null:] which is used to propagate a failing |
| 686 // compile-time compilation. | 686 // compile-time compilation. |
| 687 return null; | 687 return null; |
| 688 } | 688 } |
| 689 } | 689 } |
| 690 | 690 |
| 691 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 691 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 692 TryCompileTimeConstantEvaluator(ConstantHandler handler, | 692 TryCompileTimeConstantEvaluator(ConstantHandler handler, |
| 693 TreeElements elements, | 693 TreeElements elements, |
| 694 Compiler compiler) | 694 Compiler compiler) |
| 695 : super(handler, elements, compiler, isConst: true); | 695 : super(handler, elements, compiler, isConst: true); |
| 696 | 696 |
| 697 error(Node node) { | 697 error(Node node) { |
| 698 // Just fail without reporting it anywhere. | 698 // Just fail without reporting it anywhere. |
| 699 throw new CompileTimeConstantError( | 699 throw new CompileTimeConstantError( |
| 700 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); | 700 MessageKind.NOT_A_COMPILE_TIME_CONSTANT); |
| 701 } | 701 } |
| 702 } | 702 } |
| 703 | 703 |
| 704 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 704 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 705 final FunctionElement constructor; | 705 final FunctionElement constructor; |
| 706 final Map<Element, Constant> definitions; | 706 final Map<Element, Constant> definitions; |
| 707 final Map<Element, Constant> fieldValues; | 707 final Map<Element, Constant> fieldValues; |
| 708 | 708 |
| 709 /** | 709 /** |
| 710 * Documentation wanted -- johnniwinther | 710 * Documentation wanted -- johnniwinther |
| (...skipping 27 matching lines...) Expand all Loading... |
| 738 } | 738 } |
| 739 | 739 |
| 740 void potentiallyCheckType(Node node, Element element, Constant constant) { | 740 void potentiallyCheckType(Node node, Element element, Constant constant) { |
| 741 if (compiler.enableTypeAssertions) { | 741 if (compiler.enableTypeAssertions) { |
| 742 DartType elementType = element.computeType(compiler); | 742 DartType elementType = element.computeType(compiler); |
| 743 DartType constantType = constant.computeType(compiler); | 743 DartType constantType = constant.computeType(compiler); |
| 744 // TODO(ngeoffray): Handle type parameters. | 744 // TODO(ngeoffray): Handle type parameters. |
| 745 if (elementType.element.isTypeVariable()) return; | 745 if (elementType.element.isTypeVariable()) return; |
| 746 if (elementType.isMalformed || constantType.isMalformed || | 746 if (elementType.isMalformed || constantType.isMalformed || |
| 747 !constantSystem.isSubtype(compiler, constantType, elementType)) { | 747 !constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 748 MessageKind kind = MessageKind.NOT_ASSIGNABLE; | |
| 749 compiler.reportError(node, new CompileTimeConstantError( | 748 compiler.reportError(node, new CompileTimeConstantError( |
| 750 kind, [elementType, constantType])); | 749 MessageKind.NOT_ASSIGNABLE, |
| 750 {'fromType': elementType, 'toType': constantType})); |
| 751 } | 751 } |
| 752 } | 752 } |
| 753 } | 753 } |
| 754 | 754 |
| 755 void updateFieldValue(Node node, Element element, Constant constant) { | 755 void updateFieldValue(Node node, Element element, Constant constant) { |
| 756 potentiallyCheckType(node, element, constant); | 756 potentiallyCheckType(node, element, constant); |
| 757 fieldValues[element] = constant; | 757 fieldValues[element] = constant; |
| 758 } | 758 } |
| 759 | 759 |
| 760 /** | 760 /** |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 877 // Use the default value. | 877 // Use the default value. |
| 878 fieldValue = handler.compileConstant(field); | 878 fieldValue = handler.compileConstant(field); |
| 879 } | 879 } |
| 880 jsNewArguments.add(fieldValue); | 880 jsNewArguments.add(fieldValue); |
| 881 }, | 881 }, |
| 882 includeBackendMembers: true, | 882 includeBackendMembers: true, |
| 883 includeSuperMembers: true); | 883 includeSuperMembers: true); |
| 884 return jsNewArguments; | 884 return jsNewArguments; |
| 885 } | 885 } |
| 886 } | 886 } |
| OLD | NEW |