Skip to content

Commit c97d32a

Browse files
committed
RequirementMachine: getTermForType() produces resolved associated type atoms
1 parent e8eab41 commit c97d32a

File tree

1 file changed

+60
-6
lines changed

1 file changed

+60
-6
lines changed

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -854,26 +854,80 @@ Term RewriteContext::getTermForType(CanType paramType,
854854
/// parameter atom.
855855
///
856856
/// If \p proto is non-null, this is a term relative to a protocol's
857-
/// 'Self' type. The term is rooted in a protocol atom.
857+
/// 'Self' type. The term is rooted in a protocol atom for this protocol,
858+
/// or an associated type atom for some associated type in this protocol.
859+
///
860+
/// Resolved DependentMemberTypes map to associated type atoms.
861+
/// Unresolved DependentMemberTypes map to name atoms.
862+
///
863+
/// Note the behavior of the root term is special if it is an associated
864+
/// type atom. The protocol of the associated type is always mapped to
865+
/// \p proto if it was provided. This ensures we get the correct behavior
866+
/// if a protocol places a constraint on an associated type inherited from
867+
/// another protocol:
868+
///
869+
/// protocol P {
870+
/// associatedtype Foo
871+
/// }
872+
///
873+
/// protocol Q : P where Foo : R {}
874+
///
875+
/// protocol R {}
876+
///
877+
/// The DependentMemberType in the requirement signature of Q refers to
878+
/// P::Foo.
879+
///
880+
/// However, we want Q's requirement signature to introduce the rewrite rule
881+
///
882+
/// [Q:Foo].[R] => [Q:Foo]
883+
///
884+
/// and not
885+
///
886+
/// [P:Foo].[R] => [P:Foo]
887+
///
888+
/// This is because the rule only applies to Q's logical override of Foo, and
889+
/// not P's Foo.
890+
///
891+
/// To handle this, getMutableTermForType() behaves as follows:
892+
///
893+
/// Self.P::Foo with proto = P => [P:Foo]
894+
/// Self.P::Foo with proto = Q => [Q:Foo]
895+
/// τ_0_0.P::Foo with proto == nullptr => τ_0_0.[P:Foo]
858896
///
859-
/// The bound associated types in the interface type are ignored; the
860-
/// resulting term consists entirely of a root atom followed by zero
861-
/// or more name atoms.
862897
MutableTerm RewriteContext::getMutableTermForType(CanType paramType,
863898
const ProtocolDecl *proto) {
864899
assert(paramType->isTypeParameter());
865900

866901
// Collect zero or more nested type names in reverse order.
902+
bool innermostAssocTypeWasResolved = false;
903+
867904
SmallVector<Atom, 3> atoms;
868905
while (auto memberType = dyn_cast<DependentMemberType>(paramType)) {
869-
atoms.push_back(Atom::forName(memberType->getName(), *this));
870906
paramType = memberType.getBase();
907+
908+
if (auto *assocType = memberType->getAssocType()) {
909+
const auto *thisProto = assocType->getProtocol();
910+
if (proto && isa<GenericTypeParamType>(paramType)) {
911+
thisProto = proto;
912+
innermostAssocTypeWasResolved = true;
913+
}
914+
atoms.push_back(Atom::forAssociatedType(thisProto,
915+
assocType->getName(),
916+
*this));
917+
} else {
918+
atoms.push_back(Atom::forName(memberType->getName(), *this));
919+
innermostAssocTypeWasResolved = false;
920+
}
871921
}
872922

873923
// Add the root atom at the end.
874924
if (proto) {
875925
assert(proto->getSelfInterfaceType()->isEqual(paramType));
876-
atoms.push_back(Atom::forProtocol(proto, *this));
926+
927+
// Self.Foo becomes [P].Foo
928+
// Self.Q::Foo becomes [P:Foo] (not [Q:Foo] or [P].[Q:Foo])
929+
if (!innermostAssocTypeWasResolved)
930+
atoms.push_back(Atom::forProtocol(proto, *this));
877931
} else {
878932
atoms.push_back(Atom::forGenericParam(
879933
cast<GenericTypeParamType>(paramType), *this));

0 commit comments

Comments
 (0)