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 class UnionTypeMask implements TypeMask { | 7 class UnionTypeMask implements TypeMask { |
8 final Iterable<FlatTypeMask> disjointMasks; | 8 final Iterable<FlatTypeMask> disjointMasks; |
9 | 9 |
10 static const int MAX_UNION_LENGTH = 4; | 10 static const int MAX_UNION_LENGTH = 4; |
11 | 11 |
12 // Set this flag to `true` to perform a set-membership based containment check | 12 // Set this flag to `true` to perform a set-membership based containment check |
13 // instead of relying on normalized types. This is quite slow but can be | 13 // instead of relying on normalized types. This is quite slow but can be |
14 // helpful in debugging. | 14 // helpful in debugging. |
15 static const bool PERFORM_EXTRA_CONTAINS_CHECK = false; | 15 static const bool PERFORM_EXTRA_CONTAINS_CHECK = false; |
16 | 16 |
17 UnionTypeMask._internal(this.disjointMasks) { | 17 UnionTypeMask._internal(this.disjointMasks) { |
18 assert(disjointMasks.length > 1); | 18 assert(disjointMasks.length > 1); |
19 assert(disjointMasks.every((TypeMask mask) => !mask.isUnion)); | 19 assert(disjointMasks.every((TypeMask mask) => !mask.isUnion)); |
20 } | 20 } |
21 | 21 |
22 static TypeMask unionOf(Iterable<TypeMask> masks, ClassWorld classWorld) { | 22 static TypeMask unionOf(Iterable<TypeMask> masks, ClassWorld classWorld) { |
23 assert(masks.every((mask) => TypeMask.assertIsNormalized(mask, classWorld)))
; | 23 assert( |
| 24 masks.every((mask) => TypeMask.assertIsNormalized(mask, classWorld))); |
24 List<FlatTypeMask> disjoint = <FlatTypeMask>[]; | 25 List<FlatTypeMask> disjoint = <FlatTypeMask>[]; |
25 unionOfHelper(masks, disjoint, classWorld); | 26 unionOfHelper(masks, disjoint, classWorld); |
26 if (disjoint.isEmpty) return new TypeMask.nonNullEmpty(); | 27 if (disjoint.isEmpty) return new TypeMask.nonNullEmpty(); |
27 if (disjoint.length > MAX_UNION_LENGTH) { | 28 if (disjoint.length > MAX_UNION_LENGTH) { |
28 return flatten(disjoint, classWorld); | 29 return flatten(disjoint, classWorld); |
29 } | 30 } |
30 if (disjoint.length == 1) return disjoint[0]; | 31 if (disjoint.length == 1) return disjoint[0]; |
31 UnionTypeMask union = new UnionTypeMask._internal(disjoint); | 32 UnionTypeMask union = new UnionTypeMask._internal(disjoint); |
32 assert(TypeMask.assertIsNormalized(union, classWorld)); | 33 assert(TypeMask.assertIsNormalized(union, classWorld)); |
33 return union; | 34 return union; |
34 } | 35 } |
35 | 36 |
36 static void unionOfHelper(Iterable<TypeMask> masks, | 37 static void unionOfHelper(Iterable<TypeMask> masks, |
37 List<FlatTypeMask> disjoint, | 38 List<FlatTypeMask> disjoint, ClassWorld classWorld) { |
38 ClassWorld classWorld) { | |
39 // TODO(johnniwinther): Impose an order on the mask to ensure subclass masks | 39 // TODO(johnniwinther): Impose an order on the mask to ensure subclass masks |
40 // are preferred to subtype masks. | 40 // are preferred to subtype masks. |
41 for (TypeMask mask in masks) { | 41 for (TypeMask mask in masks) { |
42 mask = TypeMask.nonForwardingMask(mask); | 42 mask = TypeMask.nonForwardingMask(mask); |
43 if (mask.isUnion) { | 43 if (mask.isUnion) { |
44 UnionTypeMask union = mask; | 44 UnionTypeMask union = mask; |
45 unionOfHelper(union.disjointMasks, disjoint, classWorld); | 45 unionOfHelper(union.disjointMasks, disjoint, classWorld); |
46 } else if (mask.isEmpty) { | 46 } else if (mask.isEmpty) { |
47 continue; | 47 continue; |
48 } else { | 48 } else { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 | 96 |
97 List<ClassElement> masksBases = masks.map((mask) => mask.base).toList(); | 97 List<ClassElement> masksBases = masks.map((mask) => mask.base).toList(); |
98 Iterable<ClassElement> candidates = | 98 Iterable<ClassElement> candidates = |
99 classWorld.commonSupertypesOf(masksBases); | 99 classWorld.commonSupertypesOf(masksBases); |
100 | 100 |
101 // Compute the best candidate and its kind. | 101 // Compute the best candidate and its kind. |
102 ClassElement bestElement; | 102 ClassElement bestElement; |
103 int bestKind; | 103 int bestKind; |
104 int bestSize; | 104 int bestSize; |
105 for (ClassElement candidate in candidates) { | 105 for (ClassElement candidate in candidates) { |
106 bool isInstantiatedStrictSubclass(cls) => cls != candidate && | 106 bool isInstantiatedStrictSubclass(cls) => |
| 107 cls != candidate && |
107 classWorld.isDirectlyInstantiated(cls) && | 108 classWorld.isDirectlyInstantiated(cls) && |
108 classWorld.isSubclassOf(cls, candidate); | 109 classWorld.isSubclassOf(cls, candidate); |
109 | 110 |
110 int size; | 111 int size; |
111 int kind; | 112 int kind; |
112 if (useSubclass && masksBases.every(isInstantiatedStrictSubclass)) { | 113 if (useSubclass && masksBases.every(isInstantiatedStrictSubclass)) { |
113 // If both [this] and [other] are subclasses of the supertype, | 114 // If both [this] and [other] are subclasses of the supertype, |
114 // then we prefer to construct a subclass type mask because it | 115 // then we prefer to construct a subclass type mask because it |
115 // will always be at least as small as the corresponding | 116 // will always be at least as small as the corresponding |
116 // subtype type mask. | 117 // subtype type mask. |
(...skipping 14 matching lines...) Expand all Loading... |
131 bestKind = kind; | 132 bestKind = kind; |
132 } | 133 } |
133 } | 134 } |
134 return new TypeMask(bestElement, bestKind, isNullable, classWorld); | 135 return new TypeMask(bestElement, bestKind, isNullable, classWorld); |
135 } | 136 } |
136 | 137 |
137 TypeMask union(var other, ClassWorld classWorld) { | 138 TypeMask union(var other, ClassWorld classWorld) { |
138 other = TypeMask.nonForwardingMask(other); | 139 other = TypeMask.nonForwardingMask(other); |
139 if (!other.isUnion && disjointMasks.contains(other)) return this; | 140 if (!other.isUnion && disjointMasks.contains(other)) return this; |
140 | 141 |
141 List<FlatTypeMask> newList = | 142 List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks); |
142 new List<FlatTypeMask>.from(disjointMasks); | |
143 if (!other.isUnion) { | 143 if (!other.isUnion) { |
144 newList.add(other); | 144 newList.add(other); |
145 } else { | 145 } else { |
146 assert(other is UnionTypeMask); | 146 assert(other is UnionTypeMask); |
147 newList.addAll(other.disjointMasks); | 147 newList.addAll(other.disjointMasks); |
148 } | 148 } |
149 return new TypeMask.unionOf(newList, classWorld); | 149 return new TypeMask.unionOf(newList, classWorld); |
150 } | 150 } |
151 | 151 |
152 TypeMask intersection(var other, ClassWorld classWorld) { | 152 TypeMask intersection(var other, ClassWorld classWorld) { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 return disjointMasks.any((e) => e.contains(type, classWorld)); | 315 return disjointMasks.any((e) => e.contains(type, classWorld)); |
316 } | 316 } |
317 | 317 |
318 bool containsAll(ClassWorld classWorld) { | 318 bool containsAll(ClassWorld classWorld) { |
319 return disjointMasks.any((mask) => mask.containsAll(classWorld)); | 319 return disjointMasks.any((mask) => mask.containsAll(classWorld)); |
320 } | 320 } |
321 | 321 |
322 ClassElement singleClass(ClassWorld classWorld) => null; | 322 ClassElement singleClass(ClassWorld classWorld) => null; |
323 | 323 |
324 bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) { | 324 bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) { |
325 return disjointMasks.any( | 325 return disjointMasks |
326 (e) => e.needsNoSuchMethodHandling(selector, classWorld)); | 326 .any((e) => e.needsNoSuchMethodHandling(selector, classWorld)); |
327 } | 327 } |
328 | 328 |
329 bool canHit(Element element, Selector selector, ClassWorld classWorld) { | 329 bool canHit(Element element, Selector selector, ClassWorld classWorld) { |
330 return disjointMasks.any((e) => e.canHit(element, selector, classWorld)); | 330 return disjointMasks.any((e) => e.canHit(element, selector, classWorld)); |
331 } | 331 } |
332 | 332 |
333 Element locateSingleElement(Selector selector, | 333 Element locateSingleElement( |
334 TypeMask mask, | 334 Selector selector, TypeMask mask, Compiler compiler) { |
335 Compiler compiler) { | |
336 Element candidate; | 335 Element candidate; |
337 for (FlatTypeMask mask in disjointMasks) { | 336 for (FlatTypeMask mask in disjointMasks) { |
338 Element current = mask.locateSingleElement(selector, mask, compiler); | 337 Element current = mask.locateSingleElement(selector, mask, compiler); |
339 if (current == null) { | 338 if (current == null) { |
340 return null; | 339 return null; |
341 } else if (candidate == null) { | 340 } else if (candidate == null) { |
342 candidate = current; | 341 candidate = current; |
343 } else if (candidate != current) { | 342 } else if (candidate != current) { |
344 return null; | 343 return null; |
345 } | 344 } |
346 } | 345 } |
347 return candidate; | 346 return candidate; |
348 } | 347 } |
349 | 348 |
350 String toString() { | 349 String toString() { |
351 String masksString = (disjointMasks.map((TypeMask mask) => mask.toString()) | 350 String masksString = |
352 .toList()..sort()).join(", "); | 351 (disjointMasks.map((TypeMask mask) => mask.toString()).toList()..sort()) |
| 352 .join(", "); |
353 return 'Union of [$masksString]'; | 353 return 'Union of [$masksString]'; |
354 } | 354 } |
355 | 355 |
356 bool operator==(other) { | 356 bool operator ==(other) { |
357 if (identical(this, other)) return true; | 357 if (identical(this, other)) return true; |
358 | 358 |
359 bool containsAll() { | 359 bool containsAll() { |
360 return other.disjointMasks.every((e) { | 360 return other.disjointMasks.every((e) { |
361 var map = disjointMasks.map((e) => e.nonNullable()); | 361 var map = disjointMasks.map((e) => e.nonNullable()); |
362 return map.contains(e.nonNullable()); | 362 return map.contains(e.nonNullable()); |
363 }); | 363 }); |
364 } | 364 } |
365 | 365 |
366 return other is UnionTypeMask | 366 return other is UnionTypeMask && |
367 && other.isNullable == isNullable | 367 other.isNullable == isNullable && |
368 && other.disjointMasks.length == disjointMasks.length | 368 other.disjointMasks.length == disjointMasks.length && |
369 && containsAll(); | 369 containsAll(); |
370 } | 370 } |
371 | 371 |
372 int get hashCode { | 372 int get hashCode { |
373 int hashCode = isNullable ? 86 : 43; | 373 int hashCode = isNullable ? 86 : 43; |
374 // The order of the masks in [disjointMasks] must not affect the | 374 // The order of the masks in [disjointMasks] must not affect the |
375 // hashCode. | 375 // hashCode. |
376 for (var mask in disjointMasks) { | 376 for (var mask in disjointMasks) { |
377 hashCode = (hashCode ^ mask.nonNullable().hashCode) & 0x3fffffff; | 377 hashCode = (hashCode ^ mask.nonNullable().hashCode) & 0x3fffffff; |
378 } | 378 } |
379 return hashCode; | 379 return hashCode; |
380 } | 380 } |
381 } | 381 } |
OLD | NEW |