@@ -1589,17 +1589,11 @@ isUnsatisfiedReq(ConformanceChecker &checker,
15891589 if (!witness) {
15901590 // If another @objc requirement refers to the same Objective-C
15911591 // method, this requirement isn't unsatisfied.
1592- if (conformance->getProtocol ()->isObjC () &&
1593- isa<AbstractFunctionDecl>(req)) {
1594- auto funcReq = cast<AbstractFunctionDecl>(req);
1595- auto key = checker.getObjCMethodKey (funcReq);
1596- for (auto otherReq : checker.getObjCRequirements (key)) {
1597- if (otherReq == req)
1598- continue ;
1599-
1600- if (conformance->getWitness (otherReq))
1601- return false ;
1602- }
1592+ if (checker.getObjCRequirementSibling (
1593+ req, [conformance](AbstractFunctionDecl *cand) {
1594+ return static_cast <bool >(conformance->getWitness (cand));
1595+ })) {
1596+ return false ;
16031597 }
16041598
16051599 // An optional requirement might not have a witness.
@@ -3329,46 +3323,36 @@ static ArrayRef<MissingWitness> pruneMissingWitnesses(
33293323 scratch.push_back (missingWitness);
33303324 };
33313325
3332- // We only care about functions
3333- auto funcRequirement = dyn_cast<AbstractFunctionDecl>(
3334- missingWitness.requirement );
3335- if (!funcRequirement) {
3326+ // We only care about functions.
3327+ if (!isa<AbstractFunctionDecl>(missingWitness.requirement )) {
33363328 addWitness ();
33373329 continue ;
33383330 }
33393331
3340- // ... whose selector is one that maps to multiple requirement declarations.
3341- auto key = checker.getObjCMethodKey (funcRequirement);
3342- auto matchingRequirements = checker.getObjCRequirements (key);
3343- if (matchingRequirements.size () < 2 ) {
3344- addWitness ();
3345- continue ;
3346- }
3332+ auto fnRequirement = cast<AbstractFunctionDecl>(missingWitness.requirement );
3333+ auto key = checker.getObjCMethodKey (fnRequirement);
33473334
33483335 // If we have already reported a function with this selector as missing,
33493336 // don't do it again.
3350- if (! alreadyReportedAsMissing.insert (key). second ) {
3337+ if (alreadyReportedAsMissing.count (key)) {
33513338 skipWitness ();
33523339 continue ;
33533340 }
33543341
3355- // If there is a witness for any of the *other* requirements with this
3356- // same selector, don't report it.
3357- bool foundOtherWitness = false ;
3358- for (auto otherReq : matchingRequirements) {
3359- if (otherReq == funcRequirement)
3360- continue ;
3342+ auto sibling = checker.getObjCRequirementSibling (
3343+ fnRequirement, [conformance](AbstractFunctionDecl *candidate) {
3344+ return static_cast <bool >(conformance->getWitness (candidate));
3345+ });
33613346
3362- if (conformance-> getWitness (otherReq) ) {
3363- foundOtherWitness = true ;
3364- break ;
3365- }
3347+ if (!sibling ) {
3348+ alreadyReportedAsMissing. insert (key) ;
3349+ addWitness () ;
3350+ continue ;
33663351 }
33673352
3368- if (foundOtherWitness)
3369- skipWitness ();
3370- else
3371- addWitness ();
3353+ // Otherwise, there is a witness for any of the *other* requirements with
3354+ // this same selector, so prune it out.
3355+ skipWitness ();
33723356 }
33733357
33743358 if (removedAny)
@@ -4621,6 +4605,22 @@ void ConformanceChecker::resolveValueWitnesses() {
46214605 if (isa<AccessorDecl>(requirement))
46224606 continue ;
46234607
4608+ // If this requirement is part of a pair of imported async requirements,
4609+ // where one has already been witnessed, we can skip it.
4610+ //
4611+ // This situation primarily arises when the ClangImporter translates an
4612+ // async-looking ObjC protocol method requirement into two Swift protocol
4613+ // requirements: an async version and a sync version. Exactly one of the two
4614+ // must be witnessed by the conformer.
4615+ if (!requirement->isImplicit () && getObjCRequirementSibling (
4616+ requirement, [this ](AbstractFunctionDecl *cand) {
4617+ return !cand->getAttrs ().hasAttribute <OptionalAttr>() &&
4618+ !cand->isImplicit () &&
4619+ this ->Conformance ->hasWitness (cand);
4620+ })) {
4621+ continue ;
4622+ }
4623+
46244624 // Try to resolve the witness.
46254625 switch (resolveWitnessTryingAllStrategies (requirement)) {
46264626 case ResolveWitnessResult::Success:
@@ -4638,6 +4638,33 @@ void ConformanceChecker::resolveValueWitnesses() {
46384638 }
46394639}
46404640
4641+ ValueDecl *ConformanceChecker::getObjCRequirementSibling (ValueDecl *requirement,
4642+ llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
4643+ if (!Proto->isObjC ())
4644+ return nullptr ;
4645+
4646+ assert (requirement->isProtocolRequirement ());
4647+ assert (Proto == requirement->getDeclContext ()->getAsDecl ());
4648+
4649+ // We only care about functions
4650+ if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
4651+ auto fnSelector = getObjCMethodKey (fnRequirement);
4652+ auto similarRequirements = getObjCRequirements (fnSelector);
4653+ // ... whose selector is one that maps to multiple requirement declarations.
4654+ for (auto candidate : similarRequirements) {
4655+ if (candidate == fnRequirement)
4656+ continue ; // skip the requirement we're trying to resolve.
4657+
4658+ if (!predicate (candidate))
4659+ continue ; // skip if doesn't match requirements
4660+
4661+ return candidate;
4662+ }
4663+ }
4664+
4665+ return nullptr ;
4666+ }
4667+
46414668void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
46424669 assert (!Conformance->isComplete () && " Conformance is already complete" );
46434670
0 commit comments