Skip to content

Commit 46bfbde

Browse files
authored
Merge pull request #41303 from slavapestov/rqm-superclass-unification
RequirementMachine: Record rewrite loops during superclass unification
2 parents 57ce1d2 + e445335 commit 46bfbde

12 files changed

+882
-294
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4026,7 +4026,7 @@ class ClassDecl final : public NominalTypeDecl {
40264026
ClassDecl *getSuperclassDecl() const;
40274027

40284028
/// Check if this class is a superclass or equal to the given class.
4029-
bool isSuperclassOf(ClassDecl *other) const;
4029+
bool isSuperclassOf(const ClassDecl *other) const;
40304030

40314031
/// Set the superclass of this class.
40324032
void setSuperclass(Type superclass);
@@ -4121,7 +4121,7 @@ class ClassDecl final : public NominalTypeDecl {
41214121

41224122
/// Whether the class uses the ObjC object model (reference counting,
41234123
/// allocation, etc.), the Swift model, or has no reference counting at all.
4124-
ReferenceCounting getObjectModel() {
4124+
ReferenceCounting getObjectModel() const {
41254125
if (isForeignReferenceType())
41264126
return ReferenceCounting::None;
41274127

@@ -4131,7 +4131,7 @@ class ClassDecl final : public NominalTypeDecl {
41314131
return ReferenceCounting::Native;
41324132
}
41334133

4134-
LayoutConstraintKind getLayoutConstraintKind() {
4134+
LayoutConstraintKind getLayoutConstraintKind() const {
41354135
if (getObjectModel() == ReferenceCounting::ObjC)
41364136
return LayoutConstraintKind::Class;
41374137

@@ -4261,7 +4261,7 @@ class ClassDecl final : public NominalTypeDecl {
42614261
/// Used to determine if this class decl is a foriegn reference type. I.e., a
42624262
/// non-reference-counted swift reference type that was imported from a C++
42634263
/// record.
4264-
bool isForeignReferenceType();
4264+
bool isForeignReferenceType() const;
42654265
};
42664266

42674267
/// The set of known protocols for which derived conformances are supported.

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4936,7 +4936,7 @@ void swift::simple_display(llvm::raw_ostream &out, AncestryFlags value) {
49364936
out << " }";
49374937
}
49384938

4939-
bool ClassDecl::isSuperclassOf(ClassDecl *other) const {
4939+
bool ClassDecl::isSuperclassOf(const ClassDecl *other) const {
49404940
llvm::SmallPtrSet<const ClassDecl *, 8> visited;
49414941

49424942
do {
@@ -5081,7 +5081,7 @@ bool ClassDecl::walkSuperclasses(
50815081
return false;
50825082
}
50835083

5084-
bool ClassDecl::isForeignReferenceType() {
5084+
bool ClassDecl::isForeignReferenceType() const {
50855085
return getClangDecl() && isa<clang::RecordDecl>(getClangDecl());
50865086
}
50875087

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ void PropertyMap::concretizeNestedTypesFromConcreteParents() {
6363
llvm::dbgs() << "- via superclass requirement\n";
6464
}
6565

66+
const auto &superclassReq = props->getSuperclassRequirement();
6667
concretizeNestedTypesFromConcreteParent(
6768
props->getKey(),
6869
RequirementKind::Superclass,
69-
*props->SuperclassRule,
70-
props->Superclass->getConcreteType(),
71-
props->Superclass->getSubstitutions(),
70+
*superclassReq.SuperclassRule,
71+
superclassReq.SuperclassType->getConcreteType(),
72+
superclassReq.SuperclassType->getSubstitutions(),
7273
props->ConformsToRules,
7374
props->ConformsTo,
7475
props->SuperclassConformances);

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,12 @@ void PropertyBag::dump(llvm::raw_ostream &out) const {
115115
out << " layout: " << Layout;
116116
}
117117

118-
if (Superclass) {
119-
out << " superclass: " << *Superclass;
118+
if (hasSuperclassBound()) {
119+
const auto &superclassReq = getSuperclassRequirement();
120+
out << " superclass: " << *superclassReq.SuperclassType;
120121
}
121122

122-
if (ConcreteType) {
123+
if (isConcreteType()) {
123124
out << " concrete_type: " << *ConcreteType;
124125
}
125126

@@ -154,8 +155,10 @@ Type PropertyBag::getSuperclassBound(
154155
const MutableTerm &lookupTerm,
155156
const PropertyMap &map) const {
156157
MutableTerm prefix = getPrefixAfterStrippingKey(lookupTerm);
157-
return map.getTypeFromSubstitutionSchema(Superclass->getConcreteType(),
158-
Superclass->getSubstitutions(),
158+
159+
const auto &req = getSuperclassRequirement();
160+
return map.getTypeFromSubstitutionSchema(req.SuperclassType->getConcreteType(),
161+
req.SuperclassType->getSubstitutions(),
159162
genericParams, prefix);
160163
}
161164

@@ -199,17 +202,23 @@ void PropertyBag::copyPropertiesFrom(const PropertyBag *next,
199202
// T := UV should have substitutions {UX1, ..., UXn}.
200203
MutableTerm prefix(Key.begin(), Key.begin() + prefixLength);
201204

202-
if (next->Superclass) {
203-
Superclass = next->Superclass->prependPrefixToConcreteSubstitutions(
204-
prefix, ctx);
205-
SuperclassRule = next->SuperclassRule;
206-
}
207-
208205
if (next->ConcreteType) {
209206
ConcreteType = next->ConcreteType->prependPrefixToConcreteSubstitutions(
210207
prefix, ctx);
211208
ConcreteTypeRule = next->ConcreteTypeRule;
212209
}
210+
211+
// Copy over class hierarchy information.
212+
SuperclassDecl = next->SuperclassDecl;
213+
if (!next->Superclasses.empty()) {
214+
Superclasses = next->Superclasses;
215+
216+
for (auto &pair : Superclasses) {
217+
pair.second.SuperclassType =
218+
pair.second.SuperclassType->prependPrefixToConcreteSubstitutions(
219+
prefix, ctx);
220+
}
221+
}
213222
}
214223

215224
void PropertyBag::verify(const RewriteSystem &system) const {
@@ -221,11 +230,18 @@ void PropertyBag::verify(const RewriteSystem &system) const {
221230
assert(symbol.getProtocol() == ConformsTo[i]);
222231
}
223232

224-
// FIXME: Once unification introduces new rules, add asserts requiring
225-
// that the layout, superclass and concrete type symbols match, as above
233+
// FIXME: Add asserts requiring that the layout, superclass and
234+
// concrete type symbols match, as above
226235
assert(!Layout.isNull() == LayoutRule.hasValue());
227-
assert(Superclass.hasValue() == SuperclassRule.hasValue());
228236
assert(ConcreteType.hasValue() == ConcreteTypeRule.hasValue());
237+
238+
assert((SuperclassDecl == nullptr) == Superclasses.empty());
239+
for (const auto &pair : Superclasses) {
240+
const auto &req = pair.second;
241+
assert(req.SuperclassType.hasValue());
242+
assert(req.SuperclassRule.hasValue());
243+
}
244+
229245
#endif
230246
}
231247

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ namespace rewriting {
4444
class MutableTerm;
4545
class Term;
4646

47+
/// Records a superclass constraint at a given level in the class hierarchy.
48+
struct SuperclassRequirement {
49+
/// The most specific superclass constraint (in type difference order) for
50+
/// this level in the class hierarchy.
51+
Optional<Symbol> SuperclassType;
52+
53+
/// The corresponding superclass rule for the above.
54+
Optional<unsigned> SuperclassRule;
55+
};
56+
4757
/// Stores a convenient representation of all "property-like" rewrite rules of
4858
/// the form T.[p] => T, where [p] is a property symbol, for some term 'T'.
4959
class PropertyBag {
@@ -64,11 +74,14 @@ class PropertyBag {
6474
/// The corresponding layout rule for the above.
6575
Optional<unsigned> LayoutRule;
6676

67-
/// The most specific superclass constraint this type satisfies.
68-
Optional<Symbol> Superclass;
77+
/// The most specific superclass declaration for which this type has a
78+
/// superclass constraint.
79+
const ClassDecl *SuperclassDecl = nullptr;
6980

70-
/// The corresponding superclass rule for the above.
71-
Optional<unsigned> SuperclassRule;
81+
/// Used for unifying superclass rules at different levels in the class
82+
/// hierarchy. For each class declaration, stores a symbol and rule pair
83+
/// for the most specific substituted type.
84+
llvm::SmallDenseMap<const ClassDecl *, SuperclassRequirement, 2> Superclasses;
7285

7386
/// All concrete conformances of Superclass to the protocols in the
7487
/// ConformsTo list.
@@ -97,16 +110,22 @@ class PropertyBag {
97110
PropertyBag &operator=(const PropertyBag &) = delete;
98111
PropertyBag &operator=(PropertyBag &&) = delete;
99112

113+
const SuperclassRequirement &getSuperclassRequirement() const {
114+
assert(SuperclassDecl != nullptr);
115+
auto found = Superclasses.find(SuperclassDecl);
116+
return found->second;
117+
}
118+
100119
public:
101120
Term getKey() const { return Key; }
102121
void dump(llvm::raw_ostream &out) const;
103122

104123
bool hasSuperclassBound() const {
105-
return Superclass.hasValue();
124+
return SuperclassDecl != nullptr;
106125
}
107126

108127
CanType getSuperclassBound() const {
109-
return Superclass->getConcreteType();
128+
return getSuperclassRequirement().SuperclassType->getConcreteType();
110129
}
111130

112131
Type getSuperclassBound(
@@ -250,6 +269,18 @@ class PropertyMap {
250269

251270
void addConformanceProperty(Term key, Symbol property, unsigned ruleID);
252271
void addLayoutProperty(Term key, Symbol property, unsigned ruleID);
272+
273+
void unifyConcreteTypes(Term key,
274+
Optional<Symbol> &existingProperty,
275+
Optional<unsigned> &existingRuleID,
276+
Symbol property,
277+
unsigned ruleID);
278+
279+
void recordSuperclassRelation(Term key,
280+
Symbol superclassType,
281+
unsigned superclassRuleID,
282+
const ClassDecl *otherClass);
283+
253284
void addSuperclassProperty(Term key, Symbol property, unsigned ruleID);
254285
void addConcreteTypeProperty(Term key, Symbol property, unsigned ruleID);
255286

0 commit comments

Comments
 (0)