Skip to content

Extend _unsafeInheritExecutor_ to remaining @_unsafeInheritExecutor APIs #75248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7279,7 +7279,10 @@ void AttributeChecker::visitUnsafeInheritExecutorAttr(
auto fn = cast<FuncDecl>(D);
if (!fn->isAsyncContext()) {
diagnose(attr->getLocation(), diag::inherits_executor_without_async);
} else {
} else if (fn->getBaseName().isSpecial() ||
!fn->getParentModule()->getName().str().equals("_Concurrency") ||
!fn->getBaseIdentifier().str()
.startswith("_unsafeInheritExecutor_")) {
bool inConcurrencyModule = D->getDeclContext()->getParentModule()->getName()
.str().equals("_Concurrency");
auto diag = fn->diagnose(diag::unsafe_inherits_executor_deprecated);
Expand Down
6 changes: 4 additions & 2 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2105,7 +2105,8 @@ void swift::introduceUnsafeInheritExecutorReplacements(

auto isReplaceable = [&](ValueDecl *decl) {
return isa<FuncDecl>(decl) && inConcurrencyModule(decl->getDeclContext()) &&
decl->getDeclContext()->isModuleScopeContext();
decl->getDeclContext()->isModuleScopeContext() &&
cast<FuncDecl>(decl)->hasAsync();
};

// Make sure at least some of the entries are functions in the _Concurrency
Expand Down Expand Up @@ -2160,7 +2161,8 @@ void swift::introduceUnsafeInheritExecutorReplacements(
return;

auto isReplaceable = [&](ValueDecl *decl) {
return isa<FuncDecl>(decl) && inConcurrencyModule(decl->getDeclContext());
return isa<FuncDecl>(decl) && inConcurrencyModule(decl->getDeclContext()) &&
cast<FuncDecl>(decl)->hasAsync();
};

// Make sure at least some of the entries are functions in the _Concurrency
Expand Down
12 changes: 8 additions & 4 deletions stdlib/public/Concurrency/DiscardingTaskGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,16 @@ public func withDiscardingTaskGroup<GroupResult>(
return result
}

// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful
// to the type checker.
//
// This function also doubles as an ABI-compatibility shim predating the
// introduction of #isolation.
@available(SwiftStdlib 5.9, *)
@usableFromInline
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss23withDiscardingTaskGroup9returning4bodyxxm_xs0bcD0VzYaXEtYalF")
internal func __abi_withDiscardingTaskGroup<GroupResult>(
public func _unsafeInheritExecutor_withDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout DiscardingTaskGroup) async -> GroupResult
) async -> GroupResult {
Expand Down Expand Up @@ -637,10 +642,9 @@ public func withThrowingDiscardingTaskGroup<GroupResult>(
}

@available(SwiftStdlib 5.9, *)
@usableFromInline
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss31withThrowingDiscardingTaskGroup9returning4bodyxxm_xs0bcdE0Vys5Error_pGzYaKXEtYaKlF")
internal func __abi_withThrowingDiscardingTaskGroup<GroupResult>(
public func _unsafeInheritExecutor_withThrowingDiscardingTaskGroup<GroupResult>(
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout ThrowingDiscardingTaskGroup<Error>) async throws -> GroupResult
) async throws -> GroupResult {
Expand Down
8 changes: 7 additions & 1 deletion stdlib/public/Concurrency/Task+TaskExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,17 @@ public func withTaskExecutorPreference<T, Failure>(
return try await operation()
}

// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful
// to the type checker.
//
// This function also doubles as an ABI-compatibility shim predating the
// introduction of #isolation.
@_unavailableInEmbedded
@available(SwiftStdlib 6.0, *)
@_unsafeInheritExecutor // for ABI compatibility
@_silgen_name("$ss26withTaskExecutorPreference_9operationxSch_pSg_xyYaYbKXEtYaKs8SendableRzlF")
public func __abi__withTaskExecutorPreference<T: Sendable>(
public func _unsafeInheritExecutor_withTaskExecutorPreference<T: Sendable>(
_ taskExecutor: (any TaskExecutor)?,
operation: @Sendable () async throws -> T
) async rethrows -> T {
Expand Down
17 changes: 14 additions & 3 deletions stdlib/public/Concurrency/TaskGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,17 @@ public func withTaskGroup<ChildTaskResult, GroupResult>(
#endif
}

// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful
// to the type checker.
//
// This function also doubles as an ABI-compatibility shim predating the
// introduction of #isolation.
@available(SwiftStdlib 5.1, *)
@_silgen_name("$ss13withTaskGroup2of9returning4bodyq_xm_q_mq_ScGyxGzYaXEtYar0_lF")
@_unsafeInheritExecutor // for ABI compatibility
@inlinable
public func withTaskGroup<ChildTaskResult, GroupResult>(
public func _unsafeInheritExecutor_withTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout TaskGroup<ChildTaskResult>) async -> GroupResult
Expand Down Expand Up @@ -228,11 +234,16 @@ public func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
#endif
}

// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful
// to the type checker.
//
// This function also doubles as an ABI-compatibility shim predating the
// introduction of #isolation.
@available(SwiftStdlib 5.1, *)
@_silgen_name("$ss21withThrowingTaskGroup2of9returning4bodyq_xm_q_mq_Scgyxs5Error_pGzYaKXEtYaKr0_lF")
@_unsafeInheritExecutor // for ABI compatibility
@usableFromInline
internal func withThrowingTaskGroup<ChildTaskResult, GroupResult>(
public func _unsafeInheritExecutor_withThrowingTaskGroup<ChildTaskResult, GroupResult>(
of childTaskResultType: ChildTaskResult.Type,
returning returnType: GroupResult.Type = GroupResult.self,
body: (inout ThrowingTaskGroup<ChildTaskResult, Error>) async throws -> GroupResult
Expand Down
10 changes: 6 additions & 4 deletions stdlib/public/Concurrency/TaskLocal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,16 @@ public final class TaskLocal<Value: Sendable>: Sendable, CustomStringConvertible
return try await operation()
}

@_silgen_name("$ss9TaskLocalC13withValueImpl_9operation4file4lineqd__xn_qd__yYaKXESSSutYaKlF")
@inlinable
@discardableResult
@_unsafeInheritExecutor // internal for backwards compatibility; though may be able to be removed safely?
@available(SwiftStdlib 5.1, *)
@backDeployed(before: SwiftStdlib 5.9)
internal func withValueImpl<R>(_ valueDuringOperation: __owned Value,
operation: () async throws -> R,
file: String = #fileID, line: UInt = #line) async rethrows -> R {
internal func _unsafeInheritExecutor_withValueImpl<R>(
_ valueDuringOperation: __owned Value,
operation: () async throws -> R,
file: String = #fileID, line: UInt = #line
) async rethrows -> R {
_taskLocalValuePush(key: key, value: consume valueDuringOperation)
defer { _taskLocalValuePop() }

Expand Down
60 changes: 58 additions & 2 deletions test/Concurrency/unsafe_inherit_executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ enum TL {
static var string: String = "<undefined>"
}

enum MyError: Error {
case fail
}

@_unsafeInheritExecutor
func unsafeCallerAvoidsNewLoop() async throws {
func unsafeCallerAvoidsNewLoop(clock: some Clock) async throws {
// expected-warning@-1{{@_unsafeInheritExecutor attribute is deprecated; consider an 'isolated' parameter defaulted to '#isolation' instead}}

_ = await withUnsafeContinuation { (continuation: UnsafeContinuation<Int, Never>) in
Expand All @@ -113,10 +117,62 @@ func unsafeCallerAvoidsNewLoop() async throws {
} onCancel: {
}

await TL.$string.withValue("hello") {
TL.$string.withValue("hello") {
print(TL.string)
}

try await TL.$string.withValue("hello") {
try await Task.sleep(nanoseconds: 500)
print(TL.string)
}

func operation() async throws -> Int { 7 }
try await TL.$string.withValue("hello", operation: operation)

// FIXME: Clock.measure does not currently support this hack.
// expected-error@+1{{#isolation (introduced by a default argument) cannot be used within an '@_unsafeInheritExecutor' function}}
_ = try! await clock.measure {
print("so very slow")
try await Task.sleep(nanoseconds: 500)
}

_ = await withDiscardingTaskGroup(returning: Int.self) { group in
group.addTask {
print("hello")
}

return 5
}

_ = try await withThrowingDiscardingTaskGroup(returning: Int.self) { group in
group.addTask {
print("hello")
}

return 5
}

_ = await withTaskExecutorPreference(nil) {
print("hello")
}

_ = await withTaskGroup(of: Int.self, returning: Int.self) { group in
group.addTask {
return 5
}

return 5
}

_ = try await withThrowingTaskGroup(of: Int.self, returning: Int.self) { group in
group.addTask {
throw MyError.fail
}

throw MyError.fail
}
}

@_unsafeInheritExecutor
func _unsafeInheritExecutor_hacky() async { }
// expected-warning@-1{{@_unsafeInheritExecutor attribute is deprecated; consider an 'isolated' parameter defaulted to '#isolation' instead}}
6 changes: 6 additions & 0 deletions test/api-digester/stability-concurrency-abi.test
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ Func TaskLocal.withValue(_:operation:file:line:) has parameter 1 type change fro
Func TaskLocal.withValue(_:operation:file:line:) has parameter 1 type change from () throws -> τ_1_0 to () async throws -> τ_1_0
Func TaskLocal.withValue(_:operation:file:line:) has parameter 2 type change from Swift.String to (any _Concurrency.Actor)?
Func TaskLocal.withValue(_:operation:file:line:) has parameter 3 type change from Swift.UInt to Swift.String
Func withTaskGroup(of:returning:body:) has parameter 2 type change from (inout _Concurrency.TaskGroup<τ_0_0>) async -> τ_0_1 to (any _Concurrency.Actor)?
Func withThrowingTaskGroup(of:returning:body:) has been renamed to Func withThrowingTaskGroup(of:returning:isolation:body:)
Func withThrowingTaskGroup(of:returning:body:) has mangled name changing from '_Concurrency.withThrowingTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, body: (inout Swift.ThrowingTaskGroup<A, Swift.Error>) async throws -> B) async throws -> B' to '_Concurrency.withThrowingTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, isolation: isolated Swift.Optional<Swift.Actor>, body: (inout Swift.ThrowingTaskGroup<A, Swift.Error>) async throws -> B) async throws -> B'
Func withThrowingTaskGroup(of:returning:body:) has parameter 2 type change from (inout _Concurrency.ThrowingTaskGroup<τ_0_0, any Swift.Error>) async throws -> τ_0_1 to (any _Concurrency.Actor)?
Func withTaskGroup(of:returning:body:) has been renamed to Func withTaskGroup(of:returning:isolation:body:)
Func withTaskGroup(of:returning:body:) has mangled name changing from '_Concurrency.withTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, body: (inout Swift.TaskGroup<A>) async -> B) async -> B' to '_Concurrency.withTaskGroup<A, B where A: Swift.Sendable>(of: A.Type, returning: B.Type, isolation: isolated Swift.Optional<Swift.Actor>, body: (inout Swift.TaskGroup<A>) async -> B) async -> B'

// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)

Expand Down