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 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 | 437 |
438 AstConstant visitLiteralSymbol(LiteralSymbol node) { | 438 AstConstant visitLiteralSymbol(LiteralSymbol node) { |
439 InterfaceType type = compiler.symbolClass.rawType; | 439 InterfaceType type = compiler.symbolClass.rawType; |
440 String text = node.slowNameString; | 440 String text = node.slowNameString; |
441 List<AstConstant> arguments = | 441 List<AstConstant> arguments = |
442 <AstConstant>[new AstConstant(context, node, | 442 <AstConstant>[new AstConstant(context, node, |
443 new PrimitiveConstantExpression(constantSystem.createString( | 443 new PrimitiveConstantExpression(constantSystem.createString( |
444 new DartString.literal(text))))]; | 444 new DartString.literal(text))))]; |
445 AstConstant constant = makeConstructedConstant( | 445 AstConstant constant = makeConstructedConstant( |
446 compiler, handler, context, node, type, compiler.symbolConstructor, | 446 compiler, handler, context, node, type, compiler.symbolConstructor, |
447 new Selector.callConstructor('', null, 1), | 447 CallStructure.ONE_ARG, |
448 arguments, arguments); | 448 arguments, arguments); |
449 return new AstConstant( | 449 return new AstConstant( |
450 context, node, new SymbolConstantExpression(constant.value, text)); | 450 context, node, new SymbolConstantExpression(constant.value, text)); |
451 } | 451 } |
452 | 452 |
453 AstConstant makeTypeConstant(Node node, DartType elementType) { | 453 AstConstant makeTypeConstant(Node node, DartType elementType) { |
454 DartType constantType = | 454 DartType constantType = |
455 compiler.backend.typeImplementation.computeType(compiler); | 455 compiler.backend.typeImplementation.computeType(compiler); |
456 return new AstConstant( | 456 return new AstConstant( |
457 context, node, new TypeConstantExpression( | 457 context, node, new TypeConstantExpression( |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 | 645 |
646 /** | 646 /** |
647 * Returns the normalized list of constant arguments that are passed to the | 647 * Returns the normalized list of constant arguments that are passed to the |
648 * constructor including both the concrete arguments and default values for | 648 * constructor including both the concrete arguments and default values for |
649 * omitted optional arguments. | 649 * omitted optional arguments. |
650 * | 650 * |
651 * Invariant: [target] must be an implementation element. | 651 * Invariant: [target] must be an implementation element. |
652 */ | 652 */ |
653 List<AstConstant> evaluateArgumentsToConstructor( | 653 List<AstConstant> evaluateArgumentsToConstructor( |
654 Node node, | 654 Node node, |
655 Selector selector, | 655 CallStructure callStructure, |
656 Link<Node> arguments, | 656 Link<Node> arguments, |
657 FunctionElement target, | 657 FunctionElement target, |
658 {AstConstant compileArgument(Node node)}) { | 658 {AstConstant compileArgument(Node node)}) { |
659 assert(invariant(node, target.isImplementation)); | 659 assert(invariant(node, target.isImplementation)); |
660 | 660 |
661 AstConstant compileDefaultValue(VariableElement element) { | 661 AstConstant compileDefaultValue(VariableElement element) { |
662 ConstantExpression constant = handler.compileConstant(element); | 662 ConstantExpression constant = handler.compileConstant(element); |
663 return new AstConstant.fromDefaultValue(element, constant); | 663 return new AstConstant.fromDefaultValue(element, constant); |
664 } | 664 } |
665 target.computeSignature(compiler); | 665 target.computeSignature(compiler); |
666 | 666 |
667 if (!selector.applies(target, compiler.world)) { | 667 if (!callStructure.signatureApplies(target)) { |
668 String name = Elements.constructorNameForDiagnostics( | 668 String name = Elements.constructorNameForDiagnostics( |
669 target.enclosingClass.name, target.name); | 669 target.enclosingClass.name, target.name); |
670 compiler.reportError( | 670 compiler.reportError( |
671 node, | 671 node, |
672 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, | 672 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, |
673 {'constructorName': name}); | 673 {'constructorName': name}); |
674 | 674 |
675 return new List<AstConstant>.filled( | 675 return new List<AstConstant>.filled( |
676 target.functionSignature.parameterCount, | 676 target.functionSignature.parameterCount, |
677 new ErroneousAstConstant(context, node)); | 677 new ErroneousAstConstant(context, node)); |
678 } | 678 } |
679 return selector.makeArgumentsList(arguments, | 679 return callStructure.makeArgumentsList( |
680 target, | 680 arguments, |
681 compileArgument, | 681 target, |
682 compileDefaultValue); | 682 compileArgument, |
| 683 compileDefaultValue); |
683 } | 684 } |
684 | 685 |
685 AstConstant visitNewExpression(NewExpression node) { | 686 AstConstant visitNewExpression(NewExpression node) { |
686 if (!node.isConst) { | 687 if (!node.isConst) { |
687 return signalNotCompileTimeConstant(node); | 688 return signalNotCompileTimeConstant(node); |
688 } | 689 } |
689 | 690 |
690 Send send = node.send; | 691 Send send = node.send; |
691 FunctionElement constructor = elements[send]; | 692 FunctionElement constructor = elements[send]; |
692 if (Elements.isUnresolved(constructor)) { | 693 if (Elements.isUnresolved(constructor)) { |
693 return signalNotCompileTimeConstant(node); | 694 return signalNotCompileTimeConstant(node); |
694 } | 695 } |
695 | 696 |
696 // Deferred types can not be used in const instance creation expressions. | 697 // Deferred types can not be used in const instance creation expressions. |
697 // Check if the constructor comes from a deferred library. | 698 // Check if the constructor comes from a deferred library. |
698 if (isDeferredUse(node.send.selector.asSend())) { | 699 if (isDeferredUse(node.send.selector.asSend())) { |
699 return signalNotCompileTimeConstant(node, | 700 return signalNotCompileTimeConstant(node, |
700 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); | 701 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); |
701 } | 702 } |
702 | 703 |
703 // TODO(ahe): This is nasty: we must eagerly analyze the | 704 // TODO(ahe): This is nasty: we must eagerly analyze the |
704 // constructor to ensure the redirectionTarget has been computed | 705 // constructor to ensure the redirectionTarget has been computed |
705 // correctly. Find a way to avoid this. | 706 // correctly. Find a way to avoid this. |
706 compiler.analyzeElement(constructor.declaration); | 707 compiler.analyzeElement(constructor.declaration); |
707 | 708 |
708 InterfaceType type = elements.getType(node); | 709 InterfaceType type = elements.getType(node); |
709 Selector selector = elements.getSelector(send); | 710 CallStructure callStructure = elements.getSelector(send).callStructure; |
710 | 711 |
711 Map<Node, AstConstant> concreteArgumentMap = | 712 Map<Node, AstConstant> concreteArgumentMap = |
712 <Node, AstConstant>{}; | 713 <Node, AstConstant>{}; |
713 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) { | 714 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) { |
714 Node argument = link.head; | 715 Node argument = link.head; |
715 NamedArgument namedArgument = argument.asNamedArgument(); | 716 NamedArgument namedArgument = argument.asNamedArgument(); |
716 if (namedArgument != null) { | 717 if (namedArgument != null) { |
717 argument = namedArgument.expression; | 718 argument = namedArgument.expression; |
718 } | 719 } |
719 concreteArgumentMap[argument] = evaluateConstant(argument); | 720 concreteArgumentMap[argument] = evaluateConstant(argument); |
720 } | 721 } |
721 | 722 |
722 List<AstConstant> normalizedArguments = | 723 List<AstConstant> normalizedArguments = |
723 evaluateArgumentsToConstructor( | 724 evaluateArgumentsToConstructor( |
724 node, selector, send.arguments, constructor.implementation, | 725 node, callStructure, send.arguments, constructor.implementation, |
725 compileArgument: (node) => concreteArgumentMap[node]); | 726 compileArgument: (node) => concreteArgumentMap[node]); |
726 List<AstConstant> concreteArguments = | 727 List<AstConstant> concreteArguments = |
727 concreteArgumentMap.values.toList(); | 728 concreteArgumentMap.values.toList(); |
728 | 729 |
729 if (constructor == compiler.intEnvironment || | 730 if (constructor == compiler.intEnvironment || |
730 constructor == compiler.boolEnvironment || | 731 constructor == compiler.boolEnvironment || |
731 constructor == compiler.stringEnvironment) { | 732 constructor == compiler.stringEnvironment) { |
732 | 733 |
733 AstConstant createEvaluatedConstant(ConstantValue value) { | 734 AstConstant createEvaluatedConstant(ConstantValue value) { |
734 return new AstConstant( | 735 return new AstConstant( |
735 context, node, new ConstructedConstantExpression( | 736 context, node, new ConstructedConstantExpression( |
736 value, | 737 value, |
737 type, | 738 type, |
738 constructor, | 739 constructor, |
739 elements.getSelector(send), | 740 elements.getSelector(send).callStructure, |
740 concreteArguments.map((e) => e.expression).toList())); | 741 concreteArguments.map((e) => e.expression).toList())); |
741 } | 742 } |
742 | 743 |
743 var firstArgument = normalizedArguments[0].value; | 744 var firstArgument = normalizedArguments[0].value; |
744 ConstantValue defaultValue = normalizedArguments[1].value; | 745 ConstantValue defaultValue = normalizedArguments[1].value; |
745 | 746 |
746 if (firstArgument.isNull) { | 747 if (firstArgument.isNull) { |
747 compiler.reportError( | 748 compiler.reportError( |
748 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); | 749 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); |
749 return null; | 750 return null; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 return createEvaluatedConstant(defaultValue); | 805 return createEvaluatedConstant(defaultValue); |
805 } | 806 } |
806 } else { | 807 } else { |
807 assert(constructor == compiler.stringEnvironment); | 808 assert(constructor == compiler.stringEnvironment); |
808 return createEvaluatedConstant( | 809 return createEvaluatedConstant( |
809 constantSystem.createString(new DartString.literal(value))); | 810 constantSystem.createString(new DartString.literal(value))); |
810 } | 811 } |
811 } else { | 812 } else { |
812 return makeConstructedConstant( | 813 return makeConstructedConstant( |
813 compiler, handler, context, | 814 compiler, handler, context, |
814 node, type, constructor, selector, | 815 node, type, constructor, callStructure, |
815 concreteArguments, normalizedArguments); | 816 concreteArguments, normalizedArguments); |
816 } | 817 } |
817 } | 818 } |
818 | 819 |
819 static AstConstant makeConstructedConstant( | 820 static AstConstant makeConstructedConstant( |
820 Compiler compiler, | 821 Compiler compiler, |
821 ConstantCompilerBase handler, | 822 ConstantCompilerBase handler, |
822 Element context, | 823 Element context, |
823 Node node, | 824 Node node, |
824 InterfaceType type, | 825 InterfaceType type, |
825 ConstructorElement constructor, | 826 ConstructorElement constructor, |
826 Selector selector, | 827 CallStructure callStructure, |
827 List<AstConstant> concreteArguments, | 828 List<AstConstant> concreteArguments, |
828 List<AstConstant> normalizedArguments) { | 829 List<AstConstant> normalizedArguments) { |
829 assert(invariant(node, selector.applies(constructor, compiler.world) || | 830 assert(invariant(node, callStructure.signatureApplies(constructor) || |
830 compiler.compilationFailed, | 831 compiler.compilationFailed, |
831 message: "Selector $selector does not apply to constructor " | 832 message: "Call structure $callStructure does not apply to constructor " |
832 "$constructor.")); | 833 "$constructor.")); |
833 | 834 |
834 // The redirection chain of this element may not have been resolved through | 835 // The redirection chain of this element may not have been resolved through |
835 // a post-process action, so we have to make sure it is done here. | 836 // a post-process action, so we have to make sure it is done here. |
836 compiler.resolver.resolveRedirectionChain(constructor, node); | 837 compiler.resolver.resolveRedirectionChain(constructor, node); |
837 InterfaceType constructedType = | 838 InterfaceType constructedType = |
838 constructor.computeEffectiveTargetType(type); | 839 constructor.computeEffectiveTargetType(type); |
839 ConstructorElement target = constructor.effectiveTarget; | 840 ConstructorElement target = constructor.effectiveTarget; |
840 ClassElement classElement = target.enclosingClass; | 841 ClassElement classElement = target.enclosingClass; |
841 // The constructor must be an implementation to ensure that field | 842 // The constructor must be an implementation to ensure that field |
842 // initializers are handled correctly. | 843 // initializers are handled correctly. |
843 target = target.implementation; | 844 target = target.implementation; |
844 assert(invariant(node, target.isImplementation)); | 845 assert(invariant(node, target.isImplementation)); |
845 | 846 |
846 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 847 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
847 constructedType, target, handler, compiler); | 848 constructedType, target, handler, compiler); |
848 evaluator.evaluateConstructorFieldValues(normalizedArguments); | 849 evaluator.evaluateConstructorFieldValues(normalizedArguments); |
849 List<AstConstant> fieldConstants = | 850 List<AstConstant> fieldConstants = |
850 evaluator.buildFieldConstants(classElement); | 851 evaluator.buildFieldConstants(classElement); |
851 | 852 |
852 return new AstConstant( | 853 return new AstConstant( |
853 context, node, new ConstructedConstantExpression( | 854 context, node, new ConstructedConstantExpression( |
854 new ConstructedConstantValue( | 855 new ConstructedConstantValue( |
855 constructedType, | 856 constructedType, |
856 fieldConstants.map((e) => e.value).toList()), | 857 fieldConstants.map((e) => e.value).toList()), |
857 type, | 858 type, |
858 constructor, | 859 constructor, |
859 selector, | 860 callStructure, |
860 concreteArguments.map((e) => e.expression).toList())); | 861 concreteArguments.map((e) => e.expression).toList())); |
861 } | 862 } |
862 | 863 |
863 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { | 864 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
864 return node.expression.accept(this); | 865 return node.expression.accept(this); |
865 } | 866 } |
866 | 867 |
867 error(Node node, MessageKind message) { | 868 error(Node node, MessageKind message) { |
868 // TODO(floitsch): get the list of constants that are currently compiled | 869 // TODO(floitsch): get the list of constants that are currently compiled |
869 // and present some kind of stack-trace. | 870 // and present some kind of stack-trace. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
987 * Runs through the initializers of the given [constructor] and updates | 988 * Runs through the initializers of the given [constructor] and updates |
988 * the [fieldValues] map. | 989 * the [fieldValues] map. |
989 */ | 990 */ |
990 void evaluateConstructorInitializers() { | 991 void evaluateConstructorInitializers() { |
991 if (constructor.isSynthesized) { | 992 if (constructor.isSynthesized) { |
992 List<AstConstant> compiledArguments = <AstConstant>[]; | 993 List<AstConstant> compiledArguments = <AstConstant>[]; |
993 | 994 |
994 Function compileArgument = (element) => definitions[element]; | 995 Function compileArgument = (element) => definitions[element]; |
995 Function compileConstant = handler.compileConstant; | 996 Function compileConstant = handler.compileConstant; |
996 FunctionElement target = constructor.definingConstructor.implementation; | 997 FunctionElement target = constructor.definingConstructor.implementation; |
997 Selector.addForwardingElementArgumentsToList(constructor, | 998 CallStructure.addForwardingElementArgumentsToList( |
998 compiledArguments, | 999 constructor, |
999 target, | 1000 compiledArguments, |
1000 compileArgument, | 1001 target, |
1001 compileConstant, | 1002 compileArgument, |
1002 compiler.world); | 1003 compileConstant); |
1003 evaluateSuperOrRedirectSend(compiledArguments, target); | 1004 evaluateSuperOrRedirectSend(compiledArguments, target); |
1004 return; | 1005 return; |
1005 } | 1006 } |
1006 FunctionExpression functionNode = constructor.node; | 1007 FunctionExpression functionNode = constructor.node; |
1007 NodeList initializerList = functionNode.initializers; | 1008 NodeList initializerList = functionNode.initializers; |
1008 | 1009 |
1009 bool foundSuperOrRedirect = false; | 1010 bool foundSuperOrRedirect = false; |
1010 | 1011 |
1011 if (initializerList != null) { | 1012 if (initializerList != null) { |
1012 for (Link<Node> link = initializerList.nodes; | 1013 for (Link<Node> link = initializerList.nodes; |
1013 !link.isEmpty; | 1014 !link.isEmpty; |
1014 link = link.tail) { | 1015 link = link.tail) { |
1015 assert(link.head is Send); | 1016 assert(link.head is Send); |
1016 if (link.head is !SendSet) { | 1017 if (link.head is !SendSet) { |
1017 // A super initializer or constructor redirection. | 1018 // A super initializer or constructor redirection. |
1018 Send call = link.head; | 1019 Send call = link.head; |
1019 FunctionElement target = elements[call]; | 1020 FunctionElement target = elements[call]; |
1020 List<AstConstant> compiledArguments = | 1021 List<AstConstant> compiledArguments = |
1021 evaluateArgumentsToConstructor( | 1022 evaluateArgumentsToConstructor( |
1022 call, elements.getSelector(call), call.arguments, target, | 1023 call, elements.getSelector(call).callStructure, |
| 1024 call.arguments, target, |
1023 compileArgument: evaluateConstant); | 1025 compileArgument: evaluateConstant); |
1024 evaluateSuperOrRedirectSend(compiledArguments, target); | 1026 evaluateSuperOrRedirectSend(compiledArguments, target); |
1025 foundSuperOrRedirect = true; | 1027 foundSuperOrRedirect = true; |
1026 } else { | 1028 } else { |
1027 // A field initializer. | 1029 // A field initializer. |
1028 SendSet init = link.head; | 1030 SendSet init = link.head; |
1029 Link<Node> initArguments = init.arguments; | 1031 Link<Node> initArguments = init.arguments; |
1030 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); | 1032 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); |
1031 AstConstant fieldValue = evaluate(initArguments.head); | 1033 AstConstant fieldValue = evaluate(initArguments.head); |
1032 updateFieldValue(init, elements[init], fieldValue); | 1034 updateFieldValue(init, elements[init], fieldValue); |
1033 } | 1035 } |
1034 } | 1036 } |
1035 } | 1037 } |
1036 | 1038 |
1037 if (!foundSuperOrRedirect) { | 1039 if (!foundSuperOrRedirect) { |
1038 // No super initializer found. Try to find the default constructor if | 1040 // No super initializer found. Try to find the default constructor if |
1039 // the class is not Object. | 1041 // the class is not Object. |
1040 ClassElement enclosingClass = constructor.enclosingClass; | 1042 ClassElement enclosingClass = constructor.enclosingClass; |
1041 ClassElement superClass = enclosingClass.superclass; | 1043 ClassElement superClass = enclosingClass.superclass; |
1042 if (enclosingClass != compiler.objectClass) { | 1044 if (enclosingClass != compiler.objectClass) { |
1043 assert(superClass != null); | 1045 assert(superClass != null); |
1044 assert(superClass.resolutionState == STATE_DONE); | 1046 assert(superClass.resolutionState == STATE_DONE); |
1045 | 1047 |
1046 FunctionElement targetConstructor = | 1048 FunctionElement targetConstructor = |
1047 superClass.lookupDefaultConstructor(); | 1049 superClass.lookupDefaultConstructor(); |
1048 // If we do not find a default constructor, an error was reported | 1050 // If we do not find a default constructor, an error was reported |
1049 // already and compilation will fail anyway. So just ignore that case. | 1051 // already and compilation will fail anyway. So just ignore that case. |
1050 if (targetConstructor != null) { | 1052 if (targetConstructor != null) { |
1051 Selector selector = new Selector.callDefaultConstructor(); | |
1052 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( | 1053 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( |
1053 functionNode, selector, const Link<Node>(), targetConstructor); | 1054 functionNode, CallStructure.NO_ARGS, |
| 1055 const Link<Node>(), targetConstructor); |
1054 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); | 1056 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); |
1055 } | 1057 } |
1056 } | 1058 } |
1057 } | 1059 } |
1058 } | 1060 } |
1059 | 1061 |
1060 /** | 1062 /** |
1061 * Simulates the execution of the [constructor] with the given | 1063 * Simulates the execution of the [constructor] with the given |
1062 * [arguments] to obtain the field values that need to be passed to the | 1064 * [arguments] to obtain the field values that need to be passed to the |
1063 * native JavaScript constructor. | 1065 * native JavaScript constructor. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1117 ConstantValue get value => expression.value; | 1119 ConstantValue get value => expression.value; |
1118 | 1120 |
1119 String toString() => expression.toString(); | 1121 String toString() => expression.toString(); |
1120 } | 1122 } |
1121 | 1123 |
1122 /// A synthetic constant used to recover from errors. | 1124 /// A synthetic constant used to recover from errors. |
1123 class ErroneousAstConstant extends AstConstant { | 1125 class ErroneousAstConstant extends AstConstant { |
1124 ErroneousAstConstant(Element element, Node node) | 1126 ErroneousAstConstant(Element element, Node node) |
1125 : super(element, node, new ErroneousConstantExpression()); | 1127 : super(element, node, new ErroneousConstantExpression()); |
1126 } | 1128 } |
OLD | NEW |