| 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 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 int hashCode() => _hashCode; | 505 int hashCode() => _hashCode; |
| 506 List<Constant> getDependencies() => fields; | 506 List<Constant> getDependencies() => fields; |
| 507 } | 507 } |
| 508 | 508 |
| 509 /** | 509 /** |
| 510 * The [ConstantHandler] keeps track of compile-time constants, | 510 * The [ConstantHandler] keeps track of compile-time constants, |
| 511 * initializations of global and static fields, and default values of | 511 * initializations of global and static fields, and default values of |
| 512 * optional parameters. | 512 * optional parameters. |
| 513 */ | 513 */ |
| 514 class ConstantHandler extends CompilerTask { | 514 class ConstantHandler extends CompilerTask { |
| 515 // Contains the initial value of fields. Must contain all static and global | 515 /** |
| 516 // initializations of used fields. May contain caches for instance fields. | 516 * Contains the initial value of fields. Must contain all static and global |
| 517 * initializations of const fields. May contain eagerly compiled values for |
| 518 * statics and instance fields. |
| 519 */ |
| 517 final Map<VariableElement, Constant> initialVariableValues; | 520 final Map<VariableElement, Constant> initialVariableValues; |
| 518 | 521 |
| 519 // Map from compile-time constants to their JS name. | 522 /** Map from compile-time constants to their JS name. */ |
| 520 final Map<Constant, String> compiledConstants; | 523 final Map<Constant, String> compiledConstants; |
| 521 | 524 |
| 522 // The set of variable elements that are in the process of being computed. | 525 /** The set of variable elements that are in the process of being computed. */ |
| 523 final Set<VariableElement> pendingVariables; | 526 final Set<VariableElement> pendingVariables; |
| 524 | 527 |
| 528 /** Caches the statics where the initial value cannot be eagerly compiled. */ |
| 529 final Set<VariableElement> lazyStatics; |
| 530 |
| 531 |
| 525 ConstantHandler(Compiler compiler) | 532 ConstantHandler(Compiler compiler) |
| 526 : initialVariableValues = new Map<VariableElement, Dynamic>(), | 533 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
| 527 compiledConstants = new Map<Constant, String>(), | 534 compiledConstants = new Map<Constant, String>(), |
| 528 pendingVariables = new Set<VariableElement>(), | 535 pendingVariables = new Set<VariableElement>(), |
| 536 lazyStatics = new Set<VariableElement>(), |
| 529 super(compiler); | 537 super(compiler); |
| 530 String get name => 'ConstantHandler'; | 538 String get name => 'ConstantHandler'; |
| 531 | 539 |
| 532 void registerCompileTimeConstant(Constant constant) { | 540 void registerCompileTimeConstant(Constant constant) { |
| 533 Function ifAbsentThunk = (() { | 541 Function ifAbsentThunk = (() { |
| 534 return constant.isFunction() | 542 return constant.isFunction() |
| 535 ? null : compiler.namer.getFreshGlobalName("CTC"); | 543 ? null : compiler.namer.getFreshGlobalName("CTC"); |
| 536 }); | 544 }); |
| 537 compiledConstants.putIfAbsent(constant, ifAbsentThunk); | 545 compiledConstants.putIfAbsent(constant, ifAbsentThunk); |
| 538 } | 546 } |
| 539 | 547 |
| 540 /** | 548 /** |
| 541 * Compiles the initial value of the given field and stores it in an internal | 549 * Compiles the initial value of the given field and stores it in an internal |
| 542 * map. | 550 * map. Returns the initial value (a constant) if it can be computed |
| 551 * statically. Returns [:null:] if the variable must be initialized lazily. |
| 543 * | 552 * |
| 544 * [WorkItem] must contain a [VariableElement] refering to a global or | 553 * [WorkItem] must contain a [VariableElement] refering to a global or |
| 545 * static field. | 554 * static field. |
| 546 */ | 555 */ |
| 547 void compileWorkItem(WorkItem work) { | 556 Constant compileWorkItem(WorkItem work) { |
| 548 measure(() { | 557 return measure(() { |
| 549 assert(work.element.kind == ElementKind.FIELD | 558 assert(work.element.kind == ElementKind.FIELD |
| 550 || work.element.kind == ElementKind.PARAMETER | 559 || work.element.kind == ElementKind.PARAMETER |
| 551 || work.element.kind == ElementKind.FIELD_PARAMETER); | 560 || work.element.kind == ElementKind.FIELD_PARAMETER); |
| 552 VariableElement element = work.element; | 561 VariableElement element = work.element; |
| 553 // Shortcut if it has already been compiled. | 562 // Shortcut if it has already been compiled. |
| 554 if (initialVariableValues.containsKey(element)) return; | 563 Constant result = initialVariableValues[element]; |
| 555 compileVariableWithDefinitions(element, work.resolutionTree); | 564 if (result != null) return result; |
| 565 if (lazyStatics.contains(element)) return null; |
| 566 result = compileVariableWithDefinitions(element, work.resolutionTree); |
| 556 assert(pendingVariables.isEmpty()); | 567 assert(pendingVariables.isEmpty()); |
| 568 return result; |
| 557 }); | 569 }); |
| 558 } | 570 } |
| 559 | 571 |
| 560 Constant compileVariable(VariableElement element) { | 572 /** |
| 573 * Returns a compile-time constant, or reports an error if the element is not |
| 574 * a compile-time constant. |
| 575 */ |
| 576 Constant compileConstant(VariableElement element) { |
| 577 return compileVariable(element, isConst: true); |
| 578 } |
| 579 |
| 580 /** |
| 581 * Returns the a compile-time constant if the variable could be compiled |
| 582 * eagerly. Otherwise returns `null`. |
| 583 */ |
| 584 Constant compileVariable(VariableElement element, [bool isConst = false]) { |
| 561 return measure(() { | 585 return measure(() { |
| 562 if (initialVariableValues.containsKey(element)) { | 586 if (initialVariableValues.containsKey(element)) { |
| 563 Constant result = initialVariableValues[element]; | 587 Constant result = initialVariableValues[element]; |
| 564 return result; | 588 return result; |
| 565 } | 589 } |
| 566 TreeElements definitions = compiler.analyzeElement(element); | 590 TreeElements definitions = compiler.analyzeElement(element); |
| 567 Constant constant = compileVariableWithDefinitions(element, definitions); | 591 Constant constant = compileVariableWithDefinitions( |
| 592 element, definitions, isConst: isConst); |
| 568 return constant; | 593 return constant; |
| 569 }); | 594 }); |
| 570 } | 595 } |
| 571 | 596 |
| 597 /** |
| 598 * Returns the a compile-time constant if the variable could be compiled |
| 599 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 600 * If the variable is `const` but cannot be compiled eagerly reports an |
| 601 * error. |
| 602 */ |
| 572 Constant compileVariableWithDefinitions(VariableElement element, | 603 Constant compileVariableWithDefinitions(VariableElement element, |
| 573 TreeElements definitions) { | 604 TreeElements definitions, |
| 605 [bool isConst = false]) { |
| 574 return measure(() { | 606 return measure(() { |
| 607 // Initializers for parameters must be const. |
| 608 isConst = isConst || element.modifiers.isConst() |
| 609 || !Elements.isStaticOrTopLevel(element); |
| 610 if (!isConst && lazyStatics.contains(element)) return null; |
| 611 |
| 575 Node node = element.parseNode(compiler); | 612 Node node = element.parseNode(compiler); |
| 576 if (pendingVariables.contains(element)) { | 613 if (pendingVariables.contains(element)) { |
| 577 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; | 614 if (isConst) { |
| 578 compiler.reportError(node, | 615 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; |
| 579 new CompileTimeConstantError(kind, const [])); | 616 compiler.reportError(node, |
| 617 new CompileTimeConstantError(kind, const [])); |
| 618 } else { |
| 619 lazyStatics.add(element); |
| 620 return null; |
| 621 } |
| 580 } | 622 } |
| 581 pendingVariables.add(element); | 623 pendingVariables.add(element); |
| 582 | 624 |
| 583 SendSet assignment = node.asSendSet(); | 625 SendSet assignment = node.asSendSet(); |
| 584 Constant value; | 626 Constant value; |
| 585 if (assignment === null) { | 627 if (assignment === null) { |
| 586 // No initial value. | 628 // No initial value. |
| 587 value = new NullConstant(); | 629 value = new NullConstant(); |
| 588 } else { | 630 } else { |
| 589 Node right = assignment.arguments.head; | 631 Node right = assignment.arguments.head; |
| 590 value = compileNodeWithDefinitions(right, definitions); | 632 value = |
| 633 compileNodeWithDefinitions(right, definitions, isConst: isConst); |
| 591 } | 634 } |
| 592 initialVariableValues[element] = value; | 635 if (value != null) { |
| 636 initialVariableValues[element] = value; |
| 637 } else { |
| 638 assert(!isConst); |
| 639 lazyStatics.add(element); |
| 640 } |
| 593 pendingVariables.remove(element); | 641 pendingVariables.remove(element); |
| 594 return value; | 642 return value; |
| 595 }); | 643 }); |
| 596 } | 644 } |
| 597 | 645 |
| 598 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { | 646 Constant compileNodeWithDefinitions(Node node, |
| 647 TreeElements definitions, |
| 648 [bool isConst]) { |
| 599 return measure(() { | 649 return measure(() { |
| 600 assert(node !== null); | 650 assert(node !== null); |
| 601 CompileTimeConstantEvaluator evaluator = | 651 CompileTimeConstantEvaluator evaluator = |
| 602 new CompileTimeConstantEvaluator(definitions, compiler); | 652 new CompileTimeConstantEvaluator(definitions, compiler, isConst); |
| 603 return evaluator.evaluate(node); | 653 return evaluator.evaluate(node); |
| 604 }); | 654 }); |
| 605 } | 655 } |
| 606 | 656 |
| 607 /** Attempts to compile a constant expression. Returns null if not possible */ | 657 /** Attempts to compile a constant expression. Returns null if not possible */ |
| 608 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { | 658 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 609 return measure(() { | 659 return measure(() { |
| 610 assert(node !== null); | 660 assert(node !== null); |
| 611 try { | 661 try { |
| 612 TryCompileTimeConstantEvaluator evaluator = | 662 TryCompileTimeConstantEvaluator evaluator = |
| (...skipping 24 matching lines...) Expand all Loading... |
| 637 * other. | 687 * other. |
| 638 */ | 688 */ |
| 639 List<VariableElement> getStaticFinalFieldsForEmission() { | 689 List<VariableElement> getStaticFinalFieldsForEmission() { |
| 640 return initialVariableValues.getKeys().filter((element) { | 690 return initialVariableValues.getKeys().filter((element) { |
| 641 return element.kind == ElementKind.FIELD | 691 return element.kind == ElementKind.FIELD |
| 642 && !element.isInstanceMember() | 692 && !element.isInstanceMember() |
| 643 && element.modifiers.isFinal(); | 693 && element.modifiers.isFinal(); |
| 644 }); | 694 }); |
| 645 } | 695 } |
| 646 | 696 |
| 697 List<VariableElement> getLazilyInitializedFieldsForEmission() { |
| 698 return new List<VariableElement>.from(lazyStatics); |
| 699 } |
| 700 |
| 647 List<Constant> getConstantsForEmission() { | 701 List<Constant> getConstantsForEmission() { |
| 648 // We must emit dependencies before their uses. | 702 // We must emit dependencies before their uses. |
| 649 Set<Constant> seenConstants = new Set<Constant>(); | 703 Set<Constant> seenConstants = new Set<Constant>(); |
| 650 List<Constant> result = new List<Constant>(); | 704 List<Constant> result = new List<Constant>(); |
| 651 | 705 |
| 652 void addConstant(Constant constant) { | 706 void addConstant(Constant constant) { |
| 653 if (!seenConstants.contains(constant)) { | 707 if (!seenConstants.contains(constant)) { |
| 654 constant.getDependencies().forEach(addConstant); | 708 constant.getDependencies().forEach(addConstant); |
| 655 assert(!seenConstants.contains(constant)); | 709 assert(!seenConstants.contains(constant)); |
| 656 result.add(constant); | 710 result.add(constant); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 } | 794 } |
| 741 } | 795 } |
| 742 } | 796 } |
| 743 | 797 |
| 744 String getJsConstructor(ClassElement element) { | 798 String getJsConstructor(ClassElement element) { |
| 745 return compiler.namer.isolatePropertiesAccess(element); | 799 return compiler.namer.isolatePropertiesAccess(element); |
| 746 } | 800 } |
| 747 } | 801 } |
| 748 | 802 |
| 749 class CompileTimeConstantEvaluator extends AbstractVisitor { | 803 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 804 bool isEvaluatingConstant; |
| 750 final TreeElements elements; | 805 final TreeElements elements; |
| 751 final Compiler compiler; | 806 final Compiler compiler; |
| 752 | 807 |
| 753 CompileTimeConstantEvaluator(this.elements, this.compiler); | 808 CompileTimeConstantEvaluator(this.elements, this.compiler, [bool isConst]) |
| 809 : this.isEvaluatingConstant = isConst; |
| 754 | 810 |
| 755 Constant evaluate(Node node) { | 811 Constant evaluate(Node node) { |
| 756 return node.accept(this); | 812 return node.accept(this); |
| 757 } | 813 } |
| 758 | 814 |
| 759 visitNode(Node node) { | 815 Constant evaluateConstant(Node node) { |
| 760 error(node); | 816 bool oldIsEvaluatingConstant = isEvaluatingConstant; |
| 817 isEvaluatingConstant = true; |
| 818 Constant result = node.accept(this); |
| 819 isEvaluatingConstant = oldIsEvaluatingConstant; |
| 820 assert(result != null); |
| 821 return result; |
| 822 } |
| 823 |
| 824 Constant visitNode(Node node) { |
| 825 return signalNotCompileTimeConstant(node); |
| 761 } | 826 } |
| 762 | 827 |
| 763 Constant visitLiteralBool(LiteralBool node) { | 828 Constant visitLiteralBool(LiteralBool node) { |
| 764 return new BoolConstant(node.value); | 829 return new BoolConstant(node.value); |
| 765 } | 830 } |
| 766 | 831 |
| 767 Constant visitLiteralDouble(LiteralDouble node) { | 832 Constant visitLiteralDouble(LiteralDouble node) { |
| 768 return new DoubleConstant(node.value); | 833 return new DoubleConstant(node.value); |
| 769 } | 834 } |
| 770 | 835 |
| 771 Constant visitLiteralInt(LiteralInt node) { | 836 Constant visitLiteralInt(LiteralInt node) { |
| 772 return new IntConstant(node.value); | 837 return new IntConstant(node.value); |
| 773 } | 838 } |
| 774 | 839 |
| 775 Constant visitLiteralList(LiteralList node) { | 840 Constant visitLiteralList(LiteralList node) { |
| 776 if (!node.isConst()) error(node); | 841 if (!node.isConst()) { |
| 842 return signalNotCompileTimeConstant(node); |
| 843 } |
| 777 List<Constant> arguments = <Constant>[]; | 844 List<Constant> arguments = <Constant>[]; |
| 778 for (Link<Node> link = node.elements.nodes; | 845 for (Link<Node> link = node.elements.nodes; |
| 779 !link.isEmpty(); | 846 !link.isEmpty(); |
| 780 link = link.tail) { | 847 link = link.tail) { |
| 781 arguments.add(evaluate(link.head)); | 848 arguments.add(evaluateConstant(link.head)); |
| 782 } | 849 } |
| 783 // TODO(floitsch): get type from somewhere. | 850 // TODO(floitsch): get type from somewhere. |
| 784 DartType type = null; | 851 DartType type = null; |
| 785 Constant constant = new ListConstant(type, arguments); | 852 Constant constant = new ListConstant(type, arguments); |
| 786 compiler.constantHandler.registerCompileTimeConstant(constant); | 853 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 787 return constant; | 854 return constant; |
| 788 } | 855 } |
| 789 | 856 |
| 790 Constant visitLiteralMap(LiteralMap node) { | 857 Constant visitLiteralMap(LiteralMap node) { |
| 791 if (!node.isConst()) error(node); | 858 if (!node.isConst()) { |
| 859 signalNotCompileTimeConstant(node); |
| 860 error(node); |
| 861 } |
| 792 List<StringConstant> keys = <StringConstant>[]; | 862 List<StringConstant> keys = <StringConstant>[]; |
| 793 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); | 863 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 794 for (Link<Node> link = node.entries.nodes; | 864 for (Link<Node> link = node.entries.nodes; |
| 795 !link.isEmpty(); | 865 !link.isEmpty(); |
| 796 link = link.tail) { | 866 link = link.tail) { |
| 797 LiteralMapEntry entry = link.head; | 867 LiteralMapEntry entry = link.head; |
| 798 Constant key = evaluate(entry.key); | 868 Constant key = evaluateConstant(entry.key); |
| 799 if (!key.isString() || entry.key.asStringNode() === null) { | 869 if (!key.isString() || entry.key.asStringNode() === null) { |
| 800 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 870 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
| 801 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 871 compiler.reportError(entry.key, new ResolutionError(kind, const [])); |
| 802 } | 872 } |
| 803 StringConstant keyConstant = key; | 873 StringConstant keyConstant = key; |
| 804 if (!map.containsKey(key)) keys.add(key); | 874 if (!map.containsKey(key)) keys.add(key); |
| 805 map[key] = evaluate(entry.value); | 875 map[key] = evaluateConstant(entry.value); |
| 806 } | 876 } |
| 807 List<Constant> values = <Constant>[]; | 877 List<Constant> values = <Constant>[]; |
| 808 Constant protoValue = null; | 878 Constant protoValue = null; |
| 809 for (StringConstant key in keys) { | 879 for (StringConstant key in keys) { |
| 810 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { | 880 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { |
| 811 protoValue = map[key]; | 881 protoValue = map[key]; |
| 812 } else { | 882 } else { |
| 813 values.add(map[key]); | 883 values.add(map[key]); |
| 814 } | 884 } |
| 815 } | 885 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 835 return new NullConstant(); | 905 return new NullConstant(); |
| 836 } | 906 } |
| 837 | 907 |
| 838 Constant visitLiteralString(LiteralString node) { | 908 Constant visitLiteralString(LiteralString node) { |
| 839 return new StringConstant(node.dartString, node); | 909 return new StringConstant(node.dartString, node); |
| 840 } | 910 } |
| 841 | 911 |
| 842 Constant visitStringJuxtaposition(StringJuxtaposition node) { | 912 Constant visitStringJuxtaposition(StringJuxtaposition node) { |
| 843 StringConstant left = evaluate(node.first); | 913 StringConstant left = evaluate(node.first); |
| 844 StringConstant right = evaluate(node.second); | 914 StringConstant right = evaluate(node.second); |
| 915 if (left == null || right == null) return null; |
| 845 return new StringConstant(new DartString.concat(left.value, right.value), | 916 return new StringConstant(new DartString.concat(left.value, right.value), |
| 846 node); | 917 node); |
| 847 } | 918 } |
| 848 | 919 |
| 849 Constant visitStringInterpolation(StringInterpolation node) { | 920 Constant visitStringInterpolation(StringInterpolation node) { |
| 850 StringConstant initialString = evaluate(node.string); | 921 StringConstant initialString = evaluate(node.string); |
| 922 if (initialString == null) return null; |
| 851 DartString accumulator = initialString.value; | 923 DartString accumulator = initialString.value; |
| 852 for (StringInterpolationPart part in node.parts) { | 924 for (StringInterpolationPart part in node.parts) { |
| 853 Constant expression = evaluate(part.expression); | 925 Constant expression = evaluate(part.expression); |
| 854 DartString expressionString; | 926 DartString expressionString; |
| 855 if (expression.isNum() || expression.isBool()) { | 927 if (expression.isNum() || expression.isBool()) { |
| 856 PrimitiveConstant primitive = expression; | 928 PrimitiveConstant primitive = expression; |
| 857 expressionString = new DartString.literal(primitive.value.toString()); | 929 expressionString = new DartString.literal(primitive.value.toString()); |
| 858 } else if (expression.isString()) { | 930 } else if (expression.isString()) { |
| 859 PrimitiveConstant primitive = expression; | 931 PrimitiveConstant primitive = expression; |
| 860 expressionString = primitive.value; | 932 expressionString = primitive.value; |
| 861 } else { | 933 } else { |
| 862 error(part.expression); | 934 return signalNotCompileTimeConstant(part.expression); |
| 863 } | 935 } |
| 864 accumulator = new DartString.concat(accumulator, expressionString); | 936 accumulator = new DartString.concat(accumulator, expressionString); |
| 865 StringConstant partString = evaluate(part.string); | 937 StringConstant partString = evaluate(part.string); |
| 938 if (partString == null) return null; |
| 866 accumulator = new DartString.concat(accumulator, partString.value); | 939 accumulator = new DartString.concat(accumulator, partString.value); |
| 867 }; | 940 }; |
| 868 return new StringConstant(accumulator, node); | 941 return new StringConstant(accumulator, node); |
| 869 } | 942 } |
| 870 | 943 |
| 871 // TODO(floitsch): provide better error-messages. | 944 // TODO(floitsch): provide better error-messages. |
| 872 Constant visitSend(Send send) { | 945 Constant visitSend(Send send) { |
| 873 Element element = elements[send]; | 946 Element element = elements[send]; |
| 874 if (Elements.isStaticOrTopLevelField(element)) { | 947 if (Elements.isStaticOrTopLevelField(element)) { |
| 875 if (element.modifiers === null || | 948 Constant result; |
| 876 // TODO(johnniwinther): This should eventually be [isConst]. | 949 if (element.modifiers !== null) { |
| 877 !element.modifiers.isFinalOrConst()) { | 950 if (element.modifiers.isConst()) { |
| 878 error(send); | 951 result = compiler.compileConstant(element); |
| 952 } else if (element.modifiers.isFinal()) { |
| 953 // TODO(4516): remove support for final compile-time constants: if |
| 954 // isCompilingConstant is true don't compile the variable. |
| 955 result = compiler.compileVariable(element); |
| 956 } |
| 879 } | 957 } |
| 880 return compiler.compileVariable(element); | 958 if (result == null) return signalNotCompileTimeConstant(send); |
| 959 return result; |
| 881 } else if (Elements.isStaticOrTopLevelFunction(element) | 960 } else if (Elements.isStaticOrTopLevelFunction(element) |
| 882 && send.isPropertyAccess) { | 961 && send.isPropertyAccess) { |
| 883 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); | 962 compiler.codegenWorld.staticFunctionsNeedingGetter.add(element); |
| 884 Constant constant = new FunctionConstant(element); | 963 Constant constant = new FunctionConstant(element); |
| 885 compiler.constantHandler.registerCompileTimeConstant(constant); | 964 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 886 return constant; | 965 return constant; |
| 887 } else if (send.isPrefix) { | 966 } else if (send.isPrefix) { |
| 888 assert(send.isOperator); | 967 assert(send.isOperator); |
| 889 Constant receiverConstant = evaluate(send.receiver); | 968 Constant receiverConstant = evaluate(send.receiver); |
| 969 if (receiverConstant == null) return null; |
| 890 Operator op = send.selector; | 970 Operator op = send.selector; |
| 891 Constant folded; | 971 Constant folded; |
| 892 switch (op.source.stringValue) { | 972 switch (op.source.stringValue) { |
| 893 case "!": | 973 case "!": |
| 894 folded = const NotOperation().fold(receiverConstant); | 974 folded = const NotOperation().fold(receiverConstant); |
| 895 break; | 975 break; |
| 896 case "-": | 976 case "-": |
| 897 folded = const NegateOperation().fold(receiverConstant); | 977 folded = const NegateOperation().fold(receiverConstant); |
| 898 break; | 978 break; |
| 899 case "~": | 979 case "~": |
| 900 folded = const BitNotOperation().fold(receiverConstant); | 980 folded = const BitNotOperation().fold(receiverConstant); |
| 901 break; | 981 break; |
| 902 default: | 982 default: |
| 903 compiler.internalError("Unexpected operator.", node: op); | 983 compiler.internalError("Unexpected operator.", node: op); |
| 904 break; | 984 break; |
| 905 } | 985 } |
| 906 if (folded === null) error(send); | 986 if (folded === null) return signalNotCompileTimeConstant(send); |
| 907 return folded; | 987 return folded; |
| 908 } else if (send.isOperator && !send.isPostfix) { | 988 } else if (send.isOperator && !send.isPostfix) { |
| 909 assert(send.argumentCount() == 1); | 989 assert(send.argumentCount() == 1); |
| 910 Constant left = evaluate(send.receiver); | 990 Constant left = evaluate(send.receiver); |
| 911 Constant right = evaluate(send.argumentsNode.nodes.head); | 991 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 992 if (left == null || right == null) return null; |
| 912 Operator op = send.selector.asOperator(); | 993 Operator op = send.selector.asOperator(); |
| 913 Constant folded = null; | 994 Constant folded = null; |
| 914 switch (op.source.stringValue) { | 995 switch (op.source.stringValue) { |
| 915 case "+": | 996 case "+": |
| 916 folded = const AddOperation().fold(left, right); | 997 folded = const AddOperation().fold(left, right); |
| 917 break; | 998 break; |
| 918 case "-": | 999 case "-": |
| 919 folded = const SubtractOperation().fold(left, right); | 1000 folded = const SubtractOperation().fold(left, right); |
| 920 break; | 1001 break; |
| 921 case "*": | 1002 case "*": |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 988 BoolConstant areIdentical = | 1069 BoolConstant areIdentical = |
| 989 const IdentityOperation().fold(left, right); | 1070 const IdentityOperation().fold(left, right); |
| 990 if (areIdentical === null) { | 1071 if (areIdentical === null) { |
| 991 folded = null; | 1072 folded = null; |
| 992 } else { | 1073 } else { |
| 993 folded = areIdentical.negate(); | 1074 folded = areIdentical.negate(); |
| 994 } | 1075 } |
| 995 } | 1076 } |
| 996 break; | 1077 break; |
| 997 } | 1078 } |
| 998 if (folded === null) error(send); | 1079 if (folded === null) return signalNotCompileTimeConstant(send); |
| 999 return folded; | 1080 return folded; |
| 1000 } | 1081 } |
| 1001 return super.visitSend(send); | 1082 return signalNotCompileTimeConstant(send); |
| 1002 } | 1083 } |
| 1003 | 1084 |
| 1004 visitSendSet(SendSet node) { | 1085 Constant visitSendSet(SendSet node) { |
| 1005 error(node); | 1086 return signalNotCompileTimeConstant(node); |
| 1006 } | 1087 } |
| 1007 | 1088 |
| 1008 /** Returns the list of constants that are passed to the static function. */ | 1089 /** Returns the list of constants that are passed to the static function. */ |
| 1009 List<Constant> evaluateArgumentsToConstructor(Selector selector, | 1090 List<Constant> evaluateArgumentsToConstructor(Selector selector, |
| 1010 Link<Node> arguments, | 1091 Link<Node> arguments, |
| 1011 FunctionElement target) { | 1092 FunctionElement target) { |
| 1012 List<Constant> compiledArguments = <Constant>[]; | 1093 List<Constant> compiledArguments = <Constant>[]; |
| 1013 | 1094 |
| 1014 Function compileArgument = evaluate; | 1095 Function compileArgument = evaluateConstant; |
| 1015 Function compileConstant = compiler.compileVariable; | 1096 Function compileConstant = compiler.compileConstant; |
| 1016 bool succeeded = selector.addArgumentsToList(arguments, | 1097 bool succeeded = selector.addArgumentsToList(arguments, |
| 1017 compiledArguments, | 1098 compiledArguments, |
| 1018 target, | 1099 target, |
| 1019 compileArgument, | 1100 compileArgument, |
| 1020 compileConstant, | 1101 compileConstant, |
| 1021 compiler); | 1102 compiler); |
| 1022 assert(succeeded); | 1103 assert(succeeded); |
| 1023 return compiledArguments; | 1104 return compiledArguments; |
| 1024 } | 1105 } |
| 1025 | 1106 |
| 1026 Constant visitNewExpression(NewExpression node) { | 1107 Constant visitNewExpression(NewExpression node) { |
| 1027 if (!node.isConst()) error(node); | 1108 if (!node.isConst()) { |
| 1109 return signalNotCompileTimeConstant(node); |
| 1110 } |
| 1028 | 1111 |
| 1029 Send send = node.send; | 1112 Send send = node.send; |
| 1030 FunctionElement constructor = elements[send]; | 1113 FunctionElement constructor = elements[send]; |
| 1031 ClassElement classElement = constructor.getEnclosingClass(); | 1114 ClassElement classElement = constructor.getEnclosingClass(); |
| 1032 if (classElement.isInterface()) { | 1115 if (classElement.isInterface()) { |
| 1033 compiler.resolver.resolveMethodElement(constructor); | 1116 compiler.resolver.resolveMethodElement(constructor); |
| 1034 constructor = constructor.defaultImplementation; | 1117 constructor = constructor.defaultImplementation; |
| 1035 classElement = constructor.getEnclosingClass(); | 1118 classElement = constructor.getEnclosingClass(); |
| 1036 } | 1119 } |
| 1037 | 1120 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1054 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 1137 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1055 return node.expression.accept(this); | 1138 return node.expression.accept(this); |
| 1056 } | 1139 } |
| 1057 | 1140 |
| 1058 error(Node node) { | 1141 error(Node node) { |
| 1059 // TODO(floitsch): get the list of constants that are currently compiled | 1142 // TODO(floitsch): get the list of constants that are currently compiled |
| 1060 // and present some kind of stack-trace. | 1143 // and present some kind of stack-trace. |
| 1061 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1144 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1062 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1145 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1063 } | 1146 } |
| 1147 |
| 1148 Constant signalNotCompileTimeConstant(Node node) { |
| 1149 if (isEvaluatingConstant) { |
| 1150 error(node); |
| 1151 } |
| 1152 // Else we don't need to do anything. The final handler is only |
| 1153 // optimistically trying to compile constants. So it is normal that we |
| 1154 // sometimes see non-compile time constants. |
| 1155 // Simply return [:null:] which is used to propagate a failing |
| 1156 // compile-time compilation. |
| 1157 return null; |
| 1158 } |
| 1064 } | 1159 } |
| 1065 | 1160 |
| 1066 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 1161 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 1067 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): | 1162 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): |
| 1068 super(elements, compiler); | 1163 super(elements, compiler, isConst: true); |
| 1069 | 1164 |
| 1070 error(Node node) { | 1165 error(Node node) { |
| 1071 // Just fail without reporting it anywhere. | 1166 // Just fail without reporting it anywhere. |
| 1072 throw new CompileTimeConstantError( | 1167 throw new CompileTimeConstantError( |
| 1073 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); | 1168 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); |
| 1074 } | 1169 } |
| 1075 } | 1170 } |
| 1076 | 1171 |
| 1077 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 1172 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 1078 FunctionElement constructor; | 1173 FunctionElement constructor; |
| 1079 final Map<Element, Constant> definitions; | 1174 final Map<Element, Constant> definitions; |
| 1080 final Map<Element, Constant> fieldValues; | 1175 final Map<Element, Constant> fieldValues; |
| 1081 | 1176 |
| 1082 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) | 1177 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) |
| 1083 : this.constructor = constructor, | 1178 : this.constructor = constructor, |
| 1084 this.definitions = new Map<Element, Constant>(), | 1179 this.definitions = new Map<Element, Constant>(), |
| 1085 this.fieldValues = new Map<Element, Constant>(), | 1180 this.fieldValues = new Map<Element, Constant>(), |
| 1086 super(compiler.resolver.resolveMethodElement(constructor), | 1181 super(compiler.resolver.resolveMethodElement(constructor), |
| 1087 compiler); | 1182 compiler, |
| 1183 isConst: true); |
| 1088 | 1184 |
| 1089 Constant visitSend(Send send) { | 1185 Constant visitSend(Send send) { |
| 1090 Element element = elements[send]; | 1186 Element element = elements[send]; |
| 1091 if (Elements.isLocal(element)) { | 1187 if (Elements.isLocal(element)) { |
| 1092 Constant constant = definitions[element]; | 1188 Constant constant = definitions[element]; |
| 1093 if (constant === null) { | 1189 if (constant === null) { |
| 1094 compiler.internalError("Local variable without value", node: send); | 1190 compiler.internalError("Local variable without value", node: send); |
| 1095 } | 1191 } |
| 1096 return constant; | 1192 return constant; |
| 1097 } | 1193 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1203 | 1299 |
| 1204 List<Constant> buildJsNewArguments(ClassElement classElement) { | 1300 List<Constant> buildJsNewArguments(ClassElement classElement) { |
| 1205 List<Constant> jsNewArguments = <Constant>[]; | 1301 List<Constant> jsNewArguments = <Constant>[]; |
| 1206 classElement.forEachInstanceField( | 1302 classElement.forEachInstanceField( |
| 1207 includeBackendMembers: true, | 1303 includeBackendMembers: true, |
| 1208 includeSuperMembers: true, | 1304 includeSuperMembers: true, |
| 1209 f: (ClassElement enclosing, Element field) { | 1305 f: (ClassElement enclosing, Element field) { |
| 1210 Constant fieldValue = fieldValues[field]; | 1306 Constant fieldValue = fieldValues[field]; |
| 1211 if (fieldValue === null) { | 1307 if (fieldValue === null) { |
| 1212 // Use the default value. | 1308 // Use the default value. |
| 1213 fieldValue = compiler.compileVariable(field); | 1309 fieldValue = compiler.compileConstant(field); |
| 1214 } | 1310 } |
| 1215 jsNewArguments.add(fieldValue); | 1311 jsNewArguments.add(fieldValue); |
| 1216 }); | 1312 }); |
| 1217 return jsNewArguments; | 1313 return jsNewArguments; |
| 1218 } | 1314 } |
| 1219 } | 1315 } |
| OLD | NEW |