OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library dart2js.kernel.equivalence; | 5 library dart2js.kernel.equivalence; |
6 | 6 |
7 import 'package:compiler/src/common/backend_api.dart'; | 7 import 'package:compiler/src/common/backend_api.dart'; |
8 import 'package:compiler/src/common/resolution.dart'; | 8 import 'package:compiler/src/common/resolution.dart'; |
9 import 'package:compiler/src/common/work.dart'; | 9 import 'package:compiler/src/common/work.dart'; |
10 import 'package:compiler/src/constants/expressions.dart'; | 10 import 'package:compiler/src/constants/expressions.dart'; |
11 import 'package:compiler/src/constants/values.dart'; | 11 import 'package:compiler/src/constants/values.dart'; |
12 import 'package:compiler/src/compiler.dart'; | 12 import 'package:compiler/src/compiler.dart'; |
13 import 'package:compiler/src/elements/elements.dart'; | 13 import 'package:compiler/src/elements/elements.dart'; |
14 import 'package:compiler/src/elements/entities.dart'; | 14 import 'package:compiler/src/elements/entities.dart'; |
15 import 'package:compiler/src/elements/resolution_types.dart'; | 15 import 'package:compiler/src/elements/resolution_types.dart'; |
16 import 'package:compiler/src/elements/types.dart'; | 16 import 'package:compiler/src/elements/types.dart'; |
17 import 'package:compiler/src/enqueue.dart'; | 17 import 'package:compiler/src/enqueue.dart'; |
18 import 'package:compiler/src/kernel/kelements.dart'; | 18 import 'package:compiler/src/kernel/elements.dart'; |
| 19 import 'package:compiler/src/kernel/kelements.dart' show KLocalFunction; |
| 20 import 'package:compiler/src/kernel/element_map.dart'; |
19 import 'package:compiler/src/kernel/element_map_impl.dart'; | 21 import 'package:compiler/src/kernel/element_map_impl.dart'; |
20 import 'package:compiler/src/serialization/equivalence.dart'; | 22 import 'package:compiler/src/serialization/equivalence.dart'; |
21 import 'package:compiler/src/ssa/kernel_impact.dart'; | 23 import 'package:compiler/src/ssa/kernel_impact.dart'; |
22 import 'package:compiler/src/universe/world_impact.dart'; | 24 import 'package:compiler/src/universe/world_impact.dart'; |
23 import 'package:compiler/src/util/util.dart'; | 25 import 'package:compiler/src/util/util.dart'; |
24 | 26 |
25 class KernelEquivalence { | 27 class KernelEquivalence { |
26 final WorldDeconstructionForTesting testing; | 28 final WorldDeconstructionForTesting testing; |
27 | 29 |
28 /// Set of mixin applications assumed to be equivalent. | 30 /// Set of mixin applications assumed to be equivalent. |
29 /// | 31 /// |
30 /// We need co-inductive reasoning because mixin applications are compared | 32 /// We need co-inductive reasoning because mixin applications are compared |
31 /// structurally and therefore, in the case of generic mixin applications, | 33 /// structurally and therefore, in the case of generic mixin applications, |
32 /// meet themselves through the equivalence check of their type variables. | 34 /// meet themselves through the equivalence check of their type variables. |
33 Set<Pair<ClassEntity, ClassEntity>> assumedMixinApplications = | 35 Set<Pair<ClassEntity, ClassEntity>> assumedMixinApplications = |
34 new Set<Pair<ClassEntity, ClassEntity>>(); | 36 new Set<Pair<ClassEntity, ClassEntity>>(); |
35 | 37 |
36 KernelEquivalence(KernelToElementMapImpl builder) | 38 KernelEquivalence(KernelToElementMap builder) |
37 : testing = new WorldDeconstructionForTesting(builder); | 39 : testing = new WorldDeconstructionForTesting(builder); |
38 | 40 |
39 TestStrategy get defaultStrategy => new TestStrategy( | 41 TestStrategy get defaultStrategy => new TestStrategy( |
40 elementEquivalence: entityEquivalence, | 42 elementEquivalence: entityEquivalence, |
41 typeEquivalence: typeEquivalence, | 43 typeEquivalence: typeEquivalence, |
42 constantEquivalence: constantEquivalence, | 44 constantEquivalence: constantEquivalence, |
43 constantValueEquivalence: constantValueEquivalence); | 45 constantValueEquivalence: constantValueEquivalence); |
44 | 46 |
45 bool entityEquivalence(Element a, Entity b, {TestStrategy strategy}) { | 47 bool entityEquivalence(Element a, Entity b, {TestStrategy strategy}) { |
46 if (identical(a, b)) return true; | 48 if (identical(a, b)) return true; |
47 if (a == null || b == null) return false; | 49 if (a == null || b == null) return false; |
48 strategy ??= defaultStrategy; | 50 strategy ??= defaultStrategy; |
49 switch (a.kind) { | 51 switch (a.kind) { |
50 case ElementKind.GENERATIVE_CONSTRUCTOR: | 52 case ElementKind.GENERATIVE_CONSTRUCTOR: |
51 if (b is KGenerativeConstructor) { | 53 if (b is IndexedConstructor && b.isGenerativeConstructor) { |
52 return strategy.test(a, b, 'name', a.name, b.name) && | 54 return strategy.test(a, b, 'name', a.name, b.name) && |
53 strategy.testElements( | 55 strategy.testElements( |
54 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass); | 56 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass); |
55 } | 57 } |
56 return false; | 58 return false; |
57 case ElementKind.FACTORY_CONSTRUCTOR: | 59 case ElementKind.FACTORY_CONSTRUCTOR: |
58 if (b is KFactoryConstructor) { | 60 if (b is IndexedConstructor && b.isFactoryConstructor) { |
59 return strategy.test(a, b, 'name', a.name, b.name) && | 61 return strategy.test(a, b, 'name', a.name, b.name) && |
60 strategy.testElements( | 62 strategy.testElements( |
61 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass); | 63 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass); |
62 } | 64 } |
63 return false; | 65 return false; |
64 case ElementKind.CLASS: | 66 case ElementKind.CLASS: |
65 if (b is KClass) { | 67 if (b is IndexedClass) { |
66 List<InterfaceType> aMixinTypes = []; | 68 List<InterfaceType> aMixinTypes = []; |
67 List<InterfaceType> bMixinTypes = []; | 69 List<InterfaceType> bMixinTypes = []; |
68 ClassElement aClass = a; | 70 ClassElement aClass = a; |
69 if (aClass.isUnnamedMixinApplication) { | 71 if (aClass.isUnnamedMixinApplication) { |
70 if (!testing.isUnnamedMixinApplication(b)) { | 72 if (!testing.isUnnamedMixinApplication(b)) { |
71 return false; | 73 return false; |
72 } | 74 } |
73 while (aClass.isMixinApplication) { | 75 while (aClass.isMixinApplication) { |
74 MixinApplicationElement aMixinApplication = aClass; | 76 MixinApplicationElement aMixinApplication = aClass; |
75 aMixinTypes.add(aMixinApplication.mixinType); | 77 aMixinTypes.add(aMixinApplication.mixinType); |
76 aClass = aMixinApplication.superclass; | 78 aClass = aMixinApplication.superclass; |
77 } | 79 } |
78 KClass bClass = b; | 80 IndexedClass bClass = b; |
79 while (bClass != null) { | 81 while (bClass != null) { |
80 InterfaceType mixinType = testing.getMixinTypeForClass(bClass); | 82 InterfaceType mixinType = testing.getMixinTypeForClass(bClass); |
81 if (mixinType == null) break; | 83 if (mixinType == null) break; |
82 bMixinTypes.add(mixinType); | 84 bMixinTypes.add(mixinType); |
83 bClass = testing.getSuperclassForClass(bClass); | 85 bClass = testing.getSuperclassForClass(bClass); |
84 } | 86 } |
85 if (aMixinTypes.isNotEmpty || aMixinTypes.isNotEmpty) { | 87 if (aMixinTypes.isNotEmpty || aMixinTypes.isNotEmpty) { |
86 Pair<ClassEntity, ClassEntity> pair = | 88 Pair<ClassEntity, ClassEntity> pair = |
87 new Pair<ClassEntity, ClassEntity>(aClass, bClass); | 89 new Pair<ClassEntity, ClassEntity>(aClass, bClass); |
88 if (assumedMixinApplications.contains(pair)) { | 90 if (assumedMixinApplications.contains(pair)) { |
89 return true; | 91 return true; |
90 } else { | 92 } else { |
91 assumedMixinApplications.add(pair); | 93 assumedMixinApplications.add(pair); |
92 bool result = strategy.testTypeLists( | 94 bool result = strategy.testTypeLists( |
93 a, b, 'mixinTypes', aMixinTypes, bMixinTypes); | 95 a, b, 'mixinTypes', aMixinTypes, bMixinTypes); |
94 assumedMixinApplications.remove(pair); | 96 assumedMixinApplications.remove(pair); |
95 return result; | 97 return result; |
96 } | 98 } |
97 } | 99 } |
98 } else { | 100 } else { |
99 if (testing.isUnnamedMixinApplication(b)) { | 101 if (testing.isUnnamedMixinApplication(b)) { |
100 return false; | 102 return false; |
101 } | 103 } |
102 } | 104 } |
103 return strategy.test(a, b, 'name', a.name, b.name) && | 105 return strategy.test(a, b, 'name', a.name, b.name) && |
104 strategy.testElements(a, b, 'library', a.library, b.library); | 106 strategy.testElements(a, b, 'library', a.library, b.library); |
105 } | 107 } |
106 return false; | 108 return false; |
107 case ElementKind.LIBRARY: | 109 case ElementKind.LIBRARY: |
108 if (b is KLibrary) { | 110 if (b is IndexedLibrary) { |
109 LibraryElement libraryA = a; | 111 LibraryElement libraryA = a; |
110 return libraryA.canonicalUri == b.canonicalUri; | 112 return libraryA.canonicalUri == b.canonicalUri; |
111 } | 113 } |
112 return false; | 114 return false; |
113 case ElementKind.FUNCTION: | 115 case ElementKind.FUNCTION: |
114 if (b is KMethod) { | 116 if (b is IndexedFunction && b.isFunction) { |
115 return strategy.test(a, b, 'name', a.name, b.name) && | 117 return strategy.test(a, b, 'name', a.name, b.name) && |
116 strategy.testElements( | 118 strategy.testElements( |
117 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && | 119 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && |
118 strategy.testElements(a, b, 'library', a.library, b.library); | 120 strategy.testElements(a, b, 'library', a.library, b.library); |
119 } else if (b is KLocalFunction) { | 121 } else if (b is KLocalFunction) { |
120 LocalFunctionElement aLocalFunction = a; | 122 LocalFunctionElement aLocalFunction = a; |
121 return strategy.test(a, b, 'name', a.name, b.name ?? '') && | 123 return strategy.test(a, b, 'name', a.name, b.name ?? '') && |
122 strategy.testElements(a, b, 'executableContext', | 124 strategy.testElements(a, b, 'executableContext', |
123 aLocalFunction.executableContext, b.executableContext) && | 125 aLocalFunction.executableContext, b.executableContext) && |
124 strategy.testElements(a, b, 'memberContext', | 126 strategy.testElements(a, b, 'memberContext', |
125 aLocalFunction.memberContext, b.memberContext); | 127 aLocalFunction.memberContext, b.memberContext); |
126 } | 128 } |
127 return false; | 129 return false; |
128 case ElementKind.GETTER: | 130 case ElementKind.GETTER: |
129 if (b is KGetter) { | 131 if (b is IndexedFunction && b.isGetter) { |
130 return strategy.test(a, b, 'name', a.name, b.name) && | 132 return strategy.test(a, b, 'name', a.name, b.name) && |
131 strategy.testElements( | 133 strategy.testElements( |
132 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && | 134 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && |
133 strategy.testElements(a, b, 'library', a.library, b.library); | 135 strategy.testElements(a, b, 'library', a.library, b.library); |
134 } | 136 } |
135 return false; | 137 return false; |
136 case ElementKind.SETTER: | 138 case ElementKind.SETTER: |
137 if (b is KSetter) { | 139 if (b is IndexedFunction && b.isSetter) { |
138 return strategy.test(a, b, 'name', a.name, b.name) && | 140 return strategy.test(a, b, 'name', a.name, b.name) && |
139 strategy.testElements( | 141 strategy.testElements( |
140 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && | 142 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && |
141 strategy.testElements(a, b, 'library', a.library, b.library); | 143 strategy.testElements(a, b, 'library', a.library, b.library); |
142 } | 144 } |
143 return false; | 145 return false; |
144 case ElementKind.FIELD: | 146 case ElementKind.FIELD: |
145 if (b is KField) { | 147 if (b is IndexedField) { |
146 return strategy.test(a, b, 'name', a.name, b.name) && | 148 return strategy.test(a, b, 'name', a.name, b.name) && |
147 strategy.testElements( | 149 strategy.testElements( |
148 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && | 150 a, b, 'enclosingClass', a.enclosingClass, b.enclosingClass) && |
149 strategy.testElements(a, b, 'library', a.library, b.library); | 151 strategy.testElements(a, b, 'library', a.library, b.library); |
150 } | 152 } |
151 return false; | 153 return false; |
152 case ElementKind.TYPE_VARIABLE: | 154 case ElementKind.TYPE_VARIABLE: |
153 if (b is KTypeVariable) { | 155 if (b is IndexedTypeVariable) { |
154 TypeVariableElement aElement = a; | 156 TypeVariableElement aElement = a; |
155 return strategy.test(a, b, 'index', aElement.index, b.index) && | 157 return strategy.test(a, b, 'index', aElement.index, b.index) && |
156 strategy.testElements(a, b, 'typeDeclaration', | 158 strategy.testElements(a, b, 'typeDeclaration', |
157 aElement.typeDeclaration, b.typeDeclaration); | 159 aElement.typeDeclaration, b.typeDeclaration); |
158 } | 160 } |
159 return false; | 161 return false; |
160 default: | 162 default: |
161 throw new UnsupportedError('Unsupported equivalence: ' | 163 throw new UnsupportedError('Unsupported equivalence: ' |
162 '$a (${a.runtimeType}) vs $b (${b.runtimeType})'); | 164 '$a (${a.runtimeType}) vs $b (${b.runtimeType})'); |
163 } | 165 } |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 for (ConstructorElement constructor in element.constructors) { | 300 for (ConstructorElement constructor in element.constructors) { |
299 if (!constructor.isRedirectingFactory) { | 301 if (!constructor.isRedirectingFactory) { |
300 return true; | 302 return true; |
301 } | 303 } |
302 } | 304 } |
303 // The class cannot itself be instantiated. | 305 // The class cannot itself be instantiated. |
304 return false; | 306 return false; |
305 } | 307 } |
306 return true; | 308 return true; |
307 } | 309 } |
OLD | NEW |