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 /// A [ConstantEnvironment] provides access for constants compiled for variable | 7 /// A [ConstantEnvironment] provides access for constants compiled for variable |
8 /// initializers. | 8 /// initializers. |
9 abstract class ConstantEnvironment { | 9 abstract class ConstantEnvironment { |
10 /// Returns the constant for the initializer of [element]. | 10 /// Returns the constant for the initializer of [element]. |
(...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 compiler.resolver.resolveRedirectionChain(constructor, node); | 767 compiler.resolver.resolveRedirectionChain(constructor, node); |
768 InterfaceType constructedType = constructor.computeTargetType(type); | 768 InterfaceType constructedType = constructor.computeTargetType(type); |
769 constructor = constructor.redirectionTarget; | 769 constructor = constructor.redirectionTarget; |
770 ClassElement classElement = constructor.getEnclosingClass(); | 770 ClassElement classElement = constructor.getEnclosingClass(); |
771 // The constructor must be an implementation to ensure that field | 771 // The constructor must be an implementation to ensure that field |
772 // initializers are handled correctly. | 772 // initializers are handled correctly. |
773 constructor = constructor.implementation; | 773 constructor = constructor.implementation; |
774 assert(invariant(node, constructor.isImplementation)); | 774 assert(invariant(node, constructor.isImplementation)); |
775 | 775 |
776 List<Constant> arguments = getArguments(constructor); | 776 List<Constant> arguments = getArguments(constructor); |
777 ConstructorEvaluator evaluator = | 777 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
778 new ConstructorEvaluator(constructor, handler, compiler); | 778 constructedType, constructor, handler, compiler); |
779 evaluator.evaluateConstructorFieldValues(arguments); | 779 evaluator.evaluateConstructorFieldValues(arguments); |
780 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); | 780 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); |
781 | 781 |
782 return new ConstructedConstant(constructedType, jsNewArguments); | 782 return new ConstructedConstant(constructedType, jsNewArguments); |
783 } | 783 } |
784 | 784 |
785 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 785 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
786 return node.expression.accept(this); | 786 return node.expression.accept(this); |
787 } | 787 } |
788 | 788 |
(...skipping 11 matching lines...) Expand all Loading... |
800 // Else we don't need to do anything. The final handler is only | 800 // Else we don't need to do anything. The final handler is only |
801 // optimistically trying to compile constants. So it is normal that we | 801 // optimistically trying to compile constants. So it is normal that we |
802 // sometimes see non-compile time constants. | 802 // sometimes see non-compile time constants. |
803 // Simply return [:null:] which is used to propagate a failing | 803 // Simply return [:null:] which is used to propagate a failing |
804 // compile-time compilation. | 804 // compile-time compilation. |
805 return null; | 805 return null; |
806 } | 806 } |
807 } | 807 } |
808 | 808 |
809 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 809 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 810 final InterfaceType constructedType; |
810 final FunctionElement constructor; | 811 final FunctionElement constructor; |
811 final Map<Element, Constant> definitions; | 812 final Map<Element, Constant> definitions; |
812 final Map<Element, Constant> fieldValues; | 813 final Map<Element, Constant> fieldValues; |
813 | 814 |
814 /** | 815 /** |
815 * Documentation wanted -- johnniwinther | 816 * Documentation wanted -- johnniwinther |
816 * | 817 * |
817 * Invariant: [constructor] must be an implementation element. | 818 * Invariant: [constructor] must be an implementation element. |
818 */ | 819 */ |
819 ConstructorEvaluator(FunctionElement constructor, | 820 ConstructorEvaluator(InterfaceType this.constructedType, |
| 821 FunctionElement constructor, |
820 ConstantCompiler handler, | 822 ConstantCompiler handler, |
821 Compiler compiler) | 823 Compiler compiler) |
822 : this.constructor = constructor, | 824 : this.constructor = constructor, |
823 this.definitions = new Map<Element, Constant>(), | 825 this.definitions = new Map<Element, Constant>(), |
824 this.fieldValues = new Map<Element, Constant>(), | 826 this.fieldValues = new Map<Element, Constant>(), |
825 super(handler, | 827 super(handler, |
826 compiler.resolver.resolveMethodElement(constructor.declaration), | 828 compiler.resolver.resolveMethodElement(constructor.declaration), |
827 compiler, | 829 compiler, |
828 isConst: true) { | 830 isConst: true) { |
829 assert(invariant(constructor, constructor.isImplementation)); | 831 assert(invariant(constructor, constructor.isImplementation)); |
830 } | 832 } |
831 | 833 |
832 Constant visitSend(Send send) { | 834 Constant visitSend(Send send) { |
833 Element element = elements[send]; | 835 Element element = elements[send]; |
834 if (Elements.isLocal(element)) { | 836 if (Elements.isLocal(element)) { |
835 Constant constant = definitions[element]; | 837 Constant constant = definitions[element]; |
836 if (constant == null) { | 838 if (constant == null) { |
837 compiler.internalError(send, "Local variable without value."); | 839 compiler.internalError(send, "Local variable without value."); |
838 } | 840 } |
839 return constant; | 841 return constant; |
840 } | 842 } |
841 return super.visitSend(send); | 843 return super.visitSend(send); |
842 } | 844 } |
843 | 845 |
844 void potentiallyCheckType(Node node, | 846 void potentiallyCheckType(Node node, |
845 TypedElement element, | 847 TypedElement element, |
846 Constant constant) { | 848 Constant constant) { |
847 if (compiler.enableTypeAssertions) { | 849 if (compiler.enableTypeAssertions) { |
848 DartType elementType = element.type; | 850 DartType elementType = element.type.substByContext(constructedType); |
849 DartType constantType = constant.computeType(compiler); | 851 DartType constantType = constant.computeType(compiler); |
850 // TODO(ngeoffray): Handle type parameters. | |
851 if (elementType.element.isTypeVariable()) return; | |
852 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { | 852 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { |
853 // TODO(johnniwinther): Provide better [node] values that point to the | |
854 // origin of the constant and not (just) the assignment. | |
855 compiler.reportFatalError( | 853 compiler.reportFatalError( |
856 node, MessageKind.NOT_ASSIGNABLE, | 854 node, MessageKind.NOT_ASSIGNABLE, |
857 {'fromType': elementType, 'toType': constantType}); | 855 {'fromType': constantType, 'toType': elementType}); |
858 } | 856 } |
859 } | 857 } |
860 } | 858 } |
861 | 859 |
862 void updateFieldValue(Node node, TypedElement element, Constant constant) { | 860 void updateFieldValue(Node node, TypedElement element, Constant constant) { |
863 potentiallyCheckType(node, element, constant); | 861 potentiallyCheckType(node, element, constant); |
864 fieldValues[element] = constant; | 862 fieldValues[element] = constant; |
865 } | 863 } |
866 | 864 |
867 /** | 865 /** |
868 * Given the arguments (a list of constants) assigns them to the parameters, | 866 * Given the arguments (a list of constants) assigns them to the parameters, |
869 * updating the definitions map. If the constructor has field-initializer | 867 * updating the definitions map. If the constructor has field-initializer |
870 * parameters (like [:this.x:]), also updates the [fieldValues] map. | 868 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
871 */ | 869 */ |
872 void assignArgumentsToParameters(List<Constant> arguments) { | 870 void assignArgumentsToParameters(List<Constant> arguments) { |
873 // Assign arguments to parameters. | 871 // Assign arguments to parameters. |
874 FunctionSignature parameters = constructor.functionSignature; | 872 FunctionSignature signature = constructor.functionSignature; |
875 int index = 0; | 873 int index = 0; |
876 parameters.orderedForEachParameter((Element parameter) { | 874 signature.orderedForEachParameter((Element parameter) { |
877 Constant argument = arguments[index++]; | 875 Constant argument = arguments[index++]; |
878 Node node = parameter.parseNode(compiler); | 876 Node node = parameter.parseNode(compiler); |
879 potentiallyCheckType(node, parameter, argument); | 877 potentiallyCheckType(node, parameter, argument); |
880 definitions[parameter] = argument; | 878 definitions[parameter] = argument; |
881 if (parameter.kind == ElementKind.FIELD_PARAMETER) { | 879 if (parameter.kind == ElementKind.FIELD_PARAMETER) { |
882 FieldParameterElement fieldParameterElement = parameter; | 880 FieldParameterElement fieldParameterElement = parameter; |
883 updateFieldValue(node, fieldParameterElement.fieldElement, argument); | 881 updateFieldValue(node, fieldParameterElement.fieldElement, argument); |
884 } | 882 } |
885 }); | 883 }); |
886 } | 884 } |
887 | 885 |
888 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, | 886 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, |
889 FunctionElement targetConstructor) { | 887 FunctionElement targetConstructor) { |
890 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 888 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 889 constructedType.asInstanceOf(targetConstructor.getEnclosingClass()), |
891 targetConstructor, handler, compiler); | 890 targetConstructor, handler, compiler); |
892 evaluator.evaluateConstructorFieldValues(compiledArguments); | 891 evaluator.evaluateConstructorFieldValues(compiledArguments); |
893 // Copy over the fieldValues from the super/redirect-constructor. | 892 // Copy over the fieldValues from the super/redirect-constructor. |
894 // No need to go through [updateFieldValue] because the | 893 // No need to go through [updateFieldValue] because the |
895 // assignments have already been checked in checked mode. | 894 // assignments have already been checked in checked mode. |
896 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 895 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
897 } | 896 } |
898 | 897 |
899 /** | 898 /** |
900 * Runs through the initializers of the given [constructor] and updates | 899 * Runs through the initializers of the given [constructor] and updates |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 if (fieldValue == null) { | 989 if (fieldValue == null) { |
991 // Use the default value. | 990 // Use the default value. |
992 fieldValue = handler.compileConstant(field); | 991 fieldValue = handler.compileConstant(field); |
993 } | 992 } |
994 jsNewArguments.add(fieldValue); | 993 jsNewArguments.add(fieldValue); |
995 }, | 994 }, |
996 includeSuperAndInjectedMembers: true); | 995 includeSuperAndInjectedMembers: true); |
997 return jsNewArguments; | 996 return jsNewArguments; |
998 } | 997 } |
999 } | 998 } |
OLD | NEW |