Skip to content

Commit 9890088

Browse files
authored
Merge pull request #60081 from beccadax/earth-import-conflict
2 parents 0b316f8 + e908766 commit 9890088

File tree

7 files changed

+59
-11
lines changed

7 files changed

+59
-11
lines changed

lib/AST/NameLookup.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/Basic/Statistic.h"
3737
#include "swift/ClangImporter/ClangImporterRequests.h"
3838
#include "swift/Parse/Lexer.h"
39+
#include "swift/Strings.h"
3940
#include "clang/AST/DeclObjC.h"
4041
#include "clang/Basic/Specifiers.h"
4142
#include "llvm/ADT/DenseMap.h"
@@ -1716,14 +1717,34 @@ NominalTypeDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
17161717
return stored.Methods;
17171718
}
17181719

1719-
/// Is the new method an async alternative of any existing method, or vice
1720-
/// versa?
1721-
static bool isAnAsyncAlternative(AbstractFunctionDecl *newDecl,
1722-
llvm::TinyPtrVector<AbstractFunctionDecl *> &vec) {
1723-
return llvm::any_of(vec, [&](AbstractFunctionDecl *oldDecl) {
1720+
/// If there is an apparent conflict between \p newDecl and one of the methods
1721+
/// in \p vec, should we diagnose it?
1722+
static bool
1723+
shouldDiagnoseConflict(NominalTypeDecl *ty, AbstractFunctionDecl *newDecl,
1724+
llvm::TinyPtrVector<AbstractFunctionDecl *> &vec) {
1725+
// Are all conflicting methods imported from ObjC and in our ObjC half or a
1726+
// bridging header? Some code bases implement ObjC methods in Swift even
1727+
// though it's not exactly supported.
1728+
auto newDeclModuleName = newDecl->getModuleContext()->getName();
1729+
if (llvm::all_of(vec, [&](AbstractFunctionDecl *oldDecl) {
1730+
if (!oldDecl->hasClangNode())
1731+
return false;
1732+
auto oldDeclModuleName = oldDecl->getModuleContext()->getName();
1733+
return oldDeclModuleName == newDeclModuleName
1734+
|| oldDeclModuleName.str() == CLANG_HEADER_MODULE_NAME;
1735+
}))
1736+
return false;
1737+
1738+
// If we're looking at protocol requirements, is the new method an async
1739+
// alternative of any existing method, or vice versa?
1740+
if (isa<ProtocolDecl>(ty) &&
1741+
llvm::any_of(vec, [&](AbstractFunctionDecl *oldDecl) {
17241742
return newDecl->getAsyncAlternative(/*isKnownObjC=*/true) == oldDecl
17251743
|| oldDecl->getAsyncAlternative(/*isKnownObjC=*/true) == newDecl;
1726-
});
1744+
}))
1745+
return false;
1746+
1747+
return true;
17271748
}
17281749

17291750
void NominalTypeDecl::recordObjCMethod(AbstractFunctionDecl *method,
@@ -1743,7 +1764,7 @@ void NominalTypeDecl::recordObjCMethod(AbstractFunctionDecl *method,
17431764
if (auto *sf = method->getParentSourceFile()) {
17441765
if (vec.empty()) {
17451766
sf->ObjCMethodList.push_back(method);
1746-
} else if (!isa<ProtocolDecl>(this) || !isAnAsyncAlternative(method, vec)) {
1767+
} else if (shouldDiagnoseConflict(this, method, vec)) {
17471768
// We have a conflict.
17481769
sf->ObjCMethodConflicts.insert({ this, selector, isInstanceMethod });
17491770
}

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2269,7 +2269,7 @@ namespace {
22692269
// location within that source file.
22702270
SourceFile *lhsSF = lhs->getDeclContext()->getParentSourceFile();
22712271
SourceFile *rhsSF = rhs->getDeclContext()->getParentSourceFile();
2272-
if (lhsSF == rhsSF) {
2272+
if (lhsSF && lhsSF == rhsSF) {
22732273
// If only one location is valid, the valid location comes first.
22742274
if (lhs->getLoc().isValid() != rhs->getLoc().isValid()) {
22752275
return lhs->getLoc().isValid();

test/ClangImporter/Inputs/custom-modules/module.map

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,8 @@ module CommonName {
271271
header "CommonName.h"
272272
export *
273273
}
274+
275+
module objc_init_redundant {
276+
header "objc_init_redundant.h"
277+
export *
278+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <Foundation.h>
2+
3+
@interface MyObject : NSObject
4+
5+
- (void)implementedInSwift;
6+
7+
@end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <Foundation.h>
2+
3+
@interface MyBridgedObject : NSObject
4+
5+
- (void)implementedInSwift;
6+
7+
@end

test/ClangImporter/objc_init_redundant.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/Inputs/custom-modules) -emit-sil %s -verify
2-
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/Inputs/custom-modules) -emit-sil %s > %t.log 2>&1
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/Inputs/custom-modules) -import-underlying-module -import-objc-header %S/Inputs/objc_init_redundant_bridging.h -emit-sil %s -verify
2+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk -I %S/Inputs/custom-modules) -import-underlying-module -import-objc-header %S/Inputs/objc_init_redundant_bridging.h -emit-sil %s > %t.log 2>&1
33
// RUN: %FileCheck %s < %t.log
44

55
// REQUIRES: objc_interop
@@ -19,3 +19,12 @@ extension NSObject {
1919
// CHECK: ObjectiveC.NSObjectProtocol:{{.*}}note: method 'class()' declared here
2020
}
2121

22+
// rdar://96470068 - Don't want conflict diagnostics in the same module
23+
extension MyObject {
24+
@objc func implementedInSwift() {}
25+
}
26+
27+
// ...or the bridging header
28+
extension MyBridgedObject {
29+
@objc func implementedInSwift() {}
30+
}

test/Concurrency/objc_async_overload.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,4 @@ extension Delegate {
5858

5959
extension Delegate {
6060
@objc public func makeRequest(fromSwift: Request, completionHandler: (() -> Void)?) {}
61-
// expected-warning@-1 {{method 'makeRequest(fromSwift:completionHandler:)' with Objective-C selector 'makeRequestFromSwift:completionHandler:' conflicts with method 'makeRequest(fromSwift:)' with the same Objective-C selector; this is an error in Swift 6}}
6261
}

0 commit comments

Comments
 (0)