| 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 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 compiler.resolver.resolveRedirectionChain(constructor, node); | 718 compiler.resolver.resolveRedirectionChain(constructor, node); |
| 719 InterfaceType constructedType = constructor.computeTargetType(type); | 719 InterfaceType constructedType = constructor.computeTargetType(type); |
| 720 constructor = constructor.redirectionTarget; | 720 constructor = constructor.redirectionTarget; |
| 721 ClassElement classElement = constructor.getEnclosingClass(); | 721 ClassElement classElement = constructor.getEnclosingClass(); |
| 722 // The constructor must be an implementation to ensure that field | 722 // The constructor must be an implementation to ensure that field |
| 723 // initializers are handled correctly. | 723 // initializers are handled correctly. |
| 724 constructor = constructor.implementation; | 724 constructor = constructor.implementation; |
| 725 assert(invariant(node, constructor.isImplementation)); | 725 assert(invariant(node, constructor.isImplementation)); |
| 726 | 726 |
| 727 List<Constant> arguments = getArguments(constructor); | 727 List<Constant> arguments = getArguments(constructor); |
| 728 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 728 ConstructorEvaluator evaluator = |
| 729 constructedType, constructor, handler, compiler); | 729 new ConstructorEvaluator(constructor, handler, compiler); |
| 730 evaluator.evaluateConstructorFieldValues(arguments); | 730 evaluator.evaluateConstructorFieldValues(arguments); |
| 731 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); | 731 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); |
| 732 | 732 |
| 733 return new ConstructedConstant(constructedType, jsNewArguments); | 733 return new ConstructedConstant(constructedType, jsNewArguments); |
| 734 } | 734 } |
| 735 | 735 |
| 736 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 736 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 737 return node.expression.accept(this); | 737 return node.expression.accept(this); |
| 738 } | 738 } |
| 739 | 739 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 765 | 765 |
| 766 error(Node node) { | 766 error(Node node) { |
| 767 // Just fail without reporting it anywhere. | 767 // Just fail without reporting it anywhere. |
| 768 throw new CompileTimeConstantError( | 768 throw new CompileTimeConstantError( |
| 769 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const {}, | 769 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const {}, |
| 770 compiler.terseDiagnostics); | 770 compiler.terseDiagnostics); |
| 771 } | 771 } |
| 772 } | 772 } |
| 773 | 773 |
| 774 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 774 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 775 final InterfaceType constructedType; | |
| 776 final FunctionElement constructor; | 775 final FunctionElement constructor; |
| 777 final Map<Element, Constant> definitions; | 776 final Map<Element, Constant> definitions; |
| 778 final Map<Element, Constant> fieldValues; | 777 final Map<Element, Constant> fieldValues; |
| 779 | 778 |
| 780 /** | 779 /** |
| 781 * Documentation wanted -- johnniwinther | 780 * Documentation wanted -- johnniwinther |
| 782 * | 781 * |
| 783 * Invariant: [constructor] must be an implementation element. | 782 * Invariant: [constructor] must be an implementation element. |
| 784 */ | 783 */ |
| 785 ConstructorEvaluator(InterfaceType this.constructedType, | 784 ConstructorEvaluator(FunctionElement constructor, |
| 786 FunctionElement constructor, | |
| 787 ConstantHandler handler, | 785 ConstantHandler handler, |
| 788 Compiler compiler) | 786 Compiler compiler) |
| 789 : this.constructor = constructor, | 787 : this.constructor = constructor, |
| 790 this.definitions = new Map<Element, Constant>(), | 788 this.definitions = new Map<Element, Constant>(), |
| 791 this.fieldValues = new Map<Element, Constant>(), | 789 this.fieldValues = new Map<Element, Constant>(), |
| 792 super(handler, | 790 super(handler, |
| 793 compiler.resolver.resolveMethodElement(constructor.declaration), | 791 compiler.resolver.resolveMethodElement(constructor.declaration), |
| 794 compiler, | 792 compiler, |
| 795 isConst: true) { | 793 isConst: true) { |
| 796 assert(invariant(constructor, constructor.isImplementation)); | 794 assert(invariant(constructor, constructor.isImplementation)); |
| 797 } | 795 } |
| 798 | 796 |
| 799 Constant visitSend(Send send) { | 797 Constant visitSend(Send send) { |
| 800 Element element = elements[send]; | 798 Element element = elements[send]; |
| 801 if (Elements.isLocal(element)) { | 799 if (Elements.isLocal(element)) { |
| 802 Constant constant = definitions[element]; | 800 Constant constant = definitions[element]; |
| 803 if (constant == null) { | 801 if (constant == null) { |
| 804 compiler.internalError("Local variable without value", node: send); | 802 compiler.internalError("Local variable without value", node: send); |
| 805 } | 803 } |
| 806 return constant; | 804 return constant; |
| 807 } | 805 } |
| 808 return super.visitSend(send); | 806 return super.visitSend(send); |
| 809 } | 807 } |
| 810 | 808 |
| 811 void potentiallyCheckType(Node node, DartType type, Constant constant) { | 809 void potentiallyCheckType(Node node, Element element, Constant constant) { |
| 812 if (compiler.enableTypeAssertions) { | 810 if (compiler.enableTypeAssertions) { |
| 811 DartType elementType = element.computeType(compiler); |
| 813 DartType constantType = constant.computeType(compiler); | 812 DartType constantType = constant.computeType(compiler); |
| 814 if (!compiler.types.isSubtype(constantType, type)) { | 813 // TODO(ngeoffray): Handle type parameters. |
| 814 if (elementType.element.isTypeVariable()) return; |
| 815 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 815 compiler.reportFatalError( | 816 compiler.reportFatalError( |
| 816 node, MessageKind.NOT_ASSIGNABLE.error, | 817 node, MessageKind.NOT_ASSIGNABLE.error, |
| 817 {'fromType': constantType, 'toType': type}); | 818 {'fromType': elementType, 'toType': constantType}); |
| 818 } | 819 } |
| 819 } | 820 } |
| 820 } | 821 } |
| 821 | 822 |
| 822 void updateFieldValue(Node node, Element element, Constant constant) { | 823 void updateFieldValue(Node node, Element element, Constant constant) { |
| 823 DartType elementType = | 824 potentiallyCheckType(node, element, constant); |
| 824 element.computeType(compiler).substByContext(constructedType); | |
| 825 potentiallyCheckType(node, elementType, constant); | |
| 826 fieldValues[element] = constant; | 825 fieldValues[element] = constant; |
| 827 } | 826 } |
| 828 | 827 |
| 829 /** | 828 /** |
| 830 * Given the arguments (a list of constants) assigns them to the parameters, | 829 * Given the arguments (a list of constants) assigns them to the parameters, |
| 831 * updating the definitions map. If the constructor has field-initializer | 830 * updating the definitions map. If the constructor has field-initializer |
| 832 * parameters (like [:this.x:]), also updates the [fieldValues] map. | 831 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
| 833 */ | 832 */ |
| 834 void assignArgumentsToParameters(List<Constant> arguments) { | 833 void assignArgumentsToParameters(List<Constant> arguments) { |
| 835 // Assign arguments to parameters. | 834 // Assign arguments to parameters. |
| 836 FunctionSignature signature = constructor.computeSignature(compiler); | 835 FunctionSignature parameters = constructor.computeSignature(compiler); |
| 837 int index = 0; | 836 int index = 0; |
| 838 signature.orderedForEachParameter((Element parameter) { | 837 parameters.orderedForEachParameter((Element parameter) { |
| 839 DartType parameterType = | |
| 840 parameter.computeType(compiler).substByContext(constructedType); | |
| 841 Constant argument = arguments[index++]; | 838 Constant argument = arguments[index++]; |
| 842 Node node = parameter.parseNode(compiler); | 839 Node node = parameter.parseNode(compiler); |
| 843 potentiallyCheckType(node, parameterType, argument); | 840 potentiallyCheckType(node, parameter, argument); |
| 844 definitions[parameter] = argument; | 841 definitions[parameter] = argument; |
| 845 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | 842 if (parameter.kind == ElementKind.FIELD_PARAMETER) { |
| 846 FieldParameterElement fieldParameterElement = parameter; | 843 FieldParameterElement fieldParameterElement = parameter; |
| 847 updateFieldValue(node, fieldParameterElement.fieldElement, argument); | 844 updateFieldValue(node, fieldParameterElement.fieldElement, argument); |
| 848 } | 845 } |
| 849 }); | 846 }); |
| 850 } | 847 } |
| 851 | 848 |
| 852 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, | 849 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, |
| 853 FunctionElement targetConstructor) { | 850 FunctionElement targetConstructor) { |
| 854 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 851 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 855 constructedType.asInstanceOf(targetConstructor.getEnclosingClass()), | |
| 856 targetConstructor, handler, compiler); | 852 targetConstructor, handler, compiler); |
| 857 evaluator.evaluateConstructorFieldValues(compiledArguments); | 853 evaluator.evaluateConstructorFieldValues(compiledArguments); |
| 858 // Copy over the fieldValues from the super/redirect-constructor. | 854 // Copy over the fieldValues from the super/redirect-constructor. |
| 859 // No need to go through [updateFieldValue] because the | 855 // No need to go through [updateFieldValue] because the |
| 860 // assignments have already been checked in checked mode. | 856 // assignments have already been checked in checked mode. |
| 861 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 857 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 862 } | 858 } |
| 863 | 859 |
| 864 /** | 860 /** |
| 865 * Runs through the initializers of the given [constructor] and updates | 861 * Runs through the initializers of the given [constructor] and updates |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 955 if (fieldValue == null) { | 951 if (fieldValue == null) { |
| 956 // Use the default value. | 952 // Use the default value. |
| 957 fieldValue = handler.compileConstant(field); | 953 fieldValue = handler.compileConstant(field); |
| 958 } | 954 } |
| 959 jsNewArguments.add(fieldValue); | 955 jsNewArguments.add(fieldValue); |
| 960 }, | 956 }, |
| 961 includeSuperAndInjectedMembers: true); | 957 includeSuperAndInjectedMembers: true); |
| 962 return jsNewArguments; | 958 return jsNewArguments; |
| 963 } | 959 } |
| 964 } | 960 } |
| OLD | NEW |