Skip to content

Commit f1d2bcb

Browse files
committed
RequirementMachine: Stub out support for superclass and concrete type requirements
1 parent 969ac78 commit f1d2bcb

File tree

3 files changed

+87
-24
lines changed

3 files changed

+87
-24
lines changed

include/swift/AST/RewriteSystem.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_REWRITESYSTEM_H
1414
#define SWIFT_REWRITESYSTEM_H
1515

16+
#include "swift/AST/ASTContext.h"
1617
#include "swift/AST/Decl.h"
1718
#include "swift/AST/Identifier.h"
1819
#include "swift/AST/LayoutConstraint.h"
@@ -350,14 +351,20 @@ class RewriteContext final {
350351
RewriteContext &operator=(const RewriteContext &) = delete;
351352
RewriteContext &operator=(RewriteContext &&) = delete;
352353

354+
ASTContext &Context;
355+
353356
public:
354357
/// Statistical counters.
355358
UnifiedStatsReporter *Stats;
356359

357-
RewriteContext(UnifiedStatsReporter *stats) : Stats(stats) {}
360+
RewriteContext(ASTContext &ctx) : Context(ctx), Stats(ctx.Stats) {}
361+
362+
Term getTermForType(CanType paramType, const ProtocolDecl *proto);
363+
364+
MutableTerm getMutableTermForType(CanType paramType,
365+
const ProtocolDecl *proto);
358366

359-
MutableTerm getTermForType(CanType paramType,
360-
const ProtocolDecl *proto);
367+
ASTContext &getASTContext() { return Context; }
361368
};
362369

363370
/// A rewrite rule that replaces occurrences of LHS with RHS.

