| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 part of world_builder; | 5 part of world_builder; |
| 6 | 6 |
| 7 abstract class ResolutionWorldBuilder implements WorldBuilder, OpenWorld { | 7 abstract class ResolutionWorldBuilder implements WorldBuilder, OpenWorld { |
| 8 /// Set of all local functions in the program. Used by the mirror tracking | 8 /// Set of all local functions in the program. Used by the mirror tracking |
| 9 /// system to find all live closure instances. | 9 /// system to find all live closure instances. |
| 10 Iterable<LocalFunctionElement> get localFunctions; | 10 Iterable<Local> get localFunctions; |
| 11 | 11 |
| 12 /// Set of (live) local functions (closures) whose signatures reference type | 12 /// Set of (live) local functions (closures) whose signatures reference type |
| 13 /// variables. | 13 /// variables. |
| 14 /// | 14 /// |
| 15 /// A live function is one whose enclosing member function has been enqueued. | 15 /// A live function is one whose enclosing member function has been enqueued. |
| 16 Iterable<LocalFunctionElement> get localFunctionsWithFreeTypeVariables; | 16 Iterable<Local> get localFunctionsWithFreeTypeVariables; |
| 17 | 17 |
| 18 /// Set of methods in instantiated classes that are potentially closurized. | 18 /// Set of methods in instantiated classes that are potentially closurized. |
| 19 Iterable<MethodElement> get closurizedMembers; | 19 Iterable<FunctionEntity> get closurizedMembers; |
| 20 | 20 |
| 21 /// Set of live closurized members whose signatures reference type variables. | 21 /// Set of live closurized members whose signatures reference type variables. |
| 22 /// | 22 /// |
| 23 /// A closurized method is considered live if the enclosing class has been | 23 /// A closurized method is considered live if the enclosing class has been |
| 24 /// instantiated. | 24 /// instantiated. |
| 25 Iterable<MethodElement> get closurizedMembersWithFreeTypeVariables; | 25 Iterable<FunctionEntity> get closurizedMembersWithFreeTypeVariables; |
| 26 | 26 |
| 27 /// Returns `true` if [cls] is considered to be implemented by an | 27 /// Returns `true` if [cls] is considered to be implemented by an |
| 28 /// instantiated class, either directly, through subclasses or through | 28 /// instantiated class, either directly, through subclasses or through |
| 29 /// subtypes. The latter case only contains spurious information from | 29 /// subtypes. The latter case only contains spurious information from |
| 30 /// instantiations through factory constructors and mixins. | 30 /// instantiations through factory constructors and mixins. |
| 31 bool isImplemented(ClassElement cls); | 31 // TODO(johnniwinther): Improve semantic precision. |
| 32 bool isImplemented(ClassEntity cls); |
| 32 | 33 |
| 33 /// Set of all fields that are statically known to be written to. | 34 /// Set of all fields that are statically known to be written to. |
| 34 Iterable<Element> get fieldSetters; | 35 Iterable<FieldEntity> get fieldSetters; |
| 35 | 36 |
| 36 /// Call [f] for all classes with instantiated types. This includes the | 37 /// Call [f] for all classes with instantiated types. This includes the |
| 37 /// directly and abstractly instantiated classes but also classes whose type | 38 /// directly and abstractly instantiated classes but also classes whose type |
| 38 /// arguments are used in live factory constructors. | 39 /// arguments are used in live factory constructors. |
| 39 void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)); | 40 void forEachInstantiatedClass(f(ClassEntity cls, InstantiationInfo info)); |
| 40 | 41 |
| 41 /// Returns `true` if [member] is invoked as a setter. | 42 /// Returns `true` if [member] is invoked as a setter. |
| 42 bool hasInvokedSetter(Element member); | 43 bool hasInvokedSetter(MemberEntity member); |
| 43 | 44 |
| 44 /// Returns `true` if [member] has been marked as used (called, read, etc.) in | 45 /// Returns `true` if [member] has been marked as used (called, read, etc.) in |
| 45 /// this world builder. | 46 /// this world builder. |
| 46 // TODO(johnniwinther): Maybe this should be part of [ClosedWorld] (instead). | 47 // TODO(johnniwinther): Maybe this should be part of [ClosedWorld] (instead). |
| 47 bool isMemberUsed(MemberEntity member); | 48 bool isMemberUsed(MemberEntity member); |
| 48 | 49 |
| 49 /// The closed world computed by this world builder. | 50 /// The closed world computed by this world builder. |
| 50 /// | 51 /// |
| 51 /// This is only available after the world builder has been closed. | 52 /// This is only available after the world builder has been closed. |
| 52 ClosedWorld get closedWorldForTesting; | 53 ClosedWorld get closedWorldForTesting; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed); | 87 void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed); |
| 87 | 88 |
| 88 /// Register the constant [use] with this world builder. Returns `true` if | 89 /// Register the constant [use] with this world builder. Returns `true` if |
| 89 /// the constant use was new to the world. | 90 /// the constant use was new to the world. |
| 90 bool registerConstantUse(ConstantUse use); | 91 bool registerConstantUse(ConstantUse use); |
| 91 } | 92 } |
| 92 | 93 |
| 93 /// The type and kind of an instantiation registered through | 94 /// The type and kind of an instantiation registered through |
| 94 /// `ResolutionWorldBuilder.registerTypeInstantiation`. | 95 /// `ResolutionWorldBuilder.registerTypeInstantiation`. |
| 95 class Instance { | 96 class Instance { |
| 96 final ResolutionInterfaceType type; | 97 final InterfaceType type; |
| 97 final Instantiation kind; | 98 final Instantiation kind; |
| 98 final bool isRedirection; | 99 final bool isRedirection; |
| 99 | 100 |
| 100 Instance(this.type, this.kind, {this.isRedirection: false}); | 101 Instance(this.type, this.kind, {this.isRedirection: false}); |
| 101 | 102 |
| 102 int get hashCode { | 103 int get hashCode { |
| 103 return Hashing.objectHash( | 104 return Hashing.objectHash( |
| 104 type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection))); | 105 type, Hashing.objectHash(kind, Hashing.objectHash(isRedirection))); |
| 105 } | 106 } |
| 106 | 107 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 /// }, | 185 /// }, |
| 185 /// }, | 186 /// }, |
| 186 /// DivElement: { | 187 /// DivElement: { |
| 187 /// DivElement: { | 188 /// DivElement: { |
| 188 /// DivElement abstractly, // from `new DivElement()` | 189 /// DivElement abstractly, // from `new DivElement()` |
| 189 /// }, | 190 /// }, |
| 190 /// } | 191 /// } |
| 191 /// | 192 /// |
| 192 /// If the constructor is unknown, for instance for native or mirror usage, | 193 /// If the constructor is unknown, for instance for native or mirror usage, |
| 193 /// `null` is used as key. | 194 /// `null` is used as key. |
| 194 Map<ConstructorElement, Set<Instance>> instantiationMap; | 195 Map<ConstructorEntity, Set<Instance>> instantiationMap; |
| 195 | 196 |
| 196 /// Register [type] as the instantiation [kind] using [constructor]. | 197 /// Register [type] as the instantiation [kind] using [constructor]. |
| 197 void addInstantiation(ConstructorElement constructor, | 198 void addInstantiation( |
| 198 ResolutionInterfaceType type, Instantiation kind, | 199 ConstructorEntity constructor, InterfaceType type, Instantiation kind, |
| 199 {bool isRedirection: false}) { | 200 {bool isRedirection: false}) { |
| 200 instantiationMap ??= <ConstructorElement, Set<Instance>>{}; | 201 instantiationMap ??= <ConstructorEntity, Set<Instance>>{}; |
| 201 instantiationMap | 202 instantiationMap |
| 202 .putIfAbsent(constructor, () => new Set<Instance>()) | 203 .putIfAbsent(constructor, () => new Set<Instance>()) |
| 203 .add(new Instance(type, kind, isRedirection: isRedirection)); | 204 .add(new Instance(type, kind, isRedirection: isRedirection)); |
| 204 switch (kind) { | 205 switch (kind) { |
| 205 case Instantiation.DIRECTLY_INSTANTIATED: | 206 case Instantiation.DIRECTLY_INSTANTIATED: |
| 206 isDirectlyInstantiated = true; | 207 isDirectlyInstantiated = true; |
| 207 break; | 208 break; |
| 208 case Instantiation.ABSTRACTLY_INSTANTIATED: | 209 case Instantiation.ABSTRACTLY_INSTANTIATED: |
| 209 isAbstractlyInstantiated = true; | 210 isAbstractlyInstantiated = true; |
| 210 break; | 211 break; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 224 | 225 |
| 225 /// `true` if the class is abstractly instantiated. | 226 /// `true` if the class is abstractly instantiated. |
| 226 bool isAbstractlyInstantiated = false; | 227 bool isAbstractlyInstantiated = false; |
| 227 | 228 |
| 228 String toString() { | 229 String toString() { |
| 229 StringBuffer sb = new StringBuffer(); | 230 StringBuffer sb = new StringBuffer(); |
| 230 sb.write('InstantiationInfo['); | 231 sb.write('InstantiationInfo['); |
| 231 if (instantiationMap != null) { | 232 if (instantiationMap != null) { |
| 232 bool needsComma = false; | 233 bool needsComma = false; |
| 233 instantiationMap | 234 instantiationMap |
| 234 .forEach((ConstructorElement constructor, Set<Instance> set) { | 235 .forEach((ConstructorEntity constructor, Set<Instance> set) { |
| 235 if (needsComma) { | 236 if (needsComma) { |
| 236 sb.write(', '); | 237 sb.write(', '); |
| 237 } | 238 } |
| 238 if (constructor != null) { | 239 if (constructor != null) { |
| 239 sb.write(constructor); | 240 sb.write(constructor); |
| 240 } else { | 241 } else { |
| 241 sb.write('<unknown>'); | 242 sb.write('<unknown>'); |
| 242 } | 243 } |
| 243 sb.write(': '); | 244 sb.write(': '); |
| 244 sb.write(set); | 245 sb.write(set); |
| 245 needsComma = true; | 246 needsComma = true; |
| 246 }); | 247 }); |
| 247 } | 248 } |
| 248 sb.write(']'); | 249 sb.write(']'); |
| 249 return sb.toString(); | 250 return sb.toString(); |
| 250 } | 251 } |
| 251 } | 252 } |
| 252 | 253 |
| 253 /// [ResolutionEnqueuerWorldBuilder] based on the [Element] model. | 254 /// Base implementation of [ResolutionEnqueuerWorldBuilder]. |
| 254 class ElementResolutionWorldBuilder implements ResolutionEnqueuerWorldBuilder { | 255 abstract class ResolutionWorldBuilderBase |
| 256 implements ResolutionEnqueuerWorldBuilder { |
| 255 /// Instantiation information for all classes with instantiated types. | 257 /// Instantiation information for all classes with instantiated types. |
| 256 /// | 258 /// |
| 257 /// Invariant: Elements are declaration elements. | 259 /// Invariant: Elements are declaration elements. |
| 258 final Map<ClassElement, InstantiationInfo> _instantiationInfo = | 260 final Map<ClassEntity, InstantiationInfo> _instantiationInfo = |
| 259 <ClassElement, InstantiationInfo>{}; | 261 <ClassEntity, InstantiationInfo>{}; |
| 260 | 262 |
| 261 /// Classes implemented by directly instantiated classes. | 263 /// Classes implemented by directly instantiated classes. |
| 262 final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); | 264 final Set<ClassEntity> _implementedClasses = new Set<ClassEntity>(); |
| 263 | 265 |
| 264 /// The set of all referenced static fields. | 266 /// The set of all referenced static fields. |
| 265 /// | 267 /// |
| 266 /// Invariant: Elements are declaration elements. | 268 /// Invariant: Elements are declaration elements. |
| 267 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); | 269 final Set<FieldEntity> allReferencedStaticFields = new Set<FieldEntity>(); |
| 268 | 270 |
| 269 /** | 271 /** |
| 270 * Documentation wanted -- johnniwinther | 272 * Documentation wanted -- johnniwinther |
| 271 * | 273 * |
| 272 * Invariant: Elements are declaration elements. | 274 * Invariant: Elements are declaration elements. |
| 273 */ | 275 */ |
| 274 final Set<FunctionElement> methodsNeedingSuperGetter = | 276 final Set<FunctionEntity> methodsNeedingSuperGetter = |
| 275 new Set<FunctionElement>(); | 277 new Set<FunctionEntity>(); |
| 276 final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = | 278 final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = |
| 277 <String, Map<Selector, SelectorConstraints>>{}; | 279 <String, Map<Selector, SelectorConstraints>>{}; |
| 278 final Map<String, Map<Selector, SelectorConstraints>> _invokedGetters = | 280 final Map<String, Map<Selector, SelectorConstraints>> _invokedGetters = |
| 279 <String, Map<Selector, SelectorConstraints>>{}; | 281 <String, Map<Selector, SelectorConstraints>>{}; |
| 280 final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = | 282 final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = |
| 281 <String, Map<Selector, SelectorConstraints>>{}; | 283 <String, Map<Selector, SelectorConstraints>>{}; |
| 282 | 284 |
| 283 final Map<ClassElement, _ClassUsage> _processedClasses = | 285 final Map<ClassEntity, _ClassUsage> _processedClasses = |
| 284 <ClassElement, _ClassUsage>{}; | 286 <ClassEntity, _ClassUsage>{}; |
| 285 | 287 |
| 286 /// Map of registered usage of static members of live classes. | 288 /// Map of registered usage of static members of live classes. |
| 287 final Map<Entity, _StaticMemberUsage> _staticMemberUsage = | 289 final Map<Entity, _StaticMemberUsage> _staticMemberUsage = |
| 288 <Entity, _StaticMemberUsage>{}; | 290 <Entity, _StaticMemberUsage>{}; |
| 289 | 291 |
| 290 /// Map of registered usage of instance members of live classes. | 292 /// Map of registered usage of instance members of live classes. |
| 291 final Map<MemberEntity, _MemberUsage> _instanceMemberUsage = | 293 final Map<MemberEntity, _MemberUsage> _instanceMemberUsage = |
| 292 <MemberEntity, _MemberUsage>{}; | 294 <MemberEntity, _MemberUsage>{}; |
| 293 | 295 |
| 294 /// Map containing instance members of live classes that are not yet live | 296 /// Map containing instance members of live classes that are not yet live |
| 295 /// themselves. | 297 /// themselves. |
| 296 final Map<String, Set<_MemberUsage>> _instanceMembersByName = | 298 final Map<String, Set<_MemberUsage>> _instanceMembersByName = |
| 297 <String, Set<_MemberUsage>>{}; | 299 <String, Set<_MemberUsage>>{}; |
| 298 | 300 |
| 299 /// Map containing instance methods of live classes that are not yet | 301 /// Map containing instance methods of live classes that are not yet |
| 300 /// closurized. | 302 /// closurized. |
| 301 final Map<String, Set<_MemberUsage>> _instanceFunctionsByName = | 303 final Map<String, Set<_MemberUsage>> _instanceFunctionsByName = |
| 302 <String, Set<_MemberUsage>>{}; | 304 <String, Set<_MemberUsage>>{}; |
| 303 | 305 |
| 304 /// Fields set. | 306 /// Fields set. |
| 305 final Set<Element> fieldSetters = new Set<Element>(); | 307 final Set<FieldEntity> fieldSetters = new Set<FieldEntity>(); |
| 306 final Set<ResolutionDartType> isChecks = new Set<ResolutionDartType>(); | 308 final Set<DartType> isChecks = new Set<DartType>(); |
| 307 | 309 |
| 308 /// Set of all closures in the program. Used by the mirror tracking system | 310 /// Set of all closures in the program. Used by the mirror tracking system |
| 309 /// to find all live closure instances. | 311 /// to find all live closure instances. |
| 310 final Set<LocalFunctionElement> localFunctions = | 312 final Set<Local> localFunctions = new Set<Local>(); |
| 311 new Set<LocalFunctionElement>(); | |
| 312 | 313 |
| 313 /// Set of live local functions (closures) whose signatures reference type | 314 /// Set of live local functions (closures) whose signatures reference type |
| 314 /// variables. | 315 /// variables. |
| 315 /// | 316 /// |
| 316 /// A local function is considered live if the enclosing member function is | 317 /// A local function is considered live if the enclosing member function is |
| 317 /// live. | 318 /// live. |
| 318 final Set<LocalFunctionElement> localFunctionsWithFreeTypeVariables = | 319 final Set<Local> localFunctionsWithFreeTypeVariables = new Set<Local>(); |
| 319 new Set<LocalFunctionElement>(); | |
| 320 | 320 |
| 321 /// Set of methods in instantiated classes that are potentially closurized. | 321 /// Set of methods in instantiated classes that are potentially closurized. |
| 322 final Set<MethodElement> closurizedMembers = new Set<MethodElement>(); | 322 final Set<FunctionEntity> closurizedMembers = new Set<FunctionEntity>(); |
| 323 | 323 |
| 324 /// Set of live closurized members whose signatures reference type variables. | 324 /// Set of live closurized members whose signatures reference type variables. |
| 325 /// | 325 /// |
| 326 /// A closurized method is considered live if the enclosing class has been | 326 /// A closurized method is considered live if the enclosing class has been |
| 327 /// instantiated. | 327 /// instantiated. |
| 328 final Set<MethodElement> closurizedMembersWithFreeTypeVariables = | 328 final Set<FunctionEntity> closurizedMembersWithFreeTypeVariables = |
| 329 new Set<MethodElement>(); | 329 new Set<FunctionEntity>(); |
| 330 |
| 331 final ElementEnvironment _elementEnvironment; |
| 332 |
| 333 final CommonElements _commonElements; |
| 334 |
| 335 final NativeBasicData _nativeBasicData; |
| 330 | 336 |
| 331 final SelectorConstraintsStrategy selectorConstraintsStrategy; | 337 final SelectorConstraintsStrategy selectorConstraintsStrategy; |
| 332 | 338 |
| 333 bool hasRuntimeTypeSupport = false; | 339 bool hasRuntimeTypeSupport = false; |
| 334 bool hasIsolateSupport = false; | 340 bool hasIsolateSupport = false; |
| 335 bool hasFunctionApplySupport = false; | 341 bool hasFunctionApplySupport = false; |
| 336 | 342 |
| 337 /// Used for testing the new more precise computation of instantiated types | |
| 338 /// and classes. | |
| 339 static bool useInstantiationMap = false; | |
| 340 | |
| 341 final JavaScriptBackend _backend; | |
| 342 final Resolution _resolution; | |
| 343 bool _closed = false; | 343 bool _closed = false; |
| 344 ClosedWorld _closedWorldCache; | 344 ClosedWorld _closedWorldCache; |
| 345 FunctionSetBuilder _allFunctions; | 345 FunctionSetBuilder _allFunctions; |
| 346 | 346 |
| 347 final Set<TypedefElement> _allTypedefs = new Set<TypedefElement>(); | 347 final Set<TypedefElement> _allTypedefs = new Set<TypedefElement>(); |
| 348 | 348 |
| 349 final Map<ClassElement, Set<MixinApplicationElement>> _mixinUses = | 349 final Map<ClassEntity, Set<ClassEntity>> _mixinUses = |
| 350 new Map<ClassElement, Set<MixinApplicationElement>>(); | 350 new Map<ClassEntity, Set<ClassEntity>>(); |
| 351 | 351 |
| 352 // We keep track of subtype and subclass relationships in four | 352 // We keep track of subtype and subclass relationships in four |
| 353 // distinct sets to make class hierarchy analysis faster. | 353 // distinct sets to make class hierarchy analysis faster. |
| 354 final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes = | 354 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes = |
| 355 <ClassElement, ClassHierarchyNode>{}; | 355 <ClassEntity, ClassHierarchyNode>{}; |
| 356 final Map<ClassElement, ClassSet> _classSets = <ClassElement, ClassSet>{}; | 356 final Map<ClassEntity, ClassSet> _classSets = <ClassEntity, ClassSet>{}; |
| 357 | 357 |
| 358 final Set<ConstantValue> _constantValues = new Set<ConstantValue>(); | 358 final Set<ConstantValue> _constantValues = new Set<ConstantValue>(); |
| 359 | 359 |
| 360 bool get isClosed => _closed; | 360 bool get isClosed => _closed; |
| 361 | 361 |
| 362 ElementResolutionWorldBuilder( | 362 ResolutionWorldBuilderBase(this._elementEnvironment, this._commonElements, |
| 363 this._backend, this._resolution, this.selectorConstraintsStrategy) { | 363 this._nativeBasicData, this.selectorConstraintsStrategy) { |
| 364 _allFunctions = new FunctionSetBuilder(); | 364 _allFunctions = new FunctionSetBuilder(); |
| 365 } | 365 } |
| 366 | 366 |
| 367 Iterable<ClassElement> get processedClasses => _processedClasses.keys | 367 Iterable<ClassEntity> get processedClasses => _processedClasses.keys |
| 368 .where((cls) => _processedClasses[cls].isInstantiated); | 368 .where((cls) => _processedClasses[cls].isInstantiated); |
| 369 | 369 |
| 370 CommonElements get commonElements => _resolution.commonElements; | |
| 371 | |
| 372 ClosedWorld get closedWorldForTesting { | 370 ClosedWorld get closedWorldForTesting { |
| 373 if (!_closed) { | 371 if (!_closed) { |
| 374 throw new SpannableAssertionFailure( | 372 throw new SpannableAssertionFailure( |
| 375 NO_LOCATION_SPANNABLE, "The world builder has not yet been closed."); | 373 NO_LOCATION_SPANNABLE, "The world builder has not yet been closed."); |
| 376 } | 374 } |
| 377 return _closedWorldCache; | 375 return _closedWorldCache; |
| 378 } | 376 } |
| 379 | 377 |
| 380 /// All directly instantiated classes, that is, classes with a generative | 378 /// All directly instantiated classes, that is, classes with a generative |
| 381 /// constructor that has been called directly and not only through a | 379 /// constructor that has been called directly and not only through a |
| 382 /// super-call. | 380 /// super-call. |
| 383 // TODO(johnniwinther): Improve semantic precision. | 381 // TODO(johnniwinther): Improve semantic precision. |
| 384 Iterable<ClassElement> get directlyInstantiatedClasses { | 382 Iterable<ClassEntity> get directlyInstantiatedClasses { |
| 385 Set<ClassElement> classes = new Set<ClassElement>(); | 383 Set<ClassEntity> classes = new Set<ClassEntity>(); |
| 386 getInstantiationMap().forEach((ClassElement cls, InstantiationInfo info) { | 384 getInstantiationMap().forEach((ClassEntity cls, InstantiationInfo info) { |
| 387 if (info.hasInstantiation) { | 385 if (info.hasInstantiation) { |
| 388 classes.add(cls); | 386 classes.add(cls); |
| 389 } | 387 } |
| 390 }); | 388 }); |
| 391 return classes; | 389 return classes; |
| 392 } | 390 } |
| 393 | 391 |
| 394 /// All directly instantiated types, that is, the types of the directly | 392 /// All directly instantiated types, that is, the types of the directly |
| 395 /// instantiated classes. | 393 /// instantiated classes. |
| 396 /// | 394 /// |
| 397 /// See [directlyInstantiatedClasses]. | 395 /// See [directlyInstantiatedClasses]. |
| 398 // TODO(johnniwinther): Improve semantic precision. | 396 // TODO(johnniwinther): Improve semantic precision. |
| 399 Iterable<InterfaceType> get instantiatedTypes { | 397 Iterable<InterfaceType> get instantiatedTypes { |
| 400 Set<ResolutionInterfaceType> types = new Set<ResolutionInterfaceType>(); | 398 Set<InterfaceType> types = new Set<InterfaceType>(); |
| 401 getInstantiationMap().forEach((_, InstantiationInfo info) { | 399 getInstantiationMap().forEach((_, InstantiationInfo info) { |
| 402 if (info.instantiationMap != null) { | 400 if (info.instantiationMap != null) { |
| 403 for (Set<Instance> instances in info.instantiationMap.values) { | 401 for (Set<Instance> instances in info.instantiationMap.values) { |
| 404 for (Instance instance in instances) { | 402 for (Instance instance in instances) { |
| 405 types.add(instance.type); | 403 types.add(instance.type); |
| 406 } | 404 } |
| 407 } | 405 } |
| 408 } | 406 } |
| 409 }); | 407 }); |
| 410 return types; | 408 return types; |
| 411 } | 409 } |
| 412 | 410 |
| 413 /// Returns `true` if [cls] is considered to be implemented by an | 411 bool isImplemented(ClassEntity cls) { |
| 414 /// instantiated class, either directly, through subclasses or through | 412 return _implementedClasses.contains(cls); |
| 415 /// subtypes. The latter case only contains spurious information from | |
| 416 /// instantiations through factory constructors and mixins. | |
| 417 // TODO(johnniwinther): Improve semantic precision. | |
| 418 bool isImplemented(ClassElement cls) { | |
| 419 return _implementedClasses.contains(cls.declaration); | |
| 420 } | 413 } |
| 421 | 414 |
| 422 void registerClosurizedMember(MemberElement element) { | 415 void registerClosurizedMember(FunctionEntity element) { |
| 423 closurizedMembers.add(element); | 416 closurizedMembers.add(element); |
| 424 if (element.type.containsTypeVariables) { | 417 FunctionType type = _elementEnvironment.getFunctionType(element); |
| 418 if (type.containsTypeVariables) { |
| 425 closurizedMembersWithFreeTypeVariables.add(element); | 419 closurizedMembersWithFreeTypeVariables.add(element); |
| 426 } | 420 } |
| 427 } | 421 } |
| 428 | 422 |
| 429 /// Register [type] as (directly) instantiated. | 423 /// Register [type] as (directly) instantiated. |
| 430 /// | 424 /// |
| 431 /// If [byMirrors] is `true`, the instantiation is through mirrors. | 425 /// If [byMirrors] is `true`, the instantiation is through mirrors. |
| 432 // TODO(johnniwinther): Fully enforce the separation between exact, through | 426 // TODO(johnniwinther): Fully enforce the separation between exact, through |
| 433 // subclass and through subtype instantiated types/classes. | 427 // subclass and through subtype instantiated types/classes. |
| 434 // TODO(johnniwinther): Support unknown type arguments for generic types. | 428 // TODO(johnniwinther): Support unknown type arguments for generic types. |
| 435 void registerTypeInstantiation( | 429 void registerTypeInstantiation( |
| 436 ResolutionInterfaceType type, ClassUsedCallback classUsed, | 430 InterfaceType type, ClassUsedCallback classUsed, |
| 437 {ConstructorElement constructor, | 431 {ConstructorEntity constructor, |
| 438 bool byMirrors: false, | 432 bool byMirrors: false, |
| 439 bool isRedirection: false}) { | 433 bool isRedirection: false}) { |
| 440 ClassElement cls = type.element; | 434 ClassEntity cls = type.element; |
| 441 cls.ensureResolved(_resolution); | |
| 442 InstantiationInfo info = | 435 InstantiationInfo info = |
| 443 _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo()); | 436 _instantiationInfo.putIfAbsent(cls, () => new InstantiationInfo()); |
| 444 Instantiation kind = Instantiation.UNINSTANTIATED; | 437 Instantiation kind = Instantiation.UNINSTANTIATED; |
| 445 bool isNative = _backend.nativeBasicData.isNativeClass(cls); | 438 bool isNative = _nativeBasicData.isNativeClass(cls); |
| 446 if (!cls.isAbstract || | 439 if (!cls.isAbstract || |
| 447 // We can't use the closed-world assumption with native abstract | 440 // We can't use the closed-world assumption with native abstract |
| 448 // classes; a native abstract class may have non-abstract subclasses | 441 // classes; a native abstract class may have non-abstract subclasses |
| 449 // not declared to the program. Instances of these classes are | 442 // not declared to the program. Instances of these classes are |
| 450 // indistinguishable from the abstract class. | 443 // indistinguishable from the abstract class. |
| 451 isNative || | 444 isNative || |
| 452 // Likewise, if this registration comes from the mirror system, | 445 // Likewise, if this registration comes from the mirror system, |
| 453 // all bets are off. | 446 // all bets are off. |
| 454 // TODO(herhut): Track classes required by mirrors seperately. | 447 // TODO(herhut): Track classes required by mirrors seperately. |
| 455 byMirrors) { | 448 byMirrors) { |
| 456 if (isNative || byMirrors) { | 449 if (isNative || byMirrors) { |
| 457 kind = Instantiation.ABSTRACTLY_INSTANTIATED; | 450 kind = Instantiation.ABSTRACTLY_INSTANTIATED; |
| 458 } else { | 451 } else { |
| 459 kind = Instantiation.DIRECTLY_INSTANTIATED; | 452 kind = Instantiation.DIRECTLY_INSTANTIATED; |
| 460 } | 453 } |
| 461 _processInstantiatedClass(cls, classUsed); | 454 _processInstantiatedClass(cls, classUsed); |
| 462 } | 455 } |
| 463 info.addInstantiation(constructor, type, kind, | 456 info.addInstantiation(constructor, type, kind, |
| 464 isRedirection: isRedirection); | 457 isRedirection: isRedirection); |
| 465 | 458 |
| 466 // TODO(johnniwinther): Use [_instantiationInfo] to compute this information | 459 // TODO(johnniwinther): Use [_instantiationInfo] to compute this information |
| 467 // instead. | 460 // instead. |
| 468 if (_implementedClasses.add(cls)) { | 461 if (_implementedClasses.add(cls)) { |
| 469 classUsed(cls, _getClassUsage(cls).implement()); | 462 classUsed(cls, _getClassUsage(cls).implement()); |
| 470 cls.allSupertypes.forEach((ResolutionInterfaceType supertype) { | 463 _elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) { |
| 471 if (_implementedClasses.add(supertype.element)) { | 464 if (_implementedClasses.add(supertype.element)) { |
| 472 classUsed( | 465 classUsed( |
| 473 supertype.element, _getClassUsage(supertype.element).implement()); | 466 supertype.element, _getClassUsage(supertype.element).implement()); |
| 474 } | 467 } |
| 475 }); | 468 }); |
| 476 } | 469 } |
| 477 } | 470 } |
| 478 | 471 |
| 479 @override | 472 @override |
| 480 void forEachInstantiatedClass(f(ClassElement cls, InstantiationInfo info)) { | 473 void forEachInstantiatedClass(f(ClassEntity cls, InstantiationInfo info)) { |
| 481 getInstantiationMap().forEach(f); | 474 getInstantiationMap().forEach(f); |
| 482 } | 475 } |
| 483 | 476 |
| 484 bool _hasMatchingSelector( | 477 bool _hasMatchingSelector( |
| 485 Map<Selector, SelectorConstraints> selectors, Element member) { | 478 Map<Selector, SelectorConstraints> selectors, MemberEntity member) { |
| 486 if (selectors == null) return false; | 479 if (selectors == null) return false; |
| 487 for (Selector selector in selectors.keys) { | 480 for (Selector selector in selectors.keys) { |
| 488 if (selector.appliesUnnamed(member)) { | 481 if (selector.appliesUnnamed(member)) { |
| 489 SelectorConstraints masks = selectors[selector]; | 482 SelectorConstraints masks = selectors[selector]; |
| 490 if (masks.applies(member, selector, this)) { | 483 if (masks.applies(member, selector, this)) { |
| 491 return true; | 484 return true; |
| 492 } | 485 } |
| 493 } | 486 } |
| 494 } | 487 } |
| 495 return false; | 488 return false; |
| 496 } | 489 } |
| 497 | 490 |
| 498 /// Returns the instantiation map used for computing the closed world. | 491 /// Returns the instantiation map used for computing the closed world. |
| 499 /// | 492 Map<ClassEntity, InstantiationInfo> getInstantiationMap() { |
| 500 /// If [useInstantiationMap] is `true`, redirections are removed and | 493 return _instantiationInfo; |
| 501 /// redirecting factories are converted to their effective target and type. | |
| 502 Map<ClassElement, InstantiationInfo> getInstantiationMap() { | |
| 503 if (!useInstantiationMap) return _instantiationInfo; | |
| 504 | |
| 505 Map<ClassElement, InstantiationInfo> instantiationMap = | |
| 506 <ClassElement, InstantiationInfo>{}; | |
| 507 | |
| 508 InstantiationInfo infoFor(ClassElement cls) { | |
| 509 return instantiationMap.putIfAbsent(cls, () => new InstantiationInfo()); | |
| 510 } | |
| 511 | |
| 512 _instantiationInfo.forEach((cls, info) { | |
| 513 if (info.instantiationMap != null) { | |
| 514 info.instantiationMap | |
| 515 .forEach((ConstructorElement constructor, Set<Instance> set) { | |
| 516 for (Instance instance in set) { | |
| 517 if (instance.isRedirection) { | |
| 518 continue; | |
| 519 } | |
| 520 if (constructor == null || !constructor.isRedirectingFactory) { | |
| 521 infoFor(cls) | |
| 522 .addInstantiation(constructor, instance.type, instance.kind); | |
| 523 } else { | |
| 524 ConstructorElement target = constructor.effectiveTarget; | |
| 525 ResolutionInterfaceType targetType = | |
| 526 constructor.computeEffectiveTargetType(instance.type); | |
| 527 Instantiation kind = Instantiation.DIRECTLY_INSTANTIATED; | |
| 528 if (target.enclosingClass.isAbstract) { | |
| 529 // If target is a factory constructor on an abstract class. | |
| 530 kind = Instantiation.UNINSTANTIATED; | |
| 531 } | |
| 532 infoFor(targetType.element) | |
| 533 .addInstantiation(target, targetType, kind); | |
| 534 } | |
| 535 } | |
| 536 }); | |
| 537 } | |
| 538 }); | |
| 539 return instantiationMap; | |
| 540 } | 494 } |
| 541 | 495 |
| 542 bool _hasInvocation(Element member) { | 496 bool _hasInvocation(MemberEntity member) { |
| 543 return _hasMatchingSelector(_invokedNames[member.name], member); | 497 return _hasMatchingSelector(_invokedNames[member.name], member); |
| 544 } | 498 } |
| 545 | 499 |
| 546 bool _hasInvokedGetter(Element member) { | 500 bool _hasInvokedGetter(MemberEntity member) { |
| 547 return _hasMatchingSelector(_invokedGetters[member.name], member) || | 501 return _hasMatchingSelector(_invokedGetters[member.name], member) || |
| 548 member.isFunction && methodsNeedingSuperGetter.contains(member); | 502 member.isFunction && methodsNeedingSuperGetter.contains(member); |
| 549 } | 503 } |
| 550 | 504 |
| 551 bool hasInvokedSetter(Element member) { | 505 bool hasInvokedSetter(MemberEntity member) { |
| 552 return _hasMatchingSelector(_invokedSetters[member.name], member); | 506 return _hasMatchingSelector(_invokedSetters[member.name], member); |
| 553 } | 507 } |
| 554 | 508 |
| 555 void registerDynamicUse( | 509 void registerDynamicUse( |
| 556 DynamicUse dynamicUse, MemberUsedCallback memberUsed) { | 510 DynamicUse dynamicUse, MemberUsedCallback memberUsed) { |
| 557 Selector selector = dynamicUse.selector; | 511 Selector selector = dynamicUse.selector; |
| 558 String methodName = selector.name; | 512 String methodName = selector.name; |
| 559 | 513 |
| 560 void _process(Map<String, Set<_MemberUsage>> memberMap, | 514 void _process(Map<String, Set<_MemberUsage>> memberMap, |
| 561 EnumSet<MemberUse> action(_MemberUsage usage)) { | 515 EnumSet<MemberUse> action(_MemberUsage usage)) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 ReceiverConstraint mask = dynamicUse.mask; | 549 ReceiverConstraint mask = dynamicUse.mask; |
| 596 Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent( | 550 Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent( |
| 597 name, () => new Maplet<Selector, SelectorConstraints>()); | 551 name, () => new Maplet<Selector, SelectorConstraints>()); |
| 598 UniverseSelectorConstraints constraints = | 552 UniverseSelectorConstraints constraints = |
| 599 selectors.putIfAbsent(selector, () { | 553 selectors.putIfAbsent(selector, () { |
| 600 return selectorConstraintsStrategy.createSelectorConstraints(selector); | 554 return selectorConstraintsStrategy.createSelectorConstraints(selector); |
| 601 }); | 555 }); |
| 602 return constraints.addReceiverConstraint(mask); | 556 return constraints.addReceiverConstraint(mask); |
| 603 } | 557 } |
| 604 | 558 |
| 605 void registerIsCheck(ResolutionDartType type) { | 559 void registerIsCheck(DartType type) { |
| 606 type.computeUnaliased(_resolution); | |
| 607 type = type.unaliased; | |
| 608 // Even in checked mode, type annotations for return type and argument | |
| 609 // types do not imply type checks, so there should never be a check | |
| 610 // against the type variable of a typedef. | |
| 611 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | |
| 612 isChecks.add(type); | 560 isChecks.add(type); |
| 613 } | 561 } |
| 614 | 562 |
| 615 bool registerConstantUse(ConstantUse use) { | 563 bool registerConstantUse(ConstantUse use) { |
| 616 return _constantValues.add(use.value); | 564 return _constantValues.add(use.value); |
| 617 } | 565 } |
| 618 | 566 |
| 619 void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) { | 567 void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) { |
| 620 Element element = staticUse.element; | 568 MemberEntity element = staticUse.element; |
| 621 assert(invariant(element, element.isDeclaration, | |
| 622 message: "Element ${element} is not the declaration.")); | |
| 623 _StaticMemberUsage usage = _staticMemberUsage.putIfAbsent(element, () { | 569 _StaticMemberUsage usage = _staticMemberUsage.putIfAbsent(element, () { |
| 624 if ((element.isStatic || element.isTopLevel) && element.isFunction) { | 570 if ((element.isStatic || element.isTopLevel) && element.isFunction) { |
| 625 return new _StaticFunctionUsage(element); | 571 return new _StaticFunctionUsage(element); |
| 626 } else { | 572 } else { |
| 627 return new _GeneralStaticMemberUsage(element); | 573 return new _GeneralStaticMemberUsage(element); |
| 628 } | 574 } |
| 629 }); | 575 }); |
| 630 EnumSet<MemberUse> useSet = new EnumSet<MemberUse>(); | 576 EnumSet<MemberUse> useSet = new EnumSet<MemberUse>(); |
| 631 | 577 |
| 632 if (Elements.isStaticOrTopLevel(element) && element.isField) { | 578 if ((element.isStatic || element.isTopLevel) && element.isField) { |
| 633 allReferencedStaticFields.add(element); | 579 allReferencedStaticFields.add(staticUse.element); |
| 634 } | 580 } |
| 635 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 581 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
| 636 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. | 582 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. |
| 637 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot | 583 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot |
| 638 // enqueue. | 584 // enqueue. |
| 639 switch (staticUse.kind) { | 585 switch (staticUse.kind) { |
| 640 case StaticUseKind.FIELD_GET: | 586 case StaticUseKind.FIELD_GET: |
| 641 break; | 587 break; |
| 642 case StaticUseKind.FIELD_SET: | 588 case StaticUseKind.FIELD_SET: |
| 643 fieldSetters.add(element); | 589 fieldSetters.add(staticUse.element); |
| 644 break; | 590 break; |
| 645 case StaticUseKind.CLOSURE: | 591 case StaticUseKind.CLOSURE: |
| 646 LocalFunctionElement localFunction = staticUse.element; | 592 throw new UnimplementedError( |
| 647 if (localFunction.type.containsTypeVariables) { | 593 "registerStaticUse not implemented for StaticUseKind.CLOSURE."); |
| 648 localFunctionsWithFreeTypeVariables.add(localFunction); | |
| 649 } | |
| 650 localFunctions.add(element); | |
| 651 break; | |
| 652 case StaticUseKind.SUPER_TEAR_OFF: | 594 case StaticUseKind.SUPER_TEAR_OFF: |
| 653 useSet.addAll(usage.tearOff()); | 595 useSet.addAll(usage.tearOff()); |
| 654 methodsNeedingSuperGetter.add(element); | 596 methodsNeedingSuperGetter.add(staticUse.element); |
| 655 break; | 597 break; |
| 656 case StaticUseKind.SUPER_FIELD_SET: | 598 case StaticUseKind.SUPER_FIELD_SET: |
| 657 fieldSetters.add(element); | 599 fieldSetters.add(staticUse.element); |
| 658 useSet.addAll(usage.normalUse()); | 600 useSet.addAll(usage.normalUse()); |
| 659 break; | 601 break; |
| 660 case StaticUseKind.STATIC_TEAR_OFF: | 602 case StaticUseKind.STATIC_TEAR_OFF: |
| 661 useSet.addAll(usage.tearOff()); | 603 useSet.addAll(usage.tearOff()); |
| 662 break; | 604 break; |
| 663 case StaticUseKind.GENERAL: | 605 case StaticUseKind.GENERAL: |
| 664 case StaticUseKind.DIRECT_USE: | 606 case StaticUseKind.DIRECT_USE: |
| 665 case StaticUseKind.CONSTRUCTOR_INVOKE: | 607 case StaticUseKind.CONSTRUCTOR_INVOKE: |
| 666 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: | 608 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
| 667 case StaticUseKind.REDIRECTION: | 609 case StaticUseKind.REDIRECTION: |
| 668 useSet.addAll(usage.normalUse()); | 610 useSet.addAll(usage.normalUse()); |
| 669 break; | 611 break; |
| 670 case StaticUseKind.DIRECT_INVOKE: | 612 case StaticUseKind.DIRECT_INVOKE: |
| 671 invariant( | 613 invariant( |
| 672 element, 'Direct static use is not supported for resolution.'); | 614 element, 'Direct static use is not supported for resolution.'); |
| 673 break; | 615 break; |
| 674 case StaticUseKind.INLINING: | 616 case StaticUseKind.INLINING: |
| 675 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, | 617 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, |
| 676 "Static use ${staticUse.kind} is not supported during resolution."); | 618 "Static use ${staticUse.kind} is not supported during resolution."); |
| 677 } | 619 } |
| 678 if (useSet.isNotEmpty) { | 620 if (useSet.isNotEmpty) { |
| 679 memberUsed(usage.entity, useSet); | 621 memberUsed(usage.entity, useSet); |
| 680 } | 622 } |
| 681 } | 623 } |
| 682 | 624 |
| 625 /// Called to create a [_ClassUsage] for [cls]. |
| 626 /// |
| 627 /// Subclasses override this to ensure needed invariants on [cls]. |
| 628 _ClassUsage _createClassUsage(ClassEntity cls) => new _ClassUsage(cls); |
| 629 |
| 683 /// Return the canonical [_ClassUsage] for [cls]. | 630 /// Return the canonical [_ClassUsage] for [cls]. |
| 684 _ClassUsage _getClassUsage(ClassElement cls) { | 631 _ClassUsage _getClassUsage(ClassEntity cls) { |
| 685 return _processedClasses.putIfAbsent(cls, () { | 632 return _processedClasses.putIfAbsent(cls, () { |
| 686 cls.ensureResolved(_resolution); | 633 return _createClassUsage(cls); |
| 687 _ClassUsage usage = new _ClassUsage(cls); | |
| 688 _resolution.ensureClassMembers(cls); | |
| 689 return usage; | |
| 690 }); | 634 }); |
| 691 } | 635 } |
| 692 | 636 |
| 693 /// Register [cls] and all its superclasses as instantiated. | 637 /// Register [cls] and all its superclasses as instantiated. |
| 694 void _processInstantiatedClass( | 638 void _processInstantiatedClass(ClassEntity cls, ClassUsedCallback classUsed) { |
| 695 ClassElement cls, ClassUsedCallback classUsed) { | |
| 696 // Registers [superclass] as instantiated. Returns `true` if it wasn't | 639 // Registers [superclass] as instantiated. Returns `true` if it wasn't |
| 697 // already instantiated and we therefore have to process its superclass as | 640 // already instantiated and we therefore have to process its superclass as |
| 698 // well. | 641 // well. |
| 699 bool processClass(ClassElement superclass) { | 642 bool processClass(ClassEntity superclass) { |
| 700 _ClassUsage usage = _getClassUsage(superclass); | 643 _ClassUsage usage = _getClassUsage(superclass); |
| 701 if (!usage.isInstantiated) { | 644 if (!usage.isInstantiated) { |
| 702 classUsed(usage.cls, usage.instantiate()); | 645 classUsed(usage.cls, usage.instantiate()); |
| 703 return true; | 646 return true; |
| 704 } | 647 } |
| 705 return false; | 648 return false; |
| 706 } | 649 } |
| 707 | 650 |
| 708 while (cls != null && processClass(cls)) { | 651 while (cls != null && processClass(cls)) { |
| 709 cls = cls.superclass; | 652 cls = _elementEnvironment.getSuperClass(cls); |
| 710 } | 653 } |
| 711 } | 654 } |
| 712 | 655 |
| 713 /// Computes usage for all members declared by [cls]. Calls [membersUsed] with | 656 /// Computes usage for all members declared by [cls]. Calls [membersUsed] with |
| 714 /// the usage changes for each member. | 657 /// the usage changes for each member. |
| 715 void processClassMembers(ClassElement cls, MemberUsedCallback memberUsed) { | 658 void processClassMembers(ClassEntity cls, MemberUsedCallback memberUsed) { |
| 716 cls.implementation.forEachMember((ClassElement cls, MemberElement member) { | 659 _elementEnvironment.forEachClassMember(cls, |
| 660 (ClassEntity cls, MemberEntity member) { |
| 717 _processInstantiatedClassMember(cls, member, memberUsed); | 661 _processInstantiatedClassMember(cls, member, memberUsed); |
| 718 }); | 662 }); |
| 719 } | 663 } |
| 720 | 664 |
| 721 /// Call [updateUsage] on all [_MemberUsage]s in the set in [map] for | 665 /// Call [updateUsage] on all [_MemberUsage]s in the set in [map] for |
| 722 /// [memberName]. If [updateUsage] returns `true` the usage is removed from | 666 /// [memberName]. If [updateUsage] returns `true` the usage is removed from |
| 723 /// the set. | 667 /// the set. |
| 724 void _processSet(Map<String, Set<_MemberUsage>> map, String memberName, | 668 void _processSet(Map<String, Set<_MemberUsage>> map, String memberName, |
| 725 bool updateUsage(_MemberUsage e)) { | 669 bool updateUsage(_MemberUsage e)) { |
| 726 Set<_MemberUsage> members = map[memberName]; | 670 Set<_MemberUsage> members = map[memberName]; |
| 727 if (members == null) return; | 671 if (members == null) return; |
| 728 // [f] might add elements to [: map[memberName] :] during the loop below | 672 // [f] might add elements to [: map[memberName] :] during the loop below |
| 729 // so we create a new list for [: map[memberName] :] and prepend the | 673 // so we create a new list for [: map[memberName] :] and prepend the |
| 730 // [remaining] members after the loop. | 674 // [remaining] members after the loop. |
| 731 map[memberName] = new Set<_MemberUsage>(); | 675 map[memberName] = new Set<_MemberUsage>(); |
| 732 Set<_MemberUsage> remaining = new Set<_MemberUsage>(); | 676 Set<_MemberUsage> remaining = new Set<_MemberUsage>(); |
| 733 for (_MemberUsage usage in members) { | 677 for (_MemberUsage usage in members) { |
| 734 if (!updateUsage(usage)) remaining.add(usage); | 678 if (!updateUsage(usage)) remaining.add(usage); |
| 735 } | 679 } |
| 736 map[memberName].addAll(remaining); | 680 map[memberName].addAll(remaining); |
| 737 } | 681 } |
| 738 | 682 |
| 739 void _processInstantiatedClassMember( | 683 void _processInstantiatedClassMember( |
| 740 ClassElement cls, MemberElement member, MemberUsedCallback memberUsed) { | 684 ClassEntity cls, MemberEntity member, MemberUsedCallback memberUsed) { |
| 741 assert(invariant(member, member.isDeclaration)); | |
| 742 if (!member.isInstanceMember) return; | 685 if (!member.isInstanceMember) return; |
| 743 String memberName = member.name; | 686 String memberName = member.name; |
| 744 member.computeType(_resolution); | |
| 745 // The obvious thing to test here would be "member.isNative", | 687 // The obvious thing to test here would be "member.isNative", |
| 746 // however, that only works after metadata has been parsed/analyzed, | 688 // however, that only works after metadata has been parsed/analyzed, |
| 747 // and that may not have happened yet. | 689 // and that may not have happened yet. |
| 748 // So instead we use the enclosing class, which we know have had | 690 // So instead we use the enclosing class, which we know have had |
| 749 // its metadata parsed and analyzed. | 691 // its metadata parsed and analyzed. |
| 750 // Note: this assumes that there are no non-native fields on native | 692 // Note: this assumes that there are no non-native fields on native |
| 751 // classes, which may not be the case when a native class is subclassed. | 693 // classes, which may not be the case when a native class is subclassed. |
| 752 _instanceMemberUsage.putIfAbsent(member, () { | 694 _instanceMemberUsage.putIfAbsent(member, () { |
| 753 bool isNative = _backend.nativeBasicData.isNativeClass(cls); | 695 bool isNative = _nativeBasicData.isNativeClass(cls); |
| 754 _MemberUsage usage = new _MemberUsage(member, isNative: isNative); | 696 _MemberUsage usage = new _MemberUsage(member, isNative: isNative); |
| 755 EnumSet<MemberUse> useSet = new EnumSet<MemberUse>(); | 697 EnumSet<MemberUse> useSet = new EnumSet<MemberUse>(); |
| 756 useSet.addAll(usage.appliedUse); | 698 useSet.addAll(usage.appliedUse); |
| 757 if (member.isField && isNative) { | 699 if (member.isField && isNative) { |
| 758 registerUsedElement(member); | 700 registerUsedElement(member); |
| 759 } | 701 } |
| 760 if (member.isFunction && | 702 if (member.isFunction && |
| 761 member.name == Identifiers.call && | 703 member.name == Identifiers.call && |
| 762 !cls.typeVariables.isEmpty) { | 704 _elementEnvironment.getThisType(cls).typeArguments.isNotEmpty) { |
| 763 closurizedMembersWithFreeTypeVariables.add(member); | 705 closurizedMembersWithFreeTypeVariables.add(member); |
| 764 } | 706 } |
| 765 | 707 |
| 766 if (_hasInvokedGetter(member)) { | 708 if (_hasInvokedGetter(member)) { |
| 767 useSet.addAll(usage.read()); | 709 useSet.addAll(usage.read()); |
| 768 } | 710 } |
| 769 if (_hasInvocation(member)) { | 711 if (_hasInvocation(member)) { |
| 770 useSet.addAll(usage.invoke()); | 712 useSet.addAll(usage.invoke()); |
| 771 } | 713 } |
| 772 if (hasInvokedSetter(member)) { | 714 if (hasInvokedSetter(member)) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 787 .putIfAbsent(memberName, () => new Set<_MemberUsage>()) | 729 .putIfAbsent(memberName, () => new Set<_MemberUsage>()) |
| 788 .add(usage); | 730 .add(usage); |
| 789 } | 731 } |
| 790 | 732 |
| 791 memberUsed(usage.entity, useSet); | 733 memberUsed(usage.entity, useSet); |
| 792 return usage; | 734 return usage; |
| 793 }); | 735 }); |
| 794 } | 736 } |
| 795 | 737 |
| 796 /// Returns an iterable over all mixin applications that mixin [cls]. | 738 /// Returns an iterable over all mixin applications that mixin [cls]. |
| 797 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls) { | 739 Iterable<ClassEntity> allMixinUsesOf(ClassEntity cls) { |
| 798 Iterable<MixinApplicationElement> uses = _mixinUses[cls]; | 740 Iterable<ClassEntity> uses = _mixinUses[cls]; |
| 799 return uses != null ? uses : const <MixinApplicationElement>[]; | 741 return uses != null ? uses : const <ClassEntity>[]; |
| 800 } | |
| 801 | |
| 802 /// Called to add [cls] to the set of known classes. | |
| 803 /// | |
| 804 /// This ensures that class hierarchy queries can be performed on [cls] and | |
| 805 /// classes that extend or implement it. | |
| 806 void registerClass(ClassElement cls) => _registerClass(cls); | |
| 807 | |
| 808 void _registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) { | |
| 809 _ensureClassSet(cls); | |
| 810 if (isDirectlyInstantiated) { | |
| 811 _updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); | |
| 812 } | |
| 813 } | 742 } |
| 814 | 743 |
| 815 void registerTypedef(TypedefElement typdef) { | 744 void registerTypedef(TypedefElement typdef) { |
| 816 _allTypedefs.add(typdef); | 745 _allTypedefs.add(typdef); |
| 817 } | 746 } |
| 818 | 747 |
| 819 ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) { | 748 void registerMixinUse(ClassEntity mixinApplication, ClassEntity mixin) { |
| 820 cls = cls.declaration; | |
| 821 return _classHierarchyNodes.putIfAbsent(cls, () { | |
| 822 ClassHierarchyNode parentNode; | |
| 823 if (cls.superclass != null) { | |
| 824 parentNode = _ensureClassHierarchyNode(cls.superclass); | |
| 825 } | |
| 826 return new ClassHierarchyNode(parentNode, cls); | |
| 827 }); | |
| 828 } | |
| 829 | |
| 830 ClassSet _ensureClassSet(ClassElement cls) { | |
| 831 cls = cls.declaration; | |
| 832 return _classSets.putIfAbsent(cls, () { | |
| 833 ClassHierarchyNode node = _ensureClassHierarchyNode(cls); | |
| 834 ClassSet classSet = new ClassSet(node); | |
| 835 | |
| 836 for (ResolutionInterfaceType type in cls.allSupertypes) { | |
| 837 // TODO(johnniwinther): Optimization: Avoid adding [cls] to | |
| 838 // superclasses. | |
| 839 ClassSet subtypeSet = _ensureClassSet(type.element); | |
| 840 subtypeSet.addSubtype(node); | |
| 841 } | |
| 842 if (cls.isMixinApplication) { | |
| 843 // TODO(johnniwinther): Store this in the [ClassSet]. | |
| 844 MixinApplicationElement mixinApplication = cls; | |
| 845 if (mixinApplication.mixin != null) { | |
| 846 // If [mixinApplication] is malformed [mixin] is `null`. | |
| 847 registerMixinUse(mixinApplication, mixinApplication.mixin); | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 return classSet; | |
| 852 }); | |
| 853 } | |
| 854 | |
| 855 void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) { | |
| 856 // Ensure that classes implicitly implementing `Function` are in its | |
| 857 // subtype set. | |
| 858 ClassElement cls = node.cls; | |
| 859 if (cls != commonElements.functionClass && | |
| 860 cls.implementsFunction(commonElements)) { | |
| 861 ClassSet subtypeSet = _ensureClassSet(commonElements.functionClass); | |
| 862 subtypeSet.addSubtype(node); | |
| 863 } | |
| 864 if (!node.isInstantiated && node.parentNode != null) { | |
| 865 _updateSuperClassHierarchyNodeForClass(node.parentNode); | |
| 866 } | |
| 867 } | |
| 868 | |
| 869 void _updateClassHierarchyNodeForClass(ClassElement cls, | |
| 870 {bool directlyInstantiated: false, bool abstractlyInstantiated: false}) { | |
| 871 ClassHierarchyNode node = _ensureClassHierarchyNode(cls); | |
| 872 _updateSuperClassHierarchyNodeForClass(node); | |
| 873 if (directlyInstantiated) { | |
| 874 node.isDirectlyInstantiated = true; | |
| 875 } | |
| 876 if (abstractlyInstantiated) { | |
| 877 node.isAbstractlyInstantiated = true; | |
| 878 } | |
| 879 } | |
| 880 | |
| 881 ClosedWorld closeWorld(DiagnosticReporter reporter) { | |
| 882 Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses = | |
| 883 new Map<ClassElement, Set<ClassElement>>(); | |
| 884 | |
| 885 /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated` | |
| 886 /// properties of the [ClassHierarchyNode] for [cls]. | |
| 887 | |
| 888 void addSubtypes(ClassElement cls, InstantiationInfo info) { | |
| 889 if (!info.hasInstantiation) { | |
| 890 return; | |
| 891 } | |
| 892 assert(cls.isDeclaration); | |
| 893 if (!cls.isResolved) { | |
| 894 reporter.internalError(cls, 'Class "${cls.name}" is not resolved.'); | |
| 895 } | |
| 896 | |
| 897 _updateClassHierarchyNodeForClass(cls, | |
| 898 directlyInstantiated: info.isDirectlyInstantiated, | |
| 899 abstractlyInstantiated: info.isAbstractlyInstantiated); | |
| 900 | |
| 901 // Walk through the superclasses, and record the types | |
| 902 // implemented by that type on the superclasses. | |
| 903 ClassElement superclass = cls.superclass; | |
| 904 while (superclass != null) { | |
| 905 Set<Element> typesImplementedBySubclassesOfCls = | |
| 906 typesImplementedBySubclasses.putIfAbsent( | |
| 907 superclass, () => new Set<ClassElement>()); | |
| 908 for (ResolutionDartType current in cls.allSupertypes) { | |
| 909 typesImplementedBySubclassesOfCls.add(current.element); | |
| 910 } | |
| 911 superclass = superclass.superclass; | |
| 912 } | |
| 913 } | |
| 914 | |
| 915 // Use the [:seenClasses:] set to include non-instantiated | |
| 916 // classes: if the superclass of these classes require RTI, then | |
| 917 // they also need RTI, so that a constructor passes the type | |
| 918 // variables to the super constructor. | |
| 919 forEachInstantiatedClass(addSubtypes); | |
| 920 | |
| 921 _closed = true; | |
| 922 return _closedWorldCache = new ClosedWorldImpl( | |
| 923 backend: _backend, | |
| 924 commonElements: commonElements, | |
| 925 resolutionWorldBuilder: this, | |
| 926 functionSetBuilder: _allFunctions, | |
| 927 allTypedefs: _allTypedefs, | |
| 928 mixinUses: _mixinUses, | |
| 929 typesImplementedBySubclasses: typesImplementedBySubclasses, | |
| 930 classHierarchyNodes: _classHierarchyNodes, | |
| 931 classSets: _classSets); | |
| 932 } | |
| 933 | |
| 934 void registerMixinUse( | |
| 935 MixinApplicationElement mixinApplication, ClassElement mixin) { | |
| 936 // TODO(johnniwinther): Add map restricted to live classes. | 749 // TODO(johnniwinther): Add map restricted to live classes. |
| 937 // We don't support patch classes as mixin. | 750 // We don't support patch classes as mixin. |
| 938 assert(mixin.isDeclaration); | 751 Set<ClassEntity> users = |
| 939 Set<MixinApplicationElement> users = | 752 _mixinUses.putIfAbsent(mixin, () => new Set<ClassEntity>()); |
| 940 _mixinUses.putIfAbsent(mixin, () => new Set<MixinApplicationElement>()); | |
| 941 users.add(mixinApplication); | 753 users.add(mixinApplication); |
| 942 } | 754 } |
| 943 | 755 |
| 944 void registerUsedElement(MemberElement element) { | |
| 945 if (element.isInstanceMember && !element.isAbstract) { | |
| 946 _allFunctions.add(element); | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 ClosedWorld get closedWorldCache { | 756 ClosedWorld get closedWorldCache { |
| 951 assert(isClosed); | 757 assert(isClosed); |
| 952 return _closedWorldCache; | 758 return _closedWorldCache; |
| 953 } | 759 } |
| 954 | 760 |
| 955 @override | 761 @override |
| 956 bool isMemberUsed(MemberEntity member) { | 762 bool isMemberUsed(MemberEntity member) { |
| 957 if (member.isInstanceMember) { | 763 if (member.isInstanceMember) { |
| 958 _MemberUsage usage = _instanceMemberUsage[member]; | 764 _MemberUsage usage = _instanceMemberUsage[member]; |
| 959 if (usage != null && usage.hasUse) return true; | 765 if (usage != null && usage.hasUse) return true; |
| 960 } | 766 } |
| 961 _StaticMemberUsage usage = _staticMemberUsage[member]; | 767 _StaticMemberUsage usage = _staticMemberUsage[member]; |
| 962 return usage != null && usage.hasUse; | 768 return usage != null && usage.hasUse; |
| 963 } | 769 } |
| 964 } | 770 } |
| OLD | NEW |