@@ -1591,17 +1591,11 @@ isUnsatisfiedReq(ConformanceChecker &checker,
1591
1591
if (!witness) {
1592
1592
// If another @objc requirement refers to the same Objective-C
1593
1593
// 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 ;
1605
1599
}
1606
1600
1607
1601
// An optional requirement might not have a witness.
@@ -3331,46 +3325,36 @@ static ArrayRef<MissingWitness> pruneMissingWitnesses(
3331
3325
scratch.push_back (missingWitness);
3332
3326
};
3333
3327
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 )) {
3338
3330
addWitness ();
3339
3331
continue ;
3340
3332
}
3341
3333
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);
3349
3336
3350
3337
// If we have already reported a function with this selector as missing,
3351
3338
// don't do it again.
3352
- if (! alreadyReportedAsMissing.insert (key). second ) {
3339
+ if (alreadyReportedAsMissing.count (key)) {
3353
3340
skipWitness ();
3354
3341
continue ;
3355
3342
}
3356
3343
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
+ });
3363
3348
3364
- if (conformance-> getWitness (otherReq) ) {
3365
- foundOtherWitness = true ;
3366
- break ;
3367
- }
3349
+ if (!sibling ) {
3350
+ alreadyReportedAsMissing. insert (key) ;
3351
+ addWitness () ;
3352
+ continue ;
3368
3353
}
3369
3354
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 ();
3374
3358
}
3375
3359
3376
3360
if (removedAny)
@@ -4623,6 +4607,22 @@ void ConformanceChecker::resolveValueWitnesses() {
4623
4607
if (isa<AccessorDecl>(requirement))
4624
4608
continue ;
4625
4609
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
+
4626
4626
// Try to resolve the witness.
4627
4627
switch (resolveWitnessTryingAllStrategies (requirement)) {
4628
4628
case ResolveWitnessResult::Success:
@@ -4640,6 +4640,33 @@ void ConformanceChecker::resolveValueWitnesses() {
4640
4640
}
4641
4641
}
4642
4642
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
+
4643
4670
void ConformanceChecker::checkConformance (MissingWitnessDiagnosisKind Kind) {
4644
4671
assert (!Conformance->isComplete () && " Conformance is already complete" );
4645
4672
0 commit comments