Skip to content

Commit 97bd500

Browse files
committed
Break dependency cycle between @objc checking and and "renamed" availability.
The filtering used to allow `@objc` protocols to have both an `async` and a completion-handler version of the same method was dependent on the resolution of the "renamed" declaration (for `@available(..., renamed: "")`), which in tern was dependent on whether the declaration is `@objc`... causing a cycle. Break the cycle by moving the filtering later. Fixes rdar://99618060.
1 parent 965a966 commit 97bd500

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed

lib/AST/NameLookup.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,15 +1741,6 @@ shouldDiagnoseConflict(NominalTypeDecl *ty, AbstractFunctionDecl *newDecl,
17411741
}))
17421742
return false;
17431743

1744-
// If we're looking at protocol requirements, is the new method an async
1745-
// alternative of any existing method, or vice versa?
1746-
if (isa<ProtocolDecl>(ty) &&
1747-
llvm::any_of(vec, [&](AbstractFunctionDecl *oldDecl) {
1748-
return newDecl->getAsyncAlternative(/*isKnownObjC=*/true) == oldDecl
1749-
|| oldDecl->getAsyncAlternative(/*isKnownObjC=*/true) == newDecl;
1750-
}))
1751-
return false;
1752-
17531744
return true;
17541745
}
17551746

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2448,20 +2448,36 @@ getObjCMethodConflictDecls(const SourceFile::ObjCMethodConflict &conflict) {
24482448
auto methods = conflict.typeDecl->lookupDirect(conflict.selector,
24492449
conflict.isInstanceMethod);
24502450

2451+
// Find async alternatives for each.
2452+
llvm::SmallDenseMap<AbstractFunctionDecl *, AbstractFunctionDecl *>
2453+
asyncAlternatives;
2454+
for (auto method : methods) {
2455+
if (isa<ProtocolDecl>(method->getDeclContext())) {
2456+
if (auto alt = method->getAsyncAlternative(/*isKnownObjC=*/true))
2457+
asyncAlternatives[method] = alt;
2458+
}
2459+
}
2460+
24512461
// Erase any invalid or stub declarations. We don't want to complain about
24522462
// them, because we might already have complained about redeclarations
24532463
// based on Swift matching.
2454-
llvm::erase_if(methods, [](AbstractFunctionDecl *afd) -> bool {
2464+
llvm::erase_if(methods,
2465+
[&asyncAlternatives](AbstractFunctionDecl *afd) -> bool {
24552466
if (afd->isInvalid())
24562467
return true;
24572468

2469+
// If there is an async alternative, remove this entry.
2470+
if (asyncAlternatives.count(afd))
2471+
return true;
2472+
24582473
if (auto ad = dyn_cast<AccessorDecl>(afd))
24592474
return ad->getStorage()->isInvalid();
24602475

24612476
if (auto *ctor = dyn_cast<ConstructorDecl>(afd)) {
24622477
if (ctor->hasStubImplementation())
24632478
return true;
24642479
}
2480+
24652481
return false;
24662482
});
24672483

test/decl/objc_redeclaration.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,16 @@ extension MyObject {
6666
public override convenience init() {} // expected-error{{initializer 'init()' with Objective-C selector 'init' conflicts with implicit initializer 'init()' with the same Objective-C selector}}
6767
}
6868

69+
// Ensure that we don't have cycles with the "renamed decl" request.
70+
@available(SwiftStdlib 5.1, *)
71+
@objc protocol MyProtocolWithAsync {
72+
@available(*, renamed: "confirm(thing:)")
73+
@objc(confirmThing:completion:)
74+
optional func confirm(thing: AnyObject, completion: @escaping (AnyObject) -> Void)
75+
76+
@objc(confirmThing:completion:)
77+
optional func confirm(thing: AnyObject) async -> AnyObject
78+
}
79+
6980
// FIXME: Remove -verify-ignore-unknown.
7081
// <unknown>:0: error: unexpected note produced: 'nsstringProperty2' previously declared here

0 commit comments

Comments
 (0)