@@ -1591,17 +1591,11 @@ isUnsatisfiedReq(ConformanceChecker &checker,
15911591 if (!witness) {
15921592 // If another @objc requirement refers to the same Objective-C
15931593 // method, this requirement isn't unsatisfied.
1594- if (conformance->getProtocol ()->isObjC () &&
1595- isa<AbstractFunctionDecl>(req)) {
1596- auto funcReq = cast<AbstractFunctionDecl>(req);
1597- auto key = checker.getObjCMethodKey (funcReq);
1598- for (auto otherReq : checker.getObjCRequirements (key)) {
1599- if (otherReq == req)
1600- continue ;
1601-
1602- if (conformance->getWitness (otherReq))
1603- return false ;
1604- }
1594+ if (checker.getObjCRequirementSibling (
1595+ req, [conformance](AbstractFunctionDecl *cand) {
1596+ return static_cast <bool >(conformance->getWitness (cand));
1597+ })) {
1598+ return false ;
16051599 }
16061600
16071601 // An optional requirement might not have a witness.
@@ -3331,46 +3325,36 @@ static ArrayRef<MissingWitness> pruneMissingWitnesses(
33313325 scratch.push_back (missingWitness);
33323326 };
33333327
3334- // We only care about functions
3335- auto funcRequirement = dyn_cast<AbstractFunctionDecl>(
3336- missingWitness.requirement );
3337- if (!funcRequirement) {
3328+ // We only care about functions.
3329+ if (!isa<AbstractFunctionDecl>(missingWitness.requirement )) {
33383330 addWitness ();
33393331 continue ;
33403332 }
33413333
3342- // ... whose selector is one that maps to multiple requirement declarations.
3343- auto key = checker.getObjCMethodKey (funcRequirement);
3344- auto matchingRequirements = checker.getObjCRequirements (key);
3345- if (matchingRequirements.size () < 2 ) {
3346- addWitness ();
3347- continue ;
3348- }
3334+ auto fnRequirement = cast<AbstractFunctionDecl>(missingWitness.requirement );
3335+ auto key = checker.getObjCMethodKey (fnRequirement);
33493336
33503337 // If we have already reported a function with this selector as missing,
33513338 // don't do it again.
3352- if (! alreadyReportedAsMissing.insert (key). second ) {
3339+ if (alreadyReportedAsMissing.count (key)) {
33533340 skipWitness ();
33543341 continue ;
33553342 }
33563343
3357- // If there is a witness for any of the *other* requirements with this
3358- // same selector, don't report it.
3359- bool foundOtherWitness = false ;
3360- for (auto otherReq : matchingRequirements) {
3361- if (otherReq == funcRequirement)
3362- continue ;
3344+ auto sibling = checker.getObjCRequirementSibling (
3345+ fnRequirement, [conformance](AbstractFunctionDecl *candidate) {
3346+ return static_cast <bool >(conformance->getWitness (candidate));
3347+ });
33633348
3364- if (conformance-> getWitness (otherReq) ) {
3365- foundOtherWitness = true ;
3366- break ;
3367- }
3349+ if (!sibling ) {
3350+ alreadyReportedAsMissing. insert (key) ;
3351+ addWitness () ;
3352+ continue ;
33683353 }
33693354
3370- if (foundOtherWitness)
3371- skipWitness ();
3372- else
3373- addWitness ();
3355+ // Otherwise, there is a witness for any of the *other* requirements with
3356+ // this same selector, so prune it out.
3357+ skipWitness ();
33743358 }
33753359
33763360 if (removedAny)
@@ -4623,6 +4607,22 @@ void ConformanceChecker::resolveValueWitnesses() {
46234607 if (isa<AccessorDecl>(requirement))
46244608 continue ;
46254609
4610+ // If this requirement is part of a pair of imported async requirements,
4611+ // where one has already been witnessed, we can skip it.
4612+ //
4613+ // This situation primarily arises when the ClangImporter translates an
4614+ // async-looking ObjC protocol method requirement into two Swift protocol
4615+ // requirements: an async version and a sync version. Exactly one of the two
4616+ // must be witnessed by the conformer.
4617+ if (!requirement->isImplicit () && getObjCRequirementSibling (
4618+ requirement, [this ](AbstractFunctionDecl *cand) {
4619+ return !cand->getAttrs ().hasAttribute <OptionalAttr>() &&
4620+ !cand->isImplicit () &&
4621+ this ->Conformance ->hasWitness (cand);
4622+ })) {
4623+ continue ;
4624+ }
4625+
46264626 // Try to resolve the witness.
46274627 switch (resolveWitnessTryingAllStrategies (requirement)) {
46284628 case ResolveWitnessResult::Success:
@@ -4640,6 +4640,33 @@ void ConformanceChecker::resolveValueWitnesses() {
46404640 }
46414641}
46424642
4643+ ValueDecl *ConformanceChecker::getObjCRequirementSibling (ValueDecl *requirement,
4644+ llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
4645+ if (!Proto->isObjC ())
4646+ return nullptr ;
4647+
4648+ assert (requirement->isProtocolRequirement ());
4649+ assert (Proto == requirement->getDeclContext ()->getAsDecl ());
4650+
4651+ // We only care about functions
4652+ if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
4653+ auto fnSelector = getObjCMethodKey (fnRequirement);
4654+ auto similarRequirements = getObjCRequirements (fnSelector);
4655+ // ... whose selector is one that maps to multiple requirement declarations.
4656+ for (auto candidate : similarRequirements) {
4657+ if (candidate == fnRequirement)
4658+ continue ; // skip the requirement we're trying to resolve.
4659+
4660+ if (!predicate (candidate))
4661+ continue ; // skip if doesn't match requirements
4662+
4663+ return candidate;
4664+ }
4665+ }
4666+
4667+ return nullptr ;
4668+ }
4669+
46434670void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
46444671 assert (!Conformance->isComplete () && " Conformance is already complete" );
46454672
0 commit comments