Skip to content

Commit c43ca8a

Browse files
[Sema] Adapt witness resolver to fail if default RawRepresentable generic function is best witness when raw representable enum can derive equatable conformance
1 parent 7ef1325 commit c43ca8a

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3833,6 +3833,25 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
38333833
}
38343834
}
38353835

3836+
// If the given witness matches a generic RawRepresentable function conforming
3837+
// with a given protocol e.g. `func == <T : RawRepresentable>(lhs: T, rhs: T) ->
3838+
// Bool where T.RawValue : Equatable`
3839+
static bool isRawRepresentableGenericFunction(
3840+
ASTContext &ctx, const ValueDecl *witness,
3841+
const NormalProtocolConformance *conformance) {
3842+
auto *fnDecl = dyn_cast<AbstractFunctionDecl>(witness);
3843+
return fnDecl && fnDecl->isGeneric() &&
3844+
llvm::all_of(
3845+
fnDecl->getGenericRequirements(), [&](Requirement genericReq) {
3846+
return genericReq.getKind() == RequirementKind::Conformance &&
3847+
(genericReq.getProtocolDecl() ==
3848+
ctx.getProtocol(
3849+
KnownProtocolKind::RawRepresentable) ||
3850+
genericReq.getProtocolDecl() ==
3851+
conformance->getProtocol());
3852+
});
3853+
}
3854+
38363855
ResolveWitnessResult
38373856
ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
38383857
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
@@ -3881,6 +3900,16 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
38813900
bool considerRenames =
38823901
!canDerive && !requirement->getAttrs().hasAttribute<OptionalAttr>() &&
38833902
!requirement->getAttrs().isUnavailable(getASTContext());
3903+
3904+
auto &ctx = getASTContext();
3905+
bool isEquatableConformance = Conformance->getProtocol() ==
3906+
ctx.getProtocol(KnownProtocolKind::Equatable);
3907+
3908+
auto decl = Conformance->getDeclContext()->getSelfNominalTypeDecl();
3909+
auto *enumDecl = dyn_cast_or_null<EnumDecl>(decl);
3910+
bool isSwiftRawRepresentableEnum =
3911+
enumDecl && enumDecl->hasRawType() && !enumDecl->isObjC();
3912+
38843913
if (findBestWitness(requirement,
38853914
considerRenames ? &ignoringNames : nullptr,
38863915
Conformance,
@@ -3889,6 +3918,17 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
38893918
const auto &best = matches[bestIdx];
38903919
auto witness = best.Witness;
38913920

3921+
if (canDerive && isSwiftRawRepresentableEnum && isEquatableConformance) {
3922+
// For swift enum types that can derive equatable conformance,
3923+
// if the best witness is default generic conditional conforming
3924+
// `func == <T : RawRepresentable>(lhs: T, rhs: T) -> Bool where
3925+
// T.RawValue : Equatable` let's return as missing and derive
3926+
// the conformance since it is possible.
3927+
if (isRawRepresentableGenericFunction(ctx, witness, Conformance)) {
3928+
return ResolveWitnessResult::Missing;
3929+
}
3930+
}
3931+
38923932
// If the name didn't actually line up, complain.
38933933
if (ignoringNames &&
38943934
requirement->getName() != best.Witness->getName() &&

0 commit comments

Comments
 (0)