mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #34985 from DougGregor/import-swift-async-attr
[Concurrency] Implement support for swift_async attribute.
This commit is contained in:
@@ -1041,7 +1041,26 @@ bool NameImporter::hasNamingConflict(const clang::NamedDecl *decl,
|
|||||||
|
|
||||||
static bool shouldBeSwiftPrivate(NameImporter &nameImporter,
|
static bool shouldBeSwiftPrivate(NameImporter &nameImporter,
|
||||||
const clang::NamedDecl *decl,
|
const clang::NamedDecl *decl,
|
||||||
ImportNameVersion version) {
|
ImportNameVersion version,
|
||||||
|
bool isAsyncImport) {
|
||||||
|
// For an async import, check whether there is a swift_async attribute
|
||||||
|
// that specifies whether this should be considered swift_private or not.
|
||||||
|
if (isAsyncImport) {
|
||||||
|
if (auto *asyncAttr = decl->getAttr<clang::SwiftAsyncAttr>()) {
|
||||||
|
switch (asyncAttr->getKind()) {
|
||||||
|
case clang::SwiftAsyncAttr::None:
|
||||||
|
// Fall through to let us decide based on swift_private.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case clang::SwiftAsyncAttr::SwiftPrivate:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case clang::SwiftAsyncAttr::NotSwiftPrivate:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Decl with the attribute are obviously private
|
// Decl with the attribute are obviously private
|
||||||
if (decl->hasAttr<clang::SwiftPrivateAttr>())
|
if (decl->hasAttr<clang::SwiftPrivateAttr>())
|
||||||
return true;
|
return true;
|
||||||
@@ -1213,7 +1232,9 @@ NameImporter::considerAsyncImport(
|
|||||||
StringRef baseName,
|
StringRef baseName,
|
||||||
SmallVectorImpl<StringRef> ¶mNames,
|
SmallVectorImpl<StringRef> ¶mNames,
|
||||||
ArrayRef<const clang::ParmVarDecl *> params,
|
ArrayRef<const clang::ParmVarDecl *> params,
|
||||||
bool isInitializer, CustomAsyncName customName,
|
bool isInitializer,
|
||||||
|
Optional<unsigned> explicitCompletionHandlerParamIndex,
|
||||||
|
CustomAsyncName customName,
|
||||||
Optional<ForeignErrorConvention::Info> errorInfo) {
|
Optional<ForeignErrorConvention::Info> errorInfo) {
|
||||||
// If there are no unclaimed parameters, there's no .
|
// If there are no unclaimed parameters, there's no .
|
||||||
unsigned errorParamAdjust = errorInfo ? 1 : 0;
|
unsigned errorParamAdjust = errorInfo ? 1 : 0;
|
||||||
@@ -1232,43 +1253,50 @@ NameImporter::considerAsyncImport(
|
|||||||
paramNames.size() + errorParamAdjust + customAsyncNameAdjust)
|
paramNames.size() + errorParamAdjust + customAsyncNameAdjust)
|
||||||
return None;
|
return None;
|
||||||
|
|
||||||
// The last parameter will be the completion handler for an async function.
|
// If we don't already know the completion handler parameter index, go
|
||||||
unsigned completionHandlerParamIndex = params.size() - 1;
|
// try to figure it out.
|
||||||
unsigned completionHandlerParamNameIndex = paramNames.size() - 1;
|
unsigned completionHandlerParamIndex;
|
||||||
|
unsigned completionHandlerParamNameIndex;
|
||||||
|
if (!explicitCompletionHandlerParamIndex) {
|
||||||
|
// Determine whether the naming indicates that this is a completion
|
||||||
|
// handler.
|
||||||
|
completionHandlerParamIndex = params.size() - 1;
|
||||||
|
completionHandlerParamNameIndex = paramNames.size() - 1;
|
||||||
|
switch (customName) {
|
||||||
|
case CustomAsyncName::None:
|
||||||
|
// Check whether the first parameter is the completion handler and the
|
||||||
|
// base name has a suitable completion-handler suffix.
|
||||||
|
if (completionHandlerParamIndex == 0 &&
|
||||||
|
stripWithCompletionHandlerSuffix(baseName))
|
||||||
|
break;
|
||||||
|
|
||||||
// Determine whether the naming indicates that this is a completion
|
LLVM_FALLTHROUGH;
|
||||||
// handler.
|
|
||||||
switch (customName) {
|
|
||||||
case CustomAsyncName::None:
|
|
||||||
// Check whether the first parameter is the completion handler and the
|
|
||||||
// base name has a suitable completion-handler suffix.
|
|
||||||
if (completionHandlerParamIndex == 0 &&
|
|
||||||
stripWithCompletionHandlerSuffix(baseName))
|
|
||||||
break;
|
|
||||||
|
|
||||||
LLVM_FALLTHROUGH;
|
case CustomAsyncName::SwiftName:
|
||||||
|
// Check whether the argument label itself has an appropriate name.
|
||||||
|
if (isCompletionHandlerParamName(
|
||||||
|
paramNames[completionHandlerParamNameIndex]) ||
|
||||||
|
(completionHandlerParamNameIndex > 0 &&
|
||||||
|
stripWithCompletionHandlerSuffix(
|
||||||
|
paramNames[completionHandlerParamNameIndex]))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CustomAsyncName::SwiftName:
|
// Check whether the parameter itself has a name that indicates that
|
||||||
// Check whether the argument label itself has an appropriate name.
|
// it is a completion handelr.
|
||||||
if (isCompletionHandlerParamName(
|
if (isCompletionHandlerParamName(
|
||||||
paramNames[completionHandlerParamNameIndex]) ||
|
params[completionHandlerParamIndex]->getName()))
|
||||||
(completionHandlerParamNameIndex > 0 &&
|
break;
|
||||||
stripWithCompletionHandlerSuffix(
|
|
||||||
paramNames[completionHandlerParamNameIndex]))) {
|
return None;
|
||||||
|
|
||||||
|
case CustomAsyncName::SwiftAsyncName:
|
||||||
|
// Having a custom async name implies that this is a completion handler.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// Check whether the parameter itself has a name that indicates that
|
completionHandlerParamIndex = *explicitCompletionHandlerParamIndex;
|
||||||
// it is a completion handelr.
|
completionHandlerParamNameIndex = *explicitCompletionHandlerParamIndex;
|
||||||
if (isCompletionHandlerParamName(
|
|
||||||
params[completionHandlerParamIndex]->getName()))
|
|
||||||
break;
|
|
||||||
|
|
||||||
return None;
|
|
||||||
|
|
||||||
case CustomAsyncName::SwiftAsyncName:
|
|
||||||
// Having a custom async name implies that this is a completion handler.
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for returns once we've determined that the method cannot be
|
// Used for returns once we've determined that the method cannot be
|
||||||
@@ -1452,6 +1480,20 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
return ImportedName();
|
return ImportedName();
|
||||||
result.effectiveContext = effectiveCtx;
|
result.effectiveContext = effectiveCtx;
|
||||||
|
|
||||||
|
// Gather information from the swift_async attribute, if there is one.
|
||||||
|
Optional<unsigned> completionHandlerParamIndex;
|
||||||
|
if (version.supportsConcurrency()) {
|
||||||
|
if (const auto *swiftAsyncAttr = D->getAttr<clang::SwiftAsyncAttr>()) {
|
||||||
|
// If this is swift_async(none), don't import as async at all.
|
||||||
|
if (swiftAsyncAttr->getKind() == clang::SwiftAsyncAttr::None)
|
||||||
|
return ImportedName();
|
||||||
|
|
||||||
|
// Get the completion handler parameter index, if there is one.
|
||||||
|
completionHandlerParamIndex =
|
||||||
|
swiftAsyncAttr->getCompletionHandlerIndex().getASTIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: ugly to check here, instead perform unified check up front in
|
// FIXME: ugly to check here, instead perform unified check up front in
|
||||||
// containing struct...
|
// containing struct...
|
||||||
if (findSwiftNewtype(D, clangSema, version))
|
if (findSwiftNewtype(D, clangSema, version))
|
||||||
@@ -1601,6 +1643,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
if (auto asyncInfo = considerAsyncImport(
|
if (auto asyncInfo = considerAsyncImport(
|
||||||
method, parsedName.BaseName, parsedName.ArgumentLabels,
|
method, parsedName.BaseName, parsedName.ArgumentLabels,
|
||||||
params, isInitializer,
|
params, isInitializer,
|
||||||
|
completionHandlerParamIndex,
|
||||||
nameAttr->isAsync ? CustomAsyncName::SwiftAsyncName
|
nameAttr->isAsync ? CustomAsyncName::SwiftAsyncName
|
||||||
: CustomAsyncName::SwiftName,
|
: CustomAsyncName::SwiftName,
|
||||||
result.getErrorInfo())) {
|
result.getErrorInfo())) {
|
||||||
@@ -1890,7 +1933,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
result.info.accessorKind == ImportedAccessorKind::None) {
|
result.info.accessorKind == ImportedAccessorKind::None) {
|
||||||
if (auto asyncInfo = considerAsyncImport(
|
if (auto asyncInfo = considerAsyncImport(
|
||||||
objcMethod, baseName, argumentNames, params, isInitializer,
|
objcMethod, baseName, argumentNames, params, isInitializer,
|
||||||
CustomAsyncName::None, result.getErrorInfo())) {
|
completionHandlerParamIndex, CustomAsyncName::None,
|
||||||
|
result.getErrorInfo())) {
|
||||||
result.info.hasAsyncInfo = true;
|
result.info.hasAsyncInfo = true;
|
||||||
result.info.asyncInfo = *asyncInfo;
|
result.info.asyncInfo = *asyncInfo;
|
||||||
}
|
}
|
||||||
@@ -2065,7 +2109,7 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
// If this declaration has the swift_private attribute, prepend "__" to the
|
// If this declaration has the swift_private attribute, prepend "__" to the
|
||||||
// appropriate place.
|
// appropriate place.
|
||||||
SmallString<16> swiftPrivateScratch;
|
SmallString<16> swiftPrivateScratch;
|
||||||
if (shouldBeSwiftPrivate(*this, D, version)) {
|
if (shouldBeSwiftPrivate(*this, D, version, result.info.hasAsyncInfo)) {
|
||||||
// Special case: empty arg factory, "for historical reasons", is not private
|
// Special case: empty arg factory, "for historical reasons", is not private
|
||||||
if (isInitializer && argumentNames.empty() &&
|
if (isInitializer && argumentNames.empty() &&
|
||||||
(result.getInitKind() == CtorInitializerKind::Factory ||
|
(result.getInitKind() == CtorInitializerKind::Factory ||
|
||||||
|
|||||||
@@ -469,7 +469,9 @@ private:
|
|||||||
StringRef baseName,
|
StringRef baseName,
|
||||||
SmallVectorImpl<StringRef> ¶mNames,
|
SmallVectorImpl<StringRef> ¶mNames,
|
||||||
ArrayRef<const clang::ParmVarDecl *> params,
|
ArrayRef<const clang::ParmVarDecl *> params,
|
||||||
bool isInitializer, CustomAsyncName customName,
|
bool isInitializer,
|
||||||
|
Optional<unsigned> explicitCompletionHandlerParamIndex,
|
||||||
|
CustomAsyncName customName,
|
||||||
Optional<ForeignErrorConvention::Info> errorInfo);
|
Optional<ForeignErrorConvention::Info> errorInfo);
|
||||||
|
|
||||||
EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *,
|
EffectiveClangContext determineEffectiveContext(const clang::NamedDecl *,
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ func testSlowServer(slowServer: SlowServer) async throws {
|
|||||||
|
|
||||||
let _: Int = await slowServer.bestName("hello")
|
let _: Int = await slowServer.bestName("hello")
|
||||||
let _: Int = await slowServer.customize("hello")
|
let _: Int = await slowServer.customize("hello")
|
||||||
|
|
||||||
|
let _: String = await slowServer.dance("slide")
|
||||||
|
let _: String = await slowServer.__leap(17)
|
||||||
|
|
||||||
|
slowServer.repeatTrick("jump") // expected-error{{missing argument for parameter 'completionHandler' in call}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSlowServerSynchronous(slowServer: SlowServer) {
|
func testSlowServerSynchronous(slowServer: SlowServer) {
|
||||||
@@ -46,6 +51,10 @@ func testSlowServerSynchronous(slowServer: SlowServer) {
|
|||||||
let _: Int = slowServer.doSomethingConflicted("thinking")
|
let _: Int = slowServer.doSomethingConflicted("thinking")
|
||||||
slowServer.poorlyNamed("hello") { (i: Int) in print(i) }
|
slowServer.poorlyNamed("hello") { (i: Int) in print(i) }
|
||||||
slowServer.customize(with: "hello") { (i: Int) in print(i) }
|
slowServer.customize(with: "hello") { (i: Int) in print(i) }
|
||||||
|
|
||||||
|
slowServer.dance("jig") { s in print(s + "") }
|
||||||
|
slowServer.leap(17) { s in print(s + "") }
|
||||||
|
slowServer.repeatTrick("jump") { i in print(i + 1) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSlowServerOldSchool(slowServer: SlowServer) {
|
func testSlowServerOldSchool(slowServer: SlowServer) {
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
// CHECK-DAG: func findQAndA() async throws -> (String?, String)
|
// CHECK-DAG: func findQAndA() async throws -> (String?, String)
|
||||||
// CHECK-DAG: func findQuestionableAnswers() async throws -> (String, String?)
|
// CHECK-DAG: func findQuestionableAnswers() async throws -> (String, String?)
|
||||||
// CHECK-DAG: func doSomethingFun(_ operation: String) async
|
// CHECK-DAG: func doSomethingFun(_ operation: String) async
|
||||||
|
// CHECK-DAG: func dance(_ step: String) async -> String
|
||||||
|
// CHECK-DAG: func __leap(_ height: Int) async -> String
|
||||||
// CHECK: {{^[}]$}}
|
// CHECK: {{^[}]$}}
|
||||||
|
|
||||||
// CHECK-LABEL: protocol RefrigeratorDelegate
|
// CHECK-LABEL: protocol RefrigeratorDelegate
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
|
|||||||
|
|
||||||
-(void)customizedWithString:(NSString *)operation completionHandler:(void (^)(NSInteger))handler __attribute__((swift_name("customize(with:completionHandler:)"))) __attribute__((swift_async_name("customize(_:)")));
|
-(void)customizedWithString:(NSString *)operation completionHandler:(void (^)(NSInteger))handler __attribute__((swift_name("customize(with:completionHandler:)"))) __attribute__((swift_async_name("customize(_:)")));
|
||||||
|
|
||||||
|
-(void)dance:(NSString *)step andThen:(void (^)(NSString *))doSomething __attribute__((swift_async(not_swift_private,2)));
|
||||||
|
-(void)leap:(NSInteger)height andThen:(void (^)(NSString *))doSomething __attribute__((swift_async(swift_private,2)));
|
||||||
|
|
||||||
|
-(void)repeatTrick:(NSString *)trick completionHandler:(void (^)(NSInteger))handler __attribute__((swift_async(none)));
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@protocol RefrigeratorDelegate<NSObject>
|
@protocol RefrigeratorDelegate<NSObject>
|
||||||
|
|||||||
Reference in New Issue
Block a user