Chromium Code Reviews| 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 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 470 } | 470 } |
| 471 return true; | 471 return true; |
| 472 } | 472 } |
| 473 | 473 |
| 474 int hashCode() => _hashCode; | 474 int hashCode() => _hashCode; |
| 475 List<Constant> getDependencies() => fields; | 475 List<Constant> getDependencies() => fields; |
| 476 } | 476 } |
| 477 | 477 |
| 478 /** | 478 /** |
| 479 * The [ConstantHandler] keeps track of compile-time constants, | 479 * The [ConstantHandler] keeps track of compile-time constants, |
| 480 * initializations of global and static fields, and default values of | 480 * initializations of global and static const fields, and default values of |
| 481 * optional parameters. | 481 * optional parameters. |
| 482 */ | 482 */ |
| 483 class ConstantHandler extends CompilerTask { | 483 class ConstantHandler extends CompilerTask { |
| 484 // Contains the initial value of fields. Must contain all static and global | 484 /** |
| 485 // initializations of used fields. May contain caches for instance fields. | 485 * Contains the initial value of fields. Must contain all static and global |
| 486 * initializations of const fields. May contain eagerly compiled values for | |
| 487 * statics and instance fields. | |
| 488 */ | |
| 486 final Map<VariableElement, Constant> initialVariableValues; | 489 final Map<VariableElement, Constant> initialVariableValues; |
| 487 | 490 |
| 488 // Map from compile-time constants to their JS name. | 491 /** Map from compile-time constants to their JS name. */ |
| 489 final Map<Constant, String> compiledConstants; | 492 final Map<Constant, String> compiledConstants; |
| 490 | 493 |
| 491 // The set of variable elements that are in the process of being computed. | 494 /** The set of variable elements that are in the process of being computed. */ |
| 492 final Set<VariableElement> pendingVariables; | 495 final Set<VariableElement> pendingVariables; |
| 493 | 496 |
| 497 /** Caches the statics where the initial value cannot be eagerly compiled. */ | |
| 498 final Set<VariableElement> lazyStatics; | |
| 499 | |
| 500 | |
| 494 ConstantHandler(Compiler compiler) | 501 ConstantHandler(Compiler compiler) |
| 495 : initialVariableValues = new Map<VariableElement, Dynamic>(), | 502 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
| 496 compiledConstants = new Map<Constant, String>(), | 503 compiledConstants = new Map<Constant, String>(), |
| 497 pendingVariables = new Set<VariableElement>(), | 504 pendingVariables = new Set<VariableElement>(), |
| 505 lazyStatics = new Set<VariableElement>(), | |
| 498 super(compiler); | 506 super(compiler); |
| 499 String get name() => 'ConstantHandler'; | 507 String get name() => 'ConstantHandler'; |
| 500 | 508 |
| 501 void registerCompileTimeConstant(Constant constant) { | 509 void registerCompileTimeConstant(Constant constant) { |
| 502 Function ifAbsentThunk = (() => compiler.namer.getFreshGlobalName("CTC")); | 510 Function ifAbsentThunk = (() => compiler.namer.getFreshGlobalName("CTC")); |
| 503 compiledConstants.putIfAbsent(constant, ifAbsentThunk); | 511 compiledConstants.putIfAbsent(constant, ifAbsentThunk); |
| 504 } | 512 } |
| 505 | 513 |
| 506 /** | 514 /** |
| 507 * Compiles the initial value of the given field and stores it in an internal | 515 * Compiles the initial value of the given field and stores it in an internal |
| 508 * map. | 516 * map. Returns the initial value (a constant) if it can be computed |
| 517 * statically. Returns [:null:] if the variable must be initialized lazily. | |
| 509 * | 518 * |
| 510 * [WorkItem] must contain a [VariableElement] refering to a global or | 519 * [WorkItem] must contain a [VariableElement] refering to a global or |
| 511 * static field. | 520 * static field. |
| 512 */ | 521 */ |
| 513 void compileWorkItem(WorkItem work) { | 522 Constant compileWorkItem(WorkItem work) { |
| 514 measure(() { | 523 return measure(() { |
| 515 assert(work.element.kind == ElementKind.FIELD | 524 assert(work.element.kind == ElementKind.FIELD |
| 516 || work.element.kind == ElementKind.PARAMETER | 525 || work.element.kind == ElementKind.PARAMETER |
| 517 || work.element.kind == ElementKind.FIELD_PARAMETER); | 526 || work.element.kind == ElementKind.FIELD_PARAMETER); |
| 518 VariableElement element = work.element; | 527 VariableElement element = work.element; |
| 528 Constant result; | |
|
kasperl
2012/08/17 09:30:04
Constant result = initial... ?
floitsch
2012/09/04 17:32:21
Done.
| |
| 519 // Shortcut if it has already been compiled. | 529 // Shortcut if it has already been compiled. |
| 520 if (initialVariableValues.containsKey(element)) return; | 530 result = initialVariableValues[element]; |
| 521 compileVariableWithDefinitions(element, work.resolutionTree); | 531 if (result != null) return result; |
| 532 if (lazyStatics.contains(element)) return null; | |
| 533 result = compileVariableWithDefinitions(element, work.resolutionTree); | |
| 522 assert(pendingVariables.isEmpty()); | 534 assert(pendingVariables.isEmpty()); |
| 535 return result; | |
| 523 }); | 536 }); |
| 524 } | 537 } |
| 525 | 538 |
| 526 Constant compileVariable(VariableElement element) { | 539 /** |
| 540 * Returns a compile-time constant, or reports an error if the element is not | |
| 541 * a compile-time constant. | |
| 542 */ | |
| 543 Constant compileConstant(VariableElement element) { | |
| 544 return compileVariable(element, isConst: true); | |
| 545 } | |
| 546 | |
| 547 /** | |
| 548 * Returns the a compile-time constant if the variable could be compiled | |
| 549 * eagerly. Otherwise returns `null`. | |
| 550 */ | |
| 551 Constant compileVariable(VariableElement element, [bool isConst = false]) { | |
| 527 return measure(() { | 552 return measure(() { |
| 528 if (initialVariableValues.containsKey(element)) { | 553 if (initialVariableValues.containsKey(element)) { |
| 529 Constant result = initialVariableValues[element]; | 554 Constant result = initialVariableValues[element]; |
| 530 return result; | 555 return result; |
| 531 } | 556 } |
| 532 TreeElements definitions = compiler.analyzeElement(element); | 557 TreeElements definitions = compiler.analyzeElement(element); |
| 533 Constant constant = compileVariableWithDefinitions(element, definitions); | 558 Constant constant = compileVariableWithDefinitions( |
| 559 element, definitions, isConst: isConst); | |
| 534 return constant; | 560 return constant; |
| 535 }); | 561 }); |
| 536 } | 562 } |
| 537 | 563 |
| 564 /** | |
| 565 * Returns the a compile-time constant if the variable could be compiled | |
| 566 * eagerly. If the variable needs to be initialized lazily returns `null`. | |
| 567 * If the variable is `const` but cannot be compiled eagerly reports an | |
| 568 * error. | |
| 569 */ | |
| 538 Constant compileVariableWithDefinitions(VariableElement element, | 570 Constant compileVariableWithDefinitions(VariableElement element, |
| 539 TreeElements definitions) { | 571 TreeElements definitions, |
| 572 [bool isConst = false]) { | |
| 540 return measure(() { | 573 return measure(() { |
| 574 // Initializers for fields, or parameters must be const. | |
| 575 isConst = isConst || !element.modifiers.isFinal(); | |
| 576 if (!isConst && lazyStatics.contains(element)) return null; | |
| 577 | |
| 541 Node node = element.parseNode(compiler); | 578 Node node = element.parseNode(compiler); |
| 542 if (pendingVariables.contains(element)) { | 579 if (pendingVariables.contains(element)) { |
| 543 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; | 580 if (isConst) { |
| 544 compiler.reportError(node, | 581 MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS; |
| 545 new CompileTimeConstantError(kind, const [])); | 582 compiler.reportError(node, |
| 583 new CompileTimeConstantError(kind, const [])); | |
| 584 } else { | |
| 585 lazyStatics.add(element); | |
| 586 return null; | |
| 587 } | |
| 546 } | 588 } |
| 547 pendingVariables.add(element); | 589 pendingVariables.add(element); |
| 548 | 590 |
| 549 SendSet assignment = node.asSendSet(); | 591 SendSet assignment = node.asSendSet(); |
| 550 Constant value; | 592 Constant value; |
| 551 if (assignment === null) { | 593 if (assignment === null) { |
| 552 // No initial value. | 594 // No initial value. |
| 553 value = new NullConstant(); | 595 value = new NullConstant(); |
| 554 } else { | 596 } else { |
| 555 Node right = assignment.arguments.head; | 597 Node right = assignment.arguments.head; |
| 556 value = compileNodeWithDefinitions(right, definitions); | 598 value = |
| 599 compileNodeWithDefinitions(right, definitions, isConst: isConst); | |
| 557 } | 600 } |
| 558 initialVariableValues[element] = value; | 601 if (value != null) { |
| 602 initialVariableValues[element] = value; | |
| 603 } else { | |
| 604 assert(!isConst); | |
| 605 lazyStatics.add(element); | |
| 606 } | |
| 559 pendingVariables.remove(element); | 607 pendingVariables.remove(element); |
| 560 return value; | 608 return value; |
| 561 }); | 609 }); |
| 562 } | 610 } |
| 563 | 611 |
| 564 Constant compileNodeWithDefinitions(Node node, TreeElements definitions) { | 612 Constant compileNodeWithDefinitions(Node node, |
| 613 TreeElements definitions, | |
| 614 [bool isConst]) { | |
| 565 return measure(() { | 615 return measure(() { |
| 566 assert(node !== null); | 616 assert(node !== null); |
| 567 CompileTimeConstantEvaluator evaluator = | 617 CompileTimeConstantEvaluator evaluator = |
| 568 new CompileTimeConstantEvaluator(definitions, compiler); | 618 new CompileTimeConstantEvaluator(definitions, compiler, isConst); |
| 569 return evaluator.evaluate(node); | 619 return evaluator.evaluate(node); |
| 570 }); | 620 }); |
| 571 } | 621 } |
| 572 | 622 |
| 573 /** Attempts to compile a constant expression. Returns null if not possible */ | 623 /** Attempts to compile a constant expression. Returns null if not possible */ |
| 574 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { | 624 Constant tryCompileNodeWithDefinitions(Node node, TreeElements definitions) { |
| 575 return measure(() { | 625 return measure(() { |
| 576 assert(node !== null); | 626 assert(node !== null); |
| 577 try { | 627 try { |
| 578 TryCompileTimeConstantEvaluator evaluator = | 628 TryCompileTimeConstantEvaluator evaluator = |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 603 * other. | 653 * other. |
| 604 */ | 654 */ |
| 605 List<VariableElement> getStaticFinalFieldsForEmission() { | 655 List<VariableElement> getStaticFinalFieldsForEmission() { |
| 606 return initialVariableValues.getKeys().filter((element) { | 656 return initialVariableValues.getKeys().filter((element) { |
| 607 return element.kind == ElementKind.FIELD | 657 return element.kind == ElementKind.FIELD |
| 608 && !element.isInstanceMember() | 658 && !element.isInstanceMember() |
| 609 && element.modifiers.isFinal(); | 659 && element.modifiers.isFinal(); |
| 610 }); | 660 }); |
| 611 } | 661 } |
| 612 | 662 |
| 663 List<VariableElement> getLazilyInitializedFieldsForEmission() { | |
| 664 return new List<VariableElement>.from(lazyStatics); | |
| 665 } | |
| 666 | |
| 613 List<Constant> getConstantsForEmission() { | 667 List<Constant> getConstantsForEmission() { |
| 614 // We must emit dependencies before their uses. | 668 // We must emit dependencies before their uses. |
| 615 Set<Constant> seenConstants = new Set<Constant>(); | 669 Set<Constant> seenConstants = new Set<Constant>(); |
| 616 List<Constant> result = new List<Constant>(); | 670 List<Constant> result = new List<Constant>(); |
| 617 | 671 |
| 618 void addConstant(Constant constant) { | 672 void addConstant(Constant constant) { |
| 619 if (!seenConstants.contains(constant)) { | 673 if (!seenConstants.contains(constant)) { |
| 620 constant.getDependencies().forEach(addConstant); | 674 constant.getDependencies().forEach(addConstant); |
| 621 assert(!seenConstants.contains(constant)); | 675 assert(!seenConstants.contains(constant)); |
| 622 result.add(constant); | 676 result.add(constant); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 } | 760 } |
| 707 } | 761 } |
| 708 } | 762 } |
| 709 | 763 |
| 710 String getJsConstructor(ClassElement element) { | 764 String getJsConstructor(ClassElement element) { |
| 711 return compiler.namer.isolatePropertiesAccess(element); | 765 return compiler.namer.isolatePropertiesAccess(element); |
| 712 } | 766 } |
| 713 } | 767 } |
| 714 | 768 |
| 715 class CompileTimeConstantEvaluator extends AbstractVisitor { | 769 class CompileTimeConstantEvaluator extends AbstractVisitor { |
| 770 bool isEvaluatingConstant; | |
| 716 final TreeElements elements; | 771 final TreeElements elements; |
| 717 final Compiler compiler; | 772 final Compiler compiler; |
| 718 | 773 |
| 719 CompileTimeConstantEvaluator(this.elements, this.compiler); | 774 CompileTimeConstantEvaluator(this.elements, this.compiler, [bool isConst]) |
| 775 : this.isEvaluatingConstant = isConst; | |
| 720 | 776 |
| 721 Constant evaluate(Node node) { | 777 Constant evaluate(Node node) { |
| 722 return node.accept(this); | 778 return node.accept(this); |
| 723 } | 779 } |
| 724 | 780 |
| 725 visitNode(Node node) { | 781 Constant evaluateConstant(Node node) { |
| 726 error(node); | 782 bool oldIsEvaluatingConstant = isEvaluatingConstant; |
| 783 isEvaluatingConstant = true; | |
| 784 Constant result = node.accept(this); | |
| 785 isEvaluatingConstant = oldIsEvaluatingConstant; | |
| 786 assert(result != null); | |
| 787 return result; | |
| 788 } | |
| 789 | |
| 790 Constant visitNode(Node node) { | |
| 791 signalNotACompileTimeConstant(node); | |
| 792 return null; | |
| 727 } | 793 } |
| 728 | 794 |
| 729 Constant visitLiteralBool(LiteralBool node) { | 795 Constant visitLiteralBool(LiteralBool node) { |
| 730 return new BoolConstant(node.value); | 796 return new BoolConstant(node.value); |
| 731 } | 797 } |
| 732 | 798 |
| 733 Constant visitLiteralDouble(LiteralDouble node) { | 799 Constant visitLiteralDouble(LiteralDouble node) { |
| 734 return new DoubleConstant(node.value); | 800 return new DoubleConstant(node.value); |
| 735 } | 801 } |
| 736 | 802 |
| 737 Constant visitLiteralInt(LiteralInt node) { | 803 Constant visitLiteralInt(LiteralInt node) { |
| 738 return new IntConstant(node.value); | 804 return new IntConstant(node.value); |
| 739 } | 805 } |
| 740 | 806 |
| 741 Constant visitLiteralList(LiteralList node) { | 807 Constant visitLiteralList(LiteralList node) { |
| 742 if (!node.isConst()) error(node); | 808 if (!node.isConst()) { |
| 809 signalNotACompileTimeConstant(node); | |
| 810 return null; | |
| 811 } | |
| 743 List<Constant> arguments = <Constant>[]; | 812 List<Constant> arguments = <Constant>[]; |
| 744 for (Link<Node> link = node.elements.nodes; | 813 for (Link<Node> link = node.elements.nodes; |
| 745 !link.isEmpty(); | 814 !link.isEmpty(); |
| 746 link = link.tail) { | 815 link = link.tail) { |
| 747 arguments.add(evaluate(link.head)); | 816 arguments.add(evaluateConstant(link.head)); |
| 748 } | 817 } |
| 749 // TODO(floitsch): get type from somewhere. | 818 // TODO(floitsch): get type from somewhere. |
| 750 Type type = null; | 819 Type type = null; |
| 751 Constant constant = new ListConstant(type, arguments); | 820 Constant constant = new ListConstant(type, arguments); |
| 752 compiler.constantHandler.registerCompileTimeConstant(constant); | 821 compiler.constantHandler.registerCompileTimeConstant(constant); |
| 753 return constant; | 822 return constant; |
| 754 } | 823 } |
| 755 | 824 |
| 756 Constant visitLiteralMap(LiteralMap node) { | 825 Constant visitLiteralMap(LiteralMap node) { |
| 757 if (!node.isConst()) error(node); | 826 if (!node.isConst()) { |
| 827 signalNotACompileTimeConstant(node); | |
| 828 error(node); | |
| 829 } | |
| 758 List<StringConstant> keys = <StringConstant>[]; | 830 List<StringConstant> keys = <StringConstant>[]; |
| 759 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); | 831 Map<StringConstant, Constant> map = new Map<StringConstant, Constant>(); |
| 760 for (Link<Node> link = node.entries.nodes; | 832 for (Link<Node> link = node.entries.nodes; |
| 761 !link.isEmpty(); | 833 !link.isEmpty(); |
| 762 link = link.tail) { | 834 link = link.tail) { |
| 763 LiteralMapEntry entry = link.head; | 835 LiteralMapEntry entry = link.head; |
| 764 Constant key = evaluate(entry.key); | 836 Constant key = evaluateConstant(entry.key); |
| 765 if (!key.isString() || entry.key.asStringNode() === null) { | 837 if (!key.isString() || entry.key.asStringNode() === null) { |
| 766 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 838 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
| 767 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 839 compiler.reportError(entry.key, new ResolutionError(kind, const [])); |
| 768 } | 840 } |
| 769 StringConstant keyConstant = key; | 841 StringConstant keyConstant = key; |
| 770 if (!map.containsKey(key)) keys.add(key); | 842 if (!map.containsKey(key)) keys.add(key); |
| 771 map[key] = evaluate(entry.value); | 843 map[key] = evaluateConstant(entry.value); |
| 772 } | 844 } |
| 773 List<Constant> values = <Constant>[]; | 845 List<Constant> values = <Constant>[]; |
| 774 Constant protoValue = null; | 846 Constant protoValue = null; |
| 775 for (StringConstant key in keys) { | 847 for (StringConstant key in keys) { |
| 776 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { | 848 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { |
| 777 protoValue = map[key]; | 849 protoValue = map[key]; |
| 778 } else { | 850 } else { |
| 779 values.add(map[key]); | 851 values.add(map[key]); |
| 780 } | 852 } |
| 781 } | 853 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 801 return new NullConstant(); | 873 return new NullConstant(); |
| 802 } | 874 } |
| 803 | 875 |
| 804 Constant visitLiteralString(LiteralString node) { | 876 Constant visitLiteralString(LiteralString node) { |
| 805 return new StringConstant(node.dartString, node); | 877 return new StringConstant(node.dartString, node); |
| 806 } | 878 } |
| 807 | 879 |
| 808 Constant visitStringJuxtaposition(StringJuxtaposition node) { | 880 Constant visitStringJuxtaposition(StringJuxtaposition node) { |
| 809 StringConstant left = evaluate(node.first); | 881 StringConstant left = evaluate(node.first); |
| 810 StringConstant right = evaluate(node.second); | 882 StringConstant right = evaluate(node.second); |
| 883 if (left == null || right == null) return null; | |
| 811 return new StringConstant(new DartString.concat(left.value, right.value), | 884 return new StringConstant(new DartString.concat(left.value, right.value), |
| 812 node); | 885 node); |
| 813 } | 886 } |
| 814 | 887 |
| 815 Constant visitStringInterpolation(StringInterpolation node) { | 888 Constant visitStringInterpolation(StringInterpolation node) { |
| 816 StringConstant initialString = evaluate(node.string); | 889 StringConstant initialString = evaluate(node.string); |
| 890 if (initialString == null) return null; | |
| 817 DartString accumulator = initialString.value; | 891 DartString accumulator = initialString.value; |
| 818 for (StringInterpolationPart part in node.parts) { | 892 for (StringInterpolationPart part in node.parts) { |
| 819 Constant expression = evaluate(part.expression); | 893 Constant expression = evaluate(part.expression); |
| 820 DartString expressionString; | 894 DartString expressionString; |
| 821 if (expression.isNum() || expression.isBool()) { | 895 if (expression.isNum() || expression.isBool()) { |
| 822 PrimitiveConstant primitive = expression; | 896 PrimitiveConstant primitive = expression; |
| 823 expressionString = new DartString.literal(primitive.value.toString()); | 897 expressionString = new DartString.literal(primitive.value.toString()); |
| 824 } else if (expression.isString()) { | 898 } else if (expression.isString()) { |
| 825 PrimitiveConstant primitive = expression; | 899 PrimitiveConstant primitive = expression; |
| 826 expressionString = primitive.value; | 900 expressionString = primitive.value; |
| 827 } else { | 901 } else { |
| 828 error(part.expression); | 902 signalNotACompileTimeConstant(part.expression); |
| 903 return null; | |
| 829 } | 904 } |
| 830 accumulator = new DartString.concat(accumulator, expressionString); | 905 accumulator = new DartString.concat(accumulator, expressionString); |
| 831 StringConstant partString = evaluate(part.string); | 906 StringConstant partString = evaluate(part.string); |
| 907 if (partString == null) return null; | |
| 832 accumulator = new DartString.concat(accumulator, partString.value); | 908 accumulator = new DartString.concat(accumulator, partString.value); |
| 833 }; | 909 }; |
| 834 return new StringConstant(accumulator, node); | 910 return new StringConstant(accumulator, node); |
| 835 } | 911 } |
| 836 | 912 |
| 837 // TODO(floitsch): provide better error-messages. | 913 // TODO(floitsch): provide better error-messages. |
| 838 Constant visitSend(Send send) { | 914 Constant visitSend(Send send) { |
| 839 Element element = elements[send]; | 915 Element element = elements[send]; |
| 840 if (Elements.isStaticOrTopLevelField(element)) { | 916 if (Elements.isStaticOrTopLevelField(element)) { |
| 841 if (element.modifiers === null || | 917 Constant result; |
| 842 !element.modifiers.isFinal()) { | 918 if (element.modifiers !== null) { |
| 843 error(send); | 919 if (element.modifiers.isConst()) { |
| 920 result = compiler.compileConstant(element); | |
| 921 } else if (element.modifiers.isFinal()) { | |
| 922 // TODO(4516): remove support for final compile-time constants: if | |
| 923 // isCompilingConstant is true don't compile the variable. | |
| 924 result = compiler.compileVariable(element); | |
| 925 } | |
| 844 } | 926 } |
| 845 return compiler.compileVariable(element); | 927 if (result == null) signalNotACompileTimeConstant(send); |
| 928 return result; | |
| 846 } else if (send.isPrefix) { | 929 } else if (send.isPrefix) { |
| 847 assert(send.isOperator); | 930 assert(send.isOperator); |
| 848 Constant receiverConstant = evaluate(send.receiver); | 931 Constant receiverConstant = evaluate(send.receiver); |
| 932 if (receiverConstant == null) return null; | |
| 849 Operator op = send.selector; | 933 Operator op = send.selector; |
| 850 Constant folded; | 934 Constant folded; |
| 851 switch (op.source.stringValue) { | 935 switch (op.source.stringValue) { |
| 852 case "!": | 936 case "!": |
| 853 folded = const NotOperation().fold(receiverConstant); | 937 folded = const NotOperation().fold(receiverConstant); |
| 854 break; | 938 break; |
| 855 case "-": | 939 case "-": |
| 856 folded = const NegateOperation().fold(receiverConstant); | 940 folded = const NegateOperation().fold(receiverConstant); |
| 857 break; | 941 break; |
| 858 case "~": | 942 case "~": |
| 859 folded = const BitNotOperation().fold(receiverConstant); | 943 folded = const BitNotOperation().fold(receiverConstant); |
| 860 break; | 944 break; |
| 861 default: | 945 default: |
| 862 compiler.internalError("Unexpected operator.", node: op); | 946 compiler.internalError("Unexpected operator.", node: op); |
| 863 break; | 947 break; |
| 864 } | 948 } |
| 865 if (folded === null) error(send); | 949 if (folded === null) signalNotACompileTimeConstant(send); |
| 866 return folded; | 950 return folded; |
| 867 } else if (send.isOperator && !send.isPostfix) { | 951 } else if (send.isOperator && !send.isPostfix) { |
| 868 assert(send.argumentCount() == 1); | 952 assert(send.argumentCount() == 1); |
| 869 Constant left = evaluate(send.receiver); | 953 Constant left = evaluate(send.receiver); |
| 870 Constant right = evaluate(send.argumentsNode.nodes.head); | 954 Constant right = evaluate(send.argumentsNode.nodes.head); |
| 955 if (left == null || right == null) return null; | |
| 871 Operator op = send.selector.asOperator(); | 956 Operator op = send.selector.asOperator(); |
| 872 Constant folded = null; | 957 Constant folded = null; |
| 873 switch (op.source.stringValue) { | 958 switch (op.source.stringValue) { |
| 874 case "+": | 959 case "+": |
| 875 folded = const AddOperation().fold(left, right); | 960 folded = const AddOperation().fold(left, right); |
| 876 break; | 961 break; |
| 877 case "-": | 962 case "-": |
| 878 folded = const SubtractOperation().fold(left, right); | 963 folded = const SubtractOperation().fold(left, right); |
| 879 break; | 964 break; |
| 880 case "*": | 965 case "*": |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 947 BoolConstant areIdentical = | 1032 BoolConstant areIdentical = |
| 948 const IdentityOperation().fold(left, right); | 1033 const IdentityOperation().fold(left, right); |
| 949 if (areIdentical === null) { | 1034 if (areIdentical === null) { |
| 950 folded = null; | 1035 folded = null; |
| 951 } else { | 1036 } else { |
| 952 folded = areIdentical.negate(); | 1037 folded = areIdentical.negate(); |
| 953 } | 1038 } |
| 954 } | 1039 } |
| 955 break; | 1040 break; |
| 956 } | 1041 } |
| 957 if (folded === null) error(send); | 1042 if (folded === null) signalNotACompileTimeConstant(send); |
| 958 return folded; | 1043 return folded; |
| 959 } | 1044 } |
| 960 return super.visitSend(send); | 1045 signalNotACompileTimeConstant(send); |
| 1046 return null; | |
| 961 } | 1047 } |
| 962 | 1048 |
| 963 visitSendSet(SendSet node) { | 1049 Constant visitSendSet(SendSet node) { |
| 964 error(node); | 1050 signalNotACompileTimeConstant(node); |
| 1051 return null; | |
| 965 } | 1052 } |
| 966 | 1053 |
| 967 /** Returns the list of constants that are passed to the static function. */ | 1054 /** Returns the list of constants that are passed to the static function. */ |
| 968 List<Constant> evaluateArgumentsToConstructor(Selector selector, | 1055 List<Constant> evaluateArgumentsToConstructor(Selector selector, |
| 969 Link<Node> arguments, | 1056 Link<Node> arguments, |
| 970 FunctionElement target) { | 1057 FunctionElement target) { |
| 971 List<Constant> compiledArguments = <Constant>[]; | 1058 List<Constant> compiledArguments = <Constant>[]; |
| 972 | 1059 |
| 973 Function compileArgument = evaluate; | 1060 Function compileArgument = evaluateConstant; |
| 974 Function compileConstant = compiler.compileVariable; | 1061 Function compileConstant = compiler.compileConstant; |
| 975 bool succeeded = selector.addArgumentsToList(arguments, | 1062 bool succeeded = selector.addArgumentsToList(arguments, |
| 976 compiledArguments, | 1063 compiledArguments, |
| 977 target, | 1064 target, |
| 978 compileArgument, | 1065 compileArgument, |
| 979 compileConstant, | 1066 compileConstant, |
| 980 compiler); | 1067 compiler); |
| 981 assert(succeeded); | 1068 assert(succeeded); |
| 982 return compiledArguments; | 1069 return compiledArguments; |
| 983 } | 1070 } |
| 984 | 1071 |
| 985 Constant visitNewExpression(NewExpression node) { | 1072 Constant visitNewExpression(NewExpression node) { |
| 986 if (!node.isConst()) error(node); | 1073 if (!node.isConst()) { |
| 1074 signalNotACompileTimeConstant(node); | |
| 1075 return null; | |
| 1076 } | |
| 987 | 1077 |
| 988 Send send = node.send; | 1078 Send send = node.send; |
| 989 FunctionElement constructor = elements[send]; | 1079 FunctionElement constructor = elements[send]; |
| 990 ClassElement classElement = constructor.getEnclosingClass(); | 1080 ClassElement classElement = constructor.getEnclosingClass(); |
| 991 if (classElement.isInterface()) { | 1081 if (classElement.isInterface()) { |
| 992 compiler.resolver.resolveMethodElement(constructor); | 1082 compiler.resolver.resolveMethodElement(constructor); |
| 993 constructor = constructor.defaultImplementation; | 1083 constructor = constructor.defaultImplementation; |
| 994 classElement = constructor.getEnclosingClass(); | 1084 classElement = constructor.getEnclosingClass(); |
| 995 } | 1085 } |
| 996 | 1086 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1013 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 1103 Constant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1014 return node.expression.accept(this); | 1104 return node.expression.accept(this); |
| 1015 } | 1105 } |
| 1016 | 1106 |
| 1017 error(Node node) { | 1107 error(Node node) { |
| 1018 // TODO(floitsch): get the list of constants that are currently compiled | 1108 // TODO(floitsch): get the list of constants that are currently compiled |
| 1019 // and present some kind of stack-trace. | 1109 // and present some kind of stack-trace. |
| 1020 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 1110 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
| 1021 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); | 1111 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); |
| 1022 } | 1112 } |
| 1113 | |
| 1114 void signalNotACompileTimeConstant(Node node) { | |
|
kasperl
2012/08/17 09:30:04
I would remove the A.
floitsch
2012/09/04 17:32:21
Done.
| |
| 1115 if (isEvaluatingConstant) { | |
| 1116 error(node); | |
| 1117 } | |
| 1118 // Else we don't need to do anything. The final handler is only | |
| 1119 // optimistically trying to compile constants. So it is normal that we | |
| 1120 // sometimes see non-compile time constants. | |
|
kasperl
2012/08/17 09:30:04
So in this case, you'll end up returning null anyw
floitsch
2012/09/04 17:32:21
Done.
| |
| 1121 } | |
| 1023 } | 1122 } |
| 1024 | 1123 |
| 1025 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { | 1124 class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator { |
| 1026 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): | 1125 TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler): |
| 1027 super(elements, compiler); | 1126 super(elements, compiler, isConst: true); |
| 1028 | 1127 |
| 1029 error(Node node) { | 1128 error(Node node) { |
| 1030 // Just fail without reporting it anywhere. | 1129 // Just fail without reporting it anywhere. |
| 1031 throw new CompileTimeConstantError( | 1130 throw new CompileTimeConstantError( |
| 1032 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); | 1131 MessageKind.NOT_A_COMPILE_TIME_CONSTANT, const []); |
| 1033 } | 1132 } |
| 1034 } | 1133 } |
| 1035 | 1134 |
| 1036 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 1135 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 1037 FunctionElement constructor; | 1136 FunctionElement constructor; |
| 1038 final Map<Element, Constant> definitions; | 1137 final Map<Element, Constant> definitions; |
| 1039 final Map<Element, Constant> fieldValues; | 1138 final Map<Element, Constant> fieldValues; |
| 1040 | 1139 |
| 1041 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) | 1140 ConstructorEvaluator(FunctionElement constructor, Compiler compiler) |
| 1042 : this.constructor = constructor, | 1141 : this.constructor = constructor, |
| 1043 this.definitions = new Map<Element, Constant>(), | 1142 this.definitions = new Map<Element, Constant>(), |
| 1044 this.fieldValues = new Map<Element, Constant>(), | 1143 this.fieldValues = new Map<Element, Constant>(), |
| 1045 super(compiler.resolver.resolveMethodElement(constructor), | 1144 super(compiler.resolver.resolveMethodElement(constructor), |
| 1046 compiler); | 1145 compiler, |
| 1146 isConst: true); | |
| 1047 | 1147 |
| 1048 Constant visitSend(Send send) { | 1148 Constant visitSend(Send send) { |
| 1049 Element element = elements[send]; | 1149 Element element = elements[send]; |
| 1050 if (Elements.isLocal(element)) { | 1150 if (Elements.isLocal(element)) { |
| 1051 Constant constant = definitions[element]; | 1151 Constant constant = definitions[element]; |
| 1052 if (constant === null) { | 1152 if (constant === null) { |
| 1053 compiler.internalError("Local variable without value", node: send); | 1153 compiler.internalError("Local variable without value", node: send); |
| 1054 } | 1154 } |
| 1055 return constant; | 1155 return constant; |
| 1056 } | 1156 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1162 | 1262 |
| 1163 List<Constant> buildJsNewArguments(ClassElement classElement) { | 1263 List<Constant> buildJsNewArguments(ClassElement classElement) { |
| 1164 List<Constant> jsNewArguments = <Constant>[]; | 1264 List<Constant> jsNewArguments = <Constant>[]; |
| 1165 classElement.forEachInstanceField( | 1265 classElement.forEachInstanceField( |
| 1166 includeBackendMembers: true, | 1266 includeBackendMembers: true, |
| 1167 includeSuperMembers: true, | 1267 includeSuperMembers: true, |
| 1168 f: (ClassElement enclosing, Element field) { | 1268 f: (ClassElement enclosing, Element field) { |
| 1169 Constant fieldValue = fieldValues[field]; | 1269 Constant fieldValue = fieldValues[field]; |
| 1170 if (fieldValue === null) { | 1270 if (fieldValue === null) { |
| 1171 // Use the default value. | 1271 // Use the default value. |
| 1172 fieldValue = compiler.compileVariable(field); | 1272 fieldValue = compiler.compileConstant(field); |
| 1173 } | 1273 } |
| 1174 jsNewArguments.add(fieldValue); | 1274 jsNewArguments.add(fieldValue); |
| 1175 }); | 1275 }); |
| 1176 return jsNewArguments; | 1276 return jsNewArguments; |
| 1177 } | 1277 } |
| 1178 } | 1278 } |
| OLD | NEW |