| 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 class Constant implements Hashable { | 5 class Constant implements Hashable { |
| 6 const Constant(); | 6 const Constant(); |
| 7 | 7 |
| 8 bool isNull() => false; | 8 bool isNull() => false; |
| 9 bool isBool() => false; | 9 bool isBool() => false; |
| 10 bool isTrue() => false; | 10 bool isTrue() => false; |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 int hashCode() => _hashCode; | 527 int hashCode() => _hashCode; |
| 528 List<Constant> getDependencies() => fields; | 528 List<Constant> getDependencies() => fields; |
| 529 } | 529 } |
| 530 | 530 |
| 531 /** | 531 /** |
| 532 * The [ConstantHandler] keeps track of compile-time constants, | 532 * The [ConstantHandler] keeps track of compile-time constants, |
| 533 * initializations of global and static fields, and default values of | 533 * initializations of global and static fields, and default values of |
| 534 * optional parameters. | 534 * optional parameters. |
| 535 */ | 535 */ |
| 536 class ConstantHandler extends CompilerTask { | 536 class ConstantHandler extends CompilerTask { |
| 537 // Contains the initial value of fields. Must contain all static and global | 537 /** |
| 538 // initializations of used fields. May contain caches for instance fields. | 538 * Contains the initial value of fields. Must contain all static and global |
| 539 * initializations of const fields. May contain eagerly compiled values for |
| 540 * statics and instance fields. |
| 541 */ |
| 539 final Map<VariableElement, Constant> initialVariableValues; | 542 final Map<VariableElement, Constant> initialVariableValues; |
| 540 | 543 |
| 541 // Map from compile-time constants to their JS name. | 544 /** Map from compile-time constants to their JS name. */ |
| 542 final Map<Constant, String> compiledConstants; | 545 final Map<Constant, String> compiledConstants; |
| 543 | 546 |
| 544 // The set of variable elements that are in the process of being computed. | 547 /** The set of variable elements that are in the process of being computed. */ |
| 545 final Set<VariableElement> pendingVariables; | 548 final Set<VariableElement> pendingVariables; |
| 546 | 549 |
| 550 /** Caches the statics where the initial value cannot be eagerly compiled. */ |
| 551 final Set<VariableElement> lazyStatics; |
| 552 |
| 553 |
| 547 ConstantHandler(Compiler compiler) | 554 ConstantHandler(Compiler compiler) |
| 548 : initialVariableValues = new Map<VariableElement, Dynamic>(), | 555 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
| 549 compiledConstants = new Map<Constant, String>(), | 556 compiledConstants = new Map<Constant, String>(), |
| 550 pendingVariables = new Set<VariableElement>(), | 557 pendingVariables = new Set<VariableElement>(), |
| 558 lazyStatics = new Set<VariableElement>(), |
| 551 super(compiler); | 559 super(compiler); |
| 552 String get name => 'ConstantHandler'; | 560 String get name => 'ConstantHandler'; |
| 553 | 561 |
| 554 void registerCompileTimeConstant(Constant constant) { | 562 void registerCompileTimeConstant(Constant constant) { |
| 555 Function ifAbsentThunk = (() { | 563 Function ifAbsentThunk = (() { |
| 556 return constant.isFunction() | 564 return constant.isFunction() |
| 557 ? null : compiler.namer.getFreshGlobalName("CTC"); | 565 ? null : compiler.namer.getFreshGlobalName("CTC"); |
| 558 }); | 566 }); |
| 559 compiledConstants.putIfAbsent(constant, ifAbsentThunk); | 567 compiledConstants.putIfAbsent(constant, ifAbsentThunk); |
| 560 } | 568 } |
| 561 | 569 |
| 562 /** | 570 /** |
| 563 * Compiles the initial value of the given field and stores it in an internal | 571 * Compiles the initial value of the given field and stores it in an internal |
| 564 * map. | 572 * map. Returns the initial value (a constant) if it can be computed |
| 573 * statically. Returns [:null:] if the variable must be initialized lazily. |
| 565 * | 574 * |
| 566 * [WorkItem] must contain a [VariableElement] refering to a global or | 575 * [WorkItem] must contain a [VariableElement] refering to a global or |
| 567 * static field. | 576 * static field. |
| 568 */ | 577 */ |
| 569 void compileWorkItem(WorkItem work) { | 578 Constant compileWorkItem(WorkItem work) { |
| 570 measure(() { | 579 return measure(() { |
| 571 assert(work.element.kind == ElementKind.FIELD | 580 assert(work.element.kind == ElementKind.FIELD |
| 572 || work.element.kind == ElementKind.PARAMETER | 581 || work.element.kind == ElementKind.PARAMETER |
| 573 || work.element.kind == ElementKind.FIELD_PARAMETER); | 582 || work.element.kind == ElementKind.FIELD_PARAMETER); |
| 574 VariableElement element = work.element; | 583 VariableElement element = work.element; |
| 575 // Shortcut if it has already been compiled. | 584 // Shortcut if it has already been compiled. |
| 576 if (initialVariableValues.containsKey(element)) return; | 585 Constant result = initialVariableValues[element]; |
| 577 compileVariableWithDefinitions(element, work.resolutionTree); | 586 if (result != null) return result; |
| 587 if (lazyStatics.contains(element)) return null; |
| 588 result = compileVariableWithDefinitions(element, work.resolutionTree); |
| 578 assert(pendingVariables.isEmpty()); | 589 assert(pendingVariables.isEmpty()); |
| 590 return result; |
| 579 }); | 591 }); |
| 580 } | 592 } |
| 581 | 593 |
| 582 Constant compileVariable(VariableElement element) { | 594 /** |
| 595 * Returns a compile-time constant, or reports an error if the element is not |
| 596 * a compile-time constant. |
| 597 */ |
| 598 Constant compileConstant(VariableElement element) { |
| 599 return compileVariable(element, isConst: true); |
| 600 } |
| 601 |
| 602 /** |
| 603 * Returns the a compile-time constant if the variable could be compiled |
| 604 * eagerly. Otherwise returns `null`. |
| 605 */ |
| 606 Constant compileVariable(VariableElement element, [bool isConst = false]) { |
| 583 return measure(() { | 607 return measure(() { |
| 584 if (initialVariableValues.containsKey(element)) { | 608 if (initialVariableValues.containsKey(element)) { |
| 585 Constant result = initialVariableValues[element]; | 609 Constant result = initialVariableValues[element]; |
| 586 return result; | 610 return result; |
| 587 } | 611 } |
| 588 TreeElements definitions = compiler.analyzeElement(element); | 612 TreeElements definitions = compiler.analyzeElement(element); |
| 589 Constant constant = compileVariableWithDefinitions(element, definitions); | 613 Constant constant = compileVariableWithDefinitions( |
| 614 element, definitions, isConst: isConst); |
| 590 return constant; | 615 return constant; |
| 591 }); | 616 }); |
| 592 } | 617 } |
| 593 | 618 |
| 619 /** |
| 620 * Returns the a compile-time constant if the variable could be compiled |
| 621 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 622 * If the variable is `const` but cannot be compiled eagerly reports an |
| 623 * error. |
| 624 */ |
| 594 Constant compileVariableWithDefinitions(VariableElement element, | 625 Constant compileVariableWithDefinitions(VariableElement element, |
| 595 TreeElements definitions) { | 626 TreeElements definitions, |
| 627 [bool isConst = false]) { |
| 596 return measure(() { | 628 return measure(() { |
| 629 // Initializers for parameters must be const. |
| 630 isConst = isConst || element.modifiers.isConst() |
| 631 || !Elements.isStaticOrTopLevel(element); |
| 632 if (!isConst && lazyStatics.contains(element)) return null; |
| 633 |
| 597 Node node = element.parseNode(compiler); | 634 Node node = element.parseNode(compiler); |
| 598 if (pendingVariables.contains(element)) { | 635 if (pendingVariables.contains(element)) { |
| 599 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; | 636 if (isConst) { |
| 600 compiler.reportError(node, | 637 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; |
| 601 new CompileTimeConstantError(kind, const [])); | 638 compiler.reportError(node, |
| 639 new CompileTimeConstantError(kind, const [])); |
| 640 } else { |
| 641 lazyStatics.add(element); |
| 642 return null; |
| 643 } |
| 602 } | 644 } |
| 603 pendingVariables.add(element); | 645 pendingVariables.add(element); |
| 604 | 646 |
| 605 SendSet assignment = node.asSendSet(); | 647 SendSet assignment = node.asSendSet(); |
| 606 Constant value; | 648 Constant value; |
| 607 if (assignment === null) { | 649 if (assignment === null) { |
| 608 // No initial value. | 650 // No initial value. |
| 609 value = new NullConstant(); | 651 value = new NullConstant(); |
| 610 } else { | 652 } else { |
| 611 Node right = assignment.arguments.head; | 653 Node right = assignment.arguments.head; |
| 612 value = compileNodeWithDefinitions(right, definitions); | 654 value = |
| 655 compileNodeWithDefinitions(right, definitions, isConst: isConst); |
| 613 } | 656 } |
| 614 initialVariableValues[element] = value; | 657 if (value != null) { |
| 658 initialVariableValues[element] = value; |
| 659 } else { |
| 660 assert(!isConst); |
| 661 lazyStatics.add(element); |
| 662 } |
| 615 pendingVariables.remove(element); | 663 pendingVariables.remove(element); |
| 616 return value; | 664 return value; |
| 617 }); | 665 }); |
| 618 } | 666 } |
| 619 | 667 |
| 620 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { | 668 Constant compileNodeWithDefinitions(Node node, |
| 669 TreeElements definitions, |
| 670 [bool isConst]) { |
| 621 return measure(() { | 671 return measure(() { |
| 622 assert(node !== null); | 672 assert(node !== null); |
| 623 CompileTimeConstantEvaluator evaluator = | 673 CompileTimeConstantEvaluator evaluator = |
| 624 new CompileTimeConstantEvaluator(definitions, compiler); | 674 new CompileTimeConstantEvaluator(definitions, compiler, isConst); |
| 625 return evaluator.evaluate(node); | 675 return evaluator.evaluate(node); |
| 626 }); | 676 }); |
| 627 } | 677 } |
| 628 | 678 |
| 629 /** Attempts to compile a constant expression. Returns null if not possible */ | 679 /** Attempts to compile a constant expression. Returns null if not possible */ |
| 630 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { | 680 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 631 return measure(() { | 681 return measure(() { |
| 632 assert(node !== null); | 682 assert(node !== null); |
| 633 try { | 683 try { |
| 634 TryCompileTimeConstantEvaluator evaluator = | 684 TryCompileTimeConstantEvaluator evaluator = |
| (...skipping 24 matching lines...) Expand all Loading... |
| 659 * other. | 709 * other. |
| 660 */ | 710 */ |
| 661 List<VariableElement> getStaticFinalFieldsForEmission() { | 711 List<VariableElement> getStaticFinalFieldsForEmission() { |
| 662 return initialVariableValues.getKeys().filter((element) { | 712 return initialVariableValues.getKeys().filter((element) { |
| 663 return element.kind == ElementKind.FIELD | 713 return element.kind == ElementKind.FIELD |
| 664 && !element.isInstanceMember() | 714 && !element.isInstanceMember() |
| 665 && element.modifiers.isFinal(); | 715 && element.modifiers.isFinal(); |
| 666 }); | 716 }); |
| 667 } | 717 } |
| 668 | 718 |
| 719 List<VariableElement> getLazilyInitializedFieldsForEmission() { |
| 720 return new List<VariableElement>.from(lazyStatics); |
| 721 } |
| 722 |
| 669 List<Constant> getConstantsForEmission() { | 723 List<Constant> getConstantsForEmission() { |
| 670 // We must emit dependencies before their uses. | 724 // We must emit dependencies before their uses. |
| 671 Set<Constant> seenConstants = new Set<Constant>(); | 725 Set<Constant> seenConstants = new Set<Constant>(); |
| 672 List<Constant> result = new List<Constant>(); | 726 List<Constant> result = new List<Constant>(); |
| 673 | 727 |
| 674 void addConstant(Constant constant) { | 728 void addConstant(Constant constant) { |
| 675 if (!seenConstants.contains(constant)) { | 729 if (!seenConstants.contains(constant)) { |
| 676 constant.getDependencies().forEach(addConstant); | 730 constant.getDependencies().forEach(addConstant); |
| 677 assert(!seenConstants.contains(constant)); | 731 assert(!seenConstants.contains(constant)); |
| 678 result.add(constant); | 732 result.add(constant); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 } | 816 } |
| 763 } | 817 } |
| 764 } | 818 } |
| 765 | 819 |
| 766 String getJsConstructor(ClassElement element) { | 820 String getJsConstructor(ClassElement element) { |
| 767 return compiler.namer.isolatePropertiesAccess(element); | 821 return compiler.namer.isolatePropertiesAccess(element); |
| 768 } | 822 } |
| 769 } | 823 } |
| 770 | 824 |
| 771 class CompileTimeConstantEvaluator extends AbstractVisitor { | 825 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 826 bool isEvaluatingConstant; |
| 772 final TreeElements elements; | 827 final TreeElements elements; |
| 773 final Compiler compiler; | 828 final Compiler compiler; |
| 774 | 829 |
| 775 CompileTimeConstantEvaluator(this.elements, this.compiler); | 830 CompileTimeConstantEvaluator(this.elements, this.compiler, [bool isConst]) |
| 831 : this.isEvaluatingConstant = isConst; |
| 776 | 832 |
| 777 Constant evaluate(Node node) { | 833 Constant evaluate(Node node) { |
| 778 return node.accept(this); | 834 return node.accept(this); |
| 779 } | 835 } |
| 780 | 836 |
| 781 visitNode(Node node) { | 837 Constant evaluateConstant(Node node) { |
| 782 error(node); | 838 bool oldIsEvaluatingConstant = isEvaluatingConstant; |
| 839 isEvaluatingConstant = true; |
| 840 Constant result = node.accept(this); |
| 841 isEvaluatingConstant = oldIsEvaluatingConstant; |
| 842 assert(result != null); |
| 843 return result; |
| 844 } |
| 845 |
| 846 Constant visitNode(Node node) { |
| 847 return signalNotCompileTimeConstant(node); |
| 783 } | 848 } |
| 784 | 849 |
| 785 Constant visitLiteralBool(LiteralBool node) { | 850 Constant visitLiteralBool(LiteralBool node) { |
| 786 return new BoolConstant(node.value); | 851 return new BoolConstant(node.value); |
| 787 } | 852 } |
| 788 | 853 |
| 789 Constant visitLiteralDouble(LiteralDouble node) { | 854 Constant visitLiteralDouble(LiteralDouble node) { |
| 790 return new DoubleConstant(node.value); | 855 return new DoubleConstant(node.value); |
| 791 } | 856 } |
| 792 | 857 |
| 793 Constant visitLiteralInt(LiteralInt node) { | 858 Constant visitLiteralInt(LiteralInt node) { |
| 794 return new IntConstant(node.value); | 859 return new IntConstant(node.value); |
| 795 } | 860 } |
| 796 | 861 |
| 797 Constant visitLiteralList(LiteralList node) { | 862 Constant visitLiteralList(LiteralList node) { |
| 798 if (!node.isConst()) error(node); | 863 if (!node.isConst()) { |
| 864 return signalNotCompileTimeConstant(node); |
| 865 } |
| 799 List<Constant> arguments = <Constant>[]; | 866 List<Constant> arguments = <Constant>[]; |
| 800 for (Link<Node> link = node.elements.nodes; | 867 for (Link<Node> link = node.elements.nodes; |
| 801 !link.isEmpty(); | 868 !link.isEmpty(); |
| 802 link = link.tail) { | 869 link = link.tail) { |
| 803 arguments.add(evaluate(link.head)); | 870 arguments.add(evaluateConstant(link.head)); |
| 804 } | 871 } |
| 805 // TODO(floitsch): get type from somewhere. | 872 // TODO(floitsch): get type from somewhere. |
| 806 DartType type = null; | 873 DartType type = null; |
| 807 Constant constant = new ListConstant(type, arguments); | 874 Constant constant = new ListConstant(type, arguments); |
| 808 compiler.constantHandler.registerCompileTimeConstant(constant); | 875 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 809 return constant; | 876 return constant; |
| 810 } | 877 } |
| 811 | 878 |
| 812 Constant visitLiteralMap(LiteralMap node) { | 879 Constant visitLiteralMap(LiteralMap node) { |
| 813 if (!node.isConst()) error(node); | 880 if (!node.isConst()) { |
| 881 signalNotCompileTimeConstant(node); |
| 882 error(node); |
| 883 } |
| 814 List<StringConstant> keys = <StringConstant>[]; | 884 List<StringConstant> keys = <StringConstant>[]; |
| 815 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); | 885 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 816 for (Link<Node> link = node.entries.nodes; | 886 for (Link<Node> link = node.entries.nodes; |
| 817 !link.isEmpty(); | 887 !link.isEmpty(); |
| 818 link = link.tail) { | 888 link = link.tail) { |
| 819 LiteralMapEntry entry = link.head; | 889 LiteralMapEntry entry = link.head; |
| 820 Constant key = evaluate(entry.key); | 890 Constant key = evaluateConstant(entry.key); |
| 821 if (!key.isString() || entry.key.asStringNode() === null) { | 891 if (!key.isString() || entry.key.asStringNode() === null) { |
| 822 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 892 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
| 823 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 893 compiler.reportError(entry.key, new ResolutionError(kind, const [])); |
| 824 } | 894 } |
| 825 StringConstant keyConstant = key; | 895 StringConstant keyConstant = key; |
| 826 if (!map.containsKey(key)) keys.add(key); | 896 if (!map.containsKey(key)) keys.add(key); |
| 827 map[key] = evaluate(entry.value); | 897 map[key] = evaluateConstant(entry.value); |
| 828 } | 898 } |
| 829 List<Constant> values = <Constant>[]; | 899 List<Constant> values = <Constant>[]; |
| 830 Constant protoValue = null; | 900 Constant protoValue = null; |
| 831 for (StringConstant key in keys) { | 901 for (StringConstant key in keys) { |
| 832 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { | 902 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { |
| 833 protoValue = map[key]; | 903 protoValue = map[key]; |
| 834 } else { | 904 } else { |
| 835 values.add(map[key]); | 905 values.add(map[key]); |
| 836 } | 906 } |
| 837 } | 907 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 857 return new NullConstant(); | 927 return new NullConstant(); |
| 858 } | 928 } |
| 859 | 929 |
| 860 Constant visitLiteralString(LiteralString node) { | 930 Constant visitLiteralString(LiteralString node) { |
| 861 return new StringConstant(node.dartString, node); | 931 return new StringConstant(node.dartString, node); |
| 862 } | 932 } |
| 863 | 933 |
| 864 Constant visitStringJuxtaposition(StringJuxtaposition node) { | 934 Constant visitStringJuxtaposition(StringJuxtaposition node) { |
| 865 StringConstant left = evaluate(node.first); | 935 StringConstant left = evaluate(node.first); |
| 866 StringConstant right = evaluate(node.second); | 936 StringConstant right = evaluate(node.second); |
| 937 if (left == null || right == null) return null; |
| 867 return new StringConstant(new DartString.concat(left.value, right.value), | 938 return new StringConstant(new DartString.concat(left.value, right.value), |
| 868 node); | 939 node); |
| 869 } | 940 } |
| 870 | 941 |
| 871 Constant visitStringInterpolation(StringInterpolation node) { | 942 Constant visitStringInterpolation(StringInterpolation node) { |
| 872 StringConstant initialString = evaluate(node.string); | 943 StringConstant initialString = evaluate(node.string); |
| 944 if (initialString == null) return null; |
| 873 DartString accumulator = initialString.value; | 945 DartString accumulator = initialString.value; |
| 874 for (StringInterpolationPart part in node.parts) { | 946 for (StringInterpolationPart part in node.parts) { |
| 875 Constant expression = evaluate(part.expression); | 947 Constant expression = evaluate(part.expression); |
| 876 DartString expressionString; | 948 DartString expressionString; |
| 877 if (expression.isNum() || expression.isBool()) { | 949 if (expression.isNum() || expression.isBool()) { |
| 878 PrimitiveConstant primitive = expression; | 950 PrimitiveConstant primitive = expression; |
| 879 expressionString = new DartString.literal(primitive.value.toString()); | 951 expressionString = new DartString.literal(primitive.value.toString()); |
| 880 } else if (expression.isString()) { | 952 } else if (expression.isString()) { |
| 881 PrimitiveConstant primitive = expression; | 953 PrimitiveConstant primitive = expression; |
| 882 expressionString = primitive.value; | 954 expressionString = primitive.value; |
| 883 } else { | 955 } else { |
| 884 error(part.expression); | 956 return signalNotCompileTimeConstant(part.expression); |
| 885 } | 957 } |
| 886 accumulator = new DartString.concat(accumulator, expressionString); | 958 accumulator = new DartString.concat(accumulator, expressionString); |
| 887 StringConstant partString = evaluate(part.string); | 959 StringConstant partString = evaluate(part.string); |
| 960 if (partString == null) return null; |
| 888 accumulator = new DartString.concat(accumulator, partString.value); | 961 accumulator = new DartString.concat(accumulator, partString.value); |
| 889 }; | 962 }; |
| 890 return new StringConstant(accumulator, node); | 963 return new StringConstant(accumulator, node); |
| 891 } | 964 } |
| 892 | 965 |
| 893 // TODO(floitsch): provide better error-messages. | 966 // TODO(floitsch): provide better error-messages. |
| 894 Constant visitSend(Send send) { | 967 Constant visitSend(Send send) { |
| 895 Element element = elements[send]; | 968 Element element = elements[send]; |
| 896 if (Elements.isStaticOrTopLevelField(element)) { | 969 if (Elements.isStaticOrTopLevelField(element)) { |
| 897 if (element.modifiers === null || | 970 Constant result; |
| 898 // TODO(johnniwinther): This should eventually be [isConst]. | 971 if (element.modifiers !== null) { |
| 899 !element.modifiers.isFinalOrConst()) { | 972 if (element.modifiers.isConst()) { |
| 900 error(send); | 973 result = compiler.compileConstant(element); |
| 974 } else if (element.modifiers.isFinal()) { |
| 975 // TODO(4516): remove support for final compile-time constants: if |
| 976 // isCompilingConstant is true don't compile the variable. |
| 977 result = compiler.compileVariable(element); |
| 978 } |
| 901 } | 979 } |
| 902 return compiler.compileVariable(element); | 980 if (result == null) return signalNotCompileTimeConstant(send); |
| 981 return result; |
| 903 } else if (Elements.isStaticOrTopLevelFunction(element) | 982 } else if (Elements.isStaticOrTopLevelFunction(element) |
| 904 && send.isPropertyAccess) { | 983 && send.isPropertyAccess) { |
| 905 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); | 984 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); |
| 906 Constant constant = new FunctionConstant(element); | 985 Constant constant = new FunctionConstant(element); |
| 907 compiler.constantHandler.registerCompileTimeConstant(constant); | 986 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 908 return constant; | 987 return constant; |
| 909 } else if (send.isPrefix) { | 988 } else if (send.isPrefix) { |
| 910 assert(send.isOperator); | 989 assert(send.isOperator); |
| 911 Constant receiverConstant = evaluate(send.receiver); | 990 Constant receiverConstant = evaluate(send.receiver); |
| 991 if (receiverConstant == null) return null; |
| 912 Operator op = send.selector; | 992 Operator op = send.selector; |
| 913 Constant folded; | 993 Constant folded; |
| 914 switch (op.source.stringValue) { | 994 switch (op.source.stringValue) { |
| 915 case "!": | 995 case "!": |
| 916 folded = const NotOperation().fold(receiverConstant); | 996 folded = const NotOperation().fold(receiverConstant); |
| 917 break; | 997 break; |
| 918 case "-": | 998 case "-": |
| 919 folded = const NegateOperation().fold(receiverConstant); | 999 folded = const NegateOperation().fold(receiverConstant); |
| 920 break; | 1000 break; |
| 921 case "~": | 1001 case "~": |
| 922 folded = const BitNotOperation().fold(receiverConstant); | 1002 folded = const BitNotOperation().fold(receiverConstant); |
| 923 break; | 1003 break; |
| 924 default: | 1004 default: |
| 925 compiler.internalError("Unexpected operator.", node: op); | 1005 compiler.internalError("Unexpected operator.", node: op); |
| 926 break; | 1006 break; |
| 927 } | 1007 } |
| 928 if (folded === null) error(send); | 1008 if (folded === null) return signalNotCompileTimeConstant(send); |
| 929 return folded; | 1009 return folded; |
| 930 } else if (send.isOperator && !send.isPostfix) { | 1010 } else if (send.isOperator && !send.isPostfix) { |
| 931 assert(send.argumentCount() == 1); | 1011 assert(send.argumentCount() == 1); |
| 932 Constant left = evaluate(send.receiver); | 1012 Constant left = evaluate(send.receiver); |
| 933 Constant right = evaluate(send.argumentsNode.nodes.head); | 1013 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 1014 if (left == null || right == null) return null; |
| 934 Operator op = send.selector.asOperator(); | 1015 Operator op = send.selector.asOperator(); |
| 935 Constant folded = null; | 1016 Constant folded = null; |
| 936 switch (op.source.stringValue) { | 1017 switch (op.source.stringValue) { |
| 937 case "+": | 1018 case "+": |
| 938 folded = const AddOperation().fold(left, right); | 1019 folded = const AddOperation().fold(left, right); |
| 939 break; | 1020 break; |
| 940 case "-": | 1021 case "-": |
| 941 folded = const SubtractOperation().fold(left, right); | 1022 folded = const SubtractOperation().fold(left, right); |
| 942 break; | 1023 break; |
| 943 case "*": | 1024 case "*": |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 BoolConstant areIdentical = | 1091 BoolConstant areIdentical = |
| 1011 const IdentityOperation().fold(left, right); | 1092 const IdentityOperation().fold(left, right); |
| 1012 if (areIdentical === null) { | 1093 if (areIdentical === null) { |
| 1013 folded = null; | 1094 folded = null; |
| 1014 } else { | 1095 } else { |
| 1015 folded = areIdentical.negate(); | 1096 folded = areIdentical.negate(); |
| 1016 } | 1097 } |
| 1017 } | 1098 } |
| 1018 break; | 1099 break; |
| 1019 } | 1100 } |
| 1020 if (folded === null) error(send); | 1101 if (folded === null) return signalNotCompileTimeConstant(send); |
| 1021 return folded; | 1102 return folded; |
| 1022 } | 1103 } |
| 1023 return super.visitSend(send); | 1104 return signalNotCompileTimeConstant(send); |
| 1024 } | 1105 } |
| 1025 | 1106 |
| 1026 visitSendSet(SendSet node) { | 1107 Constant visitSendSet(SendSet node) { |
| 1027 error(node); | 1108 return signalNotCompileTimeConstant(node); |
| 1028 } | 1109 } |
| 1029 | 1110 |
| 1030 /** Returns the list of constants that are passed to the static function. */ | 1111 /** Returns the list of constants that are passed to the static function. */ |
| 1031 List<Constant> evaluateArgumentsToConstructor(Selector selector, | 1112 List<Constant> evaluateArgumentsToConstructor(Selector selector, |
| 1032 Link<Node> arguments, | 1113 Link<Node> arguments, |
| 1033 FunctionElement target) { | 1114 FunctionElement target) { |
| 1034 List<Constant> compiledArguments = <Constant>[]; | 1115 List<Constant> compiledArguments = <Constant>[]; |
| 1035 | 1116 |
| 1036 Function compileArgument = evaluate; | 1117 Function compileArgument = evaluateConstant; |
| 1037 Function compileConstant = compiler.compileVariable; | 1118 Function compileConstant = compiler.compileConstant; |
| 1038 bool succeeded = selector.addArgumentsToList(arguments, | 1119 bool succeeded = selector.addArgumentsToList(arguments, |
| 1039 compiledArguments, | 1120 compiledArguments, |
| 1040 target, | 1121 target, |
| 1041 compileArgument, | 1122 compileArgument, |
| 1042 compileConstant, | 1123 compileConstant, |
| 1043 compiler); | 1124 compiler); |
| 1044 assert(succeeded); | 1125 assert(succeeded); |
| 1045 return compiledArguments; | 1126 return compiledArguments; |
| 1046 } | 1127 } |
| 1047 | 1128 |
| 1048 Constant visitNewExpression(NewExpression node) { | 1129 Constant visitNewExpression(NewExpression node) { |
| 1049 if (!node.isConst()) error(node); | 1130 if (!node.isConst()) { |
| 1131 return signalNotCompileTimeConstant(node); |
| 1132 } |
| 1050 | 1133 |
| 1051 Send send = node.send; | 1134 Send send = node.send; |
| 1052 FunctionElement constructor = elements[send]; | 1135 FunctionElement constructor = elements[send]; |
| 1053 ClassElement classElement = constructor.getEnclosingClass(); | 1136 ClassElement classElement = constructor.getEnclosingClass(); |
| 1054 if (classElement.isInterface()) { | 1137 if (classElement.isInterface()) { |
| 1055 compiler.resolver.resolveMethodElement(constructor); | 1138 compiler.resolver.resolveMethodElement(constructor); |
| 1056 constructor = constructor.defaultImplementation; | 1139 constructor = constructor.defaultImplementation; |
| 1057 classElement = constructor.getEnclosingClass(); | 1140 classElement = constructor.getEnclosingClass(); |
| 1058 } | 1141 } |
| 1059 | 1142 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1076 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 1159 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1077 return node.expression.accept(this); | 1160 return node.expression.accept(this); |
| 1078 } | 1161 } |
| 1079 | 1162 |
| 1080 error(Node node) { | 1163 error(Node node) { |
| 1081 // TODO(floitsch): get the list of constants that are currently compiled | 1164 // TODO(floitsch): get the list of constants that are currently compiled |
| 1082 // and present some kind of stack-trace. | 1165 // and present some kind of stack-trace. |
| 1083 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1166 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1084 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1167 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1085 } | 1168 } |
| 1169 |
| 1170 Constant signalNotCompileTimeConstant(Node node) { |
| 1171 if (isEvaluatingConstant) { |
| 1172 error(node); |
| 1173 } |
| 1174 // Else we don't need to do anything. The final handler is only |
| 1175 // optimistically trying to compile constants. So it is normal that we |
| 1176 // sometimes see non-compile time constants. |
| 1177 // Simply return [:null:] which is used to propagate a failing |
| 1178 // compile-time compilation. |
| 1179 return null; |
| 1180 } |
| 1086 } | 1181 } |
| 1087 | 1182 |
| 1088 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 1183 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 1089 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): | 1184 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): |
| 1090 super(elements, compiler); | 1185 super(elements, compiler, isConst: true); |
| 1091 | 1186 |
| 1092 error(Node node) { | 1187 error(Node node) { |
| 1093 // Just fail without reporting it anywhere. | 1188 // Just fail without reporting it anywhere. |
| 1094 throw new CompileTimeConstantError( | 1189 throw new CompileTimeConstantError( |
| 1095 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); | 1190 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); |
| 1096 } | 1191 } |
| 1097 } | 1192 } |
| 1098 | 1193 |
| 1099 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 1194 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 1100 FunctionElement constructor; | 1195 FunctionElement constructor; |
| 1101 final Map<Element, Constant> definitions; | 1196 final Map<Element, Constant> definitions; |
| 1102 final Map<Element, Constant> fieldValues; | 1197 final Map<Element, Constant> fieldValues; |
| 1103 | 1198 |
| 1104 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) | 1199 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) |
| 1105 : this.constructor = constructor, | 1200 : this.constructor = constructor, |
| 1106 this.definitions = new Map<Element, Constant>(), | 1201 this.definitions = new Map<Element, Constant>(), |
| 1107 this.fieldValues = new Map<Element, Constant>(), | 1202 this.fieldValues = new Map<Element, Constant>(), |
| 1108 super(compiler.resolver.resolveMethodElement(constructor), | 1203 super(compiler.resolver.resolveMethodElement(constructor), |
| 1109 compiler); | 1204 compiler, |
| 1205 isConst: true); |
| 1110 | 1206 |
| 1111 Constant visitSend(Send send) { | 1207 Constant visitSend(Send send) { |
| 1112 Element element = elements[send]; | 1208 Element element = elements[send]; |
| 1113 if (Elements.isLocal(element)) { | 1209 if (Elements.isLocal(element)) { |
| 1114 Constant constant = definitions[element]; | 1210 Constant constant = definitions[element]; |
| 1115 if (constant === null) { | 1211 if (constant === null) { |
| 1116 compiler.internalError("Local variable without value", node: send); | 1212 compiler.internalError("Local variable without value", node: send); |
| 1117 } | 1213 } |
| 1118 return constant; | 1214 return constant; |
| 1119 } | 1215 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 | 1321 |
| 1226 List<Constant> buildJsNewArguments(ClassElement classElement) { | 1322 List<Constant> buildJsNewArguments(ClassElement classElement) { |
| 1227 List<Constant> jsNewArguments = <Constant>[]; | 1323 List<Constant> jsNewArguments = <Constant>[]; |
| 1228 classElement.forEachInstanceField( | 1324 classElement.forEachInstanceField( |
| 1229 includeBackendMembers: true, | 1325 includeBackendMembers: true, |
| 1230 includeSuperMembers: true, | 1326 includeSuperMembers: true, |
| 1231 f: (ClassElement enclosing, Element field) { | 1327 f: (ClassElement enclosing, Element field) { |
| 1232 Constant fieldValue = fieldValues[field]; | 1328 Constant fieldValue = fieldValues[field]; |
| 1233 if (fieldValue === null) { | 1329 if (fieldValue === null) { |
| 1234 // Use the default value. | 1330 // Use the default value. |
| 1235 fieldValue = compiler.compileVariable(field); | 1331 fieldValue = compiler.compileConstant(field); |
| 1236 } | 1332 } |
| 1237 jsNewArguments.add(fieldValue); | 1333 jsNewArguments.add(fieldValue); |
| 1238 }); | 1334 }); |
| 1239 return jsNewArguments; | 1335 return jsNewArguments; |
| 1240 } | 1336 } |
| 1241 } | 1337 } |
| OLD | NEW |