OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 library universe; | |
6 | |
7 import 'dart:collection'; | |
8 | |
9 import '../common.dart'; | |
10 import '../compiler.dart' show Compiler; | |
11 import '../dart_types.dart'; | |
12 import '../elements/elements.dart'; | |
13 import '../util/util.dart'; | |
14 import '../world.dart' show World, ClosedWorld, OpenWorld; | |
15 import 'selector.dart' show Selector; | |
16 import 'use.dart' show DynamicUse, DynamicUseKind, StaticUse, StaticUseKind; | |
17 | |
18 /// The known constraint on receiver for a dynamic call site. | |
19 /// | |
20 /// This can for instance be used to constrain this dynamic call to `foo` to | |
21 /// 'receivers of the exact instance `Bar`': | |
22 /// | |
23 /// class Bar { | |
24 /// void foo() {} | |
25 /// } | |
26 /// main() => new Bar().foo(); | |
27 /// | |
28 abstract class ReceiverConstraint { | |
29 /// Returns whether [element] is a potential target when being | |
30 /// invoked on a receiver with this constraint. [selector] is used to ensure | |
31 /// library privacy is taken into account. | |
32 bool canHit(Element element, Selector selector, World world); | |
33 | |
34 /// Returns whether this [TypeMask] applied to [selector] can hit a | |
35 /// [noSuchMethod]. | |
36 bool needsNoSuchMethodHandling(Selector selector, World world); | |
37 } | |
38 | |
39 /// The combined constraints on receivers all the dynamic call sites of the same | |
40 /// selector. | |
41 /// | |
42 /// For instance for these calls | |
43 /// | |
44 /// class A { | |
45 /// foo(a, b) {} | |
46 /// } | |
47 /// class B { | |
48 /// foo(a, b) {} | |
49 /// } | |
50 /// class C { | |
51 /// foo(a, b) {} | |
52 /// } | |
53 /// new A().foo(a, b); | |
54 /// new B().foo(0, 42); | |
55 /// | |
56 /// the selector constraints for dynamic calls to 'foo' with two positional | |
57 /// arguments could be 'receiver of exact instance `A` or `B`'. | |
58 abstract class SelectorConstraints { | |
59 /// Returns `true` if [selector] applies to [element] under these constraints | |
60 /// given the closed [world]. | |
61 /// | |
62 /// Consider for instance in this world: | |
63 /// | |
64 /// class A { | |
65 /// foo(a, b) {} | |
66 /// } | |
67 /// class B { | |
68 /// foo(a, b) {} | |
69 /// } | |
70 /// new A().foo(a, b); | |
71 /// | |
72 /// Ideally the selector constraints for calls `foo` with two positional | |
73 /// arguments apply to `A.foo` but `B.foo`. | |
74 bool applies(Element element, Selector selector, World world); | |
75 | |
76 /// Returns `true` if at least one of the receivers matching these constraints | |
77 /// in the closed [world] have no implementation matching [selector]. | |
78 /// | |
79 /// For instance for this code snippet | |
80 /// | |
81 /// class A {} | |
82 /// class B { foo() {} } | |
83 /// m(b) => (b ? new A() : new B()).foo(); | |
84 /// | |
85 /// the potential receiver `new A()` has no implementation of `foo` and thus | |
86 /// needs to handle the call through its `noSuchMethod` handler. | |
87 bool needsNoSuchMethodHandling(Selector selector, World world); | |
88 } | |
89 | |
90 /// A mutable [SelectorConstraints] used in [Universe]. | |
91 abstract class UniverseSelectorConstraints extends SelectorConstraints { | |
92 /// Adds [constraint] to these selector constraints. Return `true` if the set | |
93 /// of potential receivers expanded due to the new constraint. | |
94 bool addReceiverConstraint(ReceiverConstraint constraint); | |
95 } | |
96 | |
97 /// Strategy for computing the constraints on potential receivers of dynamic | |
98 /// call sites. | |
99 abstract class SelectorConstraintsStrategy { | |
100 /// Create a [UniverseSelectorConstraints] to represent the global receiver | |
101 /// constraints for dynamic call sites with [selector]. | |
102 UniverseSelectorConstraints createSelectorConstraints(Selector selector); | |
103 } | |
104 | |
105 /// The [Universe] is an auxiliary class used in the process of computing the | |
106 /// [ClosedWorld]. The concepts here and in [ClosedWorld] are very similar -- in | |
107 /// the same way that the "universe expands" you can think of this as a mutable | |
108 /// world that is expanding as we visit and discover parts of the program. | |
109 // TODO(sigmund): rename to "growing/expanding/mutable world"? | |
110 // TODO(johnniwinther): Move common implementation to a [UniverseBase] when | |
111 // universes and worlds have been unified. | |
112 abstract class Universe { | |
113 /// All directly instantiated classes, that is, classes with a generative | |
114 /// constructor that has been called directly and not only through a | |
115 /// super-call. | |
116 // TODO(johnniwinther): Improve semantic precision. | |
117 Iterable<ClassElement> get directlyInstantiatedClasses; | |
118 | |
119 /// All types that are checked either through is, as or checked mode checks. | |
120 Iterable<DartType> get isChecks; | |
121 | |
122 /// Registers that [type] is checked in this universe. The unaliased type is | |
123 /// returned. | |
124 DartType registerIsCheck(DartType type, Compiler compiler); | |
125 | |
126 /// All directly instantiated types, that is, the types of the directly | |
127 /// instantiated classes. | |
128 // TODO(johnniwinther): Improve semantic precision. | |
129 Iterable<DartType> get instantiatedTypes; | |
130 | |
131 /// Returns `true` if [member] is invoked as a setter. | |
132 bool hasInvokedSetter(Element member, World world); | |
133 } | |
134 | |
135 abstract class ResolutionUniverse implements Universe { | |
136 /// Set of (live) local functions (closures) whose signatures reference type | |
137 /// variables. | |
138 /// | |
139 /// A live function is one whose enclosing member function has been enqueued. | |
140 Set<Element> get closuresWithFreeTypeVariables; | |
141 | |
142 /// Set of (live) `call` methods whose signatures reference type variables. | |
143 /// | |
144 /// A live `call` method is one whose enclosing class has been instantiated. | |
145 Iterable<Element> get callMethodsWithFreeTypeVariables; | |
146 | |
147 /// Set of all closures in the program. Used by the mirror tracking system | |
148 /// to find all live closure instances. | |
149 Iterable<LocalFunctionElement> get allClosures; | |
150 | |
151 /// Set of methods in instantiated classes that are potentially closurized. | |
152 Iterable<Element> get closurizedMembers; | |
153 | |
154 /// Returns `true` if [cls] is considered to be implemented by an | |
155 /// instantiated class, either directly, through subclasses or through | |
156 /// subtypes. The latter case only contains spurious information from | |
157 /// instantiations through factory constructors and mixins. | |
158 bool isImplemented(ClassElement cls); | |
159 | |
160 /// Set of all fields that are statically known to be written to. | |
161 Iterable<Element> get fieldSetters; | |
162 } | |
163 | |
164 class ResolutionUniverseImpl implements ResolutionUniverse { | |
165 /// The set of all directly instantiated classes, that is, classes with a | |
166 /// generative constructor that has been called directly and not only through | |
167 /// a super-call. | |
168 /// | |
169 /// Invariant: Elements are declaration elements. | |
170 // TODO(johnniwinther): [_directlyInstantiatedClasses] and | |
171 // [_instantiatedTypes] sets should be merged. | |
172 final Set<ClassElement> _directlyInstantiatedClasses = | |
173 new Set<ClassElement>(); | |
174 | |
175 /// The set of all directly instantiated types, that is, the types of the | |
176 /// directly instantiated classes. | |
177 /// | |
178 /// See [_directlyInstantiatedClasses]. | |
179 final Set<DartType> _instantiatedTypes = new Set<DartType>(); | |
180 | |
181 /// Classes implemented by directly instantiated classes. | |
182 final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); | |
183 | |
184 /// The set of all referenced static fields. | |
185 /// | |
186 /// Invariant: Elements are declaration elements. | |
187 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); | |
188 | |
189 /** | |
190 * Documentation wanted -- johnniwinther | |
191 * | |
192 * Invariant: Elements are declaration elements. | |
193 */ | |
194 final Set<FunctionElement> methodsNeedingSuperGetter = | |
195 new Set<FunctionElement>(); | |
196 final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = | |
197 <String, Map<Selector, SelectorConstraints>>{}; | |
198 final Map<String, Map<Selector, SelectorConstraints>> _invokedGetters = | |
199 <String, Map<Selector, SelectorConstraints>>{}; | |
200 final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = | |
201 <String, Map<Selector, SelectorConstraints>>{}; | |
202 | |
203 /// Fields set. | |
204 final Set<Element> fieldSetters = new Set<Element>(); | |
205 final Set<DartType> isChecks = new Set<DartType>(); | |
206 | |
207 /** | |
208 * Set of (live) [:call:] methods whose signatures reference type variables. | |
209 * | |
210 * A live [:call:] method is one whose enclosing class has been instantiated. | |
211 */ | |
212 final Set<Element> callMethodsWithFreeTypeVariables = new Set<Element>(); | |
213 | |
214 /** | |
215 * Set of (live) local functions (closures) whose signatures reference type | |
216 * variables. | |
217 * | |
218 * A live function is one whose enclosing member function has been enqueued. | |
219 */ | |
220 final Set<Element> closuresWithFreeTypeVariables = new Set<Element>(); | |
221 | |
222 /** | |
223 * Set of all closures in the program. Used by the mirror tracking system | |
224 * to find all live closure instances. | |
225 */ | |
226 final Set<LocalFunctionElement> allClosures = new Set<LocalFunctionElement>(); | |
227 | |
228 /** | |
229 * Set of methods in instantiated classes that are potentially | |
230 * closurized. | |
231 */ | |
232 final Set<Element> closurizedMembers = new Set<Element>(); | |
233 | |
234 final SelectorConstraintsStrategy selectorConstraintsStrategy; | |
235 | |
236 ResolutionUniverseImpl(this.selectorConstraintsStrategy); | |
237 | |
238 /// All directly instantiated classes, that is, classes with a generative | |
239 /// constructor that has been called directly and not only through a | |
240 /// super-call. | |
241 // TODO(johnniwinther): Improve semantic precision. | |
242 Iterable<ClassElement> get directlyInstantiatedClasses { | |
243 return _directlyInstantiatedClasses; | |
244 } | |
245 | |
246 /// All directly instantiated types, that is, the types of the directly | |
247 /// instantiated classes. | |
248 /// | |
249 /// See [directlyInstantiatedClasses]. | |
250 // TODO(johnniwinther): Improve semantic precision. | |
251 Iterable<DartType> get instantiatedTypes => _instantiatedTypes; | |
252 | |
253 /// Returns `true` if [cls] is considered to be implemented by an | |
254 /// instantiated class, either directly, through subclasses or through | |
255 /// subtypes. The latter case only contains spurious information from | |
256 /// instantiations through factory constructors and mixins. | |
257 // TODO(johnniwinther): Improve semantic precision. | |
258 bool isImplemented(ClassElement cls) { | |
259 return _implementedClasses.contains(cls.declaration); | |
260 } | |
261 | |
262 /// Register [type] as (directly) instantiated. | |
263 /// | |
264 /// If [byMirrors] is `true`, the instantiation is through mirrors. | |
265 // TODO(johnniwinther): Fully enforce the separation between exact, through | |
266 // subclass and through subtype instantiated types/classes. | |
267 // TODO(johnniwinther): Support unknown type arguments for generic types. | |
268 void registerTypeInstantiation(InterfaceType type, | |
269 {bool byMirrors: false, | |
270 bool isNative: false, | |
271 void onImplemented(ClassElement cls)}) { | |
272 _instantiatedTypes.add(type); | |
273 ClassElement cls = type.element; | |
274 if (!cls.isAbstract | |
275 // We can't use the closed-world assumption with native abstract | |
276 // classes; a native abstract class may have non-abstract subclasses | |
277 // not declared to the program. Instances of these classes are | |
278 // indistinguishable from the abstract class. | |
279 || | |
280 isNative | |
281 // Likewise, if this registration comes from the mirror system, | |
282 // all bets are off. | |
283 // TODO(herhut): Track classes required by mirrors seperately. | |
284 || | |
285 byMirrors) { | |
286 _directlyInstantiatedClasses.add(cls); | |
287 } | |
288 | |
289 // TODO(johnniwinther): Replace this by separate more specific mappings that | |
290 // include the type arguments. | |
291 if (_implementedClasses.add(cls)) { | |
292 onImplemented(cls); | |
293 cls.allSupertypes.forEach((InterfaceType supertype) { | |
294 if (_implementedClasses.add(supertype.element)) { | |
295 onImplemented(supertype.element); | |
296 } | |
297 }); | |
298 } | |
299 } | |
300 | |
301 bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, | |
302 Element member, OpenWorld world) { | |
303 if (selectors == null) return false; | |
304 for (Selector selector in selectors.keys) { | |
305 if (selector.appliesUnnamed(member)) { | |
306 SelectorConstraints masks = selectors[selector]; | |
307 if (masks.applies(member, selector, world)) { | |
308 return true; | |
309 } | |
310 } | |
311 } | |
312 return false; | |
313 } | |
314 | |
315 bool hasInvocation(Element member, OpenWorld world) { | |
316 return _hasMatchingSelector(_invokedNames[member.name], member, world); | |
317 } | |
318 | |
319 bool hasInvokedGetter(Element member, OpenWorld world) { | |
320 return _hasMatchingSelector(_invokedGetters[member.name], member, world) || | |
321 member.isFunction && methodsNeedingSuperGetter.contains(member); | |
322 } | |
323 | |
324 bool hasInvokedSetter(Element member, OpenWorld world) { | |
325 return _hasMatchingSelector(_invokedSetters[member.name], member, world); | |
326 } | |
327 | |
328 bool registerDynamicUse(DynamicUse dynamicUse) { | |
329 switch (dynamicUse.kind) { | |
330 case DynamicUseKind.INVOKE: | |
331 return _registerNewSelector(dynamicUse, _invokedNames); | |
332 case DynamicUseKind.GET: | |
333 return _registerNewSelector(dynamicUse, _invokedGetters); | |
334 case DynamicUseKind.SET: | |
335 return _registerNewSelector(dynamicUse, _invokedSetters); | |
336 } | |
337 } | |
338 | |
339 bool _registerNewSelector(DynamicUse dynamicUse, | |
340 Map<String, Map<Selector, SelectorConstraints>> selectorMap) { | |
341 Selector selector = dynamicUse.selector; | |
342 String name = selector.name; | |
343 ReceiverConstraint mask = dynamicUse.mask; | |
344 Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent( | |
345 name, () => new Maplet<Selector, SelectorConstraints>()); | |
346 UniverseSelectorConstraints constraints = | |
347 selectors.putIfAbsent(selector, () { | |
348 return selectorConstraintsStrategy.createSelectorConstraints(selector); | |
349 }); | |
350 return constraints.addReceiverConstraint(mask); | |
351 } | |
352 | |
353 DartType registerIsCheck(DartType type, Compiler compiler) { | |
354 type.computeUnaliased(compiler.resolution); | |
355 type = type.unaliased; | |
356 // Even in checked mode, type annotations for return type and argument | |
357 // types do not imply type checks, so there should never be a check | |
358 // against the type variable of a typedef. | |
359 isChecks.add(type); | |
360 return type; | |
361 } | |
362 | |
363 void registerStaticUse(StaticUse staticUse) { | |
364 Element element = staticUse.element; | |
365 if (Elements.isStaticOrTopLevel(element) && element.isField) { | |
366 allReferencedStaticFields.add(element); | |
367 } | |
368 switch (staticUse.kind) { | |
369 case StaticUseKind.SUPER_FIELD_SET: | |
370 case StaticUseKind.FIELD_SET: | |
371 fieldSetters.add(element); | |
372 break; | |
373 case StaticUseKind.SUPER_TEAR_OFF: | |
374 methodsNeedingSuperGetter.add(element); | |
375 break; | |
376 case StaticUseKind.GENERAL: | |
377 case StaticUseKind.STATIC_TEAR_OFF: | |
378 case StaticUseKind.FIELD_GET: | |
379 break; | |
380 case StaticUseKind.CLOSURE: | |
381 allClosures.add(element); | |
382 break; | |
383 } | |
384 } | |
385 | |
386 void forgetElement(Element element, Compiler compiler) { | |
387 allClosures.remove(element); | |
388 slowDirectlyNestedClosures(element).forEach(compiler.forgetElement); | |
389 closurizedMembers.remove(element); | |
390 fieldSetters.remove(element); | |
391 _directlyInstantiatedClasses.remove(element); | |
392 if (element is ClassElement) { | |
393 assert(invariant(element, element.thisType.isRaw, | |
394 message: 'Generic classes not supported (${element.thisType}).')); | |
395 _instantiatedTypes..remove(element.rawType)..remove(element.thisType); | |
396 } | |
397 } | |
398 | |
399 // TODO(ahe): Replace this method with something that is O(1), for example, | |
400 // by using a map. | |
401 List<LocalFunctionElement> slowDirectlyNestedClosures(Element element) { | |
402 // Return new list to guard against concurrent modifications. | |
403 return new List<LocalFunctionElement>.from( | |
404 allClosures.where((LocalFunctionElement closure) { | |
405 return closure.executableContext == element; | |
406 })); | |
407 } | |
408 } | |
409 | |
410 /// Universe specific to codegen. | |
411 /// | |
412 /// This adds additional access to liveness of selectors and elements. | |
413 abstract class CodegenUniverse implements Universe { | |
414 void forEachInvokedName( | |
415 f(String name, Map<Selector, SelectorConstraints> selectors)); | |
416 | |
417 void forEachInvokedGetter( | |
418 f(String name, Map<Selector, SelectorConstraints> selectors)); | |
419 | |
420 void forEachInvokedSetter( | |
421 f(String name, Map<Selector, SelectorConstraints> selectors)); | |
422 | |
423 bool hasInvokedGetter(Element member, ClosedWorld world); | |
424 | |
425 Map<Selector, SelectorConstraints> invocationsByName(String name); | |
426 | |
427 Map<Selector, SelectorConstraints> getterInvocationsByName(String name); | |
428 | |
429 Map<Selector, SelectorConstraints> setterInvocationsByName(String name); | |
430 | |
431 Iterable<FunctionElement> get staticFunctionsNeedingGetter; | |
432 Iterable<FunctionElement> get methodsNeedingSuperGetter; | |
433 | |
434 /// The set of all referenced static fields. | |
435 /// | |
436 /// Invariant: Elements are declaration elements. | |
437 Iterable<FieldElement> get allReferencedStaticFields; | |
438 } | |
439 | |
440 class CodegenUniverseImpl implements CodegenUniverse { | |
441 /// The set of all directly instantiated classes, that is, classes with a | |
442 /// generative constructor that has been called directly and not only through | |
443 /// a super-call. | |
444 /// | |
445 /// Invariant: Elements are declaration elements. | |
446 // TODO(johnniwinther): [_directlyInstantiatedClasses] and | |
447 // [_instantiatedTypes] sets should be merged. | |
448 final Set<ClassElement> _directlyInstantiatedClasses = | |
449 new Set<ClassElement>(); | |
450 | |
451 /// The set of all directly instantiated types, that is, the types of the | |
452 /// directly instantiated classes. | |
453 /// | |
454 /// See [_directlyInstantiatedClasses]. | |
455 final Set<DartType> _instantiatedTypes = new Set<DartType>(); | |
456 | |
457 /// Classes implemented by directly instantiated classes. | |
458 final Set<ClassElement> _implementedClasses = new Set<ClassElement>(); | |
459 | |
460 /// The set of all referenced static fields. | |
461 /// | |
462 /// Invariant: Elements are declaration elements. | |
463 final Set<FieldElement> allReferencedStaticFields = new Set<FieldElement>(); | |
464 | |
465 /** | |
466 * Documentation wanted -- johnniwinther | |
467 * | |
468 * Invariant: Elements are declaration elements. | |
469 */ | |
470 final Set<FunctionElement> staticFunctionsNeedingGetter = | |
471 new Set<FunctionElement>(); | |
472 final Set<FunctionElement> methodsNeedingSuperGetter = | |
473 new Set<FunctionElement>(); | |
474 final Map<String, Map<Selector, SelectorConstraints>> _invokedNames = | |
475 <String, Map<Selector, SelectorConstraints>>{}; | |
476 final Map<String, Map<Selector, SelectorConstraints>> _invokedGetters = | |
477 <String, Map<Selector, SelectorConstraints>>{}; | |
478 final Map<String, Map<Selector, SelectorConstraints>> _invokedSetters = | |
479 <String, Map<Selector, SelectorConstraints>>{}; | |
480 | |
481 final Set<DartType> isChecks = new Set<DartType>(); | |
482 | |
483 final SelectorConstraintsStrategy selectorConstraintsStrategy; | |
484 | |
485 CodegenUniverseImpl(this.selectorConstraintsStrategy); | |
486 | |
487 /// All directly instantiated classes, that is, classes with a generative | |
488 /// constructor that has been called directly and not only through a | |
489 /// super-call. | |
490 // TODO(johnniwinther): Improve semantic precision. | |
491 Iterable<ClassElement> get directlyInstantiatedClasses { | |
492 return _directlyInstantiatedClasses; | |
493 } | |
494 | |
495 /// All directly instantiated types, that is, the types of the directly | |
496 /// instantiated classes. | |
497 /// | |
498 /// See [directlyInstantiatedClasses]. | |
499 // TODO(johnniwinther): Improve semantic precision. | |
500 Iterable<DartType> get instantiatedTypes => _instantiatedTypes; | |
501 | |
502 /// Register [type] as (directly) instantiated. | |
503 /// | |
504 /// If [byMirrors] is `true`, the instantiation is through mirrors. | |
505 // TODO(johnniwinther): Fully enforce the separation between exact, through | |
506 // subclass and through subtype instantiated types/classes. | |
507 // TODO(johnniwinther): Support unknown type arguments for generic types. | |
508 void registerTypeInstantiation(InterfaceType type, | |
509 {bool byMirrors: false, | |
510 bool isNative: false, | |
511 void onImplemented(ClassElement cls)}) { | |
512 _instantiatedTypes.add(type); | |
513 ClassElement cls = type.element; | |
514 if (!cls.isAbstract | |
515 // We can't use the closed-world assumption with native abstract | |
516 // classes; a native abstract class may have non-abstract subclasses | |
517 // not declared to the program. Instances of these classes are | |
518 // indistinguishable from the abstract class. | |
519 || | |
520 isNative | |
521 // Likewise, if this registration comes from the mirror system, | |
522 // all bets are off. | |
523 // TODO(herhut): Track classes required by mirrors seperately. | |
524 || | |
525 byMirrors) { | |
526 _directlyInstantiatedClasses.add(cls); | |
527 } | |
528 | |
529 // TODO(johnniwinther): Replace this by separate more specific mappings that | |
530 // include the type arguments. | |
531 if (_implementedClasses.add(cls)) { | |
532 onImplemented(cls); | |
533 cls.allSupertypes.forEach((InterfaceType supertype) { | |
534 if (_implementedClasses.add(supertype.element)) { | |
535 onImplemented(supertype.element); | |
536 } | |
537 }); | |
538 } | |
539 } | |
540 | |
541 bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors, | |
542 Element member, ClosedWorld world) { | |
543 if (selectors == null) return false; | |
544 for (Selector selector in selectors.keys) { | |
545 if (selector.appliesUnnamed(member)) { | |
546 SelectorConstraints masks = selectors[selector]; | |
547 if (masks.applies(member, selector, world)) { | |
548 return true; | |
549 } | |
550 } | |
551 } | |
552 return false; | |
553 } | |
554 | |
555 bool hasInvocation(Element member, ClosedWorld world) { | |
556 return _hasMatchingSelector(_invokedNames[member.name], member, world); | |
557 } | |
558 | |
559 bool hasInvokedGetter(Element member, ClosedWorld world) { | |
560 return _hasMatchingSelector(_invokedGetters[member.name], member, world) || | |
561 member.isFunction && methodsNeedingSuperGetter.contains(member); | |
562 } | |
563 | |
564 bool hasInvokedSetter(Element member, ClosedWorld world) { | |
565 return _hasMatchingSelector(_invokedSetters[member.name], member, world); | |
566 } | |
567 | |
568 bool registerDynamicUse(DynamicUse dynamicUse) { | |
569 switch (dynamicUse.kind) { | |
570 case DynamicUseKind.INVOKE: | |
571 return _registerNewSelector(dynamicUse, _invokedNames); | |
572 case DynamicUseKind.GET: | |
573 return _registerNewSelector(dynamicUse, _invokedGetters); | |
574 case DynamicUseKind.SET: | |
575 return _registerNewSelector(dynamicUse, _invokedSetters); | |
576 } | |
577 } | |
578 | |
579 bool _registerNewSelector(DynamicUse dynamicUse, | |
580 Map<String, Map<Selector, SelectorConstraints>> selectorMap) { | |
581 Selector selector = dynamicUse.selector; | |
582 String name = selector.name; | |
583 ReceiverConstraint mask = dynamicUse.mask; | |
584 Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent( | |
585 name, () => new Maplet<Selector, SelectorConstraints>()); | |
586 UniverseSelectorConstraints constraints = | |
587 selectors.putIfAbsent(selector, () { | |
588 return selectorConstraintsStrategy.createSelectorConstraints(selector); | |
589 }); | |
590 return constraints.addReceiverConstraint(mask); | |
591 } | |
592 | |
593 Map<Selector, SelectorConstraints> _asUnmodifiable( | |
594 Map<Selector, SelectorConstraints> map) { | |
595 if (map == null) return null; | |
596 return new UnmodifiableMapView(map); | |
597 } | |
598 | |
599 Map<Selector, SelectorConstraints> invocationsByName(String name) { | |
600 return _asUnmodifiable(_invokedNames[name]); | |
601 } | |
602 | |
603 Map<Selector, SelectorConstraints> getterInvocationsByName(String name) { | |
604 return _asUnmodifiable(_invokedGetters[name]); | |
605 } | |
606 | |
607 Map<Selector, SelectorConstraints> setterInvocationsByName(String name) { | |
608 return _asUnmodifiable(_invokedSetters[name]); | |
609 } | |
610 | |
611 void forEachInvokedName( | |
612 f(String name, Map<Selector, SelectorConstraints> selectors)) { | |
613 _invokedNames.forEach(f); | |
614 } | |
615 | |
616 void forEachInvokedGetter( | |
617 f(String name, Map<Selector, SelectorConstraints> selectors)) { | |
618 _invokedGetters.forEach(f); | |
619 } | |
620 | |
621 void forEachInvokedSetter( | |
622 f(String name, Map<Selector, SelectorConstraints> selectors)) { | |
623 _invokedSetters.forEach(f); | |
624 } | |
625 | |
626 DartType registerIsCheck(DartType type, Compiler compiler) { | |
627 type.computeUnaliased(compiler.resolution); | |
628 type = type.unaliased; | |
629 // Even in checked mode, type annotations for return type and argument | |
630 // types do not imply type checks, so there should never be a check | |
631 // against the type variable of a typedef. | |
632 isChecks.add(type); | |
633 return type; | |
634 } | |
635 | |
636 void registerStaticUse(StaticUse staticUse) { | |
637 Element element = staticUse.element; | |
638 if (Elements.isStaticOrTopLevel(element) && element.isField) { | |
639 allReferencedStaticFields.add(element); | |
640 } | |
641 switch (staticUse.kind) { | |
642 case StaticUseKind.STATIC_TEAR_OFF: | |
643 staticFunctionsNeedingGetter.add(element); | |
644 break; | |
645 case StaticUseKind.SUPER_TEAR_OFF: | |
646 methodsNeedingSuperGetter.add(element); | |
647 break; | |
648 case StaticUseKind.SUPER_FIELD_SET: | |
649 case StaticUseKind.FIELD_SET: | |
650 case StaticUseKind.GENERAL: | |
651 case StaticUseKind.CLOSURE: | |
652 case StaticUseKind.FIELD_GET: | |
653 break; | |
654 } | |
655 } | |
656 | |
657 void forgetElement(Element element, Compiler compiler) { | |
658 _directlyInstantiatedClasses.remove(element); | |
659 if (element is ClassElement) { | |
660 assert(invariant(element, element.thisType.isRaw, | |
661 message: 'Generic classes not supported (${element.thisType}).')); | |
662 _instantiatedTypes..remove(element.rawType)..remove(element.thisType); | |
663 } | |
664 } | |
665 } | |
OLD | NEW |