Skip to content

Commit 61b6cc8

Browse files
committed
AST: Add ProtocolConformanceRef::subst()
Extract this from Substitution::subst(), which is going away.
1 parent c040c71 commit 61b6cc8

File tree

3 files changed

+69
-52
lines changed

3 files changed

+69
-52
lines changed

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class ProtocolConformanceRef {
9191
/// conformance represents.
9292
ProtocolConformanceRef getInherited(ProtocolDecl *parent) const;
9393

94+
/// Apply a substitution to the conforming type.
95+
ProtocolConformanceRef subst(Type origType,
96+
TypeSubstitutionFn subs,
97+
LookupConformanceFn conformances) const;
98+
9499
void dump() const;
95100
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
96101

lib/AST/ProtocolConformance.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,67 @@ ProtocolConformanceRef::getInherited(ProtocolDecl *parent) const {
9595
llvm_unreachable("unhandled ProtocolConformanceRef");
9696
}
9797

98+
ProtocolConformanceRef
99+
ProtocolConformanceRef::subst(Type origType,
100+
TypeSubstitutionFn subs,
101+
LookupConformanceFn conformances) const {
102+
auto substType = origType.subst(subs, conformances,
103+
SubstFlags::UseErrorType);
104+
105+
if (substType->isOpenedExistential())
106+
return *this;
107+
108+
// If we have a concrete conformance, we need to substitute the
109+
// conformance to apply to the new type.
110+
if (isConcrete())
111+
return ProtocolConformanceRef(
112+
getConcrete()->subst(substType, subs, conformances));
113+
114+
auto *proto = getRequirement();
115+
116+
// If the original type was an archetype, check the conformance map.
117+
if (origType->is<SubstitutableType>()
118+
|| origType->is<DependentMemberType>()) {
119+
if (auto result = conformances(origType->getCanonicalType(),
120+
substType,
121+
proto->getDeclaredType())) {
122+
return *result;
123+
}
124+
}
125+
126+
// If that didn't find anything, we can still synthesize AnyObject
127+
// conformances from thin air. FIXME: gross.
128+
if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
129+
if (substType->isExistentialType())
130+
return *this;
131+
132+
ClassDecl *classDecl = nullptr;
133+
auto archetype = substType->getAs<ArchetypeType>();
134+
135+
if (archetype) {
136+
if (archetype->getSuperclass())
137+
classDecl = archetype->getSuperclass()->getClassOrBoundGenericClass();
138+
139+
// A class-constrained archetype without a superclass constraint
140+
// conforms to AnyObject abstractly.
141+
if (!classDecl && archetype->requiresClass())
142+
return ProtocolConformanceRef(proto);
143+
} else {
144+
classDecl = substType->getClassOrBoundGenericClass();
145+
}
146+
147+
assert(classDecl);
148+
149+
// Create a concrete conformance based on the conforming class.
150+
SmallVector<ProtocolConformance *, 1> lookupResults;
151+
classDecl->lookupConformance(classDecl->getParentModule(), proto,
152+
lookupResults);
153+
return ProtocolConformanceRef(lookupResults.front());
154+
}
155+
156+
llvm_unreachable("Invalid conformance substitution");
157+
}
158+
98159
Type
99160
ProtocolConformanceRef::getTypeWitnessByName(Type type,
100161
ProtocolConformanceRef conformance,

lib/AST/Substitution.cpp

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -68,59 +68,10 @@ Substitution Substitution::subst(TypeSubstitutionFn subs,
6868
substConformances.reserve(Conformance.size());
6969

7070
for (auto c : Conformance) {
71-
// If we have a concrete conformance, we need to substitute the
72-
// conformance to apply to the new type.
73-
if (c.isConcrete()) {
74-
auto substC = c.getConcrete()->subst(substReplacement,
75-
subs, conformances);
76-
substConformances.push_back(ProtocolConformanceRef(substC));
77-
if (c != substConformances.back())
78-
conformancesChanged = true;
79-
continue;
80-
}
81-
82-
// Otherwise, we may need to fill in the conformance.
83-
ProtocolDecl *proto = c.getAbstract();
84-
Optional<ProtocolConformanceRef> conformance;
85-
86-
// If the original type was an archetype, check the conformance map.
87-
if (Replacement->is<SubstitutableType>()
88-
|| Replacement->is<DependentMemberType>()) {
89-
conformance = conformances(Replacement->getCanonicalType(),
90-
substReplacement,
91-
proto->getDeclaredType());
92-
}
93-
94-
// If that didn't find anything, we can still synthesize AnyObject
95-
// conformances from thin air. FIXME: gross.
96-
if (!conformance &&
97-
proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
98-
auto archetype =
99-
dyn_cast<ArchetypeType>(substReplacement->getCanonicalType());
100-
// If classDecl is not nullptr, it is a concrete class.
101-
auto classDecl = substReplacement->getClassOrBoundGenericClass();
102-
if (!classDecl && archetype->getSuperclass()) {
103-
// Replacement type is an archetype with a superclass constraint.
104-
classDecl = archetype->getSuperclass()->getClassOrBoundGenericClass();
105-
assert(classDecl);
106-
}
107-
if (classDecl) {
108-
// Create a concrete conformance based on the conforming class.
109-
SmallVector<ProtocolConformance *, 1> lookupResults;
110-
classDecl->lookupConformance(classDecl->getParentModule(), proto,
111-
lookupResults);
112-
conformance = ProtocolConformanceRef(lookupResults.front());
113-
} else if (archetype && archetype->requiresClass()) {
114-
// Replacement type is an archetype with a class constraint.
115-
// Create an abstract conformance.
116-
conformance = ProtocolConformanceRef(proto);
117-
}
118-
}
119-
120-
assert(conformance);
121-
if (conformance->isConcrete())
71+
auto newC = c.subst(Replacement, subs, conformances);
72+
if (c != newC)
12273
conformancesChanged = true;
123-
substConformances.push_back(*conformance);
74+
substConformances.push_back(newC);
12475
}
12576
assert(substConformances.size() == Conformance.size());
12677

0 commit comments

Comments
 (0)