OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 types; | 5 part of types; |
6 | 6 |
7 /// An implementation of a [UniverseSelectorConstraints] that is consists if an
only | 7 /// An implementation of a [UniverseSelectorConstraints] that is consists if an
only |
8 /// increasing set of [TypeMask]s, that is, once a mask is added it cannot be | 8 /// increasing set of [TypeMask]s, that is, once a mask is added it cannot be |
9 /// removed. | 9 /// removed. |
10 class IncreasingTypeMaskSet extends UniverseSelectorConstraints { | 10 class IncreasingTypeMaskSet extends UniverseSelectorConstraints { |
11 bool isAll = false; | 11 bool isAll = false; |
12 Set<TypeMask> _masks; | 12 Set<TypeMask> _masks; |
13 | 13 |
14 @override | 14 @override |
15 bool applies(Element element, Selector selector, ClassWorld world) { | 15 bool applies(Element element, Selector selector, ClassWorld world) { |
16 if (isAll) return true; | 16 if (isAll) return true; |
17 if (_masks == null) return false; | 17 if (_masks == null) return false; |
18 for (TypeMask mask in _masks) { | 18 for (TypeMask mask in _masks) { |
19 if (mask.canHit(element, selector, world)) return true; | 19 if (mask.canHit(element, selector, world)) return true; |
20 } | 20 } |
21 return false; | 21 return false; |
22 } | 22 } |
23 | 23 |
24 @override | 24 @override |
25 bool needsNoSuchMethodHandling(Selector selector, ClassWorld world) { | 25 bool needsNoSuchMethodHandling(Selector selector, ClassWorld world) { |
26 if (isAll) { | 26 if (isAll) { |
27 TypeMask mask = | 27 TypeMask mask = new TypeMask.subclass(world.objectClass, world); |
28 new TypeMask.subclass(world.objectClass, world); | |
29 return mask.needsNoSuchMethodHandling(selector, world); | 28 return mask.needsNoSuchMethodHandling(selector, world); |
30 } | 29 } |
31 for (TypeMask mask in _masks) { | 30 for (TypeMask mask in _masks) { |
32 if (mask.needsNoSuchMethodHandling(selector, world)) { | 31 if (mask.needsNoSuchMethodHandling(selector, world)) { |
33 return true; | 32 return true; |
34 } | 33 } |
35 } | 34 } |
36 return false; | 35 return false; |
37 } | 36 } |
38 | 37 |
(...skipping 30 matching lines...) Expand all Loading... |
69 return new IncreasingTypeMaskSet(); | 68 return new IncreasingTypeMaskSet(); |
70 } | 69 } |
71 } | 70 } |
72 | 71 |
73 /** | 72 /** |
74 * A type mask represents a set of contained classes, but the | 73 * A type mask represents a set of contained classes, but the |
75 * operations on it are not guaranteed to be precise and they may | 74 * operations on it are not guaranteed to be precise and they may |
76 * yield conservative answers that contain too many classes. | 75 * yield conservative answers that contain too many classes. |
77 */ | 76 */ |
78 abstract class TypeMask implements ReceiverConstraint, AbstractValue { | 77 abstract class TypeMask implements ReceiverConstraint, AbstractValue { |
79 factory TypeMask(ClassElement base, | 78 factory TypeMask( |
80 int kind, | 79 ClassElement base, int kind, bool isNullable, ClassWorld classWorld) { |
81 bool isNullable, | |
82 ClassWorld classWorld) { | |
83 return new FlatTypeMask.normalized( | 80 return new FlatTypeMask.normalized( |
84 base, (kind << 1) | (isNullable ? 1 : 0), classWorld); | 81 base, (kind << 1) | (isNullable ? 1 : 0), classWorld); |
85 } | 82 } |
86 | 83 |
87 const factory TypeMask.empty() = FlatTypeMask.empty; | 84 const factory TypeMask.empty() = FlatTypeMask.empty; |
88 | 85 |
89 factory TypeMask.exact(ClassElement base, ClassWorld classWorld) { | 86 factory TypeMask.exact(ClassElement base, ClassWorld classWorld) { |
90 assert(invariant(base, classWorld.isInstantiated(base), | 87 assert(invariant(base, classWorld.isInstantiated(base), |
91 message: () => "Cannot create exact type mask for uninstantiated " | 88 message: () => "Cannot create exact type mask for uninstantiated " |
92 "class $base.\n${classWorld.dump(base)}")); | 89 "class $base.\n${classWorld.dump(base)}")); |
93 return new FlatTypeMask.exact(base); | 90 return new FlatTypeMask.exact(base); |
94 } | 91 } |
95 | 92 |
96 factory TypeMask.exactOrEmpty(ClassElement base, ClassWorld classWorld) { | 93 factory TypeMask.exactOrEmpty(ClassElement base, ClassWorld classWorld) { |
97 if (classWorld.isInstantiated(base)) return new FlatTypeMask.exact(base); | 94 if (classWorld.isInstantiated(base)) return new FlatTypeMask.exact(base); |
98 return const TypeMask.empty(); | 95 return const TypeMask.empty(); |
99 } | 96 } |
100 | 97 |
101 factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) { | 98 factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) { |
102 assert(invariant(base, classWorld.isInstantiated(base), | 99 assert(invariant(base, classWorld.isInstantiated(base), |
103 message: () => "Cannot create subclass type mask for uninstantiated " | 100 message: () => "Cannot create subclass type mask for uninstantiated " |
104 "class $base.\n${classWorld.dump(base)}")); | 101 "class $base.\n${classWorld.dump(base)}")); |
105 ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base); | 102 ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base); |
106 if (topmost == null) { | 103 if (topmost == null) { |
107 return new TypeMask.empty(); | 104 return new TypeMask.empty(); |
108 } else if (classWorld.hasAnyStrictSubclass(topmost)) { | 105 } else if (classWorld.hasAnyStrictSubclass(topmost)) { |
109 return new FlatTypeMask.subclass(topmost); | 106 return new FlatTypeMask.subclass(topmost); |
110 } else { | 107 } else { |
111 return new TypeMask.exact(topmost, classWorld); | 108 return new TypeMask.exact(topmost, classWorld); |
112 } | 109 } |
113 } | 110 } |
114 | 111 |
(...skipping 10 matching lines...) Expand all Loading... |
125 } else { | 122 } else { |
126 return new TypeMask.exact(topmost, classWorld); | 123 return new TypeMask.exact(topmost, classWorld); |
127 } | 124 } |
128 } | 125 } |
129 | 126 |
130 const factory TypeMask.nonNullEmpty() = FlatTypeMask.nonNullEmpty; | 127 const factory TypeMask.nonNullEmpty() = FlatTypeMask.nonNullEmpty; |
131 | 128 |
132 factory TypeMask.nonNullExact(ClassElement base, ClassWorld classWorld) { | 129 factory TypeMask.nonNullExact(ClassElement base, ClassWorld classWorld) { |
133 assert(invariant(base, classWorld.isInstantiated(base), | 130 assert(invariant(base, classWorld.isInstantiated(base), |
134 message: () => "Cannot create exact type mask for uninstantiated " | 131 message: () => "Cannot create exact type mask for uninstantiated " |
135 "class $base.\n${classWorld.dump(base)}")); | 132 "class $base.\n${classWorld.dump(base)}")); |
136 return new FlatTypeMask.nonNullExact(base); | 133 return new FlatTypeMask.nonNullExact(base); |
137 } | 134 } |
138 | 135 |
139 factory TypeMask.nonNullExactOrEmpty(ClassElement base, | 136 factory TypeMask.nonNullExactOrEmpty( |
140 ClassWorld classWorld) { | 137 ClassElement base, ClassWorld classWorld) { |
141 if (classWorld.isInstantiated(base)) { | 138 if (classWorld.isInstantiated(base)) { |
142 return new FlatTypeMask.nonNullExact(base); | 139 return new FlatTypeMask.nonNullExact(base); |
143 } | 140 } |
144 return const TypeMask.nonNullEmpty(); | 141 return const TypeMask.nonNullEmpty(); |
145 } | 142 } |
146 | 143 |
147 factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) { | 144 factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) { |
148 assert(invariant(base, classWorld.isInstantiated(base), | 145 assert(invariant(base, classWorld.isInstantiated(base), |
149 message: () => "Cannot create subclass type mask for uninstantiated " | 146 message: () => "Cannot create subclass type mask for uninstantiated " |
150 "class $base.\n${classWorld.dump(base)}")); | 147 "class $base.\n${classWorld.dump(base)}")); |
151 ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base); | 148 ClassElement topmost = classWorld.getLubOfInstantiatedSubclasses(base); |
152 if (topmost == null) { | 149 if (topmost == null) { |
153 return new TypeMask.nonNullEmpty(); | 150 return new TypeMask.nonNullEmpty(); |
154 } else if (classWorld.hasAnyStrictSubclass(topmost)) { | 151 } else if (classWorld.hasAnyStrictSubclass(topmost)) { |
155 return new FlatTypeMask.nonNullSubclass(topmost); | 152 return new FlatTypeMask.nonNullSubclass(topmost); |
156 } else { | 153 } else { |
157 return new TypeMask.nonNullExact(topmost, classWorld); | 154 return new TypeMask.nonNullExact(topmost, classWorld); |
158 } | 155 } |
159 } | 156 } |
160 | 157 |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 bool containsOnlyBool(ClassWorld classWorld); | 287 bool containsOnlyBool(ClassWorld classWorld); |
291 bool containsOnlyString(ClassWorld classWorld); | 288 bool containsOnlyString(ClassWorld classWorld); |
292 bool containsOnly(ClassElement element); | 289 bool containsOnly(ClassElement element); |
293 | 290 |
294 /** | 291 /** |
295 * Compares two [TypeMask] objects for structural equality. | 292 * Compares two [TypeMask] objects for structural equality. |
296 * | 293 * |
297 * Note: This may differ from semantic equality in the set containment sense. | 294 * Note: This may differ from semantic equality in the set containment sense. |
298 * Use [containsMask] and [isInMask] for that, instead. | 295 * Use [containsMask] and [isInMask] for that, instead. |
299 */ | 296 */ |
300 bool operator==(other); | 297 bool operator ==(other); |
301 | 298 |
302 /** | 299 /** |
303 * If this returns `true`, [other] is guaranteed to be a supertype of this | 300 * If this returns `true`, [other] is guaranteed to be a supertype of this |
304 * mask, i.e., this mask is in [other]. However, the inverse does not hold. | 301 * mask, i.e., this mask is in [other]. However, the inverse does not hold. |
305 * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of | 302 * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of |
306 * false negatives. | 303 * false negatives. |
307 */ | 304 */ |
308 bool isInMask(TypeMask other, ClassWorld classWorld); | 305 bool isInMask(TypeMask other, ClassWorld classWorld); |
309 | 306 |
310 /** | 307 /** |
(...skipping 23 matching lines...) Expand all Loading... |
334 * Returns the [ClassElement] if this type represents a single class, | 331 * Returns the [ClassElement] if this type represents a single class, |
335 * otherwise returns `null`. This method is conservative. | 332 * otherwise returns `null`. This method is conservative. |
336 */ | 333 */ |
337 ClassElement singleClass(ClassWorld classWorld); | 334 ClassElement singleClass(ClassWorld classWorld); |
338 | 335 |
339 /** | 336 /** |
340 * Returns a type mask representing the union of [this] and [other]. | 337 * Returns a type mask representing the union of [this] and [other]. |
341 */ | 338 */ |
342 TypeMask union(TypeMask other, ClassWorld classWorld); | 339 TypeMask union(TypeMask other, ClassWorld classWorld); |
343 | 340 |
344 | |
345 /// Returns whether the intersection of this and [other] is empty. | 341 /// Returns whether the intersection of this and [other] is empty. |
346 bool isDisjoint(TypeMask other, ClassWorld classWorld); | 342 bool isDisjoint(TypeMask other, ClassWorld classWorld); |
347 | 343 |
348 /** | 344 /** |
349 * Returns a type mask representing the intersection of [this] and [other]. | 345 * Returns a type mask representing the intersection of [this] and [other]. |
350 */ | 346 */ |
351 TypeMask intersection(TypeMask other, ClassWorld classWorld); | 347 TypeMask intersection(TypeMask other, ClassWorld classWorld); |
352 | 348 |
353 /** | 349 /** |
354 * Returns whether [element] is a potential target when being | 350 * Returns whether [element] is a potential target when being |
355 * invoked on this type mask. [selector] is used to ensure library | 351 * invoked on this type mask. [selector] is used to ensure library |
356 * privacy is taken into account. | 352 * privacy is taken into account. |
357 */ | 353 */ |
358 bool canHit(Element element, Selector selector, ClassWorld classWorld); | 354 bool canHit(Element element, Selector selector, ClassWorld classWorld); |
359 | 355 |
360 /** | 356 /** |
361 * Returns the [element] that is known to always be hit at runtime | 357 * Returns the [element] that is known to always be hit at runtime |
362 * on this mask. Returns null if there is none. | 358 * on this mask. Returns null if there is none. |
363 */ | 359 */ |
364 // TODO(johnniwinther): Move this method to [World]. | 360 // TODO(johnniwinther): Move this method to [World]. |
365 Element locateSingleElement( | 361 Element locateSingleElement( |
366 Selector selector, | 362 Selector selector, TypeMask mask, Compiler compiler); |
367 TypeMask mask, | |
368 Compiler compiler); | |
369 } | 363 } |
OLD | NEW |