Skip to content

Commit 0f1234d

Browse files
committed
Sema: Tweak AssociatedTypeInference::computeFixedTypeWitness()
This is part of the -disable-experimental-associated-type-inference code path for abstract type witnesses, but I want to use it in another place. - Look in local conformances only, instead of all protocols. Philosophically, we want associated type inference to reason about each nominal type declaration or extension as a single unit. - Look for an abstract witness in any protocol that declares an associated type of the same name, not just a protocol that inherits from the associated type's protocol.
1 parent 84921db commit 0f1234d

File tree

1 file changed

+86
-44
lines changed

1 file changed

+86
-44
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,50 +2125,104 @@ AssociatedTypeDecl *swift::findDefaultedAssociatedType(
21252125
return results.size() == 1 ? results.front() : nullptr;
21262126
}
21272127

2128+
static SmallVector<ProtocolConformance *, 2>
2129+
getPeerConformances(NormalProtocolConformance *conformance) {
2130+
auto *dc = conformance->getDeclContext();
2131+
IterableDeclContext *idc = dyn_cast<ExtensionDecl>(dc);
2132+
if (!idc)
2133+
idc = cast<NominalTypeDecl>(dc);
2134+
2135+
// NonStructural skips the Sendable synthesis which can cycle, and Sendable
2136+
// doesn't have associated types anyway.
2137+
return idc->getLocalConformances(ConformanceLookupKind::NonStructural);
2138+
}
2139+
21282140
Type AssociatedTypeInference::computeFixedTypeWitness(
21292141
AssociatedTypeDecl *assocType) {
21302142
Type resultType;
21312143

2132-
// Look at all of the inherited protocols to determine whether they
2133-
// require a fixed type for this associated type.
2134-
for (auto conformedProto : dc->getSelfNominalTypeDecl()->getAllProtocols()) {
2135-
if (conformedProto != assocType->getProtocol() &&
2136-
!conformedProto->inheritsFrom(assocType->getProtocol()))
2137-
continue;
2138-
2139-
auto sig = conformedProto->getGenericSignature();
2144+
if (ctx.LangOpts.EnableExperimentalAssociatedTypeInference) {
2145+
auto selfTy = assocType->getProtocol()->getSelfInterfaceType();
2146+
2147+
// Look through other local conformances of our declaration context to see if
2148+
// any fix this associated type to a concrete type.
2149+
for (auto conformance : getPeerConformances(conformance)) {
2150+
auto *conformedProto = conformance->getProtocol();
2151+
auto sig = conformedProto->getGenericSignature();
2152+
2153+
// FIXME: The RequirementMachine will assert on re-entrant construction.
2154+
// We should find a more principled way of breaking this cycle.
2155+
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
2156+
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
2157+
conformedProto->isComputingRequirementSignature())
2158+
continue;
21402159

2141-
// FIXME: The RequirementMachine will assert on re-entrant construction.
2142-
// We should find a more principled way of breaking this cycle.
2143-
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
2144-
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
2145-
conformedProto->isComputingRequirementSignature())
2146-
continue;
2160+
auto structuralTy = DependentMemberType::get(selfTy, assocType->getName());
2161+
if (!sig->isValidTypeParameter(structuralTy))
2162+
continue;
21472163

2148-
auto selfTy = conformedProto->getSelfInterfaceType();
2149-
if (!sig->requiresProtocol(selfTy, assocType->getProtocol()))
2150-
continue;
2164+
const auto ty = sig.getReducedType(structuralTy);
21512165

2152-
auto structuralTy = DependentMemberType::get(selfTy, assocType->getName());
2153-
const auto ty = sig.getReducedType(structuralTy);
2166+
// A dependent member type with an identical base and name indicates that
2167+
// the protocol does not same-type constrain it in any way; move on to
2168+
// the next protocol.
2169+
if (auto *const memberTy = ty->getAs<DependentMemberType>()) {
2170+
if (memberTy->getBase()->isEqual(selfTy) &&
2171+
memberTy->getName() == assocType->getName())
2172+
continue;
2173+
}
21542174

2155-
// A dependent member type with an identical base and name indicates that
2156-
// the protocol does not same-type constrain it in any way; move on to
2157-
// the next protocol.
2158-
if (auto *const memberTy = ty->getAs<DependentMemberType>()) {
2159-
if (memberTy->getBase()->isEqual(selfTy) &&
2160-
memberTy->getName() == assocType->getName())
2175+
if (!resultType) {
2176+
resultType = ty;
21612177
continue;
2162-
}
2178+
}
21632179

2164-
if (!resultType) {
2165-
resultType = ty;
2166-
continue;
2180+
// FIXME: Bailing out on ambiguity.
2181+
if (!resultType->isEqual(ty))
2182+
return Type();
21672183
}
2184+
} else {
2185+
// Look at all of the inherited protocols to determine whether they
2186+
// require a fixed type for this associated type.
2187+
for (auto conformedProto : dc->getSelfNominalTypeDecl()->getAllProtocols()) {
2188+
if (conformedProto != assocType->getProtocol() &&
2189+
!conformedProto->inheritsFrom(assocType->getProtocol()))
2190+
continue;
2191+
2192+
auto sig = conformedProto->getGenericSignature();
2193+
2194+
// FIXME: The RequirementMachine will assert on re-entrant construction.
2195+
// We should find a more principled way of breaking this cycle.
2196+
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
2197+
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
2198+
conformedProto->isComputingRequirementSignature())
2199+
continue;
2200+
2201+
auto selfTy = conformedProto->getSelfInterfaceType();
2202+
if (!sig->requiresProtocol(selfTy, assocType->getProtocol()))
2203+
continue;
2204+
2205+
auto structuralTy = DependentMemberType::get(selfTy, assocType->getName());
2206+
const auto ty = sig.getReducedType(structuralTy);
2207+
2208+
// A dependent member type with an identical base and name indicates that
2209+
// the protocol does not same-type constrain it in any way; move on to
2210+
// the next protocol.
2211+
if (auto *const memberTy = ty->getAs<DependentMemberType>()) {
2212+
if (memberTy->getBase()->isEqual(selfTy) &&
2213+
memberTy->getName() == assocType->getName())
2214+
continue;
2215+
}
2216+
2217+
if (!resultType) {
2218+
resultType = ty;
2219+
continue;
2220+
}
21682221

2169-
// FIXME: Bailing out on ambiguity.
2170-
if (!resultType->isEqual(ty))
2171-
return Type();
2222+
// FIXME: Bailing out on ambiguity.
2223+
if (!resultType->isEqual(ty))
2224+
return Type();
2225+
}
21722226
}
21732227

21742228
return resultType;
@@ -2359,18 +2413,6 @@ AssociatedTypeInference::computeAbstractTypeWitness(
23592413
return llvm::None;
23602414
}
23612415

2362-
static SmallVector<ProtocolConformance *, 2>
2363-
getPeerConformances(NormalProtocolConformance *conformance) {
2364-
auto *dc = conformance->getDeclContext();
2365-
IterableDeclContext *idc = dyn_cast<ExtensionDecl>(dc);
2366-
if (!idc)
2367-
idc = cast<NominalTypeDecl>(dc);
2368-
2369-
// NonStructural skips the Sendable synthesis which can cycle, and Sendable
2370-
// doesn't have associated types anyway.
2371-
return idc->getLocalConformances(ConformanceLookupKind::NonStructural);
2372-
}
2373-
23742416
void AssociatedTypeInference::collectAbstractTypeWitnesses(
23752417
TypeWitnessSystem &system,
23762418
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes) const {

0 commit comments

Comments
 (0)