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