Skip to content

Commit d736799

Browse files
authored
Merge pull request swiftlang#34985 from DougGregor/import-swift-async-attr
[Concurrency] Implement support for swift_async attribute.
2 parents 4f3f68e + 3cd115e commit d736799

File tree

5 files changed

+99
-37
lines changed

5 files changed

+99
-37
lines changed

lib/ClangImporter/ImportName.cpp

Lines changed: 80 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,26 @@ bool NameImporter::hasNamingConflict(const clang::NamedDecl *decl,
10411041

10421042
static bool shouldBeSwiftPrivate(NameImporter &nameImporter,
10431043
const clang::NamedDecl *decl,
1044-
ImportNameVersion version) {
1044+
ImportNameVersion version,
1045+
bool isAsyncImport) {
1046+
// For an async import, check whether there is a swift_async attribute
1047+
// that specifies whether this should be considered swift_private or not.
1048+
if (isAsyncImport) {
1049+
if (auto *asyncAttr = decl->getAttr<clang::SwiftAsyncAttr>()) {
1050+
switch (asyncAttr->getKind()) {
1051+
case clang::SwiftAsyncAttr::None:
1052+
// Fall through to let us decide based on swift_private.
1053+
break;
1054+
1055+
case clang::SwiftAsyncAttr::SwiftPrivate:
1056+
return true;
1057+
1058+
case clang::SwiftAsyncAttr::NotSwiftPrivate:
1059+
return false;
1060+
}
1061+
}
1062+
}
1063+
10451064
// Decl with the attribute are obviously private
10461065
if (decl->hasAttr<clang::SwiftPrivateAttr>())
10471066
return true;
@@ -1213,7 +1232,9 @@ NameImporter::considerAsyncImport(
12131232
StringRef baseName,
12141233
SmallVectorImpl<StringRef> &paramNames,
12151234
ArrayRef<const clang::ParmVarDecl *> params,
1216-
bool isInitializer, CustomAsyncName customName,
1235+
bool isInitializer,
1236+
Optional<unsigned> explicitCompletionHandlerParamIndex,
1237+
CustomAsyncName customName,
12171238
Optional<ForeignErrorConvention::Info> errorInfo) {
12181239
// If there are no unclaimed parameters, there's no .
12191240
unsigned errorParamAdjust = errorInfo ? 1 : 0;
@@ -1232,43 +1253,50 @@ NameImporter::considerAsyncImport(
12321253
paramNames.size() + errorParamAdjust + customAsyncNameAdjust)
12331254
return None;
12341255

1235-
// The last parameter will be the completion handler for an async function.
1236-
unsigned completionHandlerParamIndex = params.size() - 1;
1237-
unsigned completionHandlerParamNameIndex = paramNames.size() - 1;
1238-
1239-
// Determine whether the naming indicates that this is a completion
1240-
// handler.
1241-
switch (customName) {
1242-
case CustomAsyncName::None:
1243-
// Check whether the first parameter is the completion handler and the
1244-
// base name has a suitable completion-handler suffix.
1245-
if (completionHandlerParamIndex == 0 &&
1246-
stripWithCompletionHandlerSuffix(baseName))
1247-
break;
1256+
// If we don't already know the completion handler parameter index, go
1257+
// try to figure it out.
1258+
unsigned completionHandlerParamIndex;
1259+
unsigned completionHandlerParamNameIndex;
1260+
if (!explicitCompletionHandlerParamIndex) {
1261+
// Determine whether the naming indicates that this is a completion
1262+
// handler.
1263+
completionHandlerParamIndex = params.size() - 1;
1264+
completionHandlerParamNameIndex = paramNames.size() - 1;
1265+
switch (customName) {
1266+
case CustomAsyncName::None:
1267+
// Check whether the first parameter is the completion handler and the
1268+
// base name has a suitable completion-handler suffix.
1269+
if (completionHandlerParamIndex == 0 &&
1270+
stripWithCompletionHandlerSuffix(baseName))
1271+
break;
12481272

1249-
LLVM_FALLTHROUGH;
1273+
LLVM_FALLTHROUGH;
12501274

1251-
case CustomAsyncName::SwiftName:
1252-
// Check whether the argument label itself has an appropriate name.
1253-
if (isCompletionHandlerParamName(
1254-
paramNames[completionHandlerParamNameIndex]) ||
1255-
(completionHandlerParamNameIndex > 0 &&
1256-
stripWithCompletionHandlerSuffix(
1257-
paramNames[completionHandlerParamNameIndex]))) {
1258-
break;
1259-
}
1275+
case CustomAsyncName::SwiftName:
1276+
// Check whether the argument label itself has an appropriate name.
1277+
if (isCompletionHandlerParamName(
1278+
paramNames[completionHandlerParamNameIndex]) ||
1279+
(completionHandlerParamNameIndex > 0 &&
1280+
stripWithCompletionHandlerSuffix(
1281+
paramNames[completionHandlerParamNameIndex]))) {
1282+
break;
1283+
}
12601284

1261-
// Check whether the parameter itself has a name that indicates that
1262-
// it is a completion handelr.
1263-
if (isCompletionHandlerParamName(
1264-
params[completionHandlerParamIndex]->getName()))
1265-
break;
1285+
// Check whether the parameter itself has a name that indicates that
1286+
// it is a completion handelr.
1287+
if (isCompletionHandlerParamName(
1288+
params[completionHandlerParamIndex]->getName()))
1289+
break;
12661290

1267-
return None;
1291+
return None;
12681292

1269-
case CustomAsyncName::SwiftAsyncName:
1270-
// Having a custom async name implies that this is a completion handler.
1271-
break;
1293+
case CustomAsyncName::SwiftAsyncName:
1294+
// Having a custom async name implies that this is a completion handler.
1295+
break;
1296+
}
1297+
} else {
1298+
completionHandlerParamIndex = *explicitCompletionHandlerParamIndex;
1299+
completionHandlerParamNameIndex = *explicitCompletionHandlerParamIndex;
12721300
}
12731301

12741302
// Used for returns once we've determined that the method cannot be
@@ -1452,6 +1480,20 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
14521480
return ImportedName();
14531481
result.effectiveContext = effectiveCtx;
14541482

1483+
// Gather information from the swift_async attribute, if there is one.
1484+
Optional<unsigned> completionHandlerParamIndex;
1485+
if (version.supportsConcurrency()) {
1486+
if (const auto *swiftAsyncAttr = D->getAttr<clang::SwiftAsyncAttr>()) {
1487+
// If this is swift_async(none), don't import as async at all.
1488+
if (swiftAsyncAttr->getKind() == clang::SwiftAsyncAttr::None)
1489+
return ImportedName();
1490+
1491+
// Get the completion handler parameter index, if there is one.
1492+
completionHandlerParamIndex =
1493+
swiftAsyncAttr->getCompletionHandlerIndex().getASTIndex();
1494+
}
1495+
}
1496+
14551497
// FIXME: ugly to check here, instead perform unified check up front in
14561498
// containing struct...
14571499
if (findSwiftNewtype(D, clangSema, version))
@@ -1601,6 +1643,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
16011643
if (auto asyncInfo = considerAsyncImport(
16021644
method, parsedName.BaseName, parsedName.ArgumentLabels,
16031645
params, isInitializer,
1646+
completionHandlerParamIndex,
16041647
nameAttr->isAsync ? CustomAsyncName::SwiftAsyncName
16051648
: CustomAsyncName::SwiftName,
16061649
result.getErrorInfo())) {
@@ -1890,7 +1933,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
18901933
result.info.accessorKind == ImportedAccessorKind::None) {
18911934
if (auto asyncInfo = considerAsyncImport(
18921935
objcMethod, baseName, argumentNames, params, isInitializer,
1893-
CustomAsyncName::None, result.getErrorInfo())) {
1936+
completionHandlerParamIndex, CustomAsyncName::None,
1937+
result.getErrorInfo())) {
18941938
result.info.hasAsyncInfo = true;
18951939
result.info.asyncInfo = *asyncInfo;
18961940
}
@@ -2065,7 +2109,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
20652109
// If this declaration has the swift_private attribute, prepend "__" to the
20662110
// appropriate place.
20672111
SmallString<16> swiftPrivateScratch;
2068-
if (shouldBeSwiftPrivate(*this, D, version)) {
2112+
if (shouldBeSwiftPrivate(*this, D, version, result.info.hasAsyncInfo)) {
20692113
// Special case: empty arg factory, "for historical reasons", is not private
20702114
if (isInitializer && argumentNames.empty() &&
20712115
(result.getInitKind() == CtorInitializerKind::Factory ||

lib/ClangImporter/ImportName.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,9 @@ class NameImporter {
469469
StringRef baseName,
470470
SmallVectorImpl<StringRef> &paramNames,
471471
ArrayRef<const clang::ParmVarDecl *> params,
472-
bool isInitializer, CustomAsyncName customName,
472+
bool isInitializer,
473+
Optional<unsigned> explicitCompletionHandlerParamIndex,
474+
CustomAsyncName customName,
473475
Optional<ForeignErrorConvention::Info> errorInfo);
474476

475477
EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *,

test/ClangImporter/objc_async.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,22 @@ func testSlowServer(slowServer: SlowServer) async throws {
3939

4040
let _: Int = await slowServer.bestName("hello")
4141
let _: Int = await slowServer.customize("hello")
42+
43+
let _: String = await slowServer.dance("slide")
44+
let _: String = await slowServer.__leap(17)
45+
46+
slowServer.repeatTrick("jump") // expected-error{{missing argument for parameter 'completionHandler' in call}}
4247
}
4348

4449
func testSlowServerSynchronous(slowServer: SlowServer) {
4550
// synchronous version
4651
let _: Int = slowServer.doSomethingConflicted("thinking")
4752
slowServer.poorlyNamed("hello") { (i: Int) in print(i) }
4853
slowServer.customize(with: "hello") { (i: Int) in print(i) }
54+
55+
slowServer.dance("jig") { s in print(s + "") }
56+
slowServer.leap(17) { s in print(s + "") }
57+
slowServer.repeatTrick("jump") { i in print(i + 1) }
4958
}
5059

5160
func testSlowServerOldSchool(slowServer: SlowServer) {

test/IDE/print_clang_objc_async.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
// CHECK-DAG: func findQAndA() async throws -> (String?, String)
2424
// CHECK-DAG: func findQuestionableAnswers() async throws -> (String, String?)
2525
// CHECK-DAG: func doSomethingFun(_ operation: String) async
26+
// CHECK-DAG: func dance(_ step: String) async -> String
27+
// CHECK-DAG: func __leap(_ height: Int) async -> String
2628
// CHECK: {{^[}]$}}
2729

2830
// CHECK-LABEL: protocol RefrigeratorDelegate

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
3939

4040
-(void)customizedWithString:(NSString *)operation completionHandler:(void (^)(NSInteger))handler __attribute__((swift_name("customize(with:completionHandler:)"))) __attribute__((swift_async_name("customize(_:)")));
4141

42+
-(void)dance:(NSString *)step andThen:(void (^)(NSString *))doSomething __attribute__((swift_async(not_swift_private,2)));
43+
-(void)leap:(NSInteger)height andThen:(void (^)(NSString *))doSomething __attribute__((swift_async(swift_private,2)));
44+
45+
-(void)repeatTrick:(NSString *)trick completionHandler:(void (^)(NSInteger))handler __attribute__((swift_async(none)));
46+
4247
@end
4348

4449
@protocol RefrigeratorDelegate<NSObject>

0 commit comments

Comments
 (0)