lib/AST/RequirementMachine.cpp

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ struct RewriteSystemBuilder {
3737
ProtocolGraph Protocols;
3838
std::vector<std::pair<MutableTerm, MutableTerm>> Rules;
3939

40+
CanType getConcreteSubstitutionSchema(CanType concreteType,
41+
const ProtocolDecl *proto,
42+
SmallVector<Term> &result);
43+
4044
RewriteSystemBuilder(RewriteContext &ctx, bool debug)
4145
: Context(ctx), Debug(debug) {}
4246
void addGenericSignature(CanGenericSignature sig);
@@ -48,6 +52,32 @@ struct RewriteSystemBuilder {
4852

4953
} // end namespace
5054

55+
/// Given a concrete type that may contain type parameters in structural positions,
56+
/// collect all the structural type parameter components, and replace them all with
57+
/// fresh generic parameters. The fresh generic parameters all have a depth of 0,
58+
/// and the index is an index into the 'result' array.
59+
///
60+
/// For example, given the concrete type Foo<X.Y, Array<Z>>, this produces the
61+
/// result type Foo<τ_0_0, Array<τ_0_1>>, with result array {X.Y, Z}.
62+
CanType
63+
RewriteSystemBuilder::getConcreteSubstitutionSchema(CanType concreteType,
64+
const ProtocolDecl *proto,
65+
SmallVector<Term> &result) {
66+
if (!concreteType->hasTypeParameter())
67+
return concreteType;
68+
69+
return CanType(concreteType.transformRec(
70+
[&](Type t) -> Optional<Type> {
71+
if (!t->isTypeParameter())
72+
return None;
73+
74+
unsigned index = result.size();
75+
result.push_back(Context.getTermForType(CanType(t), proto));
76+
77+
return CanGenericTypeParamType::get(/*depth=*/0, index, Context.getASTContext());
78+
}));
79+
}
80+
5181
void RewriteSystemBuilder::addGenericSignature(CanGenericSignature sig) {
5282
// Collect all protocols transitively referenced from the generic signature's
5383
// requirements.
@@ -115,8 +145,12 @@ void RewriteSystemBuilder::addRequirement(const Requirement &req,
115145
llvm::dbgs() << "\n";
116146
}
117147

148+
// Compute the left hand side.
118149
auto subjectType = CanType(req.getFirstType());
119-
auto subjectTerm = Context.getTermForType(subjectType, proto);
150+
auto subjectTerm = Context.getMutableTermForType(subjectType, proto);
151+
152+
// Compute the right hand side.
153+
MutableTerm constraintTerm;
120154

121155
switch (req.getKind()) {
122156
case RequirementKind::Conformance: {
@@ -127,55 +161,72 @@ void RewriteSystemBuilder::addRequirement(const Requirement &req,
127161
// Intuitively, this means "any type ending with T conforms to P".
128162
auto *proto = req.getProtocolDecl();
129163

130-
auto constraintTerm = subjectTerm;
164+
constraintTerm = subjectTerm;
131165
constraintTerm.add(Atom::forProtocol(proto, Context));
132-
133-
Rules.emplace_back(subjectTerm, constraintTerm);
134166
break;
135167
}
136168

137-
case RequirementKind::Superclass:
138-
// FIXME: Implement
169+
case RequirementKind::Superclass: {
170+
// A superclass requirement T : C<X, Y> becomes a rewrite rule
171+
//
172+
// T.[superclass: C<X, Y>] => T
173+
auto otherType = CanType(req.getSecondType());
174+
175+
SmallVector<Term> substitutions;
176+
otherType = getConcreteSubstitutionSchema(otherType, proto,
177+
substitutions);
178+
179+
constraintTerm = subjectTerm;
180+
constraintTerm.add(Atom::forSuperclass(otherType, substitutions,
181+
Context));
139182
break;
183+
}
140184

141185
case RequirementKind::Layout: {
142186
// A layout requirement T : L becomes a rewrite rule
143187
//
144188
// T.[L] == T
145-
auto constraintTerm = subjectTerm;
189+
constraintTerm = subjectTerm;
146190
constraintTerm.add(Atom::forLayout(req.getLayoutConstraint(),
147191
Context));
148-
149-
Rules.emplace_back(subjectTerm, constraintTerm);
150192
break;
151193
}
152194

153195
case RequirementKind::SameType: {
154-
// A same-type requirement T == U becomes a rewrite rule
155-
//
156-
// T == U
157196
auto otherType = CanType(req.getSecondType());
158197

159-
// FIXME: Handle concrete types
160-
if (!otherType->isTypeParameter())
198+
if (!otherType->isTypeParameter()) {
199+
// A concrete same-type requirement T == C<X, Y> becomes a
200+
// rewrite rule
201+
//
202+
// T.[concrete: C<X, Y>] => T
203+
SmallVector<Term> substitutions;
204+
otherType = getConcreteSubstitutionSchema(otherType, proto,
205+
substitutions);
206+
207+
constraintTerm = subjectTerm;
208+
constraintTerm.add(Atom::forConcreteType(otherType, substitutions,
209+
Context));
161210
break;
211+
}
162212

163-
auto otherTerm = Context.getTermForType(otherType, proto);
164-
165-
Rules.emplace_back(subjectTerm, otherTerm);
213+
constraintTerm = Context.getMutableTermForType(otherType, proto);
166214
break;
167215
}
168216
}
217+
218+
Rules.emplace_back(subjectTerm, constraintTerm);
169219
}
170220

221+
171222
/// We use the PIMPL pattern to avoid creeping header dependencies.
172223
struct RequirementMachine::Implementation {
173224
RewriteContext Context;
174225
RewriteSystem System;
175226
bool Complete = false;
176227

177-
Implementation(ASTContext &ctx)
178-
: Context(ctx.Stats), System(Context) {}
228+
explicit Implementation(ASTContext &ctx)
229+
: Context(ctx), System(Context) {}
179230
};
180231

181232
RequirementMachine::RequirementMachine(ASTContext &ctx) : Context(ctx) {

lib/AST/RewriteSystem.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,11 @@ void MutableTerm::dump(llvm::raw_ostream &out) const {
865865
}
866866
}
867867

868+
Term RewriteContext::getTermForType(CanType paramType,
869+
const ProtocolDecl *proto) {
870+
return Term::get(getMutableTermForType(paramType, proto), *this);
871+
}
872+
868873
/// Map an interface type to a term.
869874
///
870875
/// If \p proto is null, this is a term relative to a generic
@@ -877,8 +882,8 @@ void MutableTerm::dump(llvm::raw_ostream &out) const {
877882
/// The bound associated types in the interface type are ignored; the
878883
/// resulting term consists entirely of a root atom followed by zero
879884
/// or more name atoms.
880-
MutableTerm RewriteContext::getTermForType(CanType paramType,
881-
const ProtocolDecl *proto) {
885+
MutableTerm RewriteContext::getMutableTermForType(CanType paramType,
886+
const ProtocolDecl *proto) {
882887
assert(paramType->isTypeParameter());
883888

884889
// Collect zero or more nested type names in reverse order.

0 commit comments

Comments
 (0)