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