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