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

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: Fix tests. Created 8 years, 4 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 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
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.*/
kasperl 2012/08/16 14:41:37 Space between . and */
floitsch 2012/08/16 22:52:33 Done.
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.*/
kasperl 2012/08/16 14:41:37 Space between . and */
floitsch 2012/08/16 22:52:33 Done.
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.
kasperl 2012/08/16 14:41:37 `null` -- back ticks, really?
floitsch 2012/08/16 22:52:33 I find it nice to read and it's the code-tag in ma
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;
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
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
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
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
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
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) {
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.
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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1159 1259
1160 List<Constant> buildJsNewArguments(ClassElement classElement) { 1260 List<Constant> buildJsNewArguments(ClassElement classElement) {
1161 List<Constant> jsNewArguments = <Constant>[]; 1261 List<Constant> jsNewArguments = <Constant>[];
1162 classElement.forEachInstanceField( 1262 classElement.forEachInstanceField(
1163 includeBackendMembers: true, 1263 includeBackendMembers: true,
1164 includeSuperMembers: true, 1264 includeSuperMembers: true,
1165 f: (ClassElement enclosing, Element field) { 1265 f: (ClassElement enclosing, Element field) {
1166 Constant fieldValue = fieldValues[field]; 1266 Constant fieldValue = fieldValues[field];
1167 if (fieldValue === null) { 1267 if (fieldValue === null) {
1168 // Use the default value. 1268 // Use the default value.
1169 fieldValue = compiler.compileVariable(field); 1269 fieldValue = compiler.compileConstant(field);
1170 } 1270 }
1171 jsNewArguments.add(fieldValue); 1271 jsNewArguments.add(fieldValue);
1172 }); 1272 });
1173 return jsNewArguments; 1273 return jsNewArguments;
1174 } 1274 }
1175 } 1275 }
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