Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(365)

Side by Side Diff: lib/compiler/implementation/compile_time_constants.dart

Issue 10855174: Lazy implementation of final variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments and move some code from compiler to backend. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/compiler.dart » ('j') | lib/compiler/implementation/compiler.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698