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

Side by Side Diff: pkg/compiler/lib/src/universe/class_set.dart

Issue 1627333002: Optimize subclass/subtype queries (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Use strictSubtypeCount Created 4 years, 11 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
« no previous file with comments | « pkg/compiler/lib/src/types/union_type_mask.dart ('k') | pkg/compiler/lib/src/world.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library dart2js.world.class_set; 5 library dart2js.world.class_set;
6 6
7 import 'dart:collection' show 7 import 'dart:collection' show
8 IterableBase; 8 IterableBase;
9 import '../common.dart';
9 import '../elements/elements.dart' show 10 import '../elements/elements.dart' show
10 ClassElement; 11 ClassElement;
11 import '../util/enumset.dart' show 12 import '../util/enumset.dart' show
12 EnumSet; 13 EnumSet;
13 import '../util/util.dart' show 14 import '../util/util.dart' show
14 Link; 15 Link;
15 16
16 /// Enum for the different kinds of instantiation of a class. 17 /// Enum for the different kinds of instantiation of a class.
17 enum Instantiation { 18 enum Instantiation {
18 UNINSTANTIATED, 19 UNINSTANTIATED,
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 } 86 }
86 if (includeIndirectlyInstantiated) { 87 if (includeIndirectlyInstantiated) {
87 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); 88 mask.add(Instantiation.INDIRECTLY_INSTANTIATED);
88 } 89 }
89 if (includeUninstantiated) { 90 if (includeUninstantiated) {
90 mask.add(Instantiation.UNINSTANTIATED); 91 mask.add(Instantiation.UNINSTANTIATED);
91 } 92 }
92 return mask; 93 return mask;
93 } 94 }
94 95
96 final ClassHierarchyNode parentNode;
95 final ClassElement cls; 97 final ClassElement cls;
96 final EnumSet<Instantiation> _mask = 98 final EnumSet<Instantiation> _mask =
97 new EnumSet<Instantiation>.fromValues( 99 new EnumSet<Instantiation>.fromValues(
98 const <Instantiation>[Instantiation.UNINSTANTIATED]); 100 const <Instantiation>[Instantiation.UNINSTANTIATED]);
99 101
100 ClassElement _leastUpperInstantiatedSubclass; 102 ClassElement _leastUpperInstantiatedSubclass;
103 int _instantiatedSubclassCount = 0;
101 104
102 /// `true` if [cls] has been directly instantiated. 105 /// `true` if [cls] has been directly instantiated.
103 /// 106 ///
104 /// For instance `C` but _not_ `B` in: 107 /// For instance `C` but _not_ `B` in:
105 /// class B {} 108 /// class B {}
106 /// class C extends B {} 109 /// class C extends B {}
107 /// main() => new C(); 110 /// main() => new C();
108 /// 111 ///
109 bool get isDirectlyInstantiated => 112 bool get isDirectlyInstantiated =>
110 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED); 113 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED);
111 114
112 void set isDirectlyInstantiated(bool value) { 115 void set isDirectlyInstantiated(bool value) {
113 if (value != isDirectlyInstantiated) { 116 if (value != isDirectlyInstantiated) {
117 ClassHierarchyNode parent = parentNode;
114 if (value) { 118 if (value) {
115 _mask.remove(Instantiation.UNINSTANTIATED); 119 _mask.remove(Instantiation.UNINSTANTIATED);
116 _mask.add(Instantiation.DIRECTLY_INSTANTIATED); 120 _mask.add(Instantiation.DIRECTLY_INSTANTIATED);
121 while (parent != null) {
122 parent._updateInstantiatedSubclassCount(1);
123 parent = parent.parentNode;
124 }
117 } else { 125 } else {
118 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); 126 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED);
119 if (_mask.isEmpty) { 127 if (_mask.isEmpty) {
120 _mask.add(Instantiation.UNINSTANTIATED); 128 _mask.add(Instantiation.UNINSTANTIATED);
121 } 129 }
130 while (parent != null) {
131 parent._updateInstantiatedSubclassCount(-1);
132 parent = parent.parentNode;
133 }
122 } 134 }
123 } 135 }
124 } 136 }
125 137
126 /// `true` if [cls] has been instantiated through subclasses. 138 /// `true` if [cls] has been instantiated through subclasses.
127 /// 139 ///
128 /// For instance `A` and `B` but _not_ `C` in: 140 /// For instance `A` and `B` but _not_ `C` in:
129 /// class A {} 141 /// class A {}
130 /// class B extends A {} 142 /// class B extends A {}
131 /// class C extends B {} 143 /// class C extends B {}
132 /// main() => [new B(), new C()]; 144 /// main() => [new B(), new C()];
133 /// 145 ///
134 bool get isIndirectlyInstantiated => 146 bool get isIndirectlyInstantiated => _instantiatedSubclassCount > 0;
135 _mask.contains(Instantiation.INDIRECTLY_INSTANTIATED);
136 147
137 void set isIndirectlyInstantiated(bool value) { 148 /// The number of strict subclasses that are directly or indirectly
138 if (value != isIndirectlyInstantiated) { 149 /// instantiated.
139 if (value) { 150 int get instantiatedSubclassCount => _instantiatedSubclassCount;
151
152 void _updateInstantiatedSubclassCount(int change) {
153 bool before = isIndirectlyInstantiated;
154 _instantiatedSubclassCount += change;
155 bool after = isIndirectlyInstantiated;
156 if (before != after) {
157 if (after) {
140 _mask.remove(Instantiation.UNINSTANTIATED); 158 _mask.remove(Instantiation.UNINSTANTIATED);
141 _mask.add(Instantiation.INDIRECTLY_INSTANTIATED); 159 _mask.add(Instantiation.INDIRECTLY_INSTANTIATED);
142 } else { 160 } else {
143 _mask.remove(Instantiation.INDIRECTLY_INSTANTIATED); 161 _mask.remove(Instantiation.INDIRECTLY_INSTANTIATED);
144 if (_mask.isEmpty) { 162 if (_mask.isEmpty) {
145 _mask.add(Instantiation.UNINSTANTIATED); 163 _mask.add(Instantiation.UNINSTANTIATED);
146 } 164 }
147 } 165 }
148 } 166 }
149 } 167 }
150 168
151 /// The nodes for the direct subclasses of [cls]. 169 /// The nodes for the direct subclasses of [cls].
152 Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>(); 170 Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>();
153 171
154 ClassHierarchyNode(this.cls); 172 ClassHierarchyNode(this.parentNode, this.cls) {
173 if (parentNode != null) {
174 parentNode.addDirectSubclass(this);
175 }
176 }
155 177
156 /// Adds [subclass] as a direct subclass of [cls]. 178 /// Adds [subclass] as a direct subclass of [cls].
157 void addDirectSubclass(ClassHierarchyNode subclass) { 179 void addDirectSubclass(ClassHierarchyNode subclass) {
158 assert(subclass.cls.superclass == cls); 180 assert(subclass.cls.superclass == cls);
159 assert(!_directSubclasses.contains(subclass)); 181 assert(!_directSubclasses.contains(subclass));
160 _directSubclasses = _directSubclasses.prepend(subclass); 182 _directSubclasses = _directSubclasses.prepend(subclass);
161 } 183 }
162 184
163 /// Returns `true` if [other] is contained in the subtree of this node. 185 /// Returns `true` if [other] is contained in the subtree of this node.
164 /// 186 ///
165 /// This means that [other] is a subclass of [cls]. 187 /// This means that [other] is a subclass of [cls].
166 bool contains(ClassElement other) { 188 bool contains(ClassElement other) {
167 while (other != null) { 189 while (other != null) {
168 if (cls == other) return true; 190 if (cls == other) return true;
169 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; 191 if (cls.hierarchyDepth >= other.hierarchyDepth) return false;
170 other = other.superclass; 192 other = other.superclass;
171 } 193 }
172 return false; 194 return false;
173 } 195 }
174 196
175 /// `true` if [cls] has been directly or indirectly instantiated. 197 /// `true` if [cls] has been directly or indirectly instantiated.
176 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; 198 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated;
177 199
178 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. 200 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
179 /// 201 ///
180 /// The directly instantiated, indirectly instantiated and uninstantiated
181 /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
182 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
183 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
184 Iterable<ClassElement> subclasses(
185 {bool includeDirectlyInstantiated: true,
186 bool includeIndirectlyInstantiated: true,
187 bool includeUninstantiated: true,
188 bool strict: false}) {
189 EnumSet<Instantiation> mask = createMask(
190 includeDirectlyInstantiated: includeDirectlyInstantiated,
191 includeIndirectlyInstantiated:includeIndirectlyInstantiated,
192 includeUninstantiated: includeUninstantiated);
193 return subclassesByMask(mask, strict: strict);
194 }
195
196 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
197 ///
198 /// Subclasses are included if their instantiation properties intersect with 202 /// Subclasses are included if their instantiation properties intersect with
199 /// their corresponding [Instantiation] values in [mask]. If [strict] is 203 /// their corresponding [Instantiation] values in [mask]. If [strict] is
200 /// `true`, [cls] itself is _not_ returned. 204 /// `true`, [cls] itself is _not_ returned.
201 Iterable<ClassElement> subclassesByMask( 205 Iterable<ClassElement> subclassesByMask(
202 EnumSet<Instantiation> mask, 206 EnumSet<Instantiation> mask,
203 {bool strict: false}) { 207 {bool strict: false}) {
204 return new ClassHierarchyNodeIterable( 208 return new ClassHierarchyNodeIterable(
205 this, mask, includeRoot: !strict); 209 this, mask, includeRoot: !strict);
206 } 210 }
207 211
212 /// Applies [predicate] to each subclass of [cls] matching the criteria
213 /// specified by [mask] and [strict]. If [predicate] returns `true` on a
214 /// class, visitation is stopped immediately and the function returns `true`.
215 ///
216 /// [predicate] is applied to subclasses if their instantiation properties
217 /// intersect with their corresponding [Instantiation] values in [mask]. If
218 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
219 bool anySubclass(
220 bool predicate(ClassElement cls),
221 EnumSet<Instantiation> mask,
222 {bool strict: false}) {
223
224 ForEach wrapper(ClassElement cls) {
225 return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
226 }
227 return forEachSubclass(wrapper, mask, strict: strict) == ForEach.STOP;
228 }
229
230 /// Applies [f] to each subclass of [cls] matching the criteria specified by
231 /// [mask] and [strict].
232 ///
233 /// [f] is a applied to subclasses if their instantiation properties intersect
234 /// with their corresponding [Instantiation] values in [mask]. If [strict] is
235 /// `true`, [f] is _not_ called on [cls] itself.
236 ///
237 /// The visitation of subclasses can be cut short by the return value of [f].
238 /// If [ForEach.STOP] is returned, no further classes are visited and the
239 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
240 /// subclasses of the last visited class are skipped, but visitation
241 /// continues. The return value of the function is either [ForEach.STOP], if
242 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
243 /// the end.
244 ForEach forEachSubclass(
245 ForEachFunction f,
246 EnumSet<Instantiation> mask,
247 {bool strict: false}) {
248 ForEach forEach;
249 if (!strict && mask.intersects(_mask)) {
250 forEach = f(cls);
251 }
252 // Interpret `forEach == null` as `forEach == ForEach.CONTINUE`.
253 forEach ??= ForEach.CONTINUE;
254
255 if (forEach == ForEach.CONTINUE) {
256 if (mask.contains(Instantiation.UNINSTANTIATED) || isInstantiated) {
257 for (ClassHierarchyNode subclass in _directSubclasses) {
258 ForEach subForEach = subclass.forEachSubclass(f, mask);
259 if (subForEach == ForEach.STOP) {
260 return subForEach;
261 }
262 }
263 }
264 }
265 if (forEach == ForEach.STOP) {
266 return forEach;
267 }
268 return ForEach.CONTINUE;
269 }
270
208 /// Returns the most specific subclass of [cls] (including [cls]) that is 271 /// Returns the most specific subclass of [cls] (including [cls]) that is
209 /// directly instantiated or a superclass of all directly instantiated 272 /// directly instantiated or a superclass of all directly instantiated
210 /// subclasses. If [cls] is not instantiated, `null` is returned. 273 /// subclasses. If [cls] is not instantiated, `null` is returned.
211 ClassElement getLubOfInstantiatedSubclasses() { 274 ClassElement getLubOfInstantiatedSubclasses() {
212 if (!isInstantiated) return null; 275 if (!isInstantiated) return null;
213 if (_leastUpperInstantiatedSubclass == null) { 276 if (_leastUpperInstantiatedSubclass == null) {
214 _leastUpperInstantiatedSubclass = 277 _leastUpperInstantiatedSubclass =
215 _computeLeastUpperInstantiatedSubclass(); 278 _computeLeastUpperInstantiatedSubclass();
216 } 279 }
217 return _leastUpperInstantiatedSubclass; 280 return _leastUpperInstantiatedSubclass;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 if (sorted) { 331 if (sorted) {
269 subclasses = _directSubclasses.toList()..sort((a, b) { 332 subclasses = _directSubclasses.toList()..sort((a, b) {
270 return a.cls.name.compareTo(b.cls.name); 333 return a.cls.name.compareTo(b.cls.name);
271 }); 334 });
272 } 335 }
273 bool needsComma = false; 336 bool needsComma = false;
274 for (ClassHierarchyNode child in subclasses) { 337 for (ClassHierarchyNode child in subclasses) {
275 if (instantiatedOnly && !child.isInstantiated) { 338 if (instantiatedOnly && !child.isInstantiated) {
276 continue; 339 continue;
277 } 340 }
278 if (withRespectTo != null && !child.subclasses().any(isRelatedTo)) { 341 if (withRespectTo != null &&
342 !child.anySubclass(isRelatedTo, ClassHierarchyNode.ALL)) {
279 continue; 343 continue;
280 } 344 }
281 if (needsComma) { 345 if (needsComma) {
282 sb.write(',\n'); 346 sb.write(',\n');
283 } else { 347 } else {
284 sb.write('\n'); 348 sb.write('\n');
285 } 349 }
286 child.printOn( 350 child.printOn(
287 sb, 351 sb,
288 '$indentation ', 352 '$indentation ',
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 class ClassSet { 424 class ClassSet {
361 final ClassHierarchyNode node; 425 final ClassHierarchyNode node;
362 ClassElement _leastUpperInstantiatedSubtype; 426 ClassElement _leastUpperInstantiatedSubtype;
363 427
364 List<ClassHierarchyNode> _directSubtypes; 428 List<ClassHierarchyNode> _directSubtypes;
365 429
366 ClassSet(this.node); 430 ClassSet(this.node);
367 431
368 ClassElement get cls => node.cls; 432 ClassElement get cls => node.cls;
369 433
370 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. 434 /// Returns the number of directly instantiated subtypes of [cls].
371 /// 435 int get instantiatedSubtypeCount {
372 /// The directly instantiated, indirectly instantiated and uninstantiated 436 int count = node.instantiatedSubclassCount;
373 /// subclasses of [cls] are returned if [includeDirectlyInstantiated], 437 if (_directSubtypes != null) {
374 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, 438 for (ClassHierarchyNode subtypeNode in _directSubtypes) {
375 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. 439 if (subtypeNode.isDirectlyInstantiated) {
376 Iterable<ClassElement> subclasses( 440 count++;
377 {bool includeDirectlyInstantiated: true, 441 }
378 bool includeIndirectlyInstantiated: true, 442 count += subtypeNode.instantiatedSubclassCount;
379 bool includeUninstantiated: true, 443 }
380 bool strict: false}) { 444 }
381 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( 445 return count;
382 includeDirectlyInstantiated: includeDirectlyInstantiated, 446 }
383 includeIndirectlyInstantiated:includeIndirectlyInstantiated, 447
384 includeUninstantiated: includeUninstantiated); 448 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of
385 return subclassesByMask(mask, strict: strict); 449 /// [cls].
450 bool get hasOnlyInstantiatedSubclasses {
Siggi Cherem (dart-lang) 2016/02/09 23:40:12 I was looking into something else and run into thi
Johnni Winther 2016/02/10 09:32:08 Yes. The cause is that implements is transitive. T
451 if (_directSubtypes != null) {
452 for (ClassHierarchyNode subtypeNode in _directSubtypes) {
453 if (subtypeNode.isInstantiated) {
454 return false;
455 }
456 }
457 }
458 return true;
386 } 459 }
387 460
388 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. 461 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
389 /// 462 ///
390 /// Subclasses are included if their instantiation properties intersect with 463 /// Subclasses are included if their instantiation properties intersect with
391 /// their corresponding [Instantiation] values in [mask]. If [strict] is 464 /// their corresponding [Instantiation] values in [mask]. If [strict] is
392 /// `true`, [cls] itself is _not_ returned. 465 /// `true`, [cls] itself is _not_ returned.
393 Iterable<ClassElement> subclassesByMask( 466 Iterable<ClassElement> subclassesByMask(
394 EnumSet<Instantiation> mask, 467 EnumSet<Instantiation> mask,
395 {bool strict: false}) { 468 {bool strict: false}) {
(...skipping 11 matching lines...) Expand all
407 bool includeIndirectlyInstantiated: true, 480 bool includeIndirectlyInstantiated: true,
408 bool includeUninstantiated: true, 481 bool includeUninstantiated: true,
409 bool strict: false}) { 482 bool strict: false}) {
410 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( 483 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask(
411 includeDirectlyInstantiated: includeDirectlyInstantiated, 484 includeDirectlyInstantiated: includeDirectlyInstantiated,
412 includeIndirectlyInstantiated:includeIndirectlyInstantiated, 485 includeIndirectlyInstantiated:includeIndirectlyInstantiated,
413 includeUninstantiated: includeUninstantiated); 486 includeUninstantiated: includeUninstantiated);
414 return subtypesByMask(mask, strict: strict); 487 return subtypesByMask(mask, strict: strict);
415 } 488 }
416 489
417
418 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. 490 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
419 /// 491 ///
420 /// Subtypes are included if their instantiation properties intersect with 492 /// Subtypes are included if their instantiation properties intersect with
421 /// their corresponding [Instantiation] values in [mask]. If [strict] is 493 /// their corresponding [Instantiation] values in [mask]. If [strict] is
422 /// `true`, [cls] itself is _not_ returned. 494 /// `true`, [cls] itself is _not_ returned.
423 Iterable<ClassElement> subtypesByMask( 495 Iterable<ClassElement> subtypesByMask(
424 EnumSet<Instantiation> mask, 496 EnumSet<Instantiation> mask,
425 {bool strict: false}) { 497 {bool strict: false}) {
426 if (_directSubtypes == null) { 498 if (_directSubtypes == null) {
427 return node.subclassesByMask( 499 return node.subclassesByMask(
428 mask, 500 mask,
429 strict: strict); 501 strict: strict);
430 } 502 }
431 503
432 return new SubtypesIterable.SubtypesIterator(this, 504 return new SubtypesIterable.SubtypesIterator(this,
433 mask, 505 mask,
434 includeRoot: !strict); 506 includeRoot: !strict);
435 } 507 }
436 508
509 /// Applies [predicate] to each subclass of [cls] matching the criteria
510 /// specified by [mask] and [strict]. If [predicate] returns `true` on a
511 /// class, visitation is stopped immediately and the function returns `true`.
512 ///
513 /// [predicate] is applied to subclasses if their instantiation properties
514 /// intersect with their corresponding [Instantiation] values in [mask]. If
515 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
516 bool anySubclass(
517 bool predicate(ClassElement cls),
518 EnumSet<Instantiation> mask,
519 {bool strict: false}) {
520 return node.anySubclass(predicate, mask, strict: strict);
521 }
522
523 /// Applies [f] to each subclass of [cls] matching the criteria specified by
524 /// [mask] and [strict].
525 ///
526 /// [f] is a applied to subclasses if their instantiation properties intersect
527 /// with their corresponding [Instantiation] values in [mask]. If [strict] is
528 /// `true`, [f] is _not_ called on [cls] itself.
529 ///
530 /// The visitation of subclasses can be cut short by the return value of [f].
531 /// If [ForEach.STOP] is returned, no further classes are visited and the
532 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
533 /// subclasses of the last visited class are skipped, but visitation
534 /// continues. The return value of the function is either [ForEach.STOP], if
535 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
536 /// the end.
537 ForEach forEachSubclass(
538 ForEachFunction f,
539 EnumSet<Instantiation> mask,
540 {bool strict: false}) {
541 return node.forEachSubclass(f, mask, strict: strict);
542 }
543
544 /// Applies [predicate] to each subtype of [cls] matching the criteria
545 /// specified by [mask] and [strict]. If [predicate] returns `true` on a
546 /// class, visitation is stopped immediately and the function returns `true`.
547 ///
548 /// [predicate] is applied to subtypes if their instantiation properties
549 /// intersect with their corresponding [Instantiation] values in [mask]. If
550 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
551 bool anySubtype(
552 bool predicate(ClassElement cls),
553 EnumSet<Instantiation> mask,
554 {bool strict: false}) {
555
556 ForEach wrapper(ClassElement cls) {
557 return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
558 }
559 return forEachSubtype(wrapper, mask, strict: strict) == ForEach.STOP;
560 }
561
562 /// Applies [f] to each subtype of [cls] matching the criteria specified by
563 /// [mask] and [strict].
564 ///
565 /// [f] is a applied to subtypes if their instantiation properties intersect
566 /// with their corresponding [Instantiation] values in [mask]. If [strict] is
567 /// `true`, [f] is _not_ called on [cls] itself.
568 ///
569 /// The visitation of subtypes can be cut short by the return value of [f].
570 /// If [ForEach.STOP] is returned, no further classes are visited and the
571 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
572 /// subclasses of the last visited class are skipped, but visitation
573 /// continues. The return value of the function is either [ForEach.STOP], if
574 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
575 /// the end.
576 ForEach forEachSubtype(
577 ForEachFunction f,
578 EnumSet<Instantiation> mask,
579 {bool strict: false}) {
580 ForEach forEach = node.forEachSubclass(f, mask, strict: strict);
581 forEach ??= ForEach.CONTINUE;
Siggi Cherem (dart-lang) 2016/02/06 00:17:26 nit: here and elsewhere, I rather keep the variabl
Johnni Winther 2016/02/10 09:32:08 Will do. Code motion caused this ;-)
582 if (forEach == ForEach.CONTINUE && _directSubtypes != null) {
583 for (ClassHierarchyNode subclass in _directSubtypes) {
584 ForEach subForEach = subclass.forEachSubclass(f, mask);
585 if (subForEach == ForEach.STOP) {
586 return subForEach;
587 }
588 }
589 }
590 assert(forEach != ForEach.SKIP_SUBCLASSES);
591 return forEach;
592 }
593
437 /// Adds [subtype] as a subtype of [cls]. 594 /// Adds [subtype] as a subtype of [cls].
438 void addSubtype(ClassHierarchyNode subtype) { 595 void addSubtype(ClassHierarchyNode subtype) {
439 if (node.contains(subtype.cls)) { 596 if (node.contains(subtype.cls)) {
440 return; 597 return;
441 } 598 }
442 if (_directSubtypes == null) { 599 if (_directSubtypes == null) {
443 _directSubtypes = <ClassHierarchyNode>[subtype]; 600 _directSubtypes = <ClassHierarchyNode>[subtype];
444 } else { 601 } else {
445 int hierarchyDepth = subtype.cls.hierarchyDepth; 602 int hierarchyDepth = subtype.cls.hierarchyDepth;
446 List<ClassHierarchyNode> newSubtypes = <ClassHierarchyNode>[]; 603 List<ClassHierarchyNode> newSubtypes = <ClassHierarchyNode>[];
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 } 845 }
689 while (hierarchyNodes.moveNext()) { 846 while (hierarchyNodes.moveNext()) {
690 elements = hierarchyNodes.current.subclassesByMask(mask).iterator; 847 elements = hierarchyNodes.current.subclassesByMask(mask).iterator;
691 if (elements.moveNext()) { 848 if (elements.moveNext()) {
692 return true; 849 return true;
693 } 850 }
694 } 851 }
695 return false; 852 return false;
696 } 853 }
697 } 854 }
855
856 /// Enum values returned from the [ForEachFunction] provided to the `forEachX`
857 /// functions of [ClassHierarchyNode] and [ClassSet]. The value is used to
858 /// control the continued iteration.
859 enum ForEach {
Siggi Cherem (dart-lang) 2016/02/06 00:17:26 naming nit: could we rename this to something that
Johnni Winther 2016/02/10 09:32:08 If find the latter confusing but like enum class n
860 /// Iteration continues.
861 CONTINUE,
862 /// Iteration stops immediately.
863 STOP,
864 /// Iteration skips the subclasses of the current class.
865 SKIP_SUBCLASSES,
866 }
867
868 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode]
869 /// and [ClassSet]. The return value controls the continued iteration. If `null`
870 /// is returned, iteration continues to the end.
871 typedef ForEach ForEachFunction(ClassElement cls);
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/types/union_type_mask.dart ('k') | pkg/compiler/lib/src/world.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698