Skip to content

Commit 106002c

Browse files
authored
Merge pull request #37168 from DougGregor/async-import-mirroring
[Clang importer] Fix mirroring of protocol decls for 'async' imports.
2 parents 7a15b7a + bf30b41 commit 106002c

File tree

3 files changed

+51
-25
lines changed

3 files changed

+51
-25
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,7 @@ static bool isPrintLikeMethod(DeclName name, const DeclContext *dc) {
21322132
}
21332133

21342134
using MirroredMethodEntry =
2135-
std::pair<const clang::ObjCMethodDecl*, ProtocolDecl*>;
2135+
std::tuple<const clang::ObjCMethodDecl*, ProtocolDecl*, bool /*isAsync*/>;
21362136

21372137
namespace {
21382138
/// Customized llvm::DenseMapInfo for storing borrowed APSInts.
@@ -7964,19 +7964,14 @@ void SwiftDeclConverter::importMirroredProtocolMembers(
79647964
if (isa<AccessorDecl>(afd))
79657965
return;
79667966

7967-
// Asynch methods are also always imported without async, so don't
7968-
// record them here.
7969-
if (afd->hasAsync())
7970-
return;
7971-
79727967
auto objcMethod =
79737968
dyn_cast_or_null<clang::ObjCMethodDecl>(member->getClangDecl());
79747969
if (!objcMethod)
79757970
return;
79767971

79777972
// For now, just remember that we saw this method.
79787973
methodsByName[objcMethod->getSelector()]
7979-
.push_back(MirroredMethodEntry{objcMethod, proto});
7974+
.push_back(std::make_tuple(objcMethod, proto, afd->hasAsync()));
79807975
};
79817976

79827977
if (name) {
@@ -8053,18 +8048,20 @@ compareMethodsForMirrorImport(ClangImporter::Implementation &importer,
80538048
/// Return true if this method is overridden by any methods in the array.
80548049
static bool suppressOverriddenMethods(ClangImporter::Implementation &importer,
80558050
const clang::ObjCMethodDecl *method,
8051+
bool isAsync,
80568052
MutableArrayRef<MirroredMethodEntry> entries) {
80578053
assert(method && "method was already suppressed");
80588054

80598055
for (auto &entry: entries) {
8060-
auto otherMethod = entry.first;
8056+
auto otherMethod = std::get<0>(entry);
80618057
if (!otherMethod) continue;
8058+
if (isAsync != std::get<2>(entry)) continue;
80628059

80638060
assert(method != otherMethod && "found same method twice?");
80648061
switch (compareMethodsForMirrorImport(importer, method, otherMethod)) {
80658062
// If the second method is suppressed, null it out.
80668063
case Suppresses:
8067-
entry.first = nullptr;
8064+
std::get<0>(entry) = nullptr;
80688065
continue;
80698066

80708067
// If the first method is suppressed, return immediately. We should
@@ -8120,8 +8117,17 @@ void addCompletionHandlerAttribute(Decl *asyncImport,
81208117
void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
81218118
MutableArrayRef<MirroredMethodEntry> entries,
81228119
SmallVectorImpl<Decl *> &members) {
8120+
// Keep track of the async imports. We'll come back to them.
8121+
llvm::SmallMapVector<const clang::ObjCMethodDecl*, Decl *, 4> asyncImports;
8122+
8123+
// Keep track of all of the synchronous imports.
8124+
llvm::SmallMapVector<
8125+
const clang::ObjCMethodDecl*, llvm::TinyPtrVector<Decl *>, 4>
8126+
syncImports;
8127+
81238128
for (size_t i = 0, e = entries.size(); i != e; ++i) {
8124-
auto objcMethod = entries[i].first;
8129+
auto objcMethod = std::get<0>(entries[i]);
8130+
bool isAsync = std::get<2>(entries[i]);
81258131

81268132
// If the method was suppressed by a previous method, ignore it.
81278133
if (!objcMethod)
@@ -8131,7 +8137,8 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
81318137
// that it overrides. If it is overridden by any of them, suppress it
81328138
// instead; but there's no need to mark that in the array, just continue
81338139
// on to the next method.
8134-
if (suppressOverriddenMethods(Impl, objcMethod, entries.slice(i + 1)))
8140+
if (suppressOverriddenMethods(
8141+
Impl, objcMethod, isAsync, entries.slice(i + 1)))
81358142
continue;
81368143

81378144
// Okay, the method wasn't suppressed, import it.
@@ -8148,9 +8155,11 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
81488155
}
81498156

81508157
// Import the method.
8151-
auto proto = entries[i].second;
8158+
auto proto = std::get<1>(entries[i]);
81528159
if (auto imported =
8153-
Impl.importMirroredDecl(objcMethod, dc, getVersion(), proto)) {
8160+
Impl.importMirroredDecl(objcMethod, dc,
8161+
getVersion().withConcurrency(isAsync),
8162+
proto)) {
81548163
size_t start = members.size();
81558164

81568165
members.push_back(imported);
@@ -8160,21 +8169,22 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
81608169
members.push_back(alternate);
81618170
}
81628171

8163-
if (!getVersion().supportsConcurrency()) {
8164-
auto asyncVersion = getVersion().withConcurrency(true);
8165-
if (auto asyncImport = Impl.importMirroredDecl(
8166-
objcMethod, dc, asyncVersion, proto)) {
8167-
if (asyncImport != imported) {
8168-
addCompletionHandlerAttribute(
8169-
asyncImport,
8170-
llvm::makeArrayRef(members).drop_front(start),
8171-
Impl.SwiftContext);
8172-
members.push_back(asyncImport);
8173-
}
8174-
}
8172+
if (isAsync) {
8173+
asyncImports[objcMethod] = imported;
8174+
} else {
8175+
syncImports[objcMethod] = llvm::TinyPtrVector<Decl *>(
8176+
llvm::makeArrayRef(members).drop_front(start + 1));
81758177
}
81768178
}
81778179
}
8180+
8181+
// Write up sync and async versions.
8182+
for (const auto &asyncImport : asyncImports) {
8183+
addCompletionHandlerAttribute(
8184+
asyncImport.second,
8185+
syncImports[asyncImport.first],
8186+
Impl.SwiftContext);
8187+
}
81788188
}
81798189

81808190
void SwiftDeclConverter::importInheritedConstructors(

test/ClangImporter/objc_async.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,10 @@ class MyButton : NXButton {
164164
func testButtons(mb: MyButton) {
165165
mb.onButtonPress()
166166
}
167+
168+
169+
func testMirrored(instance: ClassWithAsync) async {
170+
await instance.instanceAsync()
171+
await instance.protocolMethod()
172+
await instance.customAsyncName()
173+
}

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,13 @@ void doSomethingConcurrentlyButUnsafe(__attribute__((noescape)) __attribute__((s
161161
MAIN_ACTOR MAIN_ACTOR __attribute__((__swift_attr__("@MainActor(unsafe)"))) @protocol TripleMainActor
162162
@end
163163

164+
@protocol ProtocolWithAsync
165+
- (void)protocolMethodWithCompletionHandler:(void (^)(void))completionHandler;
166+
- (void)customAsyncNameProtocolMethodWithCompletionHandler:(void (^)(void))completionHandler __attribute__((swift_async_name("customAsyncName()")));
167+
@end
168+
169+
@interface ClassWithAsync: NSObject <ProtocolWithAsync>
170+
- (void)instanceMethodWithCompletionHandler:(void (^)(void))completionHandler __attribute__((swift_async_name("instanceAsync()")));
171+
@end
172+
164173
#pragma clang assume_nonnull end

0 commit comments

Comments
 (0)