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 library dart2js.js_emitter.runtime_type_generator; | 5 library dart2js.js_emitter.runtime_type_generator; |
6 | 6 |
7 import '../closure.dart' | 7 import '../closure.dart' |
8 show ClosureRepresentationInfo, ClosureFieldElement, ClosureConversionTask; | 8 show ClosureRepresentationInfo, ClosureFieldElement, ClosureConversionTask; |
9 import '../common.dart'; | 9 import '../common.dart'; |
10 import '../common/names.dart' show Identifiers; | 10 import '../common/names.dart' show Identifiers; |
11 import '../common_elements.dart' show CommonElements; | 11 import '../common_elements.dart' show CommonElements, ElementEnvironment; |
12 import '../elements/resolution_types.dart' | |
13 show ResolutionDartType, ResolutionFunctionType, ResolutionInterfaceType; | |
14 import '../elements/elements.dart' | 12 import '../elements/elements.dart' |
15 show ClassElement, Element, FunctionElement, MixinApplicationElement; | 13 show ClassElement, MethodElement, MixinApplicationElement; |
16 import '../elements/entities.dart'; | 14 import '../elements/entities.dart'; |
17 import '../elements/types.dart'; | 15 import '../elements/types.dart'; |
18 import '../js/js.dart' as jsAst; | 16 import '../js/js.dart' as jsAst; |
19 import '../js/js.dart' show js; | 17 import '../js/js.dart' show js; |
20 import '../js_backend/js_interop_analysis.dart'; | 18 import '../js_backend/js_interop_analysis.dart'; |
21 import '../js_backend/native_data.dart'; | 19 import '../js_backend/native_data.dart'; |
22 import '../js_backend/namer.dart' show Namer; | 20 import '../js_backend/namer.dart' show Namer; |
23 import '../js_backend/runtime_types.dart' | 21 import '../js_backend/runtime_types.dart' |
24 show | 22 show |
25 RuntimeTypesChecks, | 23 RuntimeTypesChecks, |
26 RuntimeTypesNeed, | 24 RuntimeTypesNeed, |
27 RuntimeTypesEncoder, | 25 RuntimeTypesEncoder, |
28 RuntimeTypesSubstitutions, | 26 RuntimeTypesSubstitutions, |
29 Substitution, | 27 Substitution, |
30 TypeCheck, | 28 TypeCheck, |
31 TypeChecks; | 29 TypeChecks; |
32 import '../util/util.dart' show Setlet; | 30 import '../util/util.dart' show Setlet; |
31 import '../world.dart'; | |
33 | 32 |
34 import 'code_emitter_task.dart' show CodeEmitterTask; | 33 import 'code_emitter_task.dart' show CodeEmitterTask; |
35 import 'type_test_registry.dart' show TypeTestRegistry; | 34 import 'type_test_registry.dart' show TypeTestRegistry; |
36 | 35 |
37 // Function signatures used in the generation of runtime type information. | 36 // Function signatures used in the generation of runtime type information. |
38 typedef void FunctionTypeSignatureEmitter( | 37 typedef void FunctionTypeSignatureEmitter( |
39 Element method, ResolutionFunctionType methodType); | 38 FunctionEntity method, FunctionType methodType); |
40 | 39 |
41 typedef void SubstitutionEmitter(Element element, {bool emitNull}); | 40 typedef void SubstitutionEmitter(ClassEntity element, {bool emitNull}); |
42 | 41 |
43 class TypeTestProperties { | 42 class TypeTestProperties { |
44 /// The index of the function type into the metadata. | 43 /// The index of the function type into the metadata. |
45 /// | 44 /// |
46 /// If the class doesn't have a function type this field is `null`. | 45 /// If the class doesn't have a function type this field is `null`. |
47 /// | 46 /// |
48 /// If the is tests were generated with `storeFunctionTypeInMetadata` set to | 47 /// If the is tests were generated with `storeFunctionTypeInMetadata` set to |
49 /// `false`, this field is `null`, and the [properties] contain a property | 48 /// `false`, this field is `null`, and the [properties] contain a property |
50 /// that encodes the function type. | 49 /// that encodes the function type. |
51 jsAst.Expression functionTypeIndex; | 50 jsAst.Expression functionTypeIndex; |
52 | 51 |
53 /// The properties that must be installed on the prototype of the | 52 /// The properties that must be installed on the prototype of the |
54 /// JS constructor of the [ClassElement] for which the is checks were | 53 /// JS constructor of the [ClassEntity] for which the is checks were |
55 /// generated. | 54 /// generated. |
56 final Map<jsAst.Name, jsAst.Node> properties = <jsAst.Name, jsAst.Node>{}; | 55 final Map<jsAst.Name, jsAst.Node> properties = <jsAst.Name, jsAst.Node>{}; |
57 } | 56 } |
58 | 57 |
59 class RuntimeTypeGenerator { | 58 class RuntimeTypeGenerator { |
59 final ElementEnvironment _elementEnvironment; | |
60 final CommonElements _commonElements; | 60 final CommonElements _commonElements; |
61 final DartTypes _types; | |
62 final ClosedWorld _closedWorld; | |
61 final ClosureConversionTask _closureDataLookup; | 63 final ClosureConversionTask _closureDataLookup; |
62 final CodeEmitterTask emitterTask; | 64 final CodeEmitterTask emitterTask; |
63 final Namer _namer; | 65 final Namer _namer; |
64 final NativeData _nativeData; | 66 final NativeData _nativeData; |
65 final RuntimeTypesChecks _rtiChecks; | 67 final RuntimeTypesChecks _rtiChecks; |
66 final RuntimeTypesEncoder _rtiEncoder; | 68 final RuntimeTypesEncoder _rtiEncoder; |
67 final RuntimeTypesNeed _rtiNeed; | 69 final RuntimeTypesNeed _rtiNeed; |
68 final RuntimeTypesSubstitutions _rtiSubstitutions; | 70 final RuntimeTypesSubstitutions _rtiSubstitutions; |
69 final JsInteropAnalysis _jsInteropAnalysis; | 71 final JsInteropAnalysis _jsInteropAnalysis; |
70 | 72 |
71 RuntimeTypeGenerator( | 73 RuntimeTypeGenerator( |
74 this._elementEnvironment, | |
72 this._commonElements, | 75 this._commonElements, |
76 this._types, | |
77 this._closedWorld, | |
73 this._closureDataLookup, | 78 this._closureDataLookup, |
74 this.emitterTask, | 79 this.emitterTask, |
75 this._namer, | 80 this._namer, |
76 this._nativeData, | 81 this._nativeData, |
77 this._rtiChecks, | 82 this._rtiChecks, |
78 this._rtiEncoder, | 83 this._rtiEncoder, |
79 this._rtiNeed, | 84 this._rtiNeed, |
80 this._rtiSubstitutions, | 85 this._rtiSubstitutions, |
81 this._jsInteropAnalysis); | 86 this._jsInteropAnalysis); |
82 | 87 |
(...skipping 10 matching lines...) Expand all Loading... | |
93 /// Generates all properties necessary for is-checks on the [classElement]. | 98 /// Generates all properties necessary for is-checks on the [classElement]. |
94 /// | 99 /// |
95 /// Returns an instance of [TypeTestProperties] that contains the properties | 100 /// Returns an instance of [TypeTestProperties] that contains the properties |
96 /// that must be installed on the prototype of the JS constructor of the | 101 /// that must be installed on the prototype of the JS constructor of the |
97 /// [classElement]. | 102 /// [classElement]. |
98 /// | 103 /// |
99 /// If [storeFunctionTypeInMetadata] is `true`, stores the reified function | 104 /// If [storeFunctionTypeInMetadata] is `true`, stores the reified function |
100 /// type (if class has one) in the metadata object and stores its index in | 105 /// type (if class has one) in the metadata object and stores its index in |
101 /// the result. This is only possible for function types that do not contain | 106 /// the result. This is only possible for function types that do not contain |
102 /// type variables. | 107 /// type variables. |
103 TypeTestProperties generateIsTests(ClassEntity cls, | 108 TypeTestProperties generateIsTests(ClassEntity classElement, |
104 {bool storeFunctionTypeInMetadata: true}) { | 109 {bool storeFunctionTypeInMetadata: true}) { |
105 TypeTestProperties result = new TypeTestProperties(); | 110 TypeTestProperties result = new TypeTestProperties(); |
106 if (cls is! ClassElement) return result; | |
107 | 111 |
108 // TODO(johnniwinther): Handle class entities. | 112 assert(!(classElement is ClassElement && !classElement.isDeclaration), |
109 ClassElement classElement = cls; | 113 failedAt(classElement)); |
110 assert(classElement.isDeclaration, failedAt(classElement)); | |
111 | 114 |
112 /// Generates an is-test if the test is not inherited from a superclass | 115 /// Generates an is-test if the test is not inherited from a superclass |
113 /// This assumes that for every class an is-tests is generated | 116 /// This assumes that for every class an is-tests is generated |
114 /// dynamically at runtime. We also always generate tests against | 117 /// dynamically at runtime. We also always generate tests against |
115 /// native classes. | 118 /// native classes. |
116 /// TODO(herhut): Generate tests for native classes dynamically, as well. | 119 /// TODO(herhut): Generate tests for native classes dynamically, as well. |
117 void generateIsTest(ClassElement other) { | 120 void generateIsTest(ClassEntity other) { |
118 if (_nativeData.isNativeClass(classElement) || | 121 if (_nativeData.isNativeClass(classElement) || |
119 !classElement.isSubclassOf(other)) { | 122 !_closedWorld.isSubclassOf(classElement, other)) { |
120 result.properties[_namer.operatorIs(other)] = js('1'); | 123 result.properties[_namer.operatorIs(other)] = js('1'); |
121 } | 124 } |
122 } | 125 } |
123 | 126 |
124 void generateFunctionTypeSignature( | 127 void generateFunctionTypeSignature( |
125 FunctionElement method, ResolutionFunctionType type) { | 128 FunctionEntity method, FunctionType type) { |
126 assert(method.isImplementation); | 129 assert(!(method is MethodElement && !method.isImplementation)); |
127 jsAst.Expression thisAccess = new jsAst.This(); | 130 jsAst.Expression thisAccess = new jsAst.This(); |
128 if (!method.isAbstract) { | 131 if (!method.isAbstract) { |
129 ClosureRepresentationInfo closureData = | 132 ClosureRepresentationInfo closureData = |
130 _closureDataLookup.getClosureRepresentationInfo(method); | 133 _closureDataLookup.getClosureRepresentationInfo(method); |
131 if (closureData != null) { | 134 if (closureData != null) { |
132 ClosureFieldElement thisLocal = closureData.thisFieldEntity; | 135 ClosureFieldElement thisLocal = closureData.thisFieldEntity; |
133 if (thisLocal != null) { | 136 if (thisLocal != null) { |
134 jsAst.Name thisName = _namer.instanceFieldPropertyName(thisLocal); | 137 jsAst.Name thisName = _namer.instanceFieldPropertyName(thisLocal); |
135 thisAccess = js('this.#', thisName); | 138 thisAccess = js('this.#', thisName); |
136 } | 139 } |
137 } | 140 } |
138 } | 141 } |
139 | 142 |
140 if (storeFunctionTypeInMetadata && !type.containsTypeVariables) { | 143 if (storeFunctionTypeInMetadata && !type.containsTypeVariables) { |
141 result.functionTypeIndex = | 144 result.functionTypeIndex = |
142 emitterTask.metadataCollector.reifyType(type); | 145 emitterTask.metadataCollector.reifyType(type); |
143 } else { | 146 } else { |
144 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( | 147 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( |
145 emitterTask.emitter, type, thisAccess); | 148 emitterTask.emitter, type, thisAccess); |
146 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); | 149 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); |
147 result.properties[operatorSignature] = encoding; | 150 result.properties[operatorSignature] = encoding; |
148 } | 151 } |
149 } | 152 } |
150 | 153 |
151 void generateSubstitution(ClassElement cls, {bool emitNull: false}) { | 154 void generateSubstitution(ClassEntity cls, {bool emitNull: false}) { |
152 if (cls.typeVariables.isEmpty) return; | 155 if (!_elementEnvironment.isGenericClass(cls)) return; |
153 jsAst.Expression expression; | 156 jsAst.Expression expression; |
154 bool needsNativeCheck = | 157 bool needsNativeCheck = |
155 emitterTask.nativeEmitter.requiresNativeIsCheck(cls); | 158 emitterTask.nativeEmitter.requiresNativeIsCheck(cls); |
156 Substitution substitution = | 159 Substitution substitution = |
157 _rtiSubstitutions.getSubstitution(classElement, cls); | 160 _rtiSubstitutions.getSubstitution(classElement, cls); |
158 if (substitution != null) { | 161 if (substitution != null) { |
159 expression = | 162 expression = |
160 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); | 163 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); |
161 } | 164 } |
162 if (expression == null && (emitNull || needsNativeCheck)) { | 165 if (expression == null && (emitNull || needsNativeCheck)) { |
163 expression = new jsAst.LiteralNull(); | 166 expression = new jsAst.LiteralNull(); |
164 } | 167 } |
165 if (expression != null) { | 168 if (expression != null) { |
166 result.properties[_namer.substitutionName(cls)] = expression; | 169 result.properties[_namer.substitutionName(cls)] = expression; |
167 } | 170 } |
168 } | 171 } |
169 | 172 |
170 void generateTypeCheck(TypeCheck check) { | 173 void generateTypeCheck(TypeCheck check) { |
171 ClassElement checkedClass = check.cls; | 174 ClassEntity checkedClass = check.cls; |
172 generateIsTest(checkedClass); | 175 generateIsTest(checkedClass); |
173 Substitution substitution = check.substitution; | 176 Substitution substitution = check.substitution; |
174 if (substitution != null) { | 177 if (substitution != null) { |
175 jsAst.Expression body = | 178 jsAst.Expression body = |
176 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); | 179 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); |
177 result.properties[_namer.substitutionName(checkedClass)] = body; | 180 result.properties[_namer.substitutionName(checkedClass)] = body; |
178 } | 181 } |
179 } | 182 } |
180 | 183 |
181 _generateIsTestsOn(classElement, (Element e) { | 184 _generateIsTestsOn( |
182 generateIsTest(e); | 185 classElement, |
183 }, (Element e, ResolutionFunctionType t) { | 186 generateIsTest, |
184 generateFunctionTypeSignature(e, t); | 187 generateFunctionTypeSignature, |
185 }, | 188 (ClassEntity e, {bool emitNull: false}) => |
186 (Element e, {bool emitNull: false}) => | |
187 generateSubstitution(e, emitNull: emitNull), | 189 generateSubstitution(e, emitNull: emitNull), |
188 generateTypeCheck); | 190 generateTypeCheck); |
189 | 191 |
190 if (classElement == _commonElements.jsJavaScriptFunctionClass) { | 192 if (classElement == _commonElements.jsJavaScriptFunctionClass) { |
191 var type = _jsInteropAnalysis.buildJsFunctionType(); | 193 var type = _jsInteropAnalysis.buildJsFunctionType(); |
192 if (type != null) { | 194 if (type != null) { |
193 jsAst.Expression thisAccess = new jsAst.This(); | 195 jsAst.Expression thisAccess = new jsAst.This(); |
194 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( | 196 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( |
195 emitterTask.emitter, type, thisAccess); | 197 emitterTask.emitter, type, thisAccess); |
196 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); | 198 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); |
197 result.properties[operatorSignature] = encoding; | 199 result.properties[operatorSignature] = encoding; |
198 } | 200 } |
199 } | 201 } |
200 return result; | 202 return result; |
201 } | 203 } |
202 | 204 |
203 /** | 205 /** |
204 * Generate "is tests" for [cls] itself, and the "is tests" for the | 206 * Generate "is tests" for [cls] itself, and the "is tests" for the |
205 * classes it implements and type argument substitution functions for these | 207 * classes it implements and type argument substitution functions for these |
206 * tests. We don't need to add the "is tests" of the super class because | 208 * tests. We don't need to add the "is tests" of the super class because |
207 * they will be inherited at runtime, but we may need to generate the | 209 * they will be inherited at runtime, but we may need to generate the |
208 * substitutions, because they may have changed. | 210 * substitutions, because they may have changed. |
209 */ | 211 */ |
210 void _generateIsTestsOn( | 212 void _generateIsTestsOn( |
211 ClassElement cls, | 213 ClassEntity cls, |
212 void generateIsTest(Element element), | 214 void generateIsTest(ClassEntity element), |
213 FunctionTypeSignatureEmitter generateFunctionTypeSignature, | 215 FunctionTypeSignatureEmitter generateFunctionTypeSignature, |
214 SubstitutionEmitter generateSubstitution, | 216 SubstitutionEmitter generateSubstitution, |
215 void emitTypeCheck(TypeCheck check)) { | 217 void emitTypeCheck(TypeCheck check)) { |
216 Setlet<ClassElement> generated = new Setlet<ClassElement>(); | 218 Setlet<ClassEntity> generated = new Setlet<ClassEntity>(); |
217 | 219 |
218 if (checkedClasses.contains(cls)) { | 220 if (checkedClasses.contains(cls)) { |
219 generateIsTest(cls); | 221 generateIsTest(cls); |
220 generateSubstitution(cls); | 222 generateSubstitution(cls); |
221 generated.add(cls); | 223 generated.add(cls); |
222 } | 224 } |
223 | 225 |
224 // Precomputed is checks. | 226 // Precomputed is checks. |
225 TypeChecks typeChecks = _rtiChecks.requiredChecks; | 227 TypeChecks typeChecks = _rtiChecks.requiredChecks; |
226 Iterable<TypeCheck> classChecks = typeChecks[cls]; | 228 Iterable<TypeCheck> classChecks = typeChecks[cls]; |
227 if (classChecks != null) { | 229 if (classChecks != null) { |
228 for (TypeCheck check in classChecks) { | 230 for (TypeCheck check in classChecks) { |
229 if (!generated.contains(check.cls)) { | 231 if (!generated.contains(check.cls)) { |
230 emitTypeCheck(check); | 232 emitTypeCheck(check); |
231 generated.add(check.cls); | 233 generated.add(check.cls); |
232 } | 234 } |
233 } | 235 } |
234 } | 236 } |
235 | 237 |
236 ClassElement superclass = cls.superclass; | 238 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
237 | 239 |
238 bool haveSameTypeVariables(ClassElement a, ClassElement b) { | 240 bool haveSameTypeVariables(ClassEntity a, ClassEntity b) { |
239 if (a.isClosure) return true; | 241 if (a.isClosure) return true; |
240 return _rtiSubstitutions.isTrivialSubstitution(a, b); | 242 return _rtiSubstitutions.isTrivialSubstitution(a, b); |
241 } | 243 } |
242 | 244 |
243 bool supertypesNeedSubstitutions = false; | 245 bool supertypesNeedSubstitutions = false; |
244 | 246 |
245 if (superclass != null && | 247 if (superclass != null && |
246 superclass != _commonElements.objectClass && | 248 superclass != _commonElements.objectClass && |
247 !haveSameTypeVariables(cls, superclass)) { | 249 !haveSameTypeVariables(cls, superclass)) { |
248 // We cannot inherit the generated substitutions, because the type | 250 // We cannot inherit the generated substitutions, because the type |
249 // variable layout for this class is different. Instead we generate | 251 // variable layout for this class is different. Instead we generate |
250 // substitutions for all checks and make emitSubstitution a NOP for the | 252 // substitutions for all checks and make emitSubstitution a NOP for the |
251 // rest of this function. | 253 // rest of this function. |
252 | 254 |
253 // TODO(karlklose): move the computation of these checks to | 255 // TODO(karlklose): move the computation of these checks to |
254 // RuntimeTypeInformation. | 256 // RuntimeTypeInformation. |
255 while (superclass != null) { | 257 while (superclass != null) { |
256 if (_rtiNeed.classNeedsRti(superclass)) { | 258 if (_rtiNeed.classNeedsRti(superclass)) { |
257 generateSubstitution(superclass, emitNull: true); | 259 generateSubstitution(superclass, emitNull: true); |
258 generated.add(superclass); | 260 generated.add(superclass); |
259 } | 261 } |
260 superclass = superclass.superclass; | 262 superclass = _elementEnvironment.getSuperClass(superclass); |
261 } | 263 } |
262 supertypesNeedSubstitutions = true; | 264 supertypesNeedSubstitutions = true; |
263 } | 265 } |
264 | 266 |
265 if (cls is MixinApplicationElement) { | 267 if (cls is MixinApplicationElement) { |
266 supertypesNeedSubstitutions = true; | 268 supertypesNeedSubstitutions = true; |
267 } | 269 } |
268 | 270 |
269 if (supertypesNeedSubstitutions) { | 271 if (supertypesNeedSubstitutions) { |
270 for (ResolutionInterfaceType supertype in cls.allSupertypes) { | 272 _elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) { |
271 ClassElement superclass = supertype.element; | 273 ClassEntity superclass = supertype.element; |
272 if (generated.contains(superclass)) continue; | 274 if (generated.contains(superclass)) return; |
273 | 275 |
274 if (classesUsingTypeVariableTests.contains(superclass) || | 276 if (classesUsingTypeVariableTests.contains(superclass) || |
275 _rtiNeed.classUsesTypeVariableExpression(superclass) || | 277 _rtiNeed.classUsesTypeVariableExpression(superclass) || |
276 checkedClasses.contains(superclass)) { | 278 checkedClasses.contains(superclass)) { |
277 // Generate substitution. If no substitution is necessary, emit | 279 // Generate substitution. If no substitution is necessary, emit |
278 // `null` to overwrite a (possibly) existing substitution from the | 280 // `null` to overwrite a (possibly) existing substitution from the |
279 // super classes. | 281 // super classes. |
280 generateSubstitution(superclass, emitNull: true); | 282 generateSubstitution(superclass, emitNull: true); |
281 } | 283 } |
282 } | 284 }); |
283 | 285 |
284 void emitNothing(_, {emitNull}) {} | 286 void emitNothing(_, {emitNull}) {} |
285 | 287 |
286 generateSubstitution = emitNothing; | 288 generateSubstitution = emitNothing; |
287 } | 289 } |
288 | 290 |
289 // A class that defines a `call` method implicitly implements | 291 // A class that defines a `call` method implicitly implements |
290 // [Function] and needs checks for all typedefs that are used in is-checks. | 292 // [Function] and needs checks for all typedefs that are used in is-checks. |
291 if (checkedClasses.contains(_commonElements.functionClass) || | 293 if (checkedClasses.contains(_commonElements.functionClass) || |
292 checkedFunctionTypes.isNotEmpty) { | 294 checkedFunctionTypes.isNotEmpty) { |
293 Element call = cls.lookupLocalMember(Identifiers.call); | 295 MemberEntity call = |
294 if (call == null) { | 296 _elementEnvironment.lookupClassMember(cls, Identifiers.call); |
295 // If [cls] is a closure, it has a synthetic call operator method. | |
296 call = cls.lookupConstructorBody(Identifiers.call); | |
Siggi Cherem (dart-lang)
2017/06/23 19:49:28
Was this basically dead code?
I'm guessing this u
Johnni Winther
2017/06/26 09:17:44
Yes. Yes.
| |
297 } | |
298 if (call != null && call.isFunction) { | 297 if (call != null && call.isFunction) { |
299 FunctionElement callFunction = call; | 298 FunctionEntity callFunction = call; |
300 // A superclass might already implement the Function interface. In such | 299 // A superclass might already implement the Function interface. In such |
301 // a case, we can avoid emiting the is test here. | 300 // a case, we can avoid emitting the is test here. |
302 if (!cls.superclass.implementsFunction(_commonElements)) { | 301 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
302 if (!_closedWorld.isSubclassOf( | |
303 superclass, _commonElements.functionClass)) { | |
303 _generateInterfacesIsTests(_commonElements.functionClass, | 304 _generateInterfacesIsTests(_commonElements.functionClass, |
304 generateIsTest, generateSubstitution, generated); | 305 generateIsTest, generateSubstitution, generated); |
305 } | 306 } |
306 ResolutionFunctionType callType = callFunction.type; | 307 FunctionType callType = |
308 _elementEnvironment.getFunctionType(callFunction); | |
307 generateFunctionTypeSignature(callFunction, callType); | 309 generateFunctionTypeSignature(callFunction, callType); |
308 } | 310 } |
309 } | 311 } |
310 | 312 |
311 for (ResolutionDartType interfaceType in cls.interfaces) { | 313 for (InterfaceType interfaceType in _types.getInterfaces(cls)) { |
312 _generateInterfacesIsTests(interfaceType.element, generateIsTest, | 314 _generateInterfacesIsTests(interfaceType.element, generateIsTest, |
313 generateSubstitution, generated); | 315 generateSubstitution, generated); |
314 } | 316 } |
315 } | 317 } |
316 | 318 |
317 /** | 319 /** |
318 * Generate "is tests" where [cls] is being implemented. | 320 * Generate "is tests" where [cls] is being implemented. |
319 */ | 321 */ |
320 void _generateInterfacesIsTests( | 322 void _generateInterfacesIsTests( |
321 ClassElement cls, | 323 ClassEntity cls, |
322 void generateIsTest(ClassElement element), | 324 void generateIsTest(ClassEntity element), |
323 SubstitutionEmitter generateSubstitution, | 325 SubstitutionEmitter generateSubstitution, |
324 Set<Element> alreadyGenerated) { | 326 Set<ClassEntity> alreadyGenerated) { |
325 void tryEmitTest(ClassElement check) { | 327 void tryEmitTest(ClassEntity check) { |
326 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { | 328 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
327 alreadyGenerated.add(check); | 329 alreadyGenerated.add(check); |
328 generateIsTest(check); | 330 generateIsTest(check); |
329 generateSubstitution(check); | 331 generateSubstitution(check); |
330 } | 332 } |
331 } | 333 } |
332 | 334 |
333 tryEmitTest(cls); | 335 tryEmitTest(cls); |
334 | 336 |
335 for (ResolutionDartType interfaceType in cls.interfaces) { | 337 for (InterfaceType interfaceType in _types.getInterfaces(cls)) { |
336 Element element = interfaceType.element; | 338 ClassEntity element = interfaceType.element; |
337 tryEmitTest(element); | 339 tryEmitTest(element); |
338 _generateInterfacesIsTests( | 340 _generateInterfacesIsTests( |
339 element, generateIsTest, generateSubstitution, alreadyGenerated); | 341 element, generateIsTest, generateSubstitution, alreadyGenerated); |
340 } | 342 } |
341 | 343 |
342 // We need to also emit "is checks" for the superclass and its supertypes. | 344 // We need to also emit "is checks" for the superclass and its supertypes. |
343 ClassElement superclass = cls.superclass; | 345 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
344 if (superclass != null) { | 346 if (superclass != null) { |
345 tryEmitTest(superclass); | 347 tryEmitTest(superclass); |
346 _generateInterfacesIsTests( | 348 _generateInterfacesIsTests( |
347 superclass, generateIsTest, generateSubstitution, alreadyGenerated); | 349 superclass, generateIsTest, generateSubstitution, alreadyGenerated); |
348 } | 350 } |
349 } | 351 } |
350 } | 352 } |
OLD | NEW |