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

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

Issue 1304083008: Add ClassSet to support ClassWorld.strictSubtypesOf (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 5 years, 3 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) 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 IterableBase; 7 import 'dart:collection' show IterableBase;
8 import '../elements/elements.dart' show ClassElement; 8 import '../elements/elements.dart' show ClassElement;
9 import '../util/util.dart' show Link; 9 import '../util/util.dart' show Link;
10 10
11 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. 11 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s.
12 /// 12 ///
13 /// This is used by the [ClassWorld] to perform queries on subclass and subtype 13 /// This is used by the [ClassWorld] to perform queries on subclass and subtype
14 /// relations. 14 /// relations.
15 // TODO(johnniwinther): Use this for `ClassWorld.subtypesOf`. 15 ///
16 /// For this class hierarchy:
17 ///
18 /// class A {}
19 /// class B extends A {}
20 /// class C extends A {}
21 /// class D extends B {}
22 /// class E extends D {}
23 ///
24 /// the [ClassHierarchyNode]s form this subclass tree:
25 ///
26 /// Object
27 /// |
28 /// A
29 /// / \
30 /// B C
31 /// |
32 /// D
33 /// |
34 /// E
35 ///
16 class ClassHierarchyNode { 36 class ClassHierarchyNode {
17 final ClassElement cls; 37 final ClassElement cls;
18 38
19 /// `true` if [cls] has been directly instantiated. 39 /// `true` if [cls] has been directly instantiated.
20 /// 40 ///
21 /// For instance `C` but _not_ `B` in: 41 /// For instance `C` but _not_ `B` in:
22 /// class B {} 42 /// class B {}
23 /// class C extends B {} 43 /// class C extends B {}
24 /// main() => new C(); 44 /// main() => new C();
25 /// 45 ///
(...skipping 14 matching lines...) Expand all
40 60
41 ClassHierarchyNode(this.cls); 61 ClassHierarchyNode(this.cls);
42 62
43 /// Adds [subclass] as a direct subclass of [cls]. 63 /// Adds [subclass] as a direct subclass of [cls].
44 void addDirectSubclass(ClassHierarchyNode subclass) { 64 void addDirectSubclass(ClassHierarchyNode subclass) {
45 assert(subclass.cls.superclass == cls); 65 assert(subclass.cls.superclass == cls);
46 assert(!_directSubclasses.contains(subclass)); 66 assert(!_directSubclasses.contains(subclass));
47 _directSubclasses = _directSubclasses.prepend(subclass); 67 _directSubclasses = _directSubclasses.prepend(subclass);
48 } 68 }
49 69
70 /// Returns `true` if [other] is contained in the subtree of this node.
71 ///
72 /// This means that [other] is a subclass of [cls].
73 bool contains(ClassElement other) {
74 while (other != null) {
75 if (cls == other) return true;
76 if (cls.hierarchyDepth >= other.hierarchyDepth) return false;
77 other = other.superclass;
78 }
79 return false;
80 }
81
50 /// `true` if [cls] has been directly or indirectly instantiated. 82 /// `true` if [cls] has been directly or indirectly instantiated.
51 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; 83 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated;
52 84
53 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. 85 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
54 /// If [directlyInstantiated] is `true`, the iterable only returns the 86 ///
55 /// directly instantiated subclasses of [cls]. 87 /// The directly instantiated, indirectly instantiated and uninstantiated
56 Iterable<ClassElement> subclasses({bool directlyInstantiated: true}) { 88 /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
89 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
90 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
91 Iterable<ClassElement> subclasses(
92 {bool includeDirectlyInstantiated: true,
93 bool includeIndirectlyInstantiated: true,
94 bool includeUninstantiated: true,
95 bool strict: false}) {
57 return new ClassHierarchyNodeIterable( 96 return new ClassHierarchyNodeIterable(
58 this, directlyInstantiatedOnly: directlyInstantiated); 97 this,
59 } 98 includeRoot: !strict,
60 99 includeDirectlyInstantiated: includeDirectlyInstantiated,
61 /// Returns an [Iterable] of the strict subclasses of [cls] _not_ including 100 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
62 /// [cls] itself. If [directlyInstantiated] is `true`, the iterable only 101 includeUninstantiated: includeUninstantiated);
63 /// returns the directly instantiated subclasses of [cls]. 102 }
64 Iterable<ClassElement> strictSubclasses( 103
65 {bool directlyInstantiated: true}) { 104 void dump(StringBuffer sb, String indentation) {
66 return new ClassHierarchyNodeIterable(this, 105 sb.write('$indentation$cls:[');
67 includeRoot: false, directlyInstantiatedOnly: directlyInstantiated); 106 if (_directSubclasses.isEmpty) {
107 sb.write(']');
108 } else {
109 sb.write('\n');
110 bool needsComma = false;
111 for (Link<ClassHierarchyNode> link = _directSubclasses;
112 !link.isEmpty;
113 link = link.tail) {
114 if (needsComma) {
115 sb.write(',\n');
116 }
117 link.head.dump(sb, '$indentation ');
118 needsComma = true;
119 }
120 sb.write('\n');
121 sb.write('$indentation]');
122 }
68 } 123 }
69 124
70 String toString() => cls.toString(); 125 String toString() => cls.toString();
71 } 126 }
72 127
128 /// Object holding the subclass and subtype relation for a single
129 /// [ClassElement].
130 ///
131 /// The subclass relation for a class `C` is modelled through a reference to
132 /// the [ClassHierarchyNode] for `C` in the global [ClassHierarchyNode] tree
133 /// computed in [World].
134 ///
135 /// The subtype relation for a class `C` is modelled through a collection of
136 /// disjoint [ClassHierarchyNode] subtrees. The subclasses of `C`, modelled
137 /// through the aforementioned [ClassHierarchyNode] pointer, are extended with
138 /// the subtypes that do not extend `C` through a list of additional
139 /// [ClassHierarchyNode] nodes. This list is normalized to contain only the
140 /// nodes for the topmost subtypes and is furthermore ordered in increasing
141 /// hierarchy depth order.
142 ///
143 /// For this class hierarchy:
144 ///
145 /// class A {}
146 /// class B extends A {}
147 /// class C implements B {}
148 /// class D implements A {}
149 /// class E extends D {}
150 /// class F implements D {}
151 ///
152 /// the [ClassHierarchyNode] tree is
153 ///
154 /// Object
155 /// / | | \
156 /// A C D F
157 /// | |
158 /// B E
159 ///
160 /// and the [ClassSet] for `A` holds these [ClassHierarchyNode] nodes:
161 ///
162 /// A -> [C, D, F]
163 ///
164 /// The subtypes `B` and `E` are not directly modeled because they are implied
165 /// by their subclass relation to `A` and `D`, repectively. This can be seen
166 /// if we expand the subclass subtrees:
167 ///
168 /// A -> [C, D, F]
169 /// | |
170 /// B E
171 ///
172 class ClassSet {
173 final ClassHierarchyNode node;
174
175 List<ClassHierarchyNode> _directSubtypes;
176
177 ClassSet(this.node);
178
179 ClassElement get cls => node.cls;
180
181 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
182 ///
183 /// The directly instantiated, indirectly instantiated and uninstantiated
184 /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
185 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
186 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
187 Iterable<ClassElement> subclasses(
188 {bool includeDirectlyInstantiated: true,
189 bool includeIndirectlyInstantiated: true,
190 bool includeUninstantiated: true,
191 bool strict: false}) {
192 return node.subclasses(
193 strict: strict,
194 includeDirectlyInstantiated: includeDirectlyInstantiated,
195 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
196 includeUninstantiated: includeUninstantiated);
197 }
198
199 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
200 ///
201 /// The directly instantiated, indirectly instantiated and uninstantiated
202 /// subtypes of [cls] are returned if [includeDirectlyInstantiated],
203 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
204 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
205 Iterable<ClassElement> subtypes(
206 {bool includeDirectlyInstantiated: true,
207 bool includeIndirectlyInstantiated: true,
208 bool includeUninstantiated: true,
209 bool strict: false}) {
210 if (_directSubtypes == null) {
211 return node.subclasses(
212 strict: strict,
213 includeDirectlyInstantiated: includeDirectlyInstantiated,
214 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
215 includeUninstantiated: includeUninstantiated);
216 }
217 return new SubtypesIterable.SubtypesIterator(this,
218 includeRoot: !strict,
219 includeDirectlyInstantiated: includeDirectlyInstantiated,
220 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
221 includeUninstantiated: includeUninstantiated);
222 }
223
224 /// Adds [subtype] as a subtype of [cls].
225 void addSubtype(ClassHierarchyNode subtype) {
226 if (node.contains(subtype.cls)) {
227 return;
228 }
229 if (_directSubtypes == null) {
230 _directSubtypes = <ClassHierarchyNode>[subtype];
231 } else {
232 int hierarchyDepth = subtype.cls.hierarchyDepth;
233 List<ClassHierarchyNode> newSubtypes = <ClassHierarchyNode>[];
234 bool added = false;
235 for (ClassHierarchyNode otherSubtype in _directSubtypes) {
236 int otherHierarchyDepth = otherSubtype.cls.hierarchyDepth;
237 if (hierarchyDepth == otherHierarchyDepth) {
238 if (subtype == otherSubtype) {
239 return;
240 } else {
241 // [otherSubtype] is unrelated to [subtype].
242 newSubtypes.add(otherSubtype);
243 }
244 } else if (hierarchyDepth > otherSubtype.cls.hierarchyDepth) {
245 // [otherSubtype] could be a superclass of [subtype].
246 if (otherSubtype.contains(subtype.cls)) {
247 // [subtype] is already in this set.
248 return;
249 } else {
250 // [otherSubtype] is unrelated to [subtype].
251 newSubtypes.add(otherSubtype);
252 }
253 } else {
254 if (!added) {
255 // Insert [subtype] before other subtypes of higher hierarchy depth.
256 newSubtypes.add(subtype);
257 added = true;
258 }
259 // [subtype] could be a superclass of [otherSubtype].
260 if (subtype.contains(otherSubtype.cls)) {
261 // Replace [otherSubtype].
262 } else {
263 newSubtypes.add(otherSubtype);
264 }
265 }
266 }
267 if (!added) {
268 newSubtypes.add(subtype);
269 }
270 _directSubtypes = newSubtypes;
271 }
272 }
273
274 String toString() {
275 StringBuffer sb = new StringBuffer();
276 sb.write('[\n');
277 node.dump(sb, ' ');
278 sb.write('\n');
279 if (_directSubtypes != null) {
280 for (ClassHierarchyNode node in _directSubtypes) {
281 node.dump(sb, ' ');
282 sb.write('\n');
283 }
284 }
285 sb.write(']');
286 return sb.toString();
287 }
288 }
289
73 /// Iterable for subclasses of a [ClassHierarchyNode]. 290 /// Iterable for subclasses of a [ClassHierarchyNode].
74 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { 291 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> {
75 final ClassHierarchyNode root; 292 final ClassHierarchyNode root;
76 final bool includeRoot; 293 final bool includeRoot;
77 final bool directlyInstantiatedOnly; 294 final bool includeDirectlyInstantiated;
295 final bool includeIndirectlyInstantiated;
296 final bool includeUninstantiated;
78 297
79 ClassHierarchyNodeIterable( 298 ClassHierarchyNodeIterable(
80 this.root, 299 this.root,
81 {this.includeRoot: true, 300 {this.includeRoot: true,
82 this.directlyInstantiatedOnly: false}) { 301 this.includeDirectlyInstantiated: true,
302 this.includeIndirectlyInstantiated: true,
303 this.includeUninstantiated: true}) {
83 if (root == null) throw new StateError("No root for iterable."); 304 if (root == null) throw new StateError("No root for iterable.");
84 } 305 }
85 306
86 @override 307 @override
87 Iterator<ClassElement> get iterator { 308 Iterator<ClassElement> get iterator {
88 return new ClassHierarchyNodeIterator(this); 309 return new ClassHierarchyNodeIterator(this);
89 } 310 }
90 } 311 }
91 312
92 /// Iterator for subclasses of a [ClassHierarchyNode]. 313 /// Iterator for subclasses of a [ClassHierarchyNode].
(...skipping 12 matching lines...) Expand all
105 /// 326 ///
106 /// This is `null` before the first call to [moveNext]. 327 /// This is `null` before the first call to [moveNext].
107 Link<ClassHierarchyNode> stack; 328 Link<ClassHierarchyNode> stack;
108 329
109 ClassHierarchyNodeIterator(this.iterable); 330 ClassHierarchyNodeIterator(this.iterable);
110 331
111 ClassHierarchyNode get root => iterable.root; 332 ClassHierarchyNode get root => iterable.root;
112 333
113 bool get includeRoot => iterable.includeRoot; 334 bool get includeRoot => iterable.includeRoot;
114 335
115 bool get directlyInstantiatedOnly => iterable.directlyInstantiatedOnly; 336 bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
337
338 bool get includeIndirectlyInstantiated {
339 return iterable.includeIndirectlyInstantiated;
340 }
341
342 bool get includeUninstantiated => iterable.includeUninstantiated;
116 343
117 @override 344 @override
118 ClassElement get current { 345 ClassElement get current {
119 return currentNode != null ? currentNode.cls : null; 346 return currentNode != null ? currentNode.cls : null;
120 } 347 }
121 348
122 @override 349 @override
123 bool moveNext() { 350 bool moveNext() {
124 if (stack == null) { 351 if (stack == null) {
125 // First call to moveNext 352 // First call to moveNext
(...skipping 10 matching lines...) Expand all
136 bool _findNext() { 363 bool _findNext() {
137 while (true) { 364 while (true) {
138 if (stack.isEmpty) { 365 if (stack.isEmpty) {
139 // No more classes. Set [currentNode] to `null` to signal the end of 366 // No more classes. Set [currentNode] to `null` to signal the end of
140 // iteration. 367 // iteration.
141 currentNode = null; 368 currentNode = null;
142 return false; 369 return false;
143 } 370 }
144 currentNode = stack.head; 371 currentNode = stack.head;
145 stack = stack.tail; 372 stack = stack.tail;
373 if (!includeUninstantiated && !currentNode.isInstantiated) {
374 // We're only iterating instantiated classes so there is no use in
375 // visiting the current node and its subtree.
376 continue;
377 }
146 for (Link<ClassHierarchyNode> link = currentNode._directSubclasses; 378 for (Link<ClassHierarchyNode> link = currentNode._directSubclasses;
147 !link.isEmpty; 379 !link.isEmpty;
148 link = link.tail) { 380 link = link.tail) {
149 stack = stack.prepend(link.head); 381 stack = stack.prepend(link.head);
150 } 382 }
151 if (_isValid(currentNode)) { 383 if (_isValid(currentNode)) {
152 return true; 384 return true;
153 } 385 }
154 } 386 }
155 } 387 }
156 388
157 /// Returns `true` if the class of [node] is a valid result for this iterator. 389 /// Returns `true` if the class of [node] is a valid result for this iterator.
158 bool _isValid(ClassHierarchyNode node) { 390 bool _isValid(ClassHierarchyNode node) {
159 if (!includeRoot && node == root) return false; 391 if (!includeRoot && node == root) return false;
160 if (directlyInstantiatedOnly && !node.isDirectlyInstantiated) return false; 392 if (includeDirectlyInstantiated && node.isDirectlyInstantiated) {
161 return true; 393 return true;
394 }
395 if (includeIndirectlyInstantiated && node.isIndirectlyInstantiated) {
396 return true;
397 }
398 if (includeUninstantiated && !node.isInstantiated) {
399 return true;
400 }
401 return false;
162 } 402 }
163 } 403 }
164 404
405 /// Iterable for the subtypes in a [ClassSet].
406 class SubtypesIterable extends IterableBase<ClassElement> {
407 final ClassSet subtypeSet;
408 final bool includeRoot;
409 final bool includeDirectlyInstantiated;
410 final bool includeIndirectlyInstantiated;
411 final bool includeUninstantiated;
165 412
413 SubtypesIterable.SubtypesIterator(
414 this.subtypeSet,
415 {this.includeRoot: true,
416 this.includeDirectlyInstantiated: true,
417 this.includeIndirectlyInstantiated: true,
418 this.includeUninstantiated: true});
419
420 @override
421 Iterator<ClassElement> get iterator => new SubtypesIterator(this);
422 }
423
424 /// Iterator for the subtypes in a [ClassSet].
425 class SubtypesIterator extends Iterator<ClassElement> {
426 final SubtypesIterable iterable;
427 Iterator<ClassElement> elements;
428 Iterator<ClassHierarchyNode> hierarchyNodes;
429
430 SubtypesIterator(this.iterable);
431
432 bool get includeRoot => iterable.includeRoot;
433
434 bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
435
436 bool get includeIndirectlyInstantiated {
437 return iterable.includeIndirectlyInstantiated;
438 }
439
440 bool get includeUninstantiated => iterable.includeUninstantiated;
441
442 @override
443 ClassElement get current {
444 if (elements != null) {
445 return elements.current;
446 }
447 return null;
448 }
449
450 @override
451 bool moveNext() {
452 if (elements == null && hierarchyNodes == null) {
453 // Initial state. Iterate through subclasses.
454 elements = iterable.subtypeSet.node.subclasses(
455 strict: !includeRoot,
456 includeDirectlyInstantiated: includeDirectlyInstantiated,
457 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
458 includeUninstantiated: includeUninstantiated).iterator;
459 }
460 if (elements != null && elements.moveNext()) {
461 return true;
462 }
463 if (hierarchyNodes == null) {
464 // Start iterating through subtypes.
465 hierarchyNodes = iterable.subtypeSet._directSubtypes.iterator;
466 }
467 while (hierarchyNodes.moveNext()) {
468 elements = hierarchyNodes.current.subclasses(
469 includeDirectlyInstantiated: includeDirectlyInstantiated,
470 includeIndirectlyInstantiated: includeIndirectlyInstantiated,
471 includeUninstantiated: includeUninstantiated).iterator;
472 if (elements.moveNext()) {
473 return true;
474 }
475 }
476 return false;
477 }
478 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/use_unused_api.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698