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 |