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

Side by Side Diff: pkg/kernel/lib/class_hierarchy.dart

Issue 2848083002: Implement Dart 1.0 LUB algorithm (for interface types) in kernel. (Closed)
Patch Set: Created 3 years, 7 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 | « no previous file | pkg/kernel/lib/heap.dart » ('j') | pkg/kernel/lib/heap.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 library kernel.class_hierarchy; 4 library kernel.class_hierarchy;
5 5
6 import 'ast.dart'; 6 import 'ast.dart';
7 import 'dart:math'; 7 import 'dart:math';
8 import 'dart:typed_data'; 8 import 'dart:typed_data';
9 import 'heap.dart';
9 import 'type_algebra.dart'; 10 import 'type_algebra.dart';
10 11
11 /// Data structure for answering various subclassing queries. 12 /// Data structure for answering various subclassing queries.
12 class ClassHierarchy { 13 class ClassHierarchy {
13 /// All classes in the program. 14 /// All classes in the program.
14 /// 15 ///
15 /// The list is ordered so that classes occur after their super classes. 16 /// The list is ordered so that classes occur after their super classes.
16 final List<Class> classes; 17 final List<Class> classes;
17 18
18 final Map<Class, _ClassInfo> _infoFor = <Class, _ClassInfo>{}; 19 final Map<Class, _ClassInfo> _infoFor = <Class, _ClassInfo>{};
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 /// mixin application (i.e. [Class.mixedInType]). 56 /// mixin application (i.e. [Class.mixedInType]).
56 bool isUsedAsMixin(Class class_) { 57 bool isUsedAsMixin(Class class_) {
57 return _infoFor[class_].directMixers.isNotEmpty; 58 return _infoFor[class_].directMixers.isNotEmpty;
58 } 59 }
59 60
60 /// True if the given class is used in an `implements` clause. 61 /// True if the given class is used in an `implements` clause.
61 bool isUsedAsSuperInterface(Class class_) { 62 bool isUsedAsSuperInterface(Class class_) {
62 return _infoFor[class_].directImplementers.isNotEmpty; 63 return _infoFor[class_].directImplementers.isNotEmpty;
63 } 64 }
64 65
66 /// Returns the number of steps in the longest inheritance path from [class_]
67 /// to [rootClass].
68 int getClassDepth(Class class_) => _infoFor[class_].depth;
69
70 /// Returns a list of classes appropriate for use in calculating a least upper
71 /// bound.
72 ///
73 /// The returned list is a list of all classes that [class_] is a subtype of
74 /// (including itself), sorted first by depth (deepest first) and then by
75 /// class index.
76 List<Class> getLeastUpperBoundClasses(Class class_) {
ahe 2017/05/01 16:50:34 Consider renaming to something like getRankedSuper
Paul Berry 2017/05/01 18:12:13 Done. I went with "getRankedSuperclasses" to emph
77 return _getLeastUpperBoundInfos(_infoFor[class_])
78 .map((info) => info.classNode)
79 .toList();
80 }
81
82 List<_ClassInfo> _getLeastUpperBoundInfos(_ClassInfo info) {
83 if (info.leastUpperBoundInfos != null) return info.leastUpperBoundInfos;
84 var heap = new _LubHeap()..add(info);
85 var chain = <_ClassInfo>[];
86 info.leastUpperBoundInfos = chain;
87 _ClassInfo lastInfo = null;
88 while (heap.isNotEmpty) {
89 var nextInfo = heap.remove();
90 if (identical(nextInfo, lastInfo)) continue;
91 chain.add(nextInfo);
92 lastInfo = nextInfo;
93 var classNode = nextInfo.classNode;
94 void addToHeap(Supertype supertype) {
95 heap.add(_infoFor[supertype.classNode]);
96 }
97
98 if (classNode.supertype != null) addToHeap(classNode.supertype);
99 if (classNode.mixedInType != null) addToHeap(classNode.mixedInType);
100 classNode.implementedTypes.forEach(addToHeap);
101 }
102 return chain;
103 }
104
105 /// Returns the least upper bound of two interface types, as defined by Dart
106 /// 1.0.
107 ///
108 /// Given two interfaces I and J, lest S_I be the set of superinterfaces of I,
ahe 2017/05/01 16:50:34 lest -> let.
Paul Berry 2017/05/01 18:12:13 Done.
109 /// let S_J be the set of superinterfaces of J, and let
110 /// S = (I union S_I) intersect (J union S_J). Furthermore, we define
111 /// S_n = {T | T in S and depth(T) = n} for any finite n where depth(T) is
112 /// the number of steps in the longest inheritance path from T to Object. Let
113 /// q be the largest number such that S_q has cardinality one. The least
114 /// upper bound of I and J is the sole element of S_q.
115 ///
116 /// This is called the "classic" least upper bound to distinguish it from the
117 /// strong mode least upper bound, which has special behaviors in the case
118 /// where one type is a subtype of the other, or where both types are based on
119 /// the same class.
120 InterfaceType getClassicLeastUpperBound(
121 InterfaceType type1, InterfaceType type2) {
122 // The algorithm is: first we compute a list of superclasses for both types,
123 // ordered from greatest to least depth, and ordered by topological sort
124 // index within each depth. Due to the sort order, we can find the
125 // intersection of these lists by a simple walk.
126 //
127 // Then, for each class in the intersection, determine the exact type that
128 // is implemented by type1 and type2. If the types match, that type is a
129 // candidate (it's a member of S_n). As soon as we find a candidate which
130 // is unique for its depth, we return it.
131 //
132 // As an optimization, if the class for I is a subtype of the class for J,
133 // then we know that the list of superclasses of J is a subset of the list
134 // of superclasses for I; therefore it is sufficient to compute just the
135 // list of superclasses for J. To avoid complicating the code below (which
136 // intersects the two lists), we set both lists equal to the list of
137 // superclasses for J. And vice versa with the role of I and J swapped.
138
139 // Compute the list of superclasses for both types, with the above
140 // optimization.
141 _ClassInfo info1 = _infoFor[type1.classNode];
142 _ClassInfo info2 = _infoFor[type2.classNode];
143 List<_ClassInfo> classes1;
144 List<_ClassInfo> classes2;
145 if (identical(info1, info2) || info1.isSubtypeOf(info2)) {
146 classes1 = classes2 = _getLeastUpperBoundInfos(info2);
147 } else if (info2.isSubtypeOf(info1)) {
148 classes1 = classes2 = _getLeastUpperBoundInfos(info1);
149 } else {
150 classes1 = _getLeastUpperBoundInfos(info1);
151 classes2 = _getLeastUpperBoundInfos(info2);
152 }
153
154 // Walk the lists finding their intersection, looking for a depth that has a
155 // single candidate.
156 int i1 = 0;
157 int i2 = 0;
158 InterfaceType candidate = null;
159 int currentDepth = -1;
160 int numCandidatesAtThisDepth = 0;
161 while (true) {
162 _ClassInfo next = classes1[i1];
163 _ClassInfo next2 = classes2[i2];
164 if (!identical(next, next2)) {
165 if (_LubHeap.sortsBeforeStatic(next, next2)) {
166 ++i1;
167 } else {
168 ++i2;
169 }
170 continue;
171 }
172 ++i2;
173 ++i1;
174 if (next.depth != currentDepth) {
175 if (numCandidatesAtThisDepth == 1) return candidate;
176 currentDepth = next.depth;
177 numCandidatesAtThisDepth = 0;
178 candidate = null;
179 } else if (numCandidatesAtThisDepth > 1) {
180 continue;
181 }
182
183 // For each class in the intersection, find the exact type that is
184 // implemented by type1 and type2. If they match, it's a candidate.
185 //
186 // Two additional optimizations:
187 //
188 // - If this class lacks type parameters, we know there is a match without
189 // needing to substitute.
190 //
191 // - If the depth is 0, we have reached Object, so we can return it
192 // immediately. Since all interface types are subtypes of Object, this
193 // ensures the loop terminates.
194 if (next.classNode.typeParameters.isEmpty) {
195 candidate = next.classNode.rawType;
196 if (currentDepth == 0) return candidate;
197 ++numCandidatesAtThisDepth;
198 } else {
199 var superType1 = identical(info1, next)
200 ? type1
201 : Substitution.fromInterfaceType(type1).substituteType(
202 info1.genericSuperTypes[next.classNode].asInterfaceType);
203 var superType2 = identical(info2, next)
204 ? type2
205 : Substitution.fromInterfaceType(type2).substituteType(
206 info2.genericSuperTypes[next.classNode].asInterfaceType);
207 if (superType1 == superType2) {
208 candidate = superType1;
209 ++numCandidatesAtThisDepth;
210 }
211 }
212 }
213 }
214
65 /// Returns the instantiation of [superclass] that is implemented by [class_], 215 /// Returns the instantiation of [superclass] that is implemented by [class_],
66 /// or `null` if [class_] does not implement [superclass] at all. 216 /// or `null` if [class_] does not implement [superclass] at all.
67 Supertype getClassAsInstanceOf(Class class_, Class superclass) { 217 Supertype getClassAsInstanceOf(Class class_, Class superclass) {
68 if (identical(class_, superclass)) return class_.asThisSupertype; 218 if (identical(class_, superclass)) return class_.asThisSupertype;
69 _ClassInfo info = _infoFor[class_]; 219 _ClassInfo info = _infoFor[class_];
70 _ClassInfo superInfo = _infoFor[superclass]; 220 _ClassInfo superInfo = _infoFor[superclass];
71 if (!info.isSubtypeOf(superInfo)) return null; 221 if (!info.isSubtypeOf(superInfo)) return null;
72 if (superclass.typeParameters.isEmpty) return superclass.asRawSupertype; 222 if (superclass.typeParameters.isEmpty) return superclass.asRawSupertype;
73 return info.genericSuperTypes[superclass]; 223 return info.genericSuperTypes[superclass];
74 } 224 }
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 429
280 for (int i = 0; i < classes.length; ++i) { 430 for (int i = 0; i < classes.length; ++i) {
281 var class_ = classes[i]; 431 var class_ = classes[i];
282 _buildInterfaceMembers(class_, _infoFor[class_], setters: true); 432 _buildInterfaceMembers(class_, _infoFor[class_], setters: true);
283 _buildInterfaceMembers(class_, _infoFor[class_], setters: false); 433 _buildInterfaceMembers(class_, _infoFor[class_], setters: false);
284 } 434 }
285 } 435 }
286 436
287 /// Upwards traversal of the class hierarchy that orders classes so super 437 /// Upwards traversal of the class hierarchy that orders classes so super
288 /// types before their subtypes. 438 /// types before their subtypes.
439 ///
440 /// Returns the depth of the visited class (the number of steps in the longest
441 /// inheritance path to the root class).
289 int _topSortIndex = 0; 442 int _topSortIndex = 0;
290 void _topologicalSortVisit(Class classNode) { 443 int _topologicalSortVisit(Class classNode) {
291 var info = _infoFor[classNode]; 444 var info = _infoFor[classNode];
292 if (info != null) { 445 if (info != null) {
293 if (info.isBeingVisited) { 446 if (info.isBeingVisited) {
294 throw 'Cyclic inheritance involving ${info.classNode.name}'; 447 throw 'Cyclic inheritance involving ${info.classNode.name}';
295 } 448 }
296 return; // Already built. 449 return info.depth; // Already built.
297 } 450 }
451 int superDepth = -1;
298 _infoFor[classNode] = info = new _ClassInfo(classNode); 452 _infoFor[classNode] = info = new _ClassInfo(classNode);
299 info.isBeingVisited = true; 453 info.isBeingVisited = true;
300 if (classNode.supertype != null) { 454 if (classNode.supertype != null) {
301 _topologicalSortVisit(classNode.supertype.classNode); 455 superDepth =
456 max(superDepth, _topologicalSortVisit(classNode.supertype.classNode));
302 _recordSuperTypes(info, classNode.supertype); 457 _recordSuperTypes(info, classNode.supertype);
303 } 458 }
304 if (classNode.mixedInType != null) { 459 if (classNode.mixedInType != null) {
305 _topologicalSortVisit(classNode.mixedInType.classNode); 460 superDepth = max(
461 superDepth, _topologicalSortVisit(classNode.mixedInType.classNode));
306 _recordSuperTypes(info, classNode.mixedInType); 462 _recordSuperTypes(info, classNode.mixedInType);
307 } 463 }
308 for (var supertype in classNode.implementedTypes) { 464 for (var supertype in classNode.implementedTypes) {
309 _topologicalSortVisit(supertype.classNode); 465 superDepth = max(superDepth, _topologicalSortVisit(supertype.classNode));
310 _recordSuperTypes(info, supertype); 466 _recordSuperTypes(info, supertype);
311 } 467 }
312 _buildDeclaredMembers(classNode, info); 468 _buildDeclaredMembers(classNode, info);
313 _buildImplementedMembers(classNode, info); 469 _buildImplementedMembers(classNode, info);
314 int id = _topSortIndex++; 470 int id = _topSortIndex++;
315 info.topologicalIndex = id; 471 info.topologicalIndex = id;
316 classes[id] = info.classNode; 472 classes[id] = info.classNode;
317 info.isBeingVisited = false; 473 info.isBeingVisited = false;
474 return info.depth = superDepth + 1;
318 } 475 }
319 476
320 void _buildDeclaredMembers(Class classNode, _ClassInfo info) { 477 void _buildDeclaredMembers(Class classNode, _ClassInfo info) {
321 if (classNode.mixedInType != null) { 478 if (classNode.mixedInType != null) {
322 _ClassInfo mixedInfo = _infoFor[classNode.mixedInType.classNode]; 479 _ClassInfo mixedInfo = _infoFor[classNode.mixedInType.classNode];
323 info.declaredGettersAndCalls = mixedInfo.declaredGettersAndCalls; 480 info.declaredGettersAndCalls = mixedInfo.declaredGettersAndCalls;
324 info.declaredSetters = mixedInfo.declaredSetters; 481 info.declaredSetters = mixedInfo.declaredSetters;
325 } else { 482 } else {
326 var members = info.declaredGettersAndCalls = <Member>[]; 483 var members = info.declaredGettersAndCalls = <Member>[];
327 var setters = info.declaredSetters = <Member>[]; 484 var setters = info.declaredSetters = <Member>[];
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 if (delta != 0) return delta; 941 if (delta != 0) return delta;
785 } 942 }
786 return 0; 943 return 0;
787 } 944 }
788 945
789 class _ClassInfo { 946 class _ClassInfo {
790 final Class classNode; 947 final Class classNode;
791 int topologicalIndex = 0; 948 int topologicalIndex = 0;
792 int topDownIndex = -1; 949 int topDownIndex = -1;
793 bool isBeingVisited = false; 950 bool isBeingVisited = false;
951 int depth = 0;
794 952
795 // Super types must always occur before subtypes in these lists. 953 // Super types must always occur before subtypes in these lists.
796 // For example: 954 // For example:
797 // 955 //
798 // class A extends Object 956 // class A extends Object
799 // class B extends Object implements A 957 // class B extends Object implements A
800 // 958 //
801 // Here `A` must occur before `B` in the list of direct extenders of Object, 959 // Here `A` must occur before `B` in the list of direct extenders of Object,
802 // because `B` is a subtype of `A`. 960 // because `B` is a subtype of `A`.
803 final List<_ClassInfo> directExtenders = <_ClassInfo>[]; 961 final List<_ClassInfo> directExtenders = <_ClassInfo>[];
804 final List<_ClassInfo> directMixers = <_ClassInfo>[]; 962 final List<_ClassInfo> directMixers = <_ClassInfo>[];
805 final List<_ClassInfo> directImplementers = <_ClassInfo>[]; 963 final List<_ClassInfo> directImplementers = <_ClassInfo>[];
806 964
807 /// Top-down indices of all subclasses of this class, represented as 965 /// Top-down indices of all subclasses of this class, represented as
808 /// interleaved begin/end interval end points. 966 /// interleaved begin/end interval end points.
809 Uint32List subclassIntervalList; 967 Uint32List subclassIntervalList;
810 Uint32List submixtureIntervalList; 968 Uint32List submixtureIntervalList;
811 Uint32List subtypeIntervalList; 969 Uint32List subtypeIntervalList;
812 970
971 List<_ClassInfo> leastUpperBoundInfos;
972
813 bool isSubclassOf(_ClassInfo other) { 973 bool isSubclassOf(_ClassInfo other) {
814 return _intervalListContains(other.subclassIntervalList, topDownIndex); 974 return _intervalListContains(other.subclassIntervalList, topDownIndex);
815 } 975 }
816 976
817 bool isSubmixtureOf(_ClassInfo other) { 977 bool isSubmixtureOf(_ClassInfo other) {
818 return _intervalListContains(other.submixtureIntervalList, topDownIndex); 978 return _intervalListContains(other.submixtureIntervalList, topDownIndex);
819 } 979 }
820 980
821 bool isSubtypeOf(_ClassInfo other) { 981 bool isSubtypeOf(_ClassInfo other) {
822 return _intervalListContains(other.subtypeIntervalList, topDownIndex); 982 return _intervalListContains(other.subtypeIntervalList, topDownIndex);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
893 1053
894 ClassSet union(ClassSet other) { 1054 ClassSet union(ClassSet other) {
895 assert(_hierarchy == other._hierarchy); 1055 assert(_hierarchy == other._hierarchy);
896 if (identical(_intervalList, other._intervalList)) return this; 1056 if (identical(_intervalList, other._intervalList)) return this;
897 _IntervalListBuilder builder = new _IntervalListBuilder(); 1057 _IntervalListBuilder builder = new _IntervalListBuilder();
898 builder.addIntervalList(_intervalList); 1058 builder.addIntervalList(_intervalList);
899 builder.addIntervalList(other._intervalList); 1059 builder.addIntervalList(other._intervalList);
900 return new ClassSet(_hierarchy, builder.buildIntervalList()); 1060 return new ClassSet(_hierarchy, builder.buildIntervalList());
901 } 1061 }
902 } 1062 }
1063
1064 /// Heap for use in computing least upper bounds.
1065 ///
1066 /// The heap is sorted such that classes that are deepest in the hierarchy
1067 /// are removed first; in the case of ties, classes with lower topological sort
1068 /// index are removed first.
1069 class _LubHeap extends Heap<_ClassInfo> {
1070 @override
1071 bool sortsBefore(_ClassInfo a, _ClassInfo b) => sortsBeforeStatic(a, b);
1072
1073 static bool sortsBeforeStatic(_ClassInfo a, _ClassInfo b) {
1074 if (a.depth > b.depth) return true;
1075 if (a.depth < b.depth) return false;
1076 return a.topologicalIndex < b.topologicalIndex;
1077 }
1078 }
OLDNEW
« no previous file with comments | « no previous file | pkg/kernel/lib/heap.dart » ('j') | pkg/kernel/lib/heap.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698