Skip to content

Commit c4725f6

Browse files
committed
Sema: Refactor resolveTypeWitnessViaLookup() to call lookupQualified() directly
lookupMemberType() does additional things that we don't need here. By using lookupQualified() we can avoid realizing the substituted type until after checking the 'where' clause constraints. This should (in theory, at least) break cycles where performing the substitution triggers a recursive conformance check.
1 parent 9ea0741 commit c4725f6

File tree

1 file changed

+59
-31
lines changed

1 file changed

+59
-31
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3862,58 +3862,86 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
38623862
abort();
38633863
}
38643864

3865+
NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers);
3866+
38653867
// Look for a member type with the same name as the associated type.
3866-
auto candidates = TypeChecker::lookupMemberType(
3867-
DC, Adoptee, assocType->createNameRef(),
3868-
NameLookupFlags::ProtocolMembers);
3868+
SmallVector<ValueDecl *, 4> candidates;
3869+
3870+
DC->lookupQualified(Adoptee->getAnyNominal(),
3871+
assocType->createNameRef(),
3872+
subOptions, candidates);
38693873

38703874
// If there aren't any candidates, we're done.
3871-
if (!candidates) {
3875+
if (candidates.empty()) {
38723876
return ResolveWitnessResult::Missing;
38733877
}
38743878

38753879
// Determine which of the candidates is viable.
38763880
SmallVector<LookupTypeResultEntry, 2> viable;
38773881
SmallVector<std::pair<TypeDecl *, CheckTypeWitnessResult>, 2> nonViable;
3882+
SmallPtrSet<CanType, 4> viableTypes;
3883+
38783884
for (auto candidate : candidates) {
3879-
// Skip nested generic types.
3880-
if (auto *genericDecl = dyn_cast<GenericTypeDecl>(candidate.Member)) {
3881-
// If the declaration has generic parameters, it cannot witness an
3882-
// associated type.
3883-
if (genericDecl->isGeneric())
3884-
continue;
3885+
auto *typeDecl = cast<TypeDecl>(candidate);
38853886

3886-
// As a narrow fix for a source compatibility issue with SwiftUI's
3887-
// swiftinterface, allow the conformance if the underlying type of
3888-
// the typealias is Never.
3889-
//
3890-
// FIXME: This should be conditionalized on a new language version.
3891-
bool skipRequirementCheck = false;
3892-
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(candidate.Member)) {
3893-
if (typeAliasDecl->getUnderlyingType()->isUninhabited())
3894-
skipRequirementCheck = true;
3895-
}
3887+
// Skip other associated types.
3888+
if (isa<AssociatedTypeDecl>(typeDecl))
3889+
continue;
38963890

3897-
// If the type comes from a constrained extension or has a 'where'
3898-
// clause, check those requirements now.
3899-
if (!skipRequirementCheck &&
3900-
!TypeChecker::checkContextualRequirements(genericDecl, Adoptee,
3901-
SourceLoc(), DC)) {
3902-
continue;
3903-
}
3891+
auto *genericDecl = cast<GenericTypeDecl>(typeDecl);
3892+
3893+
// If the declaration has generic parameters, it cannot witness an
3894+
// associated type.
3895+
if (genericDecl->isGeneric())
3896+
continue;
3897+
3898+
// As a narrow fix for a source compatibility issue with SwiftUI's
3899+
// swiftinterface, allow the conformance if the underlying type of
3900+
// the typealias is Never.
3901+
//
3902+
// FIXME: This should be conditionalized on a new language version.
3903+
bool skipRequirementCheck = false;
3904+
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
3905+
if (typeAliasDecl->getUnderlyingType()->isUninhabited())
3906+
skipRequirementCheck = true;
39043907
}
39053908

39063909
// Skip typealiases with an unbound generic type as their underlying type.
3907-
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(candidate.Member))
3910+
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl))
39083911
if (typeAliasDecl->getDeclaredInterfaceType()->is<UnboundGenericType>())
39093912
continue;
39103913

3914+
// Skip dependent protocol typealiases.
3915+
//
3916+
// FIXME: This should not be necessary.
3917+
if (auto *typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
3918+
if (isa<ProtocolDecl>(typeAliasDecl->getDeclContext()) &&
3919+
typeAliasDecl->getUnderlyingType()->getCanonicalType()
3920+
->hasTypeParameter()) {
3921+
continue;
3922+
}
3923+
}
3924+
3925+
// If the type comes from a constrained extension or has a 'where'
3926+
// clause, check those requirements now.
3927+
if (!skipRequirementCheck &&
3928+
!TypeChecker::checkContextualRequirements(genericDecl, Adoptee,
3929+
SourceLoc(), DC)) {
3930+
continue;
3931+
}
3932+
3933+
auto memberType = TypeChecker::substMemberTypeWithBase(DC->getParentModule(),
3934+
typeDecl, Adoptee);
3935+
3936+
if (!viableTypes.insert(memberType->getCanonicalType()).second)
3937+
continue;
3938+
39113939
// Check this type against the protocol requirements.
39123940
if (auto checkResult =
3913-
checkTypeWitness(candidate.MemberType, assocType, Conformance)) {
3914-
nonViable.push_back({candidate.Member, checkResult});
3941+
checkTypeWitness(memberType, assocType, Conformance)) {
3942+
nonViable.push_back({typeDecl, checkResult});
39153943
} else {
3916-
viable.push_back(candidate);
3944+
viable.push_back({typeDecl, memberType, nullptr});
39173945
}
39183946
}
39193947

0 commit comments

Comments
 (0)