| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of types; | |
| 6 | |
| 7 /** | |
| 8 * A type mask represents a set of contained classes, but the | |
| 9 * operations on it are not guaranteed to be precise and they may | |
| 10 * yield conservative answers that contain too many classes. | |
| 11 */ | |
| 12 abstract class TypeMask { | |
| 13 factory TypeMask(ClassElement base, | |
| 14 int kind, | |
| 15 bool isNullable, | |
| 16 ClassWorld classWorld) { | |
| 17 return new FlatTypeMask.normalized( | |
| 18 base, (kind << 1) | (isNullable ? 1 : 0), classWorld); | |
| 19 } | |
| 20 | |
| 21 const factory TypeMask.empty() = FlatTypeMask.empty; | |
| 22 | |
| 23 factory TypeMask.exact(ClassElement base, ClassWorld classWorld) { | |
| 24 assert(invariant(base, classWorld.isInstantiated(base), | |
| 25 message: "Cannot create extact type mask for uninstantiated class")); | |
| 26 return new FlatTypeMask.exact(base); | |
| 27 } | |
| 28 | |
| 29 factory TypeMask.exactOrEmpty(ClassElement base, ClassWorld classWorld) { | |
| 30 if (classWorld.isInstantiated(base)) return new FlatTypeMask.exact(base); | |
| 31 return const TypeMask.empty(); | |
| 32 } | |
| 33 | |
| 34 factory TypeMask.subclass(ClassElement base, ClassWorld classWorld) { | |
| 35 if (classWorld.hasAnySubclass(base)) { | |
| 36 return new FlatTypeMask.subclass(base); | |
| 37 } else { | |
| 38 return new TypeMask.exactOrEmpty(base, classWorld); | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 factory TypeMask.subtype(ClassElement base, ClassWorld classWorld) { | |
| 43 if (classWorld.hasOnlySubclasses(base)) { | |
| 44 return new TypeMask.subclass(base, classWorld); | |
| 45 } | |
| 46 if (classWorld.hasAnySubtype(base)) { | |
| 47 return new FlatTypeMask.subtype(base); | |
| 48 } else { | |
| 49 return new TypeMask.exactOrEmpty(base, classWorld); | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 const factory TypeMask.nonNullEmpty() = FlatTypeMask.nonNullEmpty; | |
| 54 | |
| 55 factory TypeMask.nonNullExact(ClassElement base, ClassWorld classWorld) { | |
| 56 assert(invariant(base, classWorld.isInstantiated(base), | |
| 57 message: "Cannot create extact type mask for uninstantiated class")); | |
| 58 return new FlatTypeMask.nonNullExact(base); | |
| 59 } | |
| 60 | |
| 61 factory TypeMask.nonNullExactOrEmpty(ClassElement base, | |
| 62 ClassWorld classWorld) { | |
| 63 if (classWorld.isInstantiated(base)) { | |
| 64 return new FlatTypeMask.nonNullExact(base); | |
| 65 } | |
| 66 return const TypeMask.nonNullEmpty(); | |
| 67 } | |
| 68 | |
| 69 factory TypeMask.nonNullSubclass(ClassElement base, ClassWorld classWorld) { | |
| 70 if (classWorld.hasAnySubclass(base)) { | |
| 71 return new FlatTypeMask.nonNullSubclass(base); | |
| 72 } else { | |
| 73 return new TypeMask.nonNullExactOrEmpty(base, classWorld); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 factory TypeMask.nonNullSubtype(ClassElement base, ClassWorld classWorld) { | |
| 78 if (classWorld.hasOnlySubclasses(base)) { | |
| 79 return new TypeMask.nonNullSubclass(base, classWorld); | |
| 80 } | |
| 81 if (classWorld.hasAnySubtype(base)) { | |
| 82 return new FlatTypeMask.nonNullSubtype(base); | |
| 83 } else { | |
| 84 return new TypeMask.nonNullExactOrEmpty(base, classWorld); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 factory TypeMask.unionOf(Iterable<TypeMask> masks, ClassWorld classWorld) { | |
| 89 return UnionTypeMask.unionOf(masks, classWorld); | |
| 90 } | |
| 91 | |
| 92 /** | |
| 93 * If [mask] is forwarding, returns the first non-forwarding [TypeMask] in | |
| 94 * [mask]'s forwarding chain. | |
| 95 */ | |
| 96 static TypeMask nonForwardingMask(mask) { | |
| 97 while (mask.isForwarding) { | |
| 98 mask = mask.forwardTo; | |
| 99 } | |
| 100 return mask; | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * Asserts that this mask uses the smallest possible representation for | |
| 105 * its types. Currently, we normalize subtype and subclass to exact if no | |
| 106 * subtypes or subclasses are present and subtype to subclass if only | |
| 107 * subclasses exist. We also normalize exact to empty if the corresponding | |
| 108 * baseclass was never instantiated. | |
| 109 */ | |
| 110 static bool assertIsNormalized(TypeMask mask, ClassWorld classWorld) { | |
| 111 String reason = getNotNormalizedReason(mask, classWorld); | |
| 112 return invariant(NO_LOCATION_SPANNABLE, reason == null, | |
| 113 message: () => '$mask is not normalized: $reason'); | |
| 114 } | |
| 115 | |
| 116 static String getNotNormalizedReason(TypeMask mask, ClassWorld classWorld) { | |
| 117 mask = nonForwardingMask(mask); | |
| 118 if (mask is FlatTypeMask) { | |
| 119 if (mask.isEmpty) return null; | |
| 120 if (mask.isExact) { | |
| 121 if (!classWorld.isInstantiated(mask.base)) { | |
| 122 return 'Exact ${mask.base} is not instantiated.'; | |
| 123 } | |
| 124 return null; | |
| 125 } | |
| 126 if (mask.isSubclass) { | |
| 127 if (!classWorld.hasAnySubclass(mask.base)) { | |
| 128 return 'Subclass ${mask.base} does not have any subclasses.'; | |
| 129 } | |
| 130 return null; | |
| 131 } | |
| 132 assert(mask.isSubtype); | |
| 133 if (!classWorld.hasAnySubtype(mask.base)) { | |
| 134 return 'Subtype ${mask.base} does not have any subclasses.'; | |
| 135 } | |
| 136 if (classWorld.hasOnlySubclasses(mask.base)) { | |
| 137 return 'Subtype ${mask.base} only has subclasses.'; | |
| 138 } | |
| 139 return null; | |
| 140 } else if (mask is UnionTypeMask) { | |
| 141 for (TypeMask submask in mask.disjointMasks) { | |
| 142 String submaskReason = getNotNormalizedReason(submask, classWorld); | |
| 143 if (submaskReason != null) { | |
| 144 return 'Submask $submask in $mask: $submaskReason.'; | |
| 145 } | |
| 146 } | |
| 147 return null; | |
| 148 } | |
| 149 return 'Unknown type mask $mask.'; | |
| 150 } | |
| 151 | |
| 152 /** | |
| 153 * Returns a nullable variant of [this] type mask. | |
| 154 */ | |
| 155 TypeMask nullable(); | |
| 156 | |
| 157 /** | |
| 158 * Returns a non-nullable variant of [this] type mask. | |
| 159 */ | |
| 160 TypeMask nonNullable(); | |
| 161 | |
| 162 bool get isEmpty; | |
| 163 bool get isNullable; | |
| 164 bool get isExact; | |
| 165 | |
| 166 /// Returns true if this mask is a union type. | |
| 167 bool get isUnion; | |
| 168 | |
| 169 /// Returns `true` if this mask is a [ContainerTypeMask]. | |
| 170 bool get isContainer; | |
| 171 | |
| 172 /// Returns `true` if this mask is a [MapTypeMask]. | |
| 173 bool get isMap; | |
| 174 | |
| 175 /// Returns `true` if this mask is a [MapTypeMask] in dictionary mode, i.e., | |
| 176 /// all keys are known string values and we have specific type information for | |
| 177 /// corresponding values. | |
| 178 bool get isDictionary; | |
| 179 | |
| 180 /// Returns `true` if this mask is wrapping another mask for the purpose of | |
| 181 /// tracing. | |
| 182 bool get isForwarding; | |
| 183 | |
| 184 /// Returns `true` if this mask holds encodes an exact value within a type. | |
| 185 bool get isValue; | |
| 186 | |
| 187 bool containsOnlyInt(ClassWorld classWorld); | |
| 188 bool containsOnlyDouble(ClassWorld classWorld); | |
| 189 bool containsOnlyNum(ClassWorld classWorld); | |
| 190 bool containsOnlyBool(ClassWorld classWorld); | |
| 191 bool containsOnlyString(ClassWorld classWorld); | |
| 192 bool containsOnly(ClassElement element); | |
| 193 | |
| 194 /** | |
| 195 * Compares two [TypeMask] objects for structural equality. | |
| 196 * | |
| 197 * Note: This may differ from semantic equality in the set containment sense. | |
| 198 * Use [containsMask] and [isInMask] for that, instead. | |
| 199 */ | |
| 200 bool operator==(other); | |
| 201 | |
| 202 /** | |
| 203 * Returns `true` if [other] is a supertype of this mask, i.e., if | |
| 204 * this mask is in [other]. | |
| 205 */ | |
| 206 bool isInMask(TypeMask other, ClassWorld classWorld); | |
| 207 | |
| 208 /** | |
| 209 * Returns `true` if [other] is a subtype of this mask, i.e., if | |
| 210 * this mask contains [other]. | |
| 211 */ | |
| 212 bool containsMask(TypeMask other, ClassWorld classWorld); | |
| 213 | |
| 214 /** | |
| 215 * Returns whether this type mask is an instance of [cls]. | |
| 216 */ | |
| 217 bool satisfies(ClassElement cls, ClassWorld classWorld); | |
| 218 | |
| 219 /** | |
| 220 * Returns whether or not this type mask contains the given type. | |
| 221 */ | |
| 222 bool contains(ClassElement type, ClassWorld classWorld); | |
| 223 | |
| 224 /** | |
| 225 * Returns whether or not this type mask contains all types. | |
| 226 */ | |
| 227 bool containsAll(ClassWorld classWorld); | |
| 228 | |
| 229 /** | |
| 230 * Returns the [ClassElement] if this type represents a single class, | |
| 231 * otherwise returns `null`. This method is conservative. | |
| 232 */ | |
| 233 ClassElement singleClass(ClassWorld classWorld); | |
| 234 | |
| 235 /** | |
| 236 * Returns a type mask representing the union of [this] and [other]. | |
| 237 */ | |
| 238 TypeMask union(TypeMask other, ClassWorld classWorld); | |
| 239 | |
| 240 /** | |
| 241 * Returns a type mask representing the intersection of [this] and [other]. | |
| 242 */ | |
| 243 TypeMask intersection(TypeMask other, ClassWorld classWorld); | |
| 244 | |
| 245 /** | |
| 246 * Returns whether this [TypeMask] applied to [selector] can hit a | |
| 247 * [noSuchMethod]. | |
| 248 */ | |
| 249 bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld); | |
| 250 | |
| 251 /** | |
| 252 * Returns whether [element] is a potential target when being | |
| 253 * invoked on this type mask. [selector] is used to ensure library | |
| 254 * privacy is taken into account. | |
| 255 */ | |
| 256 bool canHit(Element element, Selector selector, ClassWorld classWorld); | |
| 257 | |
| 258 /** | |
| 259 * Returns the [element] that is known to always be hit at runtime | |
| 260 * on this mask. Returns null if there is none. | |
| 261 */ | |
| 262 // TODO(johnniwinther): Move this method to [World]. | |
| 263 Element locateSingleElement(Selector selector, Compiler compiler); | |
| 264 } | |
| OLD | NEW |