From b2bcd21b10b4cb3ab7cc455fea6dd5a455a15716 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 6 Jun 2025 17:08:22 -0700 Subject: [PATCH 1/2] [ClangImporter] Use `DefaultsToSendable` with completion handler parameter This lifts the check for the feature flag up into the `importParameterType` from `importType` and means that completion handler type for `async` variant is no longer gains `@Sendable` attribute. (cherry picked from commit 74471e858be655a2334f24ff08cc892763962a4f) --- .../swift/AST/DiagnosticsClangImporter.def | 3 -- lib/ClangImporter/ImportType.cpp | 19 ++++++---- lib/ClangImporter/ImporterImpl.h | 3 +- test/ClangImporter/regionbasedisolation.swift | 13 +++---- test/SILGen/objc_async.swift | 38 +++++++++---------- test/SILGen/objc_async_checked.swift | 30 +++++++-------- test/SILGen/objc_async_from_swift.swift | 20 +++++----- test/SILGen/objc_effectful_properties.swift | 8 ++-- .../objc_effectful_properties_checked.swift | 8 ++-- 9 files changed, 69 insertions(+), 73 deletions(-) diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 729814de3fc7b..8ab826cc04839 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -99,9 +99,6 @@ GROUPED_WARNING(clang_ignored_sendable_attr, ClangDeclarationImport, none, "cannot make type %0 sendable because '@Sendable' and '& Sendable' " "cannot be added to it", (Type)) -NOTE(clang_param_should_be_implicitly_sendable,none, - "parameter should be implicitly 'Sendable' because it is a completion " - "handler", ()) WARNING(implicit_bridging_header_imported_from_module,none, "implicit import of bridging header '%0' via module %1 " diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 474324510ba13..5062eb2160cfd 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -1712,9 +1712,7 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext, ImportTypeKind importKind, ImportTypeAttrs &attrs, clang::QualType type) { bool isMainActor = false; - bool isSendable = - SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) && - importKind == ImportTypeKind::CompletionHandlerParameter; + bool isSendable = false; bool isNonSendable = false; // Consider only immediate attributes, don't look through the typerefs @@ -1733,8 +1731,10 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext, attrs |= ImportTypeAttr::MainActor; if (isSendable) attrs |= ImportTypeAttr::Sendable; - if (isNonSendable) + if (isNonSendable) { attrs -= ImportTypeAttr::Sendable; + attrs -= ImportTypeAttr::DefaultsToSendable; + } } ImportedType ClangImporter::Implementation::importType( @@ -2189,16 +2189,14 @@ applyImportTypeAttrs(ImportTypeAttrs attrs, Type type, } } - if (attrs.contains(ImportTypeAttr::Sendable)) { + if (attrs.contains(ImportTypeAttr::Sendable) || + attrs.contains(ImportTypeAttr::DefaultsToSendable)) { bool changed; std::tie(type, changed) = GetSendableType(SwiftContext).convert(type); // Diagnose if we couldn't find a place to add `Sendable` to the type. if (!changed) { addDiag(Diagnostic(diag::clang_ignored_sendable_attr, type)); - - if (attrs.contains(ImportTypeAttr::DefaultsToSendable)) - addDiag(Diagnostic(diag::clang_param_should_be_implicitly_sendable)); } } @@ -2445,6 +2443,11 @@ ClangImporter::Implementation::importParameterType( bool isConsuming = false; bool isParamTypeImplicitlyUnwrapped = false; + if (SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) && + paramIsCompletionHandler) { + attrs |= ImportTypeAttr::DefaultsToSendable; + } + if (auto optionSetEnum = importer::findOptionSetEnum(paramTy, *this)) { swiftParamTy = optionSetEnum.getType(); } else if (isa(paramTy) && diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index f3b1c817eebff..10736259a8c4a 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -202,8 +202,7 @@ enum class ImportTypeAttr : uint8_t { Sendable = 1 << 2, /// Type is in a declaration where it would be imported as Sendable by - /// default. This comes directly from the parameters to - /// \c getImportTypeAttrs() and merely affects diagnostics. + /// default. Currently used for completion handlers. DefaultsToSendable = 1 << 3, /// Import the type of a parameter declared with diff --git a/test/ClangImporter/regionbasedisolation.swift b/test/ClangImporter/regionbasedisolation.swift index 63a2364dafbb2..0f1529100e073 100644 --- a/test/ClangImporter/regionbasedisolation.swift +++ b/test/ClangImporter/regionbasedisolation.swift @@ -72,7 +72,7 @@ extension ObjCObject { // CHECK: [[RESULT:%.*]] = alloc_stack $Array // Our method. - // CHECK: [[METHOD:%.*]] = objc_method [[SELF]], #ObjCObject.loadObjects2!foreign : (ObjCObject) -> () async throws -> [NSObject], $@convention(objc_method) (@convention(block) @Sendable (Optional, Optional) -> (), ObjCObject) -> () + // CHECK: [[METHOD:%.*]] = objc_method [[SELF]], #ObjCObject.loadObjects2!foreign : (ObjCObject) -> () async throws -> [NSObject], $@convention(objc_method) (@convention(block) (Optional, Optional) -> (), ObjCObject) -> () // Begin setting up the unsafe continuation for our method. Importantly note // that [[UNSAFE_CONT]] is Sendable, so we lose any connection from the @@ -101,18 +101,17 @@ extension ObjCObject { // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[EXISTENTIAL_BLOCK_STORAGE]] // CHECK: merge_isolation_region [[BLOCK_STORAGE]], [[RESULT]] - // Then create the actual block. NOTE: Since the block is @Sendable, the block - // does not propagate regions. + // Then create the actual block. NOTE: Since the block is not @Sendable, the block does propagate regions. // - // CHECK: [[COMPLETION_HANDLER_BLOCK:%.*]] = function_ref @$sSo7NSArrayCSgSo7NSErrorCSgIeyBhyy_SaySo8NSObjectCGTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[COMPLETION_HANDLER_BLOCK:%.*]] = function_ref @$sSo7NSArrayCSgSo7NSErrorCSgIeyByy_SaySo8NSObjectCGTz_ : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[COMPLETION_BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]], invoke [[COMPLETION_HANDLER_BLOCK]] // - // Since the block is @Sendable, it does not propagate the connection in + // Since the block is not @Sendable, it does propagate the connection in // between self and the block storage when we just call the method. Thus we - // need to perform a merge_isolation_region to communicate that the block + // don't need to perform a merge_isolation_region to communicate that the block // storage and self are part of the same region. // - // CHECK: merge_isolation_region [[SELF]], [[BLOCK_STORAGE]] + // CHECK-NOT: merge_isolation_region [[SELF]], [[BLOCK_STORAGE]] // // Then call the method. // CHECK: apply [[METHOD]]([[COMPLETION_BLOCK]], [[SELF]]) diff --git a/test/SILGen/objc_async.swift b/test/SILGen/objc_async.swift index bf6eb7a038823..f5012bc10d86c 100644 --- a/test/SILGen/objc_async.swift +++ b/test/SILGen/objc_async.swift @@ -10,14 +10,14 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int // CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : // CHECK: [[ARG:%.*]] = apply [[STRINGINIT]] - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any // CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]] // CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]] // CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]] - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0) // CHECK: [[COPY:%.*]] = copy_value [[ARG]] @@ -33,14 +33,14 @@ func testSlowServer(slowServer: SlowServer) async throws { let _: Int = await slowServer.doSomethingSlowNullably("mail") // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $String - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (Optional, Optional) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (Optional, Optional) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr [throws] String, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any // CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]] // CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]] // CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]] - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]], error [[ERROR:bb[0-9]+]] @@ -50,18 +50,18 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: dealloc_stack [[RESUME_BUF]] let _: String = try await slowServer.findAnswer() - // CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable () -> (), SlowServer) -> () - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> () + // CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) () -> (), SlowServer) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any) -> () await slowServer.serverRestart("somewhere") - // CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional) -> () + // CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional) -> () let _: String = try await slowServer.doSomethingFlaggy() - // CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, {{.*}}Bool, Optional) -> () + // CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, {{.*}}Bool, Optional) -> () let _: String = try await slowServer.doSomethingZeroFlaggy() - // CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional, Optional) -> () + // CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional, Optional) -> () let _: (String, String) = try await slowServer.doSomethingMultiResultFlaggy() - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Int, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Int, Optional) -> () let (_, _): (String, Int) = try await slowServer.findMultipleAnswers() let (_, _): (Bool, Bool) = try await slowServer.findDifferentlyFlavoredBooleans() @@ -189,14 +189,14 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int // CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : // CHECK: [[ARG:%.*]] = apply [[STRINGINIT]] - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any // CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]] // CHECK: [[CONT_SLOT_ANY:%.*]] = init_existential_addr [[CONT_SLOT]] // CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ANY]] - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0) // CHECK: [[COPY:%.*]] = copy_value [[ARG]] @@ -223,10 +223,10 @@ func testThrowingMethodFromMain(slowServer: SlowServer) async -> String { // CHECK: [[PROJECTED:%.*]] = project_block_storage [[STORE_ALLOC]] : $*@block_storage // CHECK: [[PROJECTED_ANY:%.*]] = init_existential_addr [[PROJECTED]] // CHECK: store [[CONT]] to [trivial] [[PROJECTED_ANY]] -// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyBhyy_SSTz_ +// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyByy_SSTz_ // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORE_ALLOC]] {{.*}}, invoke [[INVOKER]] // CHECK: [[OPTIONAL_BLK:%.*]] = enum {{.*}}, #Optional.some!enumelt, [[BLOCK]] -// CHECK: apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) @Sendable (Optional, Optional) -> ()>, SlowServer) -> () +// CHECK: apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) (Optional, Optional) -> ()>, SlowServer) -> () // CHECK: [[STRING_ARG_COPY:%.*]] = copy_value [[STRING_ARG]] : $NSString // CHECK: dealloc_stack [[STORE_ALLOC]] : $*@block_storage Any // CHECK: destroy_value [[STRING_ARG]] : $NSString @@ -340,10 +340,10 @@ extension SlowServer: @retroactive FailableFloatLoader { } // CHECK-LABEL: sil [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKF : $@convention(method) @async (@guaranteed SlowServer) -> (Float, @error any Error) -// CHECK-LABEL: sil private [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFTo : $@convention(objc_method) (@convention(block) @Sendable (Float, Optional) -> (), SlowServer) -> () { +// CHECK-LABEL: sil private [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFTo : $@convention(objc_method) (@convention(block) (Float, Optional) -> (), SlowServer) -> () { // CHECK: function_ref @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To -// CHECK-LABEL: sil shared [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable (Float, Optional) -> (), SlowServer) -> () +// CHECK-LABEL: sil shared [thunk] [ossa] @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) (Float, Optional) -> (), SlowServer) -> () // CHECK: [[BLOCK:%.*]] = copy_block // CHECK: [[METHOD:%.*]] = function_ref @$sSo10SlowServerC10objc_asyncE16loadFloatOrThrowSfyYaKF : // CHECK: try_apply [[METHOD]]({{%.*}}) : {{.*}}, normal bb1, error bb2 @@ -370,7 +370,7 @@ extension SlowServer: @retroactive FailableFloatLoader { // CHECK: [[SLOWSERVER_ANYOBJECT_M_B:%.*]] = begin_borrow [[SLOWSERVER_ANYOBJECT_M]] // CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O:%.*]] = open_existential_ref [[SLOWSERVER_ANYOBJECT_M_B]] // CHECK: [[SLOWSERVER_ANYOBJECT_M_B_O_C:%.*]] = copy_value [[SLOWSERVER_ANYOBJECT_M_B_O]] -// CHECK: [[METHOD:%.*]] = objc_method [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, #SlowServer.start!foreign : (SlowServer) -> (NSDate?) async -> (), $@convention(objc_method) (Optional, @convention(block) @Sendable () -> (), @opened("{{.*}}", AnyObject) Self) -> () +// CHECK: [[METHOD:%.*]] = objc_method [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, #SlowServer.start!foreign : (SlowServer) -> (NSDate?) async -> (), $@convention(objc_method) (Optional, @convention(block) () -> (), @opened("{{.*}}", AnyObject) Self) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr () // CHECK: [[UNSAFE_CONT:%.*]] = struct $UnsafeContinuation<(), Never> ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK:%.*]] = alloc_stack $@block_storage Any @@ -378,9 +378,9 @@ extension SlowServer: @retroactive FailableFloatLoader { // CHECK: [[BLOCK_PROJECT_EX:%.*]] = init_existential_addr [[BLOCK_PROJECT]] // CHECK: store [[UNSAFE_CONT]] to [trivial] [[BLOCK_PROJECT_EX]] // CHECK: merge_isolation_region [[BLOCK]] : $*@block_storage Any, -// CHECK: [[CONT_HANDLER:%.*]] = function_ref @$sIeyBh_ytTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> () +// CHECK: [[CONT_HANDLER:%.*]] = function_ref @$sIeyB_ytTz_ : $@convention(c) (@inout_aliasable @block_storage Any) -> () // CHECK: [[INIT_BLOCK_STORAGE_HEADER:%.*]] = init_block_storage_header [[BLOCK]] : $*@block_storage Any, invoke [[CONT_HANDLER]] -// CHECK: merge_isolation_region [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, [[BLOCK]] +// CHECK-NOT: merge_isolation_region [[SLOWSERVER_ANYOBJECT_M_B_O_C]] : $@opened("{{.*}}", AnyObject) Self, [[BLOCK]] // CHECK: apply [[METHOD]]({{%.*}}, [[INIT_BLOCK_STORAGE_HEADER]], [[SLOWSERVER_ANYOBJECT_M_B_O_C]]) // CHECK: await_async_continuation [[CONT]] : $Builtin.RawUnsafeContinuation, resume bb1 // CHECK: } // end sil function '$s10objc_async13testAnyObjectyySo10SlowServerCYaF' diff --git a/test/SILGen/objc_async_checked.swift b/test/SILGen/objc_async_checked.swift index d716256c1b974..05e45c4345592 100644 --- a/test/SILGen/objc_async_checked.swift +++ b/test/SILGen/objc_async_checked.swift @@ -11,7 +11,7 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int // CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : // CHECK: [[ARG:%.*]] = apply [[STRINGINIT]] - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -21,7 +21,7 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN]]([[CHECKED_CONT]], [[WRAPPED]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, Never>) -> @out CheckedContinuation<τ_0_0, Never> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0) // CHECK: [[COPY:%.*]] = copy_value [[ARG]] @@ -40,7 +40,7 @@ func testSlowServer(slowServer: SlowServer) async throws { let _: Int = await slowServer.doSomethingSlowNullably("mail") // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $String - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (Optional, Optional) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (Optional, Optional) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr [throws] String, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -50,7 +50,7 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN]]([[CHECKED_CONT]], [[WRAPPED]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, any Error>) -> @out CheckedContinuation<τ_0_0, any Error> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[STRING_COMPLETION_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: destroy_addr [[CHECKED_CONT_SLOT]] : $*CheckedContinuation @@ -62,18 +62,18 @@ func testSlowServer(slowServer: SlowServer) async throws { // CHECK: dealloc_stack [[RESUME_BUF]] let _: String = try await slowServer.findAnswer() - // CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable () -> (), SlowServer) -> () - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any) -> () + // CHECK: objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) () -> (), SlowServer) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[VOID_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any) -> () await slowServer.serverRestart("somewhere") - // CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional) -> () + // CHECK: function_ref @[[STRING_NONZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional) -> () let _: String = try await slowServer.doSomethingFlaggy() - // CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, {{.*}}Bool, Optional) -> () + // CHECK: function_ref @[[STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, {{.*}}Bool, Optional) -> () let _: String = try await slowServer.doSomethingZeroFlaggy() - // CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional, Optional) -> () + // CHECK: function_ref @[[STRING_STRING_ZERO_FLAG_THROW_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, {{.*}}Bool, Optional, Optional, Optional) -> () let _: (String, String) = try await slowServer.doSomethingMultiResultFlaggy() - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Int, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSSTRING_INT_THROW_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Int, Optional) -> () let (_, _): (String, Int) = try await slowServer.findMultipleAnswers() let (_, _): (Bool, Bool) = try await slowServer.findDifferentlyFlavoredBooleans() @@ -198,7 +198,7 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Int // CHECK: [[STRINGINIT:%.*]] = function_ref @$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : // CHECK: [[ARG:%.*]] = apply [[STRINGINIT]] - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) @Sendable (Int) -> (), SlowServer) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (NSString, @convention(block) (Int) -> (), SlowServer) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr Int, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -208,7 +208,7 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN]]([[CHECKED_CONT]], [[WRAPPED]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, Never>) -> @out CheckedContinuation<τ_0_0, Never> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Int) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[INT_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Int) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[ARG]], [[BLOCK]], %0) // CHECK: [[COPY:%.*]] = copy_value [[ARG]] @@ -229,7 +229,7 @@ func testSlowServerFromMain(slowServer: SlowServer) async throws { // CHECK: [[STR:%.*]] = alloc_stack $String // CHECK: [[ERR:%.*]] = alloc_stack [dynamic_lifetime] $Optional // CHECK: inject_enum_addr [[ERR]] : $*Optional, #Optional.none!enumelt -// CHECK: [[METHOD:%.*]] = objc_method %0 : $SlowServer, #SlowServer.findAnswerFailingly!foreign : (SlowServer) -> () async throws -> String, $@convention(objc_method) (Optional>>, @convention(block) @Sendable (Optional, Optional) -> (), SlowServer) -> ObjCBool +// CHECK: [[METHOD:%.*]] = objc_method %0 : $SlowServer, #SlowServer.findAnswerFailingly!foreign : (SlowServer) -> () async throws -> String, $@convention(objc_method) (Optional>>, @convention(block) (Optional, Optional) -> (), SlowServer) -> ObjCBool // CHECK: [[RAW_CONT:%.*]] = get_async_continuation_addr [throws] String, {{.*}} : $*String // CHECK: [[UNSAFE_CONT:%.*]] = struct $UnsafeContinuation ([[RAW_CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -272,10 +272,10 @@ func testThrowingMethodFromMain(slowServer: SlowServer) async -> String { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN]]([[CHECKED_CONT]], [[CONT]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, any Error>) -> @out CheckedContinuation<τ_0_0, any Error> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation -// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyBhyy_SSTz_ +// CHECK: [[INVOKER:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyByy_SSTz_ // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORE_ALLOC]] {{.*}}, invoke [[INVOKER]] // CHECK: [[OPTIONAL_BLK:%.*]] = enum {{.*}}, #Optional.some!enumelt, [[BLOCK]] -// CHECK: {{.*}} = apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) @Sendable (Optional, Optional) -> ()>, SlowServer) -> () +// CHECK: {{.*}} = apply [[METH]]([[STRING_ARG]], [[OPTIONAL_BLK]], {{%.*}}) : $@convention(objc_method) (NSString, Optional<@convention(block) (Optional, Optional) -> ()>, SlowServer) -> () // CHECK: [[STRING_ARG_COPY:%.*]] = copy_value [[STRING_ARG]] : $NSString // CHECK: destroy_addr [[CHECKED_CONT_SLOT]] : $*CheckedContinuation // CHECK: dealloc_stack [[CHECKED_CONT]] : $*CheckedContinuation diff --git a/test/SILGen/objc_async_from_swift.swift b/test/SILGen/objc_async_from_swift.swift index 53d11d9c7ce93..686c2cca9451a 100644 --- a/test/SILGen/objc_async_from_swift.swift +++ b/test/SILGen/objc_async_from_swift.swift @@ -136,7 +136,7 @@ class SlowServerlet: SlowServer { // // @objc thunk closure // - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC011doSomethingE8NullablyySiSSYaFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) @Sendable (Int) -> ()>, SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC011doSomethingE8NullablyySiSSYaFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) (Int) -> ()>, SlowServerlet) -> () { // CHECK-NN: [[NONE:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[STR_ARG:%.*]] = begin_borrow {{.*}} : $String // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet @@ -163,7 +163,7 @@ class SlowServerlet: SlowServer { // CHECK-NN: } // end sil function '$s21objc_async_from_swift13SlowServerletC18findAnswerNullablyyS2SYaF' // @objc closure thunk - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC18findAnswerNullablyyS2SYaFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) @Sendable (NSString) -> ()>, SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC18findAnswerNullablyyS2SYaFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) (NSString) -> ()>, SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[STR_ARG:%.*]] = begin_borrow {{.*}} : $String // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet @@ -191,7 +191,7 @@ class SlowServerlet: SlowServer { // @objc thunk closure // - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC28doSomethingDangerousNullablyyS2SYaKFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) @Sendable (Optional, Optional) -> ()>, SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC28doSomethingDangerousNullablyyS2SYaKFyyYacfU_To : $@convention(thin) @Sendable @async (NSString, Optional<@convention(block) (Optional, Optional) -> ()>, SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[STR_ARG:%.*]] = begin_borrow {{.*}} : $String // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet @@ -218,7 +218,7 @@ class SlowServerlet: SlowServer { // CHECK-NN: } // end sil function '$s21objc_async_from_swift13SlowServerletC30doSomethingUnspecifiedNullablySSyYaKF' // @objc closure thunk - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC30doSomethingUnspecifiedNullablySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (Optional<@convention(block) @Sendable (Optional, Optional) -> ()>, SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC30doSomethingUnspecifiedNullablySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (Optional<@convention(block) (Optional, Optional) -> ()>, SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet // CHECK-C: [[NATIVE:%.*]] = function_ref @$s21objc_async_from_swift13SlowServerletC30doSomethingUnspecifiedNullablySSyYaKF : $@convention(method) @async (@guaranteed SlowServerlet) -> (@owned String, @error any Error) @@ -244,7 +244,7 @@ class SlowServerlet: SlowServer { // CHECK-NN: } // end sil function '$s21objc_async_from_swift13SlowServerletC17doSomethingFlaggySSyYaKF' // @objc thunk closure - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC17doSomethingFlaggySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable ({{.*}}, Optional, Optional) -> (), SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC17doSomethingFlaggySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) ({{.*}}, Optional, Optional) -> (), SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet // CHECK-C: [[NATIVE:%.*]] = function_ref @$s21objc_async_from_swift13SlowServerletC17doSomethingFlaggySSyYaKF : $@convention(method) @async (@guaranteed SlowServerlet) -> (@owned String, @error any Error) @@ -276,7 +276,7 @@ class SlowServerlet: SlowServer { // CHECK-NN: } // end sil function '$s21objc_async_from_swift13SlowServerletC21doSomethingZeroFlaggySSyYaKF' // // @objc thunk closure - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC21doSomethingZeroFlaggySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable (Optional, {{.*}}, Optional) -> (), SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC21doSomethingZeroFlaggySSyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) (Optional, {{.*}}, Optional) -> (), SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet // CHECK-C: [[NATIVE:%.*]] = function_ref @$s21objc_async_from_swift13SlowServerletC21doSomethingZeroFlaggySSyYaKF : $@convention(method) @async (@guaranteed SlowServerlet) -> (@owned String, @error any Error) @@ -306,7 +306,7 @@ class SlowServerlet: SlowServer { // CHECK-NN: hop_to_executor [[ACTOR]] // CHECK-NN: } // end sil function '$s21objc_async_from_swift13SlowServerletC28doSomethingMultiResultFlaggySS_SStyYaKF' // - // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC28doSomethingMultiResultFlaggySS_SStyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) @Sendable ({{.*}}, Optional, Optional, Optional) -> (), SlowServerlet) -> () { + // CHECK-LABEL: sil shared [thunk] [ossa] @$s21objc_async_from_swift13SlowServerletC28doSomethingMultiResultFlaggySS_SStyYaKFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) ({{.*}}, Optional, Optional, Optional) -> (), SlowServerlet) -> () { // CHECK-NN: [[ACTOR:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK: [[SELF:%.*]] = begin_borrow {{.*}} : $SlowServerlet // CHECK-C: [[NATIVE:%.*]] = function_ref @$s21objc_async_from_swift13SlowServerletC28doSomethingMultiResultFlaggySS_SStyYaKF : $@convention(method) @async (@guaranteed SlowServerlet) -> (@owned String, @owned String, @error any Error) @@ -436,9 +436,8 @@ func testAutoclosureInStaticMethod() { // CHECK: [[INIT_PROJ_BLOCK_STORAGE:%.*]] = init_existential_addr [[PROJ_BLOCK_STORAGE]] // CHECK: store [[UNSAFE_CONT]] to [trivial] [[INIT_PROJ_BLOCK_STORAGE]] // CHECK: merge_isolation_region [[BLOCK_STORAGE]] : $*@block_storage Any, [[RESULT]] - // CHECK: [[OBJC_COMPLETION_HANDLER_IMPL:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyBhyy_SSTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[OBJC_COMPLETION_HANDLER_IMPL:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyByy_SSTz_ : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] : $*@block_storage Any, invoke [[OBJC_COMPLETION_HANDLER_IMPL]] - // CHECK: merge_isolation_region [[CAPTURE]] : $SlowServer, [[BLOCK_STORAGE]] // CHECK: apply [[OBJC_METHOD]]([[NS_STRING]], [[BLOCK]], [[CAPTURE]]) // CHECK: await_async_continuation [[RAW_UNSAFE_CONT]] : $Builtin.RawUnsafeContinuation, resume [[RESUME_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] // @@ -545,9 +544,8 @@ func testAutoclosureInStaticMethod() { // CHECK: [[INIT_PROJ_BLOCK_STORAGE:%.*]] = init_existential_addr [[PROJ_BLOCK_STORAGE]] // CHECK: store [[UNSAFE_CONT]] to [trivial] [[INIT_PROJ_BLOCK_STORAGE]] // CHECK: merge_isolation_region [[BLOCK_STORAGE]] : $*@block_storage Any, [[RESULT]] - // CHECK: [[OBJC_COMPLETION_HANDLER_IMPL:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyBhyy_SSTz_ : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[OBJC_COMPLETION_HANDLER_IMPL:%.*]] = function_ref @$sSo8NSStringCSgSo7NSErrorCSgIeyByy_SSTz_ : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] : $*@block_storage Any, invoke [[OBJC_COMPLETION_HANDLER_IMPL]] - // CHECK: merge_isolation_region [[CAPTURE]] : $SlowServer, [[BLOCK_STORAGE]] // CHECK: apply [[OBJC_METHOD]]([[NS_STRING]], [[BLOCK]], [[CAPTURE]]) // CHECK: await_async_continuation [[RAW_UNSAFE_CONT]] : $Builtin.RawUnsafeContinuation, resume [[RESUME_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] // diff --git a/test/SILGen/objc_effectful_properties.swift b/test/SILGen/objc_effectful_properties.swift index 24dba591ecfae..6f60a8941e832 100644 --- a/test/SILGen/objc_effectful_properties.swift +++ b/test/SILGen/objc_effectful_properties.swift @@ -8,14 +8,14 @@ import EffectfulProperties // CHECK-LABEL: sil {{.*}}@${{.*}}13testJustAsync func testJustAsync(eff : EffProps) async { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $NSObject - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (NSObject) -> (), EffProps) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (NSObject) -> (), EffProps) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr NSObject, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any // CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]] // CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]] // CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]] - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, NSObject) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, NSObject) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]] @@ -29,14 +29,14 @@ func testJustAsync(eff : EffProps) async { // CHECK-LABEL: sil {{.*}}@${{.*}}15testAsyncThrows func testAsyncThrows(eff : EffProps) async { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Optional - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (Optional, Optional) -> (), EffProps) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (Optional, Optional) -> (), EffProps) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr [throws] Optional, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation, any Error> ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any // CHECK: [[CONT_SLOT:%.*]] = project_block_storage [[BLOCK_STORAGE]] // CHECK: [[CONT_SLOT_ADDR:%.*]] = init_existential_addr [[CONT_SLOT]] // CHECK: store [[WRAPPED]] to [trivial] [[CONT_SLOT_ADDR]] - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: await_async_continuation [[CONT]] {{.*}}, resume [[RESUME:bb[0-9]+]], error [[RESUME_ERROR:bb[0-9]+]] diff --git a/test/SILGen/objc_effectful_properties_checked.swift b/test/SILGen/objc_effectful_properties_checked.swift index 14f891b76b69c..79fa319daff5b 100644 --- a/test/SILGen/objc_effectful_properties_checked.swift +++ b/test/SILGen/objc_effectful_properties_checked.swift @@ -8,7 +8,7 @@ import EffectfulProperties // CHECK-LABEL: sil {{.*}}@${{.*}}13testJustAsync func testJustAsync(eff : EffProps) async { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $NSObject - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (NSObject) -> (), EffProps) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (NSObject) -> (), EffProps) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr NSObject, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -18,7 +18,7 @@ func testJustAsync(eff : EffProps) async { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN]]([[CHECKED_CONT]], [[WRAPPED]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, Never>) -> @out CheckedContinuation<τ_0_0, Never> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, NSObject) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, NSObject) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: destroy_addr [[CHECKED_CONT_SLOT]] : $*CheckedContinuation @@ -34,7 +34,7 @@ func testJustAsync(eff : EffProps) async { // CHECK-LABEL: sil {{.*}}@${{.*}}15testAsyncThrows func testAsyncThrows(eff : EffProps) async { // CHECK: [[RESUME_BUF:%.*]] = alloc_stack $Optional - // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) @Sendable (Optional, Optional) -> (), EffProps) -> () + // CHECK: [[METHOD:%.*]] = objc_method {{.*}} $@convention(objc_method) (@convention(block) (Optional, Optional) -> (), EffProps) -> () // CHECK: [[CONT:%.*]] = get_async_continuation_addr [throws] Optional, [[RESUME_BUF]] // CHECK: [[WRAPPED:%.*]] = struct $UnsafeContinuation, any Error> ([[CONT]] : $Builtin.RawUnsafeContinuation) // CHECK: [[BLOCK_STORAGE:%.*]] = alloc_stack $@block_storage Any @@ -44,7 +44,7 @@ func testAsyncThrows(eff : EffProps) async { // CHECK: [[CHECKED_CONT:%.*]] = alloc_stack $CheckedContinuation, any Error> // CHECK: {{.*}} = apply [[CHECKED_CONT_INIT_FN:%.*]]>([[CHECKED_CONT]], [[WRAPPED]]) : $@convention(thin) <τ_0_0> (UnsafeContinuation<τ_0_0, any Error>) -> @out CheckedContinuation<τ_0_0, any Error> // CHECK: copy_addr [take] [[CHECKED_CONT]] to [init] [[CHECKED_CONT_SLOT]] : $*CheckedContinuation, any Error> - // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) @Sendable (@inout_aliasable @block_storage Any, Optional, Optional) -> () + // CHECK: [[BLOCK_IMPL:%.*]] = function_ref @[[NSO_COMPLETION_BLOCK:.*]] : $@convention(c) (@inout_aliasable @block_storage Any, Optional, Optional) -> () // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[BLOCK_STORAGE]] {{.*}}, invoke [[BLOCK_IMPL]] // CHECK: apply [[METHOD]]([[BLOCK]], %0) // CHECK: destroy_addr [[CHECKED_CONT_SLOT]] : $*CheckedContinuation, any Error> From 56383771fee83f47ec53c55ad9928744e0c44bf5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 6 Jun 2025 23:35:10 -0700 Subject: [PATCH 2/2] [ClangImporter] SE-0463: Implement `@Sendable` inference exception for global actor isolated functions Functions that are isolated to a global actor don't have completion handlers imported as `@Sendable`. Main actor isolated functions with completion handlers that are always called on the main actor is a very common Objective-C pattern, and this carve out will eliminate false positive warnings in the cases where the main actor annotation is missing on the completion handler parameter. Resolves: rdar://149811049 (cherry picked from commit ab227b401d3ddbfaa3ba47cdeb48646b8808ba47) --- lib/ClangImporter/ImportType.cpp | 45 +++++--- lib/ClangImporter/ImporterImpl.h | 3 + ...l_actor_isolated_completion_handlers.swift | 102 ++++++++++++++++++ 3 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 test/Concurrency/global_actor_isolated_completion_handlers.swift diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 5062eb2160cfd..aafb93ffd8b1b 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2421,11 +2421,30 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType( return {swiftResultTy, importedType.isImplicitlyUnwrapped()}; } +static bool isParameterContextGlobalActorIsolated(DeclContext *dc, + const clang::Decl *parent) { + if (getActorIsolationOfContext(dc).isGlobalActor()) + return true; + + if (!parent->hasAttrs()) + return false; + + for (const auto *attr : parent->getAttrs()) { + if (auto swiftAttr = dyn_cast(attr)) { + if (isMainActorAttr(swiftAttr)) + return true; + } + } + + return false; +} + std::optional ClangImporter::Implementation::importParameterType( - const clang::ParmVarDecl *param, OptionalTypeKind optionalityOfParam, - bool allowNSUIntegerAsInt, bool isNSDictionarySubscriptGetter, - bool paramIsError, bool paramIsCompletionHandler, + DeclContext *dc, const clang::Decl *parent, const clang::ParmVarDecl *param, + OptionalTypeKind optionalityOfParam, bool allowNSUIntegerAsInt, + bool isNSDictionarySubscriptGetter, bool paramIsError, + bool paramIsCompletionHandler, std::optional completionHandlerErrorParamIndex, ArrayRef genericParams, llvm::function_ref addImportDiagnosticFn) { @@ -2445,7 +2464,8 @@ ClangImporter::Implementation::importParameterType( if (SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) && paramIsCompletionHandler) { - attrs |= ImportTypeAttr::DefaultsToSendable; + if (!isParameterContextGlobalActorIsolated(dc, parent)) + attrs |= ImportTypeAttr::DefaultsToSendable; } if (auto optionSetEnum = importer::findOptionSetEnum(paramTy, *this)) { @@ -2722,13 +2742,13 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( ImportDiagnosticAdder paramAddDiag(*this, clangDecl, param->getLocation()); - auto swiftParamTyOpt = - importParameterType(param, optionalityOfParam, allowNSUIntegerAsInt, - /*isNSDictionarySubscriptGetter=*/false, - /*paramIsError=*/false, - /*paramIsCompletionHandler=*/false, - /*completionHandlerErrorParamIndex=*/std::nullopt, - genericParams, paramAddDiag); + auto swiftParamTyOpt = importParameterType( + dc, clangDecl, param, optionalityOfParam, allowNSUIntegerAsInt, + /*isNSDictionarySubscriptGetter=*/false, + /*paramIsError=*/false, + /*paramIsCompletionHandler=*/false, + /*completionHandlerErrorParamIndex=*/std::nullopt, genericParams, + paramAddDiag); if (!swiftParamTyOpt) { addImportDiagnostic(param, Diagnostic(diag::parameter_type_not_imported, param), @@ -3285,7 +3305,8 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType( ImportDiagnosticAdder paramAddDiag(*this, clangDecl, param->getLocation()); auto swiftParamTyOpt = importParameterType( - param, optionalityOfParam, allowNSUIntegerAsIntInParam, + origDC, clangDecl, param, optionalityOfParam, + allowNSUIntegerAsIntInParam, kind == SpecialMethodKind::NSDictionarySubscriptGetter, paramIsError, paramIsCompletionHandler, completionHandlerErrorParamIndex, ArrayRef(), paramAddDiag); diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 10736259a8c4a..50cd880db8456 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1458,6 +1458,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Import a parameter type /// + /// \param dc The declaration context in which this parameter appears. + /// \param parent The declaration with which this parameter is associated. /// \param param The underlaying parameter declaraction. /// \param optionalityOfParam The kind of optionality for the parameter /// being imported. @@ -1485,6 +1487,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// /// \returns The imported parameter result on success, or None on failure. std::optional importParameterType( + DeclContext *dc, const clang::Decl *parent, const clang::ParmVarDecl *param, OptionalTypeKind optionalityOfParam, bool allowNSUIntegerAsInt, bool isNSDictionarySubscriptGetter, bool paramIsError, bool paramIsCompletionHandler, diff --git a/test/Concurrency/global_actor_isolated_completion_handlers.swift b/test/Concurrency/global_actor_isolated_completion_handlers.swift new file mode 100644 index 0000000000000..613154e8a263a --- /dev/null +++ b/test/Concurrency/global_actor_isolated_completion_handlers.swift @@ -0,0 +1,102 @@ +// RUN: %empty-directory(%t/src) +// RUN: %empty-directory(%t/sdk) +// RUN: split-file %s %t/src + +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \ +// RUN: -import-objc-header %t/src/Test.h \ +// RUN: -swift-version 6 \ +// RUN: -module-name main -I %t -verify + +// REQUIRES: objc_interop + +//--- Test.h +#define SWIFT_SENDABLE __attribute__((__swift_attr__("@Sendable"))) +#define NONSENDABLE __attribute__((__swift_attr__("@_nonSendable"))) +#define MAIN_ACTOR __attribute__((__swift_attr__("@MainActor"))) + +#pragma clang assume_nonnull begin + +@import Foundation; + +MAIN_ACTOR +@protocol P +@end + +@interface TestFromProtocol

