Skip to content

Commit 5d61083

Browse files
committed
RequirementMachine: Split off getRelativeTermForType() from concretizeNestedTypesFromConcreteParent()
The logic for handling the abstract type witness case correctly handles DependentMemberTypes. We want to use this for concrete type witnesses too, since they might contain type parameters as structural sub-components.
1 parent e36b95d commit 5d61083

File tree

1 file changed

+66
-20
lines changed

1 file changed

+66
-20
lines changed

lib/AST/RequirementMachine/EquivalenceClassMap.cpp

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,67 @@ Type EquivalenceClass::getConcreteType(
143143
ctx);
144144
}
145145

146+
/// Computes the term corresponding to a member type access on a substitution.
147+
///
148+
/// The type witness is a type parameter of the form τ_0_n.X.Y.Z,
149+
/// where 'n' is an index into the substitution array.
150+
///
151+
/// If the nth entry in the array is S, this will produce S.X.Y.Z.
152+
///
153+
/// There is a special behavior if the substitution is a term consisting of a
154+
/// single protocol atom [P]. If the innermost associated type in
155+
/// \p typeWitness is [Q:Foo], the result will be [P:Foo], not [P].[Q:Foo] or
156+
/// [Q:Foo].
157+
static MutableTerm getRelativeTermForType(CanType typeWitness,
158+
ArrayRef<Term> substitutions,
159+
RewriteContext &ctx) {
160+
MutableTerm result;
161+
162+
// Get the substitution S corresponding to τ_0_n.
163+
unsigned index = getGenericParamIndex(typeWitness->getRootGenericParam());
164+
result = MutableTerm(substitutions[index]);
165+
166+
// If the substitution is a term consisting of a single protocol atom
167+
// [P], save P for later.
168+
const ProtocolDecl *proto = nullptr;
169+
if (result.size() == 1 &&
170+
result[0].getKind() == Atom::Kind::Protocol) {
171+
proto = result[0].getProtocol();
172+
}
173+
174+
// Collect zero or more member type names in reverse order.
175+
SmallVector<Atom, 3> atoms;
176+
while (auto memberType = dyn_cast<DependentMemberType>(typeWitness)) {
177+
typeWitness = memberType.getBase();
178+
179+
auto *assocType = memberType->getAssocType();
180+
assert(assocType != nullptr &&
181+
"Conformance checking should not produce unresolved member types");
182+
183+
// If the substitution is a term consisting of a single protocol atom [P],
184+
// produce [P:Foo] instead of [P].[Q:Foo] or [Q:Foo].
185+
const auto *thisProto = assocType->getProtocol();
186+
if (proto && isa<GenericTypeParamType>(typeWitness)) {
187+
thisProto = proto;
188+
189+
assert(result.size() == 1);
190+
assert(result[0].getKind() == Atom::Kind::Protocol);
191+
assert(result[0].getProtocol() == proto);
192+
result = MutableTerm();
193+
}
194+
195+
atoms.push_back(Atom::forAssociatedType(thisProto,
196+
assocType->getName(), ctx));
197+
}
198+
199+
// Add the member type names.
200+
std::reverse(atoms.begin(), atoms.end());
201+
for (auto atom : atoms)
202+
result.add(atom);
203+
204+
return result;
205+
}
206+
146207
/// Given a concrete type that is a structural sub-component of a concrete
147208
/// type produced by RewriteSystemBuilder::getConcreteSubstitutionSchema(),
148209
/// collect the subset of referenced substitutions and renumber the generic
@@ -607,23 +668,9 @@ void EquivalenceClassMap::concretizeNestedTypesFromConcreteParent(
607668
// The type witness is a type parameter of the form τ_0_n.X.Y...Z,
608669
// where 'n' is an index into the substitution array.
609670
//
610-
// Collect zero or more member type names in reverse order.
611-
SmallVector<Atom, 3> atoms;
612-
while (auto memberType = dyn_cast<DependentMemberType>(typeWitness)) {
613-
atoms.push_back(Atom::forName(memberType->getName(), Context));
614-
typeWitness = memberType.getBase();
615-
}
616-
617-
// Get the substitution S corresponding to τ_0_n.
618-
unsigned index = getGenericParamIndex(typeWitness);
619-
constraintType = MutableTerm(substitutions[index]);
620-
621-
// Add the member type names.
622-
std::reverse(atoms.begin(), atoms.end());
623-
for (auto atom : atoms)
624-
constraintType.add(atom);
625-
626-
// Add a rule T => S.X.Y...Z.
671+
// Add a rule T => S.X.Y...Z, where S is the nth substitution term.
672+
constraintType = getRelativeTermForType(typeWitness, substitutions,
673+
Context);
627674

628675
} else {
629676
// The type witness is a concrete type.
@@ -635,12 +682,11 @@ void EquivalenceClassMap::concretizeNestedTypesFromConcreteParent(
635682
remapConcreteSubstitutionSchema(typeWitness, substitutions,
636683
Context.getASTContext(),
637684
result);
685+
686+
// Add a rule T.[P:A].[concrete: Foo.A] => T.[P:A].
638687
constraintType.add(
639688
Atom::forConcreteType(
640689
typeWitnessSchema, result, Context));
641-
642-
// Add a rule T.[P:A].[concrete: Foo.A] => T.[P:A].
643-
644690
}
645691

646692
inducedRules.emplace_back(subjectType, constraintType);

0 commit comments

Comments
 (0)