Skip to content

Commit 83e8588

Browse files
committed
[AST Verifier] Handle ObjC requirements satisfied by alternative requirements.
With 'async' imports of Objective-C protocol requirements, a single Objective-C method will produce two different requirements in the protocol, with the same Objective-C selector. Teach the AST verifier that it is sufficient for just one of the requirements with that Objective-C selector to be satisfied by a witness. Fixes rdar://72742910.
1 parent 344747c commit 83e8588

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,41 @@ class Verifier : public ASTWalker {
26202620
abort();
26212621
}
26222622

2623+
// Tracking for those Objective-C requirements that have witnesses.
2624+
llvm::SmallDenseSet<std::pair<ObjCSelector, char>> hasObjCWitnessMap;
2625+
bool populatedObjCWitnesses = false;
2626+
auto populateObjCWitnesses = [&] {
2627+
if (populatedObjCWitnesses)
2628+
return;
2629+
2630+
populatedObjCWitnesses = true;
2631+
for (auto req : proto->getMembers()) {
2632+
if (auto reqFunc = dyn_cast<AbstractFunctionDecl>(req)) {
2633+
if (normal->hasWitness(reqFunc)) {
2634+
hasObjCWitnessMap.insert(
2635+
{reqFunc->getObjCSelector(), reqFunc->isInstanceMember()});
2636+
}
2637+
}
2638+
}
2639+
};
2640+
2641+
// Check whether there is a witness with the same selector and kind as
2642+
// this requirement.
2643+
auto hasObjCWitness = [&](ValueDecl *req) {
2644+
if (!proto->isObjC())
2645+
return false;
2646+
2647+
auto func = dyn_cast<AbstractFunctionDecl>(req);
2648+
if (!func)
2649+
return false;
2650+
2651+
populateObjCWitnesses();
2652+
2653+
std::pair<ObjCSelector, char> key(
2654+
func->getObjCSelector(), func->isInstanceMember());
2655+
return hasObjCWitnessMap.count(key) > 0;
2656+
};
2657+
26232658
// Check that a normal protocol conformance is complete.
26242659
for (auto member : proto->getMembers()) {
26252660
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
@@ -2649,7 +2684,6 @@ class Verifier : public ASTWalker {
26492684
if (isa<AccessorDecl>(member))
26502685
continue;
26512686

2652-
26532687
if (auto req = dyn_cast<ValueDecl>(member)) {
26542688
if (!normal->hasWitness(req)) {
26552689
if ((req->getAttrs().isUnavailable(Ctx) ||
@@ -2658,6 +2692,10 @@ class Verifier : public ASTWalker {
26582692
continue;
26592693
}
26602694

2695+
// Check if *any* witness matches the Objective-C selector.
2696+
if (hasObjCWitness(req))
2697+
continue;
2698+
26612699
dumpRef(decl);
26622700
Out << " is missing witness for "
26632701
<< conformance->getProtocol()->getName().str()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -I %S/Inputs/custom-modules -enable-experimental-concurrency %s -verify
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: concurrency
5+
import Foundation
6+
import ObjCConcurrency
7+
8+
// Conform via async method
9+
class C1: ConcurrentProtocol {
10+
func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }
11+
12+
func askUser(toJumpThroughHoop hoop: String) async -> String { "hello" }
13+
}

0 commit comments

Comments
 (0)