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 |