OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 // This code was auto-generated, is not intended to be edited, and is subject to | 5 // This code was auto-generated, is not intended to be edited, and is subject to |
6 // significant change. Please see the README file for more information. | 6 // significant change. Please see the README file for more information. |
7 | 7 |
8 library engine.constant; | 8 library engine.constant; |
9 | 9 |
10 import 'dart:collection'; | 10 import 'dart:collection'; |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 definingClass, new SymbolState(argumentValue)); | 421 definingClass, new SymbolState(argumentValue)); |
422 } | 422 } |
423 // Either it's an external const factory constructor that we can't | 423 // Either it's an external const factory constructor that we can't |
424 // emulate, or an error occurred (a cycle, or a const constructor trying | 424 // emulate, or an error occurred (a cycle, or a const constructor trying |
425 // to delegate to a non-const constructor). | 425 // to delegate to a non-const constructor). |
426 // In the former case, the best we can do is consider it an unknown value. | 426 // In the former case, the best we can do is consider it an unknown value. |
427 // In the latter case, the error has already been reported, so considering | 427 // In the latter case, the error has already been reported, so considering |
428 // it an unknown value will suppress further errors. | 428 // it an unknown value will suppress further errors. |
429 return new DartObjectImpl.validWithUnknownValue(definingClass); | 429 return new DartObjectImpl.validWithUnknownValue(definingClass); |
430 } | 430 } |
431 validator.beforeGetConstantInitializers(constructor); | |
432 ConstructorElementImpl constructorBase = _getConstructorBase(constructor); | 431 ConstructorElementImpl constructorBase = _getConstructorBase(constructor); |
| 432 validator.beforeGetConstantInitializers(constructorBase); |
433 List<ConstructorInitializer> initializers = | 433 List<ConstructorInitializer> initializers = |
434 constructorBase.constantInitializers; | 434 constructorBase.constantInitializers; |
435 if (initializers == null) { | 435 if (initializers == null) { |
436 // This can happen in some cases where there are compile errors in the | 436 // This can happen in some cases where there are compile errors in the |
437 // code being analyzed (for example if the code is trying to create a | 437 // code being analyzed (for example if the code is trying to create a |
438 // const instance using a non-const constructor, or the node we're | 438 // const instance using a non-const constructor, or the node we're |
439 // visiting is involved in a cycle). The error has already been reported, | 439 // visiting is involved in a cycle). The error has already been reported, |
440 // so consider it an unknown value to suppress further errors. | 440 // so consider it an unknown value to suppress further errors. |
441 return new DartObjectImpl.validWithUnknownValue(definingClass); | 441 return new DartObjectImpl.validWithUnknownValue(definingClass); |
442 } | 442 } |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 } | 695 } |
696 } | 696 } |
697 | 697 |
698 /** | 698 /** |
699 * Interface used by unit tests to verify correct dependency analysis during | 699 * Interface used by unit tests to verify correct dependency analysis during |
700 * constant evaluation. | 700 * constant evaluation. |
701 */ | 701 */ |
702 abstract class ConstantEvaluationValidator { | 702 abstract class ConstantEvaluationValidator { |
703 /** | 703 /** |
704 * This method is called just before computing the constant value associated | 704 * This method is called just before computing the constant value associated |
705 * with [constNode]. Unit tests will override this method to introduce | 705 * with [element]. Unit tests will override this method to introduce |
706 * additional error checking. | 706 * additional error checking. |
707 */ | 707 */ |
708 void beforeComputeValue(AstNode constNode); | 708 void beforeComputeValue(Element element); |
709 | 709 |
710 /** | 710 /** |
711 * This method is called just before getting the constant initializers | 711 * This method is called just before getting the constant initializers |
712 * associated with the [constructor]. Unit tests will override this method to | 712 * associated with the [constructor]. Unit tests will override this method to |
713 * introduce additional error checking. | 713 * introduce additional error checking. |
714 */ | 714 */ |
715 void beforeGetConstantInitializers(ConstructorElement constructor); | 715 void beforeGetConstantInitializers(ConstructorElement constructor); |
716 | 716 |
717 /** | 717 /** |
718 * This method is called just before retrieving an evaluation result from an | 718 * This method is called just before retrieving an evaluation result from an |
719 * AST node. Unit tests will override it to introduce additional error | 719 * element. Unit tests will override it to introduce additional error |
720 * checking. | 720 * checking. |
721 */ | 721 */ |
722 void beforeGetEvaluationResult(AstNode node); | 722 void beforeGetEvaluationResult(Element element); |
723 | 723 |
724 /** | 724 /** |
725 * This method is called just before getting the constant value of a field | 725 * This method is called just before getting the constant value of a field |
726 * with an initializer. Unit tests will override this method to introduce | 726 * with an initializer. Unit tests will override this method to introduce |
727 * additional error checking. | 727 * additional error checking. |
728 */ | 728 */ |
729 void beforeGetFieldEvaluationResult(FieldElementImpl field); | 729 void beforeGetFieldEvaluationResult(FieldElementImpl field); |
730 | 730 |
731 /** | 731 /** |
732 * This method is called just before getting a parameter's default value. Unit | 732 * This method is called just before getting a parameter's default value. Unit |
733 * tests will override this method to introduce additional error checking. | 733 * tests will override this method to introduce additional error checking. |
734 */ | 734 */ |
735 void beforeGetParameterDefault(ParameterElement parameter); | 735 void beforeGetParameterDefault(ParameterElement parameter); |
736 } | 736 } |
737 | 737 |
738 /** | 738 /** |
739 * Implementation of [ConstantEvaluationValidator] used in production; does no | 739 * Implementation of [ConstantEvaluationValidator] used in production; does no |
740 * validation. | 740 * validation. |
741 */ | 741 */ |
742 class ConstantEvaluationValidator_ForProduction | 742 class ConstantEvaluationValidator_ForProduction |
743 implements ConstantEvaluationValidator { | 743 implements ConstantEvaluationValidator { |
744 @override | 744 @override |
745 void beforeComputeValue(AstNode constNode) {} | 745 void beforeComputeValue(Element element) {} |
746 | 746 |
747 @override | 747 @override |
748 void beforeGetConstantInitializers(ConstructorElement constructor) {} | 748 void beforeGetConstantInitializers(ConstructorElement constructor) {} |
749 | 749 |
750 @override | 750 @override |
751 void beforeGetEvaluationResult(AstNode node) {} | 751 void beforeGetEvaluationResult(Element element) {} |
752 | 752 |
753 @override | 753 @override |
754 void beforeGetFieldEvaluationResult(FieldElementImpl field) {} | 754 void beforeGetFieldEvaluationResult(FieldElementImpl field) {} |
755 | 755 |
756 @override | 756 @override |
757 void beforeGetParameterDefault(ParameterElement parameter) {} | 757 void beforeGetParameterDefault(ParameterElement parameter) {} |
758 } | 758 } |
759 | 759 |
760 /** | 760 /** |
761 * Instances of the class `ConstantEvaluator` evaluate constant expressions to | 761 * Instances of the class `ConstantEvaluator` evaluate constant expressions to |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 } | 845 } |
846 | 846 |
847 /** | 847 /** |
848 * A visitor used to traverse the AST structures of all of the compilation units | 848 * A visitor used to traverse the AST structures of all of the compilation units |
849 * being resolved and build tables of the constant variables, constant | 849 * being resolved and build tables of the constant variables, constant |
850 * constructors, constant constructor invocations, and annotations found in | 850 * constructors, constant constructor invocations, and annotations found in |
851 * those compilation units. | 851 * those compilation units. |
852 */ | 852 */ |
853 class ConstantFinder extends RecursiveAstVisitor<Object> { | 853 class ConstantFinder extends RecursiveAstVisitor<Object> { |
854 /** | 854 /** |
855 * A table mapping constant variable elements to the declarations of those | 855 * The elements whose constant values need to be computed, with the exception |
856 * variables. | 856 * of annotations. |
857 */ | 857 */ |
858 final HashMap<PotentiallyConstVariableElement, VariableDeclaration> variableMa
p = | 858 HashSet<Element> constantsToCompute = new HashSet<Element>(); |
859 new HashMap<PotentiallyConstVariableElement, VariableDeclaration>(); | |
860 | |
861 /** | |
862 * A table mapping constant constructors to the declarations of those | |
863 * constructors. | |
864 */ | |
865 final HashMap<ConstructorElement, ConstructorDeclaration> constructorMap = | |
866 new HashMap<ConstructorElement, ConstructorDeclaration>(); | |
867 | 859 |
868 /** | 860 /** |
869 * A collection of annotations. | 861 * A collection of annotations. |
870 */ | 862 */ |
871 final List<Annotation> annotations = <Annotation>[]; | 863 final List<Annotation> annotations = <Annotation>[]; |
872 | 864 |
873 /** | 865 /** |
874 * True if instance variables marked as "final" should be treated as "const". | 866 * True if instance variables marked as "final" should be treated as "const". |
875 */ | 867 */ |
876 bool treatFinalInstanceVarAsConst = false; | 868 bool treatFinalInstanceVarAsConst = false; |
(...skipping 20 matching lines...) Expand all Loading... |
897 treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst; | 889 treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst; |
898 } | 890 } |
899 } | 891 } |
900 | 892 |
901 @override | 893 @override |
902 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 894 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
903 super.visitConstructorDeclaration(node); | 895 super.visitConstructorDeclaration(node); |
904 if (node.constKeyword != null) { | 896 if (node.constKeyword != null) { |
905 ConstructorElement element = node.element; | 897 ConstructorElement element = node.element; |
906 if (element != null) { | 898 if (element != null) { |
907 constructorMap[element] = node; | 899 constantsToCompute.add(element); |
| 900 constantsToCompute.addAll(element.parameters); |
908 } | 901 } |
909 } | 902 } |
910 return null; | 903 return null; |
911 } | 904 } |
912 | 905 |
913 @override | 906 @override |
914 Object visitVariableDeclaration(VariableDeclaration node) { | 907 Object visitVariableDeclaration(VariableDeclaration node) { |
915 super.visitVariableDeclaration(node); | 908 super.visitVariableDeclaration(node); |
916 Expression initializer = node.initializer; | 909 Expression initializer = node.initializer; |
917 VariableElement element = node.element; | 910 VariableElement element = node.element; |
918 if (initializer != null && | 911 if (initializer != null && |
919 (node.isConst || | 912 (node.isConst || |
920 treatFinalInstanceVarAsConst && | 913 treatFinalInstanceVarAsConst && |
921 element is FieldElement && | 914 element is FieldElement && |
922 node.isFinal && | 915 node.isFinal && |
923 !element.isStatic)) { | 916 !element.isStatic)) { |
924 if (node.element != null) { | 917 if (node.element != null) { |
925 variableMap[node.element as PotentiallyConstVariableElement] = node; | 918 constantsToCompute.add(node.element); |
926 } | 919 } |
927 } | 920 } |
928 return null; | 921 return null; |
929 } | 922 } |
930 } | 923 } |
931 | 924 |
932 /** | 925 /** |
933 * An object used to compute the values of constant variables and constant | 926 * An object used to compute the values of constant variables and constant |
934 * constructor invocations in one or more compilation units. The expected usage | 927 * constructor invocations in one or more compilation units. The expected usage |
935 * pattern is for the compilation units to be added to this computer using the | 928 * pattern is for the compilation units to be added to this computer using the |
(...skipping 19 matching lines...) Expand all Loading... |
955 /** | 948 /** |
956 * The object used to find constant variables and constant constructor | 949 * The object used to find constant variables and constant constructor |
957 * invocations in the compilation units that were added. | 950 * invocations in the compilation units that were added. |
958 */ | 951 */ |
959 ConstantFinder _constantFinder = new ConstantFinder(); | 952 ConstantFinder _constantFinder = new ConstantFinder(); |
960 | 953 |
961 /** | 954 /** |
962 * A graph in which the nodes are the constants, and the edges are from each | 955 * A graph in which the nodes are the constants, and the edges are from each |
963 * constant to the other constants that are referenced by it. | 956 * constant to the other constants that are referenced by it. |
964 */ | 957 */ |
965 DirectedGraph<AstNode> referenceGraph = new DirectedGraph<AstNode>(); | 958 DirectedGraph<Element> referenceGraph = new DirectedGraph<Element>(); |
966 | 959 |
967 /** | 960 /** |
968 * A table mapping constant variables to the declarations of those variables. | 961 * The elements whose constant values need to be computed. Any elements |
| 962 * which appear in [referenceGraph] but not in this set either belong to a |
| 963 * different library cycle (and hence don't need to be recomputed) or were |
| 964 * computed during a previous stage of resolution stage (e.g. constants |
| 965 * associated with enums). |
969 */ | 966 */ |
970 HashMap<PotentiallyConstVariableElement, VariableDeclaration> _variableDeclara
tionMap; | 967 HashSet<Element> _constantsToCompute; |
971 | |
972 /** | |
973 * A table mapping constant constructors to the declarations of those | |
974 * constructors. | |
975 */ | |
976 HashMap<ConstructorElement, ConstructorDeclaration> constructorDeclarationMap; | |
977 | 968 |
978 /** | 969 /** |
979 * A collection of annotations. | 970 * A collection of annotations. |
980 */ | 971 */ |
981 List<Annotation> _annotations; | 972 List<Annotation> _annotations; |
982 | 973 |
983 /** | 974 /** |
984 * The evaluation engine that does the work of evaluating instance creation | 975 * The evaluation engine that does the work of evaluating instance creation |
985 * expressions. | 976 * expressions. |
986 */ | 977 */ |
(...skipping 16 matching lines...) Expand all Loading... |
1003 */ | 994 */ |
1004 void add(CompilationUnit unit) { | 995 void add(CompilationUnit unit) { |
1005 unit.accept(_constantFinder); | 996 unit.accept(_constantFinder); |
1006 } | 997 } |
1007 | 998 |
1008 /** | 999 /** |
1009 * Compute values for all of the constants in the compilation units that were | 1000 * Compute values for all of the constants in the compilation units that were |
1010 * added. | 1001 * added. |
1011 */ | 1002 */ |
1012 void computeValues() { | 1003 void computeValues() { |
1013 _variableDeclarationMap = _constantFinder.variableMap; | 1004 _constantsToCompute = _constantFinder.constantsToCompute; |
1014 constructorDeclarationMap = _constantFinder.constructorMap; | |
1015 _annotations = _constantFinder.annotations; | 1005 _annotations = _constantFinder.annotations; |
1016 _variableDeclarationMap.values.forEach((VariableDeclaration declaration) { | 1006 for (Element element in _constantsToCompute) { |
1017 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, | 1007 referenceGraph.addNode(element); |
1018 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); | 1008 if (element is ParameterElement) { |
1019 referenceGraph.addNode(declaration); | 1009 if (element.initializer != null) { |
1020 declaration.initializer.accept(referenceFinder); | 1010 Expression defaultValue = |
1021 }); | 1011 (element as ConstVariableElement).constantInitializer; |
1022 constructorDeclarationMap.forEach((ConstructorElementImpl element, | |
1023 ConstructorDeclaration declaration) { | |
1024 element.isCycleFree = false; | |
1025 ConstructorElement redirectedConstructor = | |
1026 evaluationEngine.getConstRedirectedConstructor(element); | |
1027 if (redirectedConstructor != null) { | |
1028 ConstructorElement redirectedConstructorBase = | |
1029 ConstantEvaluationEngine._getConstructorBase(redirectedConstructor); | |
1030 ConstructorDeclaration redirectedConstructorDeclaration = | |
1031 findConstructorDeclaration(redirectedConstructorBase); | |
1032 referenceGraph.addEdge(declaration, redirectedConstructorDeclaration); | |
1033 return; | |
1034 } | |
1035 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, | |
1036 referenceGraph, _variableDeclarationMap, constructorDeclarationMap); | |
1037 referenceGraph.addNode(declaration); | |
1038 bool superInvocationFound = false; | |
1039 NodeList<ConstructorInitializer> initializers = declaration.initializers; | |
1040 for (ConstructorInitializer initializer in initializers) { | |
1041 if (initializer is SuperConstructorInvocation) { | |
1042 superInvocationFound = true; | |
1043 } | |
1044 initializer.accept(referenceFinder); | |
1045 } | |
1046 if (!superInvocationFound) { | |
1047 // No explicit superconstructor invocation found, so we need to | |
1048 // manually insert a reference to the implicit superconstructor. | |
1049 InterfaceType superclass = | |
1050 (element.returnType as InterfaceType).superclass; | |
1051 if (superclass != null && !superclass.isObject) { | |
1052 ConstructorElement unnamedConstructor = | |
1053 superclass.element.unnamedConstructor; | |
1054 ConstructorDeclaration superConstructorDeclaration = | |
1055 findConstructorDeclaration(unnamedConstructor); | |
1056 if (superConstructorDeclaration != null) { | |
1057 referenceGraph.addEdge(declaration, superConstructorDeclaration); | |
1058 } | |
1059 } | |
1060 } | |
1061 for (FieldElement field in element.enclosingElement.fields) { | |
1062 // Note: non-static const isn't allowed but we handle it anyway so that | |
1063 // we won't be confused by incorrect code. | |
1064 if ((field.isFinal || field.isConst) && !field.isStatic) { | |
1065 VariableDeclaration fieldDeclaration = _variableDeclarationMap[field]; | |
1066 if (fieldDeclaration != null) { | |
1067 referenceGraph.addEdge(declaration, fieldDeclaration); | |
1068 } | |
1069 } | |
1070 } | |
1071 for (FormalParameter parameter in declaration.parameters.parameters) { | |
1072 referenceGraph.addNode(parameter); | |
1073 referenceGraph.addEdge(declaration, parameter); | |
1074 if (parameter is DefaultFormalParameter) { | |
1075 Expression defaultValue = parameter.defaultValue; | |
1076 if (defaultValue != null) { | 1012 if (defaultValue != null) { |
1077 ReferenceFinder parameterReferenceFinder = new ReferenceFinder( | 1013 ReferenceFinder parameterReferenceFinder = |
1078 parameter, referenceGraph, _variableDeclarationMap, | 1014 new ReferenceFinder(element, referenceGraph); |
1079 constructorDeclarationMap); | |
1080 defaultValue.accept(parameterReferenceFinder); | 1015 defaultValue.accept(parameterReferenceFinder); |
1081 } | 1016 } |
1082 } | 1017 } |
| 1018 } else if (element is PotentiallyConstVariableElement) { |
| 1019 ReferenceFinder referenceFinder = |
| 1020 new ReferenceFinder(element, referenceGraph); |
| 1021 element.constantInitializer.accept(referenceFinder); |
| 1022 } else if (element is ConstructorElementImpl) { |
| 1023 element.isCycleFree = false; |
| 1024 ConstructorElement redirectedConstructor = |
| 1025 evaluationEngine.getConstRedirectedConstructor(element); |
| 1026 if (redirectedConstructor != null) { |
| 1027 ConstructorElement redirectedConstructorBase = |
| 1028 ConstantEvaluationEngine |
| 1029 ._getConstructorBase(redirectedConstructor); |
| 1030 referenceGraph.addEdge(element, redirectedConstructorBase); |
| 1031 continue; |
| 1032 } |
| 1033 ReferenceFinder referenceFinder = |
| 1034 new ReferenceFinder(element, referenceGraph); |
| 1035 bool superInvocationFound = false; |
| 1036 List<ConstructorInitializer> initializers = |
| 1037 element.constantInitializers; |
| 1038 for (ConstructorInitializer initializer in initializers) { |
| 1039 if (initializer is SuperConstructorInvocation) { |
| 1040 superInvocationFound = true; |
| 1041 } |
| 1042 initializer.accept(referenceFinder); |
| 1043 } |
| 1044 if (!superInvocationFound) { |
| 1045 // No explicit superconstructor invocation found, so we need to |
| 1046 // manually insert a reference to the implicit superconstructor. |
| 1047 InterfaceType superclass = |
| 1048 (element.returnType as InterfaceType).superclass; |
| 1049 if (superclass != null && !superclass.isObject) { |
| 1050 ConstructorElement unnamedConstructor = ConstantEvaluationEngine |
| 1051 ._getConstructorBase(superclass.element.unnamedConstructor); |
| 1052 if (unnamedConstructor != null) { |
| 1053 referenceGraph.addEdge(element, unnamedConstructor); |
| 1054 } |
| 1055 } |
| 1056 } |
| 1057 for (FieldElement field in element.enclosingElement.fields) { |
| 1058 // Note: non-static const isn't allowed but we handle it anyway so tha
t |
| 1059 // we won't be confused by incorrect code. |
| 1060 if ((field.isFinal || field.isConst) && |
| 1061 !field.isStatic && |
| 1062 field.initializer != null) { |
| 1063 referenceGraph.addEdge(element, field); |
| 1064 } |
| 1065 } |
| 1066 for (ParameterElement parameterElement in element.parameters) { |
| 1067 referenceGraph.addEdge(element, parameterElement); |
| 1068 } |
| 1069 } else { |
| 1070 // Should not happen. |
| 1071 assert(false); |
| 1072 AnalysisEngine.instance.logger.logError( |
| 1073 "Constant value computer trying to compute the value of a node of ty
pe ${element.runtimeType}"); |
1083 } | 1074 } |
1084 }); | 1075 } |
1085 List<List<AstNode>> topologicalSort = | 1076 List<List<Element>> topologicalSort = |
1086 referenceGraph.computeTopologicalSort(); | 1077 referenceGraph.computeTopologicalSort(); |
1087 for (List<AstNode> constantsInCycle in topologicalSort) { | 1078 for (List<Element> constantsInCycle in topologicalSort) { |
1088 if (constantsInCycle.length == 1) { | 1079 if (constantsInCycle.length == 1) { |
1089 _computeValueFor(constantsInCycle[0]); | 1080 _computeValueFor(constantsInCycle[0]); |
1090 } else { | 1081 } else { |
1091 for (AstNode constant in constantsInCycle) { | 1082 for (Element constant in constantsInCycle) { |
1092 _generateCycleError(constantsInCycle, constant); | 1083 _generateCycleError(constantsInCycle, constant); |
1093 } | 1084 } |
1094 } | 1085 } |
1095 } | 1086 } |
1096 // Since no constant can depend on an annotation, we don't waste time | 1087 // Since no constant can depend on an annotation, we don't waste time |
1097 // including them in the topological sort. We just process all the | 1088 // including them in the topological sort. We just process all the |
1098 // annotations after all other constants are finished. | 1089 // annotations after all other constants are finished. |
1099 for (Annotation annotation in _annotations) { | 1090 for (Annotation annotation in _annotations) { |
1100 _computeValueFor(annotation); | 1091 _computeValueForAnnotation(annotation); |
1101 } | 1092 } |
1102 } | 1093 } |
1103 | 1094 |
1104 ConstructorDeclaration findConstructorDeclaration( | |
1105 ConstructorElement constructor) => constructorDeclarationMap[ | |
1106 ConstantEvaluationEngine._getConstructorBase(constructor)]; | |
1107 | |
1108 VariableDeclaration findVariableDeclaration( | |
1109 PotentiallyConstVariableElement variable) => | |
1110 _variableDeclarationMap[variable]; | |
1111 | |
1112 /** | 1095 /** |
1113 * Compute a value for the given [constNode]. | 1096 * Compute a value for the given [element]. |
1114 */ | 1097 */ |
1115 void _computeValueFor(AstNode constNode) { | 1098 void _computeValueFor(Element element) { |
1116 evaluationEngine.validator.beforeComputeValue(constNode); | 1099 if (!_constantsToCompute.contains(element)) { |
1117 if (constNode is VariableDeclaration) { | 1100 // Element is in the dependency graph but should have been computed by |
1118 VariableElement element = constNode.element; | 1101 // a previous stage of analysis. |
| 1102 return; |
| 1103 } |
| 1104 evaluationEngine.validator.beforeComputeValue(element); |
| 1105 if (element is ParameterElement) { |
| 1106 if (element.initializer != null) { |
| 1107 Expression defaultValue = |
| 1108 (element as PotentiallyConstVariableElement).constantInitializer; |
| 1109 if (defaultValue != null) { |
| 1110 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1111 ErrorReporter errorReporter = |
| 1112 new ErrorReporter(errorListener, element.source); |
| 1113 DartObjectImpl dartObject = defaultValue |
| 1114 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); |
| 1115 (element as ParameterElementImpl).evaluationResult = |
| 1116 new EvaluationResultImpl.con2(dartObject, errorListener.errors); |
| 1117 } |
| 1118 } |
| 1119 } else if (element is VariableElement) { |
1119 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1120 RecordingErrorListener errorListener = new RecordingErrorListener(); |
1120 ErrorReporter errorReporter = | 1121 ErrorReporter errorReporter = |
1121 new ErrorReporter(errorListener, element.source); | 1122 new ErrorReporter(errorListener, element.source); |
1122 DartObjectImpl dartObject = | 1123 DartObjectImpl dartObject = |
1123 (element as PotentiallyConstVariableElement).constantInitializer | 1124 (element as PotentiallyConstVariableElement).constantInitializer |
1124 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); | 1125 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); |
1125 // Only check the type for truly const declarations (don't check final | 1126 // Only check the type for truly const declarations (don't check final |
1126 // fields with initializers, since their types may be generic. The type | 1127 // fields with initializers, since their types may be generic. The type |
1127 // of the final field will be checked later, when the constructor is | 1128 // of the final field will be checked later, when the constructor is |
1128 // invoked). | 1129 // invoked). |
1129 if (dartObject != null && constNode.isConst) { | 1130 if (dartObject != null && element.isConst) { |
1130 if (!evaluationEngine.runtimeTypeMatch(dartObject, element.type)) { | 1131 if (!evaluationEngine.runtimeTypeMatch(dartObject, element.type)) { |
1131 errorReporter.reportErrorForElement( | 1132 errorReporter.reportErrorForElement( |
1132 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, element, [ | 1133 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, element, [ |
1133 dartObject.type, | 1134 dartObject.type, |
1134 element.type | 1135 element.type |
1135 ]); | 1136 ]); |
1136 } | 1137 } |
1137 } | 1138 } |
1138 (element as VariableElementImpl).evaluationResult = | 1139 (element as VariableElementImpl).evaluationResult = |
1139 new EvaluationResultImpl.con2(dartObject, errorListener.errors); | 1140 new EvaluationResultImpl.con2(dartObject, errorListener.errors); |
1140 } else if (constNode is ConstructorDeclaration) { | 1141 } else if (element is ConstructorElement) { |
1141 // No evaluation needs to be done; constructor declarations are only in | 1142 // No evaluation needs to be done; constructor declarations are only in |
1142 // the dependency graph to ensure that any constants referred to in | 1143 // the dependency graph to ensure that any constants referred to in |
1143 // initializer lists and parameter defaults are evaluated before | 1144 // initializer lists and parameter defaults are evaluated before |
1144 // invocations of the constructor. However we do need to annotate the | 1145 // invocations of the constructor. However we do need to annotate the |
1145 // element as being free of constant evaluation cycles so that later code | 1146 // element as being free of constant evaluation cycles so that later code |
1146 // will know that it is safe to evaluate. | 1147 // will know that it is safe to evaluate. |
1147 ConstructorElementImpl constructor = constNode.element; | 1148 (element as ConstructorElementImpl).isCycleFree = true; |
1148 constructor.isCycleFree = true; | |
1149 } else if (constNode is FormalParameter) { | |
1150 if (constNode is DefaultFormalParameter) { | |
1151 ParameterElement element = constNode.element; | |
1152 Expression defaultValue = | |
1153 (element as PotentiallyConstVariableElement).constantInitializer; | |
1154 if (defaultValue != null) { | |
1155 RecordingErrorListener errorListener = new RecordingErrorListener(); | |
1156 ErrorReporter errorReporter = | |
1157 new ErrorReporter(errorListener, element.source); | |
1158 DartObjectImpl dartObject = defaultValue | |
1159 .accept(new ConstantVisitor(evaluationEngine, errorReporter)); | |
1160 (element as ParameterElementImpl).evaluationResult = | |
1161 new EvaluationResultImpl.con2(dartObject, errorListener.errors); | |
1162 } | |
1163 } | |
1164 } else if (constNode is Annotation) { | |
1165 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; | |
1166 // elementAnnotation is null if the annotation couldn't be resolved, in | |
1167 // which case we skip it. | |
1168 if (elementAnnotation != null) { | |
1169 Element element = elementAnnotation.element; | |
1170 if (element is PropertyAccessorElement && | |
1171 element.variable is VariableElementImpl) { | |
1172 // The annotation is a reference to a compile-time constant variable. | |
1173 // Just copy the evaluation result. | |
1174 VariableElementImpl variableElement = | |
1175 element.variable as VariableElementImpl; | |
1176 elementAnnotation.evaluationResult = variableElement.evaluationResult; | |
1177 } else if (element is ConstructorElementImpl && | |
1178 constNode.arguments != null) { | |
1179 RecordingErrorListener errorListener = new RecordingErrorListener(); | |
1180 CompilationUnit sourceCompilationUnit = | |
1181 constNode.getAncestor((node) => node is CompilationUnit); | |
1182 ErrorReporter errorReporter = new ErrorReporter( | |
1183 errorListener, sourceCompilationUnit.element.source); | |
1184 ConstantVisitor constantVisitor = | |
1185 new ConstantVisitor(evaluationEngine, errorReporter); | |
1186 DartObjectImpl result = evaluationEngine.evaluateConstructorCall( | |
1187 constNode, constNode.arguments.arguments, element, | |
1188 constantVisitor, errorReporter); | |
1189 elementAnnotation.evaluationResult = | |
1190 new EvaluationResultImpl.con2(result, errorListener.errors); | |
1191 } else { | |
1192 // This may happen for invalid code (e.g. failing to pass arguments | |
1193 // to an annotation which references a const constructor). The error | |
1194 // is detected elsewhere, so just silently ignore it here. | |
1195 elementAnnotation.evaluationResult = | |
1196 new EvaluationResultImpl.con1(null); | |
1197 } | |
1198 } | |
1199 } else { | 1149 } else { |
1200 // Should not happen. | 1150 // Should not happen. |
1201 assert(false); | 1151 assert(false); |
1202 AnalysisEngine.instance.logger.logError( | 1152 AnalysisEngine.instance.logger.logError( |
1203 "Constant value computer trying to compute the value of a node which i
s not a VariableDeclaration, InstanceCreationExpression, FormalParameter, or Con
structorDeclaration"); | 1153 "Constant value computer trying to compute the value of a node of type
${element.runtimeType}"); |
1204 return; | 1154 return; |
1205 } | 1155 } |
1206 } | 1156 } |
1207 | 1157 |
1208 /** | 1158 /** |
| 1159 * Compute a value for the given annotation. |
| 1160 */ |
| 1161 void _computeValueForAnnotation(Annotation constNode) { |
| 1162 ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; |
| 1163 // elementAnnotation is null if the annotation couldn't be resolved, in |
| 1164 // which case we skip it. |
| 1165 if (elementAnnotation != null) { |
| 1166 Element element = elementAnnotation.element; |
| 1167 if (element is PropertyAccessorElement && |
| 1168 element.variable is VariableElementImpl) { |
| 1169 // The annotation is a reference to a compile-time constant variable. |
| 1170 // Just copy the evaluation result. |
| 1171 VariableElementImpl variableElement = |
| 1172 element.variable as VariableElementImpl; |
| 1173 elementAnnotation.evaluationResult = variableElement.evaluationResult; |
| 1174 } else if (element is ConstructorElementImpl && |
| 1175 constNode.arguments != null) { |
| 1176 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1177 CompilationUnit sourceCompilationUnit = |
| 1178 constNode.getAncestor((node) => node is CompilationUnit); |
| 1179 ErrorReporter errorReporter = new ErrorReporter( |
| 1180 errorListener, sourceCompilationUnit.element.source); |
| 1181 ConstantVisitor constantVisitor = |
| 1182 new ConstantVisitor(evaluationEngine, errorReporter); |
| 1183 DartObjectImpl result = evaluationEngine.evaluateConstructorCall( |
| 1184 constNode, constNode.arguments.arguments, element, constantVisitor, |
| 1185 errorReporter); |
| 1186 elementAnnotation.evaluationResult = |
| 1187 new EvaluationResultImpl.con2(result, errorListener.errors); |
| 1188 } else { |
| 1189 // This may happen for invalid code (e.g. failing to pass arguments |
| 1190 // to an annotation which references a const constructor). The error |
| 1191 // is detected elsewhere, so just silently ignore it here. |
| 1192 elementAnnotation.evaluationResult = |
| 1193 new EvaluationResultImpl.con1(null); |
| 1194 } |
| 1195 } |
| 1196 } |
| 1197 |
| 1198 /** |
1209 * Generate an error indicating that the given [constNode] is not a valid | 1199 * Generate an error indicating that the given [constNode] is not a valid |
1210 * compile-time constant because it references at least one of the constants | 1200 * compile-time constant because it references at least one of the constants |
1211 * in the given [cycle], each of which directly or indirectly references the | 1201 * in the given [cycle], each of which directly or indirectly references the |
1212 * constant. | 1202 * constant. |
1213 */ | 1203 */ |
1214 void _generateCycleError(List<AstNode> cycle, AstNode constNode) { | 1204 void _generateCycleError(List<Element> cycle, Element element) { |
1215 if (constNode is VariableDeclaration) { | 1205 if (element is VariableElement) { |
1216 VariableElement element = constNode.element; | |
1217 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1206 RecordingErrorListener errorListener = new RecordingErrorListener(); |
1218 ErrorReporter errorReporter = | 1207 ErrorReporter errorReporter = |
1219 new ErrorReporter(errorListener, element.source); | 1208 new ErrorReporter(errorListener, element.source); |
1220 // TODO(paulberry): It would be really nice if we could extract enough | 1209 // TODO(paulberry): It would be really nice if we could extract enough |
1221 // information from the 'cycle' argument to provide the user with a | 1210 // information from the 'cycle' argument to provide the user with a |
1222 // description of the cycle. | 1211 // description of the cycle. |
1223 errorReporter.reportErrorForElement( | 1212 errorReporter.reportErrorForElement( |
1224 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, element, []); | 1213 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, element, []); |
1225 (element as VariableElementImpl).evaluationResult = | 1214 (element as VariableElementImpl).evaluationResult = |
1226 new EvaluationResultImpl.con2(null, errorListener.errors); | 1215 new EvaluationResultImpl.con2(null, errorListener.errors); |
1227 } else if (constNode is ConstructorDeclaration) { | 1216 } else if (element is ConstructorElement) { |
1228 // We don't report cycle errors on constructor declarations since there | 1217 // We don't report cycle errors on constructor declarations since there |
1229 // is nowhere to put the error information. | 1218 // is nowhere to put the error information. |
1230 } else { | 1219 } else { |
1231 // Should not happen. Formal parameter defaults and annotations should | 1220 // Should not happen. Formal parameter defaults and annotations should |
1232 // never appear as part of a cycle because they can't be referred to. | 1221 // never appear as part of a cycle because they can't be referred to. |
1233 assert(false); | 1222 assert(false); |
1234 AnalysisEngine.instance.logger.logError( | 1223 AnalysisEngine.instance.logger.logError( |
1235 "Constant value computer trying to report a cycle error for a node of
type ${constNode.runtimeType}"); | 1224 "Constant value computer trying to report a cycle error for a node of
type ${element.runtimeType}"); |
1236 } | 1225 } |
1237 } | 1226 } |
1238 } | 1227 } |
1239 | 1228 |
1240 /** | 1229 /** |
1241 * A visitor used to evaluate constant expressions to produce their compile-time | 1230 * A visitor used to evaluate constant expressions to produce their compile-time |
1242 * value. According to the Dart Language Specification: <blockquote> A constant | 1231 * value. According to the Dart Language Specification: <blockquote> A constant |
1243 * expression is one of the following: | 1232 * expression is one of the following: |
1244 * | 1233 * |
1245 * * A literal number. | 1234 * * A literal number. |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1716 * Return the constant value of the static constant represented by the given | 1705 * Return the constant value of the static constant represented by the given |
1717 * [element]. The [node] is the node to be used if an error needs to be | 1706 * [element]. The [node] is the node to be used if an error needs to be |
1718 * reported. | 1707 * reported. |
1719 */ | 1708 */ |
1720 DartObjectImpl _getConstantValue(AstNode node, Element element) { | 1709 DartObjectImpl _getConstantValue(AstNode node, Element element) { |
1721 if (element is PropertyAccessorElement) { | 1710 if (element is PropertyAccessorElement) { |
1722 element = (element as PropertyAccessorElement).variable; | 1711 element = (element as PropertyAccessorElement).variable; |
1723 } | 1712 } |
1724 if (element is VariableElementImpl) { | 1713 if (element is VariableElementImpl) { |
1725 VariableElementImpl variableElementImpl = element; | 1714 VariableElementImpl variableElementImpl = element; |
1726 evaluationEngine.validator.beforeGetEvaluationResult(node); | 1715 evaluationEngine.validator.beforeGetEvaluationResult(element); |
1727 EvaluationResultImpl value = variableElementImpl.evaluationResult; | 1716 EvaluationResultImpl value = variableElementImpl.evaluationResult; |
1728 if (variableElementImpl.isConst && value != null) { | 1717 if (variableElementImpl.isConst && value != null) { |
1729 return value.value; | 1718 return value.value; |
1730 } | 1719 } |
1731 } else if (element is ExecutableElement) { | 1720 } else if (element is ExecutableElement) { |
1732 ExecutableElement function = element; | 1721 ExecutableElement function = element; |
1733 if (function.isStatic) { | 1722 if (function.isStatic) { |
1734 ParameterizedType functionType = function.type; | 1723 ParameterizedType functionType = function.type; |
1735 if (functionType == null) { | 1724 if (functionType == null) { |
1736 functionType = _typeProvider.functionType; | 1725 functionType = _typeProvider.functionType; |
(...skipping 3134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4871 } | 4860 } |
4872 | 4861 |
4873 /** | 4862 /** |
4874 * An object used to add reference information for a given variable to the | 4863 * An object used to add reference information for a given variable to the |
4875 * bi-directional mapping used to order the evaluation of constants. | 4864 * bi-directional mapping used to order the evaluation of constants. |
4876 */ | 4865 */ |
4877 class ReferenceFinder extends RecursiveAstVisitor<Object> { | 4866 class ReferenceFinder extends RecursiveAstVisitor<Object> { |
4878 /** | 4867 /** |
4879 * The element representing the construct that will be visited. | 4868 * The element representing the construct that will be visited. |
4880 */ | 4869 */ |
4881 final AstNode _source; | 4870 final Element _source; |
4882 | 4871 |
4883 /** | 4872 /** |
4884 * A graph in which the nodes are the constant variables and the edges are | 4873 * A graph in which the nodes are the constant variables and the edges are |
4885 * from each variable to the other constant variables that are referenced in | 4874 * from each variable to the other constant variables that are referenced in |
4886 * the head's initializer. | 4875 * the head's initializer. |
4887 */ | 4876 */ |
4888 final DirectedGraph<AstNode> _referenceGraph; | 4877 final DirectedGraph<Element> _referenceGraph; |
4889 | |
4890 /** | |
4891 * A table mapping constant variables to the declarations of those variables. | |
4892 */ | |
4893 final HashMap<PotentiallyConstVariableElement, VariableDeclaration> _variableD
eclarationMap; | |
4894 | |
4895 /** | |
4896 * A table mapping constant constructors to the declarations of those | |
4897 * constructors. | |
4898 */ | |
4899 final HashMap<ConstructorElement, ConstructorDeclaration> _constructorDeclarat
ionMap; | |
4900 | 4878 |
4901 /** | 4879 /** |
4902 * Initialize a newly created reference finder to find references from a given | 4880 * Initialize a newly created reference finder to find references from a given |
4903 * variable to other variables and to add those references to the given graph. | 4881 * variable to other variables and to add those references to the given graph. |
4904 * The [source] is the element representing the variable whose initializer | 4882 * The [source] is the element representing the variable whose initializer |
4905 * will be visited. The [referenceGraph] is a graph recording which variables | 4883 * will be visited. The [referenceGraph] is a graph recording which variables |
4906 * (heads) reference which other variables (tails) in their initializers. The | 4884 * (heads) reference which other variables (tails) in their initializers. |
4907 * [variableDeclarationMap] is a table mapping constant variables to the | |
4908 * declarations of those variables. The [constructorDeclarationMap] is a table | |
4909 * mapping constant constructors to the declarations of those constructors. | |
4910 */ | 4885 */ |
4911 ReferenceFinder(this._source, this._referenceGraph, | 4886 ReferenceFinder(this._source, this._referenceGraph); |
4912 this._variableDeclarationMap, this._constructorDeclarationMap); | |
4913 | |
4914 ConstructorDeclaration findConstructorDeclaration( | |
4915 ConstructorElement constructor) => _constructorDeclarationMap[ | |
4916 ConstantEvaluationEngine._getConstructorBase(constructor)]; | |
4917 | 4887 |
4918 @override | 4888 @override |
4919 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | 4889 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
4920 if (node.isConst) { | 4890 if (node.isConst) { |
4921 ConstructorElement constructor = node.staticElement; | 4891 ConstructorElement constructor = |
| 4892 ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
4922 if (constructor != null) { | 4893 if (constructor != null) { |
4923 ConstructorDeclaration declaration = | 4894 _referenceGraph.addEdge(_source, constructor); |
4924 findConstructorDeclaration(constructor); | |
4925 if (declaration != null) { | |
4926 _referenceGraph.addEdge(_source, declaration); | |
4927 } | |
4928 } | 4895 } |
4929 } | 4896 } |
4930 return super.visitInstanceCreationExpression(node); | 4897 return super.visitInstanceCreationExpression(node); |
4931 } | 4898 } |
4932 | 4899 |
4933 @override | 4900 @override |
4934 Object visitRedirectingConstructorInvocation( | 4901 Object visitRedirectingConstructorInvocation( |
4935 RedirectingConstructorInvocation node) { | 4902 RedirectingConstructorInvocation node) { |
4936 super.visitRedirectingConstructorInvocation(node); | 4903 super.visitRedirectingConstructorInvocation(node); |
4937 ConstructorElement target = node.staticElement; | 4904 ConstructorElement target = |
| 4905 ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
4938 if (target != null && target.isConst) { | 4906 if (target != null && target.isConst) { |
4939 ConstructorDeclaration targetDeclaration = | 4907 _referenceGraph.addEdge(_source, target); |
4940 _constructorDeclarationMap[target]; | |
4941 if (targetDeclaration != null) { | |
4942 _referenceGraph.addEdge(_source, targetDeclaration); | |
4943 } | |
4944 } | 4908 } |
4945 return null; | 4909 return null; |
4946 } | 4910 } |
4947 | 4911 |
4948 @override | 4912 @override |
4949 Object visitSimpleIdentifier(SimpleIdentifier node) { | 4913 Object visitSimpleIdentifier(SimpleIdentifier node) { |
4950 Element element = node.staticElement; | 4914 Element element = node.staticElement; |
4951 if (element is PropertyAccessorElement) { | 4915 if (element is PropertyAccessorElement) { |
4952 element = (element as PropertyAccessorElement).variable; | 4916 element = (element as PropertyAccessorElement).variable; |
4953 } | 4917 } |
4954 if (element is VariableElement) { | 4918 if (element is VariableElement) { |
4955 if (element.isConst) { | 4919 if (element.isConst) { |
4956 VariableDeclaration variableDeclaration = | 4920 _referenceGraph.addEdge(_source, element); |
4957 _variableDeclarationMap[element]; | |
4958 // The declaration will be null when the variable is not defined in the | |
4959 // compilation units that were used to produce the | |
4960 // variableDeclarationMap. In such cases, the variable should already | |
4961 // have a value associated with it, but we don't bother to check because | |
4962 // there's nothing we can do about it at this point. | |
4963 if (variableDeclaration != null) { | |
4964 _referenceGraph.addEdge(_source, variableDeclaration); | |
4965 } | |
4966 } | 4921 } |
4967 } | 4922 } |
4968 return null; | 4923 return null; |
4969 } | 4924 } |
4970 | 4925 |
4971 @override | 4926 @override |
4972 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | 4927 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
4973 super.visitSuperConstructorInvocation(node); | 4928 super.visitSuperConstructorInvocation(node); |
4974 ConstructorElement constructor = node.staticElement; | 4929 ConstructorElement constructor = |
| 4930 ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
4975 if (constructor != null && constructor.isConst) { | 4931 if (constructor != null && constructor.isConst) { |
4976 ConstructorDeclaration constructorDeclaration = | 4932 _referenceGraph.addEdge(_source, constructor); |
4977 _constructorDeclarationMap[constructor]; | |
4978 // The declaration will be null when the constructor is not defined in the | |
4979 // compilation units that were used to produce the | |
4980 // constructorDeclarationMap. In such cases, the constructor should | |
4981 // already have its initializer AST's stored in it, but we don't bother | |
4982 // to check because there's nothing we can do about it at this point. | |
4983 if (constructorDeclaration != null) { | |
4984 _referenceGraph.addEdge(_source, constructorDeclaration); | |
4985 } | |
4986 } | 4933 } |
4987 return null; | 4934 return null; |
4988 } | 4935 } |
4989 } | 4936 } |
4990 | 4937 |
4991 /** | 4938 /** |
4992 * The state of an object representing a string. | 4939 * The state of an object representing a string. |
4993 */ | 4940 */ |
4994 class StringState extends InstanceState { | 4941 class StringState extends InstanceState { |
4995 /** | 4942 /** |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5197 return BoolState.from(_element == rightElement); | 5144 return BoolState.from(_element == rightElement); |
5198 } else if (rightOperand is DynamicState) { | 5145 } else if (rightOperand is DynamicState) { |
5199 return BoolState.UNKNOWN_VALUE; | 5146 return BoolState.UNKNOWN_VALUE; |
5200 } | 5147 } |
5201 return BoolState.FALSE_STATE; | 5148 return BoolState.FALSE_STATE; |
5202 } | 5149 } |
5203 | 5150 |
5204 @override | 5151 @override |
5205 String toString() => _element == null ? "-unknown-" : _element.name; | 5152 String toString() => _element == null ? "-unknown-" : _element.name; |
5206 } | 5153 } |
OLD | NEW |