| 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 |