@@ -1589,17 +1589,11 @@ isUnsatisfiedReq(ConformanceChecker &checker,
1589
1589
if (!witness) {
1590
1590
// If another @objc requirement refers to the same Objective-C
1591
1591
// 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 ;
1603
1597
}
1604
1598
1605
1599
// An optional requirement might not have a witness.
@@ -3329,46 +3323,36 @@ static ArrayRef<MissingWitness> pruneMissingWitnesses(
3329
3323
scratch.push_back (missingWitness);
3330
3324
};
3331
3325
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 )) {
3336
3328
addWitness ();
3337
3329
continue ;
3338
3330
}
3339
3331
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);
3347
3334
3348
3335
// If we have already reported a function with this selector as missing,
3349
3336
// don't do it again.
3350
- if (! alreadyReportedAsMissing.insert (key). second ) {
3337
+ if (alreadyReportedAsMissing.count (key)) {
3351
3338
skipWitness ();
3352
3339
continue ;
3353
3340
}
3354
3341
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
+ });
3361
3346
3362
- if (conformance-> getWitness (otherReq) ) {
3363
- foundOtherWitness = true ;
3364
- break ;
3365
- }
3347
+ if (!sibling ) {
3348
+ alreadyReportedAsMissing. insert (key) ;
3349
+ addWitness () ;
3350
+ continue ;
3366
3351
}
3367
3352
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 ();
3372
3356
}
3373
3357
3374
3358
if (removedAny)
@@ -4621,6 +4605,22 @@ void ConformanceChecker::resolveValueWitnesses() {
4621
4605
if (isa<AccessorDecl>(requirement))
4622
4606
continue ;
4623
4607
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
+
4624
4624
// Try to resolve the witness.
4625
4625
switch (resolveWitnessTryingAllStrategies (requirement)) {
4626
4626
case ResolveWitnessResult::Success:
@@ -4638,6 +4638,33 @@ void ConformanceChecker::resolveValueWitnesses() {
4638
4638
}
4639
4639
}
4640
4640
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
+
4641
4668
void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
4642
4669
assert (!Conformance->isComplete () && " Conformance is already complete" );
4643
4670
0 commit comments