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

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

Powered by Google App Engine
This is Rietveld 408576698