Skip to content

Commit 7c4708f

Browse files
committed
Sema: Introduce shouldRecordMissingWitness()
1 parent 516662b commit 7c4708f

File tree

1 file changed

+51
-1
lines changed

1 file changed

+51
-1
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,55 @@ filterProtocolRequirements(
35913591
return Filtered;
35923592
}
35933593

3594+
/// Sometimes a witness isn't really diagnosed as missing if we have two
3595+
/// complementary Objective-C protocol requirements, only one of which must
3596+
/// be witnessed.
3597+
static bool shouldRecordMissingWitness(
3598+
ProtocolDecl *proto,
3599+
NormalProtocolConformance *conformance,
3600+
ValueDecl *requirement) {
3601+
assert(proto == requirement->getDeclContext());
3602+
assert(proto == conformance->getProtocol());
3603+
3604+
// We only care about functions.
3605+
auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement);
3606+
if (fnRequirement == nullptr)
3607+
return true;
3608+
3609+
if (!proto->isObjC())
3610+
return true;
3611+
3612+
auto map = getObjCRequirementMap(proto);
3613+
3614+
if (getObjCRequirementSibling(
3615+
proto, fnRequirement, map,
3616+
[proto, conformance](AbstractFunctionDecl *candidate) {
3617+
// FIXME: This performs a recursive lookup in the lazy case, so
3618+
// we have to dodge the cycle.
3619+
auto &ctx = proto->getASTContext();
3620+
3621+
// If we've already resolved the sibling candidate to a valid
3622+
// witness, don't record a missing witness.
3623+
if (conformance->getWitnessUncached(candidate))
3624+
return true;
3625+
3626+
// If we're currently resolving the sibling candidate, it may
3627+
// be that the sibling is missing also, so we must record a
3628+
// missing witness.
3629+
if (ctx.evaluator.hasActiveRequest(
3630+
ValueWitnessRequest{conformance, candidate}))
3631+
return false;
3632+
3633+
// Otherwise, resolve the sibling cadidate; if its valid, don't
3634+
// record a missing witness.
3635+
return static_cast<bool>(conformance->getWitness(candidate));
3636+
})) {
3637+
return false;
3638+
}
3639+
3640+
return true;
3641+
}
3642+
35943643
/// Prune the set of missing witnesses for the given conformance, eliminating
35953644
/// any requirements that do not actually need to satisfied.
35963645
static ArrayRef<ASTContext::MissingWitness> pruneMissingWitnesses(
@@ -4393,7 +4442,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43934442

43944443
if (!numViable) {
43954444
// Save the missing requirement for later diagnosis.
4396-
GlobalMissingWitnesses.insert({requirement, matches});
4445+
if (shouldRecordMissingWitness(Proto, Conformance, requirement))
4446+
GlobalMissingWitnesses.insert({requirement, matches});
43974447
return ResolveWitnessResult::Missing;
43984448
}
43994449

0 commit comments

Comments
 (0)