Skip to content

[Concurrency] Add an API in the Concurrency library for extracting isolation from a dynamically isolated function value. #71906

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 2 commits into from
Feb 27, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ extension DestructureStructInst : ForwardingInstruction {
public var canForwardOwnedValues: Bool { true }
}

extension FunctionExtractIsolationInst : ForwardingInstruction {
public var preservesIdentity: Bool { false }
public var preservesRepresentation: Bool { true }
public var canForwardGuaranteedValues: Bool { true }
public var canForwardOwnedValues: Bool { false }
}

extension InitExistentialRefInst : ForwardingInstruction {
public var preservesIdentity: Bool { false }
public var preservesRepresentation: Bool { true }
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ EXPERIMENTAL_FEATURE(DynamicActorIsolation, false)
EXPERIMENTAL_FEATURE(BorrowingSwitch, true)

// Enable isolated(any) attribute on function types.
EXPERIMENTAL_FEATURE(IsolatedAny, false)
EXPERIMENTAL_FEATURE(IsolatedAny, true)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ struct OwnershipModelEliminatorVisitor
HANDLE_FORWARDING_INST(LinearFunctionExtract)
HANDLE_FORWARDING_INST(DifferentiableFunctionExtract)
HANDLE_FORWARDING_INST(MarkUninitialized)
HANDLE_FORWARDING_INST(FunctionExtractIsolation)
#undef HANDLE_FORWARDING_INST
};

Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/SemanticARC/SemanticARCOptVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ struct LLVM_LIBRARY_VISIBILITY SemanticARCOptVisitor
FORWARDING_INST(LinearFunction)
FORWARDING_INST(DifferentiableFunctionExtract)
FORWARDING_INST(LinearFunctionExtract)
FORWARDING_INST(FunctionExtractIsolation)
#undef FORWARDING_INST

bool processWorklist();
Expand Down
8 changes: 8 additions & 0 deletions stdlib/public/Concurrency/Actor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ internal func _enqueueOnMain(_ job: UnownedJob)
public macro isolation<T>() -> T = Builtin.IsolationMacro
#endif

#if $IsolatedAny
@available(SwiftStdlib 5.1, *)
public func extractIsolation<each Arg, Result>(
_ fn: @escaping @isolated(any) (repeat each Arg) async throws -> Result
) -> (any Actor)? {
return Builtin.extractFunctionIsolation(fn)
}
#endif
4 changes: 4 additions & 0 deletions stdlib/public/Concurrency/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ else()
list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=never")
endif()

list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS
"-enable-experimental-feature"
"IsolatedAny"
)

list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS
"-D__STDC_WANT_LIB_EXT1__=1")
Expand Down
12 changes: 12 additions & 0 deletions test/Concurrency/isolated_any.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ func globalNonisolatedFunction() {}

actor A {
func actorFunction() {}
func asyncActorFunction() async {}
func asyncThrowsActorFunction() async throws {}
func actorFunctionWithArgs(value: Int) async -> String { "" }
}

func testBasic_sync() {
Expand Down Expand Up @@ -71,3 +74,12 @@ func testConvertIsolatedAnyToMainActor(fn: @Sendable @isolated(any) () -> ()) {
// expected-error @+1 {{cannot convert value of type '@isolated(any) @Sendable () -> ()' to expected argument type '@MainActor @Sendable () -> ()'}}
requireSendableGlobalActor(fn)
}

func extractFunctionIsolation(_ fn: @isolated(any) @escaping () async -> Void) {
let _: (any Actor)? = extractIsolation(fn)

let myActor = A()
let _: (any Actor)? = extractIsolation(myActor.asyncActorFunction)
let _: (any Actor)? = extractIsolation(myActor.asyncThrowsActorFunction)
let _: (any Actor)? = extractIsolation(myActor.actorFunctionWithArgs(value:))
}
Copy link
Contributor

@ktoso ktoso Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test with myActor being a distributed actor? Doug did the work for #isolated to convert, but would it work here as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a test for this separately; it'll work as long as the type checker erasure to an @isolated(any) function type works when the function has an isolated distributed actor parameter. The type checker support was added in #71433, this PR just exposes a surface syntax for Builtin.extractFunctionIsolation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'm just always nervous when we add such surface API that we might break it if not covered with DA tests. Thanks in advance, should be quick one to add :)