Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(406)

Side by Side Diff: pkg/compiler/lib/src/types/flat_type_mask.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 /** 7 /**
8 * A flat type mask is a type mask that has been flattened to contain a 8 * A flat type mask is a type mask that has been flattened to contain a
9 * base type. 9 * base type.
10 */ 10 */
11 class FlatTypeMask implements TypeMask { 11 class FlatTypeMask implements TypeMask {
12 static const int EMPTY = 0; 12 static const int EMPTY = 0;
13 static const int EXACT = 1; 13 static const int EXACT = 1;
14 static const int SUBCLASS = 2; 14 static const int SUBCLASS = 2;
15 static const int SUBTYPE = 3; 15 static const int SUBTYPE = 3;
16 16
17 final ClassElement base; 17 final ClassElement base;
18 final int flags; 18 final int flags;
19 19
20 FlatTypeMask(ClassElement base, int kind, bool isNullable) 20 FlatTypeMask(ClassElement base, int kind, bool isNullable)
21 : this.internal(base, (kind << 1) | (isNullable ? 1 : 0)); 21 : this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
22 22
23 FlatTypeMask.exact(ClassElement base) 23 FlatTypeMask.exact(ClassElement base) : this.internal(base, (EXACT << 1) | 1);
24 : this.internal(base, (EXACT << 1) | 1);
25 FlatTypeMask.subclass(ClassElement base) 24 FlatTypeMask.subclass(ClassElement base)
26 : this.internal(base, (SUBCLASS << 1) | 1); 25 : this.internal(base, (SUBCLASS << 1) | 1);
27 FlatTypeMask.subtype(ClassElement base) 26 FlatTypeMask.subtype(ClassElement base)
28 : this.internal(base, (SUBTYPE << 1) | 1); 27 : this.internal(base, (SUBTYPE << 1) | 1);
29 28
30 const FlatTypeMask.nonNullEmpty(): base = null, flags = 0; 29 const FlatTypeMask.nonNullEmpty()
31 const FlatTypeMask.empty() : base = null, flags = 1; 30 : base = null,
31 flags = 0;
32 const FlatTypeMask.empty()
33 : base = null,
34 flags = 1;
32 35
33 FlatTypeMask.nonNullExact(ClassElement base) 36 FlatTypeMask.nonNullExact(ClassElement base)
34 : this.internal(base, EXACT << 1); 37 : this.internal(base, EXACT << 1);
35 FlatTypeMask.nonNullSubclass(ClassElement base) 38 FlatTypeMask.nonNullSubclass(ClassElement base)
36 : this.internal(base, SUBCLASS << 1); 39 : this.internal(base, SUBCLASS << 1);
37 FlatTypeMask.nonNullSubtype(ClassElement base) 40 FlatTypeMask.nonNullSubtype(ClassElement base)
38 : this.internal(base, SUBTYPE << 1); 41 : this.internal(base, SUBTYPE << 1);
39 42
40 FlatTypeMask.internal(this.base, this.flags) { 43 FlatTypeMask.internal(this.base, this.flags) {
41 assert(base == null || base.isDeclaration); 44 assert(base == null || base.isDeclaration);
(...skipping 11 matching lines...) Expand all
53 if (!world.hasAnyStrictSubtype(base) || world.hasOnlySubclasses(base)) { 56 if (!world.hasAnyStrictSubtype(base) || world.hasOnlySubclasses(base)) {
54 flags = (flags & 0x1) | (SUBCLASS << 1); 57 flags = (flags & 0x1) | (SUBCLASS << 1);
55 } 58 }
56 } 59 }
57 if (((flags >> 1) == SUBCLASS) && !world.hasAnyStrictSubclass(base)) { 60 if (((flags >> 1) == SUBCLASS) && !world.hasAnyStrictSubclass(base)) {
58 flags = (flags & 0x1) | (EXACT << 1); 61 flags = (flags & 0x1) | (EXACT << 1);
59 } 62 }
60 Map<ClassElement, TypeMask> cachedMasks = 63 Map<ClassElement, TypeMask> cachedMasks =
61 world.canonicalizedTypeMasks[flags]; 64 world.canonicalizedTypeMasks[flags];
62 if (cachedMasks == null) { 65 if (cachedMasks == null) {
63 world.canonicalizedTypeMasks[flags] = cachedMasks = 66 world.canonicalizedTypeMasks[flags] =
64 <ClassElement, TypeMask>{}; 67 cachedMasks = <ClassElement, TypeMask>{};
65 } 68 }
66 return cachedMasks.putIfAbsent(base, 69 return cachedMasks.putIfAbsent(
67 () => new FlatTypeMask.internal(base, flags)); 70 base, () => new FlatTypeMask.internal(base, flags));
68 } 71 }
69 72
70 bool get isEmpty => isEmptyOrNull && !isNullable; 73 bool get isEmpty => isEmptyOrNull && !isNullable;
71 bool get isNull => isEmptyOrNull && isNullable; 74 bool get isNull => isEmptyOrNull && isNullable;
72 bool get isEmptyOrNull => (flags >> 1) == EMPTY; 75 bool get isEmptyOrNull => (flags >> 1) == EMPTY;
73 bool get isExact => (flags >> 1) == EXACT; 76 bool get isExact => (flags >> 1) == EXACT;
74 bool get isNullable => (flags & 1) != 0; 77 bool get isNullable => (flags & 1) != 0;
75 78
76 bool get isUnion => false; 79 bool get isUnion => false;
77 bool get isContainer => false; 80 bool get isContainer => false;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 115
113 bool isSingleImplementationOf(ClassElement cls, ClassWorld classWorld) { 116 bool isSingleImplementationOf(ClassElement cls, ClassWorld classWorld) {
114 // Special case basic types so that, for example, JSString is the 117 // Special case basic types so that, for example, JSString is the
115 // single implementation of String. 118 // single implementation of String.
116 // The general optimization is to realize there is only one class that 119 // The general optimization is to realize there is only one class that
117 // implements [base] and [base] is not instantiated. We however do 120 // implements [base] and [base] is not instantiated. We however do
118 // not track correctly the list of truly instantiated classes. 121 // not track correctly the list of truly instantiated classes.
119 Backend backend = classWorld.backend; 122 Backend backend = classWorld.backend;
120 if (containsOnlyString(classWorld)) { 123 if (containsOnlyString(classWorld)) {
121 return cls == classWorld.stringClass || 124 return cls == classWorld.stringClass ||
122 cls == backend.stringImplementation; 125 cls == backend.stringImplementation;
123 } 126 }
124 if (containsOnlyBool(classWorld)) { 127 if (containsOnlyBool(classWorld)) {
125 return cls == classWorld.boolClass || cls == backend.boolImplementation; 128 return cls == classWorld.boolClass || cls == backend.boolImplementation;
126 } 129 }
127 if (containsOnlyInt(classWorld)) { 130 if (containsOnlyInt(classWorld)) {
128 return cls == classWorld.intClass 131 return cls == classWorld.intClass ||
129 || cls == backend.intImplementation 132 cls == backend.intImplementation ||
130 || cls == backend.positiveIntImplementation 133 cls == backend.positiveIntImplementation ||
131 || cls == backend.uint32Implementation 134 cls == backend.uint32Implementation ||
132 || cls == backend.uint31Implementation; 135 cls == backend.uint31Implementation;
133 } 136 }
134 if (containsOnlyDouble(classWorld)) { 137 if (containsOnlyDouble(classWorld)) {
135 return cls == classWorld.doubleClass 138 return cls == classWorld.doubleClass ||
136 || cls == backend.doubleImplementation; 139 cls == backend.doubleImplementation;
137 } 140 }
138 return false; 141 return false;
139 } 142 }
140 143
141 bool isInMask(TypeMask other, ClassWorld classWorld) { 144 bool isInMask(TypeMask other, ClassWorld classWorld) {
142 if (isEmptyOrNull) return isNullable ? other.isNullable : true; 145 if (isEmptyOrNull) return isNullable ? other.isNullable : true;
143 // The empty type contains no classes. 146 // The empty type contains no classes.
144 if (other.isEmptyOrNull) return false; 147 if (other.isEmptyOrNull) return false;
145 // Quick check whether to handle null. 148 // Quick check whether to handle null.
146 if (isNullable && !other.isNullable) return false; 149 if (isNullable && !other.isNullable) return false;
147 other = TypeMask.nonForwardingMask(other); 150 other = TypeMask.nonForwardingMask(other);
148 // If other is union, delegate to UnionTypeMask.containsMask. 151 // If other is union, delegate to UnionTypeMask.containsMask.
149 if (other is! FlatTypeMask) return other.containsMask(this, classWorld); 152 if (other is! FlatTypeMask) return other.containsMask(this, classWorld);
150 // The other must be flat, so compare base and flags. 153 // The other must be flat, so compare base and flags.
151 FlatTypeMask flatOther = other; 154 FlatTypeMask flatOther = other;
152 ClassElement otherBase = flatOther.base; 155 ClassElement otherBase = flatOther.base;
153 // If other is exact, it only contains its base. 156 // If other is exact, it only contains its base.
154 // TODO(herhut): Get rid of isSingleImplementationOf. 157 // TODO(herhut): Get rid of isSingleImplementationOf.
155 if (flatOther.isExact) { 158 if (flatOther.isExact) {
156 return (isExact && base == otherBase) 159 return (isExact && base == otherBase) ||
157 || isSingleImplementationOf(otherBase, classWorld); 160 isSingleImplementationOf(otherBase, classWorld);
158 } 161 }
159 // If other is subclass, this has to be subclass, as well. Unless 162 // If other is subclass, this has to be subclass, as well. Unless
160 // flatOther.base covers all subtypes of this. Currently, we only 163 // flatOther.base covers all subtypes of this. Currently, we only
161 // consider object to behave that way. 164 // consider object to behave that way.
162 // TODO(herhut): Add check whether flatOther.base is superclass of 165 // TODO(herhut): Add check whether flatOther.base is superclass of
163 // all subclasses of this.base. 166 // all subclasses of this.base.
164 if (flatOther.isSubclass) { 167 if (flatOther.isSubclass) {
165 if (isSubtype) return (otherBase == classWorld.objectClass); 168 if (isSubtype) return (otherBase == classWorld.objectClass);
166 return classWorld.isSubclassOf(base, otherBase); 169 return classWorld.isSubclassOf(base, otherBase);
167 } 170 }
168 assert(flatOther.isSubtype); 171 assert(flatOther.isSubtype);
169 // Check whether this TypeMask satisfies otherBase's interface. 172 // Check whether this TypeMask satisfies otherBase's interface.
170 return satisfies(otherBase, classWorld); 173 return satisfies(otherBase, classWorld);
171 } 174 }
172 175
173 bool containsMask(TypeMask other, ClassWorld classWorld) { 176 bool containsMask(TypeMask other, ClassWorld classWorld) {
174 return other.isInMask(this, classWorld); 177 return other.isInMask(this, classWorld);
175 } 178 }
176 179
177 bool containsOnlyInt(ClassWorld classWorld) { 180 bool containsOnlyInt(ClassWorld classWorld) {
178 Backend backend = classWorld.backend; 181 Backend backend = classWorld.backend;
179 return base == classWorld.intClass 182 return base == classWorld.intClass ||
180 || base == backend.intImplementation 183 base == backend.intImplementation ||
181 || base == backend.positiveIntImplementation 184 base == backend.positiveIntImplementation ||
182 || base == backend.uint31Implementation 185 base == backend.uint31Implementation ||
183 || base == backend.uint32Implementation; 186 base == backend.uint32Implementation;
184 } 187 }
185 188
186 bool containsOnlyDouble(ClassWorld classWorld) { 189 bool containsOnlyDouble(ClassWorld classWorld) {
187 Backend backend = classWorld.backend; 190 Backend backend = classWorld.backend;
188 return base == classWorld.doubleClass 191 return base == classWorld.doubleClass ||
189 || base == backend.doubleImplementation; 192 base == backend.doubleImplementation;
190 } 193 }
191 194
192 bool containsOnlyNum(ClassWorld classWorld) { 195 bool containsOnlyNum(ClassWorld classWorld) {
193 Backend backend = classWorld.backend; 196 Backend backend = classWorld.backend;
194 return containsOnlyInt(classWorld) 197 return containsOnlyInt(classWorld) ||
195 || containsOnlyDouble(classWorld) 198 containsOnlyDouble(classWorld) ||
196 || base == classWorld.numClass 199 base == classWorld.numClass ||
197 || base == backend.numImplementation; 200 base == backend.numImplementation;
198 } 201 }
199 202
200 bool containsOnlyBool(ClassWorld classWorld) { 203 bool containsOnlyBool(ClassWorld classWorld) {
201 Backend backend = classWorld.backend; 204 Backend backend = classWorld.backend;
202 return base == classWorld.boolClass 205 return base == classWorld.boolClass || base == backend.boolImplementation;
203 || base == backend.boolImplementation;
204 } 206 }
205 207
206 bool containsOnlyString(ClassWorld classWorld) { 208 bool containsOnlyString(ClassWorld classWorld) {
207 Backend backend = classWorld.backend; 209 Backend backend = classWorld.backend;
208 return base == classWorld.stringClass 210 return base == classWorld.stringClass ||
209 || base == backend.stringImplementation; 211 base == backend.stringImplementation;
210 } 212 }
211 213
212 bool containsOnly(ClassElement cls) { 214 bool containsOnly(ClassElement cls) {
213 assert(cls.isDeclaration); 215 assert(cls.isDeclaration);
214 return base == cls; 216 return base == cls;
215 } 217 }
216 218
217 bool satisfies(ClassElement cls, ClassWorld classWorld) { 219 bool satisfies(ClassElement cls, ClassWorld classWorld) {
218 assert(cls.isDeclaration); 220 assert(cls.isDeclaration);
219 if (isEmptyOrNull) return false; 221 if (isEmptyOrNull) return false;
220 if (classWorld.isSubtypeOf(base, cls)) return true; 222 if (classWorld.isSubtypeOf(base, cls)) return true;
221 return false; 223 return false;
222 } 224 }
223 225
224 /** 226 /**
225 * Returns the [ClassElement] if this type represents a single class, 227 * Returns the [ClassElement] if this type represents a single class,
226 * otherwise returns `null`. This method is conservative. 228 * otherwise returns `null`. This method is conservative.
227 */ 229 */
228 ClassElement singleClass(ClassWorld classWorld) { 230 ClassElement singleClass(ClassWorld classWorld) {
229 if (isEmptyOrNull) return null; 231 if (isEmptyOrNull) return null;
230 if (isNullable) return null; // It is Null and some other class. 232 if (isNullable) return null; // It is Null and some other class.
231 if (isExact) { 233 if (isExact) {
232 return base; 234 return base;
233 } else if (isSubclass) { 235 } else if (isSubclass) {
234 return classWorld.hasAnyStrictSubclass(base) ? null : base; 236 return classWorld.hasAnyStrictSubclass(base) ? null : base;
235 } else { 237 } else {
236 assert(isSubtype); 238 assert(isSubtype);
237 return null; 239 return null;
238 } 240 }
239 } 241 }
240 242
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 } 387 }
386 388
387 static bool _isDisjointHelper( 389 static bool _isDisjointHelper(
388 FlatTypeMask a, FlatTypeMask b, ClassWorld classWorld) { 390 FlatTypeMask a, FlatTypeMask b, ClassWorld classWorld) {
389 if (!a.isSubclass && b.isSubclass) { 391 if (!a.isSubclass && b.isSubclass) {
390 return _isDisjointHelper(b, a, classWorld); 392 return _isDisjointHelper(b, a, classWorld);
391 } 393 }
392 assert(a.isSubclass || a.isSubtype); 394 assert(a.isSubclass || a.isSubtype);
393 assert(b.isSubtype); 395 assert(b.isSubtype);
394 var elements = a.isSubclass 396 var elements = a.isSubclass
395 ? classWorld.strictSubclassesOf(a.base) 397 ? classWorld.strictSubclassesOf(a.base)
396 : classWorld.strictSubtypesOf(a.base); 398 : classWorld.strictSubtypesOf(a.base);
397 for (var element in elements) { 399 for (var element in elements) {
398 if (classWorld.isSubtypeOf(element, b.base)) return false; 400 if (classWorld.isSubtypeOf(element, b.base)) return false;
399 } 401 }
400 return true; 402 return true;
401 } 403 }
402 404
403 TypeMask intersectionSame(FlatTypeMask other, ClassWorld classWorld) { 405 TypeMask intersectionSame(FlatTypeMask other, ClassWorld classWorld) {
404 assert(base == other.base); 406 assert(base == other.base);
405 // The two masks share the base type, so we must chose the most 407 // The two masks share the base type, so we must chose the most
406 // constraining kind (the lowest) of the two. Only if both masks 408 // constraining kind (the lowest) of the two. Only if both masks
407 // are nullable, will the result be nullable too. 409 // are nullable, will the result be nullable too.
408 // The result will be normalized, as the two inputs are normalized, too. 410 // The result will be normalized, as the two inputs are normalized, too.
409 int combined = (flags < other.flags) 411 int combined = (flags < other.flags)
410 ? flags & ((other.flags & 1) | ~1) 412 ? flags & ((other.flags & 1) | ~1)
411 : other.flags & ((flags & 1) | ~1); 413 : other.flags & ((flags & 1) | ~1);
412 if (flags == combined) { 414 if (flags == combined) {
413 return this; 415 return this;
414 } else if (other.flags == combined) { 416 } else if (other.flags == combined) {
415 return other; 417 return other;
416 } else { 418 } else {
417 return new FlatTypeMask.normalized(base, combined, classWorld); 419 return new FlatTypeMask.normalized(base, combined, classWorld);
418 } 420 }
419 } 421 }
420 422
421 TypeMask intersectionStrictSubclass(FlatTypeMask other, 423 TypeMask intersectionStrictSubclass(
422 ClassWorld classWorld) { 424 FlatTypeMask other, ClassWorld classWorld) {
423 assert(base != other.base); 425 assert(base != other.base);
424 assert(classWorld.isSubclassOf(other.base, base)); 426 assert(classWorld.isSubclassOf(other.base, base));
425 // If this mask isn't at least a subclass mask, then the 427 // If this mask isn't at least a subclass mask, then the
426 // intersection with the other mask is empty. 428 // intersection with the other mask is empty.
427 if (isExact) return intersectionEmpty(other); 429 if (isExact) return intersectionEmpty(other);
428 // Only the other mask puts constraints on the intersection mask, 430 // Only the other mask puts constraints on the intersection mask,
429 // so base the combined flags on the other mask. Only if both 431 // so base the combined flags on the other mask. Only if both
430 // masks are nullable, will the result be nullable too. 432 // masks are nullable, will the result be nullable too.
431 // The result is guaranteed to be normalized, as the other type 433 // The result is guaranteed to be normalized, as the other type
432 // was normalized. 434 // was normalized.
433 int combined = other.flags & ((flags & 1) | ~1); 435 int combined = other.flags & ((flags & 1) | ~1);
434 if (other.flags == combined) { 436 if (other.flags == combined) {
435 return other; 437 return other;
436 } else { 438 } else {
437 return new FlatTypeMask.normalized(other.base, combined, classWorld); 439 return new FlatTypeMask.normalized(other.base, combined, classWorld);
438 } 440 }
439 } 441 }
440 442
441 TypeMask intersectionStrictSubtype(FlatTypeMask other, 443 TypeMask intersectionStrictSubtype(
442 ClassWorld classWorld) { 444 FlatTypeMask other, ClassWorld classWorld) {
443 assert(base != other.base); 445 assert(base != other.base);
444 assert(classWorld.isSubtypeOf(other.base, base)); 446 assert(classWorld.isSubtypeOf(other.base, base));
445 if (!isSubtype) return intersectionHelper(other, classWorld); 447 if (!isSubtype) return intersectionHelper(other, classWorld);
446 // Only the other mask puts constraints on the intersection mask, 448 // Only the other mask puts constraints on the intersection mask,
447 // so base the combined flags on the other mask. Only if both 449 // so base the combined flags on the other mask. Only if both
448 // masks are nullable, will the result be nullable too. 450 // masks are nullable, will the result be nullable too.
449 // The result is guaranteed to be normalized, as the other type 451 // The result is guaranteed to be normalized, as the other type
450 // was normalized. 452 // was normalized.
451 int combined = other.flags & ((flags & 1) | ~1); 453 int combined = other.flags & ((flags & 1) | ~1);
452 if (other.flags == combined) { 454 if (other.flags == combined) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 // result will only be nullable if both masks are nullable. We have 500 // result will only be nullable if both masks are nullable. We have
499 // to normalize here, as we generate types based on new base classes. 501 // to normalize here, as we generate types based on new base classes.
500 int combined = (kind << 1) | (flags & other.flags & 1); 502 int combined = (kind << 1) | (flags & other.flags & 1);
501 Iterable<TypeMask> masks = candidates.map((ClassElement cls) { 503 Iterable<TypeMask> masks = candidates.map((ClassElement cls) {
502 return new FlatTypeMask.normalized(cls, combined, classWorld); 504 return new FlatTypeMask.normalized(cls, combined, classWorld);
503 }); 505 });
504 return UnionTypeMask.unionOf(masks, classWorld); 506 return UnionTypeMask.unionOf(masks, classWorld);
505 } 507 }
506 508
507 TypeMask intersectionEmpty(FlatTypeMask other) { 509 TypeMask intersectionEmpty(FlatTypeMask other) {
508 return isNullable && other.isNullable ? new TypeMask.empty() 510 return isNullable && other.isNullable
511 ? new TypeMask.empty()
509 : new TypeMask.nonNullEmpty(); 512 : new TypeMask.nonNullEmpty();
510 } 513 }
511 514
512 /** 515 /**
513 * Returns whether [element] will be the one used at runtime when being 516 * Returns whether [element] will be the one used at runtime when being
514 * invoked on an instance of [cls]. [selector] is used to ensure library 517 * invoked on an instance of [cls]. [selector] is used to ensure library
515 * privacy is taken into account. 518 * privacy is taken into account.
516 */ 519 */
517 static bool hasElementIn(ClassElement cls, 520 static bool hasElementIn(
518 Selector selector, 521 ClassElement cls, Selector selector, Element element) {
519 Element element) {
520 // Use [:implementation:] of [element] 522 // Use [:implementation:] of [element]
521 // because our function set only stores declarations. 523 // because our function set only stores declarations.
522 Element result = findMatchIn(cls, selector); 524 Element result = findMatchIn(cls, selector);
523 return result == null 525 return result == null
524 ? false 526 ? false
525 : result.implementation == element.implementation; 527 : result.implementation == element.implementation;
526 } 528 }
527 529
528 static Element findMatchIn(ClassElement cls, 530 static Element findMatchIn(ClassElement cls, Selector selector) {
529 Selector selector) {
530 // Use the [:implementation] of [cls] in case the found [element] 531 // Use the [:implementation] of [cls] in case the found [element]
531 // is in the patch class. 532 // is in the patch class.
532 return cls.implementation.lookupByName(selector.memberName); 533 return cls.implementation.lookupByName(selector.memberName);
533 } 534 }
534 535
535 /** 536 /**
536 * Returns whether [element] is a potential target when being 537 * Returns whether [element] is a potential target when being
537 * invoked on this type mask. [selector] is used to ensure library 538 * invoked on this type mask. [selector] is used to ensure library
538 * privacy is taken into account. 539 * privacy is taken into account.
539 */ 540 */
(...skipping 14 matching lines...) Expand all
554 return false; 555 return false;
555 } 556 }
556 557
557 ClassElement other = element.enclosingClass; 558 ClassElement other = element.enclosingClass;
558 if (other == backend.nullImplementation) { 559 if (other == backend.nullImplementation) {
559 return isNullable; 560 return isNullable;
560 } else if (isExact) { 561 } else if (isExact) {
561 return hasElementIn(self, selector, element); 562 return hasElementIn(self, selector, element);
562 } else if (isSubclass) { 563 } else if (isSubclass) {
563 assert(classWorld.isClosed); 564 assert(classWorld.isClosed);
564 return hasElementIn(self, selector, element) 565 return hasElementIn(self, selector, element) ||
565 || other.isSubclassOf(self) 566 other.isSubclassOf(self) ||
566 || classWorld.hasAnySubclassThatMixes(self, other); 567 classWorld.hasAnySubclassThatMixes(self, other);
567 } else { 568 } else {
568 assert(isSubtype); 569 assert(isSubtype);
569 assert(classWorld.isClosed); 570 assert(classWorld.isClosed);
570 bool result = hasElementIn(self, selector, element) 571 bool result = hasElementIn(self, selector, element) ||
571 || other.implementsInterface(self) 572 other.implementsInterface(self) ||
572 || classWorld.hasAnySubclassThatImplements(other, base) 573 classWorld.hasAnySubclassThatImplements(other, base) ||
573 || classWorld.hasAnySubclassOfMixinUseThatImplements(other, base); 574 classWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
574 if (result) return true; 575 if (result) return true;
575 // If the class is used as a mixin, we have to check if the element 576 // If the class is used as a mixin, we have to check if the element
576 // can be hit from any of the mixin applications. 577 // can be hit from any of the mixin applications.
577 Iterable<ClassElement> mixinUses = classWorld.mixinUsesOf(self); 578 Iterable<ClassElement> mixinUses = classWorld.mixinUsesOf(self);
578 return mixinUses.any((mixinApplication) => 579 return mixinUses.any((mixinApplication) =>
579 hasElementIn(mixinApplication, selector, element) 580 hasElementIn(mixinApplication, selector, element) ||
580 || other.isSubclassOf(mixinApplication) 581 other.isSubclassOf(mixinApplication) ||
581 || classWorld.hasAnySubclassThatMixes(mixinApplication, other)); 582 classWorld.hasAnySubclassThatMixes(mixinApplication, other));
582 } 583 }
583 } 584 }
584 585
585 /** 586 /**
586 * Returns whether a [selector] call on an instance of [cls] 587 * Returns whether a [selector] call on an instance of [cls]
587 * will hit a method at runtime, and not go through [noSuchMethod]. 588 * will hit a method at runtime, and not go through [noSuchMethod].
588 */ 589 */
589 static bool hasConcreteMatch(ClassElement cls, 590 static bool hasConcreteMatch(
590 Selector selector, 591 ClassElement cls, Selector selector, ClassWorld world) {
591 ClassWorld world) {
592 assert(invariant(cls, world.isInstantiated(cls), 592 assert(invariant(cls, world.isInstantiated(cls),
593 message: '$cls has not been instantiated.')); 593 message: '$cls has not been instantiated.'));
594 Element element = findMatchIn(cls, selector); 594 Element element = findMatchIn(cls, selector);
595 if (element == null) return false; 595 if (element == null) return false;
596 596
597 if (element.isAbstract) { 597 if (element.isAbstract) {
598 ClassElement enclosingClass = element.enclosingClass; 598 ClassElement enclosingClass = element.enclosingClass;
599 return hasConcreteMatch(enclosingClass.superclass, selector, world); 599 return hasConcreteMatch(enclosingClass.superclass, selector, world);
600 } 600 }
601 return selector.appliesUntyped(element, world); 601 return selector.appliesUntyped(element, world);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
654 bool needsNoSuchMethod(ClassElement cls) { 654 bool needsNoSuchMethod(ClassElement cls) {
655 // We can skip uninstantiated subclasses. 655 // We can skip uninstantiated subclasses.
656 // TODO(johnniwinther): Put filtering into the (Class)World. 656 // TODO(johnniwinther): Put filtering into the (Class)World.
657 if (!classWorld.isInstantiated(cls)) { 657 if (!classWorld.isInstantiated(cls)) {
658 return false; 658 return false;
659 } 659 }
660 // We can just skip abstract classes because we know no 660 // We can just skip abstract classes because we know no
661 // instance of them will be created at runtime, and 661 // instance of them will be created at runtime, and
662 // therefore there is no instance that will require 662 // therefore there is no instance that will require
663 // [noSuchMethod] handling. 663 // [noSuchMethod] handling.
664 return !cls.isAbstract 664 return !cls.isAbstract && !hasConcreteMatch(cls, selector, classWorld);
665 && !hasConcreteMatch(cls, selector, classWorld);
666 } 665 }
667 666
668 bool baseNeedsNoSuchMethod = needsNoSuchMethod(base); 667 bool baseNeedsNoSuchMethod = needsNoSuchMethod(base);
669 if (isExact || baseNeedsNoSuchMethod) { 668 if (isExact || baseNeedsNoSuchMethod) {
670 return baseNeedsNoSuchMethod; 669 return baseNeedsNoSuchMethod;
671 } 670 }
672 671
673 Iterable<ClassElement> subclassesToCheck; 672 Iterable<ClassElement> subclassesToCheck;
674 if (isSubtype) { 673 if (isSubtype) {
675 subclassesToCheck = classWorld.strictSubtypesOf(base); 674 subclassesToCheck = classWorld.strictSubtypesOf(base);
676 } else { 675 } else {
677 assert(isSubclass); 676 assert(isSubclass);
678 subclassesToCheck = classWorld.strictSubclassesOf(base); 677 subclassesToCheck = classWorld.strictSubclassesOf(base);
679 } 678 }
680 679
681 return subclassesToCheck != null && 680 return subclassesToCheck != null &&
682 subclassesToCheck.any(needsNoSuchMethod); 681 subclassesToCheck.any(needsNoSuchMethod);
683 } 682 }
684 683
685 Element locateSingleElement(Selector selector, 684 Element locateSingleElement(
686 TypeMask mask, 685 Selector selector, TypeMask mask, Compiler compiler) {
687 Compiler compiler) {
688 if (isEmptyOrNull) return null; 686 if (isEmptyOrNull) return null;
689 Iterable<Element> targets = 687 Iterable<Element> targets =
690 compiler.world.allFunctions.filter(selector, mask); 688 compiler.world.allFunctions.filter(selector, mask);
691 if (targets.length != 1) return null; 689 if (targets.length != 1) return null;
692 Element result = targets.first; 690 Element result = targets.first;
693 ClassElement enclosing = result.enclosingClass; 691 ClassElement enclosing = result.enclosingClass;
694 // We only return the found element if it is guaranteed to be 692 // We only return the found element if it is guaranteed to be
695 // implemented on the exact receiver type. It could be found in a 693 // implemented on the exact receiver type. It could be found in a
696 // subclass or in an inheritance-wise unrelated class in case of 694 // subclass or in an inheritance-wise unrelated class in case of
697 // subtype selectors. 695 // subtype selectors.
698 return (base.isSubclassOf(enclosing)) ? result : null; 696 return (base.isSubclassOf(enclosing)) ? result : null;
699 } 697 }
700 698
701 bool operator ==(var other) { 699 bool operator ==(var other) {
702 if (identical(this, other)) return true; 700 if (identical(this, other)) return true;
703 if (other is !FlatTypeMask) return false; 701 if (other is! FlatTypeMask) return false;
704 FlatTypeMask otherMask = other; 702 FlatTypeMask otherMask = other;
705 return (flags == otherMask.flags) && (base == otherMask.base); 703 return (flags == otherMask.flags) && (base == otherMask.base);
706 } 704 }
707 705
708 int get hashCode { 706 int get hashCode {
709 return (base == null ? 0 : base.hashCode) + 31 * flags.hashCode; 707 return (base == null ? 0 : base.hashCode) + 31 * flags.hashCode;
710 } 708 }
711 709
712 String toString() { 710 String toString() {
713 if (isEmptyOrNull) return isNullable ? '[null]' : '[empty]'; 711 if (isEmptyOrNull) return isNullable ? '[null]' : '[empty]';
714 StringBuffer buffer = new StringBuffer(); 712 StringBuffer buffer = new StringBuffer();
715 if (isNullable) buffer.write('null|'); 713 if (isNullable) buffer.write('null|');
716 if (isExact) buffer.write('exact='); 714 if (isExact) buffer.write('exact=');
717 if (isSubclass) buffer.write('subclass='); 715 if (isSubclass) buffer.write('subclass=');
718 if (isSubtype) buffer.write('subtype='); 716 if (isSubtype) buffer.write('subtype=');
719 buffer.write(base.name); 717 buffer.write(base.name);
720 return "[$buffer]"; 718 return "[$buffer]";
721 } 719 }
722 720
723 static Set<ClassElement> commonContainedClasses(FlatTypeMask x, 721 static Set<ClassElement> commonContainedClasses(
724 FlatTypeMask y, 722 FlatTypeMask x, FlatTypeMask y, ClassWorld classWorld) {
725 ClassWorld classWorld) {
726 Iterable<ClassElement> xSubset = containedSubset(x, classWorld); 723 Iterable<ClassElement> xSubset = containedSubset(x, classWorld);
727 if (xSubset == null) return null; 724 if (xSubset == null) return null;
728 Iterable<ClassElement> ySubset = containedSubset(y, classWorld); 725 Iterable<ClassElement> ySubset = containedSubset(y, classWorld);
729 if (ySubset == null) return null; 726 if (ySubset == null) return null;
730 return xSubset.toSet().intersection(ySubset.toSet()); 727 return xSubset.toSet().intersection(ySubset.toSet());
731 } 728 }
732 729
733 static Iterable<ClassElement> containedSubset(FlatTypeMask x, 730 static Iterable<ClassElement> containedSubset(
734 ClassWorld classWorld) { 731 FlatTypeMask x, ClassWorld classWorld) {
735 ClassElement element = x.base; 732 ClassElement element = x.base;
736 if (x.isExact) { 733 if (x.isExact) {
737 return null; 734 return null;
738 } else if (x.isSubclass) { 735 } else if (x.isSubclass) {
739 return classWorld.strictSubclassesOf(element); 736 return classWorld.strictSubclassesOf(element);
740 } else { 737 } else {
741 assert(x.isSubtype); 738 assert(x.isSubtype);
742 return classWorld.strictSubtypesOf(element); 739 return classWorld.strictSubtypesOf(element);
743 } 740 }
744 } 741 }
745 } 742 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/types/dictionary_type_mask.dart ('k') | pkg/compiler/lib/src/types/forwarding_type_mask.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698