+-(void) compute: (void (^)(void)) completion; +@end + +MAIN_ACTOR +@interface TestFromType +-(void) compute: (void (^)(void)) completion; +@end + +@interface TestSubclass : TestFromType +-(void) subCompute: (void (^)(void)) completion; +@end + +@interface TestFromMethod +-(void) MAIN_ACTOR compute: (void (^)(void)) completion; ++(void) MAIN_ACTOR computeStatic: (void (^)(void)) completion; +@end + +#pragma clang assume_nonnull end + +//--- main.swift + +func testFromProtocol(v: TestFromProtocol) { + let _: Int = v.compute + // expected-error@-1 {{cannot convert value of type '@MainActor @Sendable (@escaping () -> Void) -> Void' to specified type 'Int'}} +} + +func testFromType(v: TestFromType) { + let _: Int = v.compute + // expected-error@-1 {{annot convert value of type '@MainActor @Sendable (@escaping () -> Void) -> Void' to specified type 'Int'}} +} + +func testFromSuperclass(v: TestSubclass) { + let _: Int = v.subCompute + // expected-error@-1 {{cannot convert value of type '@MainActor @Sendable (@escaping () -> Void) -> Void' to specified type 'Int'}} +} + +func testFromMethod(v: TestFromMethod, t: TestFromMethod.Type) { + let _: Int = v.compute + // expected-error@-1 {{cannot convert value of type '@MainActor (@escaping () -> Void) -> Void' to specified type 'Int'}} + + let _: Int = t.computeStatic + // expected-error@-1 {{cannot convert value of type '@MainActor @Sendable (@escaping () -> Void) -> Void' to specified type 'Int'}} +} + +nonisolated func testUse(v1: TestFromProtocol, v2: TestFromType, v3: TestSubclass, v4: TestFromMethod, v5: TestFromMethod.Type) async { + var val: Int = 0 + + await v1.compute { val += 1 } // No execution warning because parameter type isn't Sendable + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v1.compute { @Sendable in val += 1 } // expected-warning {{mutation of captured var 'val' in concurrently-executing code}} + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v2.compute { val += 1 } // No execution warning because parameter type isn't Sendable + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v2.compute { @Sendable in val += 1 } // expected-warning {{mutation of captured var 'val' in concurrently-executing code}} + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v3.subCompute { val += 1 } // No execution warning because parameter type isn't Sendable + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v3.subCompute { @Sendable in val += 1 } // expected-warning {{mutation of captured var 'val' in concurrently-executing code}} + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v4.compute { val += 1 } // No execution warning because parameter type isn't Sendable + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v4.compute { @Sendable in val += 1 } // expected-warning {{mutation of captured var 'val' in concurrently-executing code}} + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v5.computeStatic { val += 1 } // No execution warning because parameter type isn't Sendable + // expected-warning@-1 {{consider using asynchronous alternative function}} + + await v5.computeStatic { @Sendable in val += 1 } // expected-warning {{mutation of captured var 'val' in concurrently-executing code}} + // expected-warning@-1 {{consider using asynchronous alternative function}} +}