diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f441094..041d95b 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -67,21 +67,21 @@ jobs: id: destination run: | case "${{ matrix.platform }}" in - ios) - destination="platform=iOS Simulator,name=iPhone 16 Pro Max,OS=latest" - ;; maccatalyst) destination="platform=macOS,variant=Mac Catalyst" ;; + ios) + destination="platform=iOS Simulator,name=iPhone 16 Pro Max,OS=latest" + ;; tvos) destination="platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=latest" ;; - visionos) - destination="platform=visionOS Simulator,name=Apple Vision Pro,OS=latest" - ;; watchos) destination="platform=watchOS Simulator,name=Apple Watch Series 10 (46mm),OS=latest" ;; + visionos) + destination="platform=visionOS Simulator,name=Apple Vision Pro,OS=latest" + ;; *) echo "Unknown platform: ${{ matrix.platform }}" exit 1 diff --git a/.swift-version b/.swift-version index e0ea36f..e8f1734 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -6.0 +6.1 \ No newline at end of file diff --git a/Sources/PrincipleConcurrency/DeadlineExceededError.swift b/Sources/PrincipleConcurrency/DeadlineExceededError.swift index 1edb2b2..21966ce 100644 --- a/Sources/PrincipleConcurrency/DeadlineExceededError.swift +++ b/Sources/PrincipleConcurrency/DeadlineExceededError.swift @@ -33,7 +33,7 @@ public func withDeadline( clock: C, priority: TaskPriority? = nil, isolation: isolated (any Actor)? = #isolation, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success ) async throws -> Success { try await withTimeLimit( throwing: DeadlineExceededError(), @@ -65,7 +65,7 @@ public func withDeadline( tolerance: Duration? = nil, priority: TaskPriority? = nil, isolation: isolated (any Actor)? = #isolation, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success ) async throws -> Success { try await withDeadline( until: deadline, diff --git a/Sources/PrincipleConcurrency/TaskTimeLimit.swift b/Sources/PrincipleConcurrency/TaskTimeLimit.swift index 4bede52..b3f7a66 100644 --- a/Sources/PrincipleConcurrency/TaskTimeLimit.swift +++ b/Sources/PrincipleConcurrency/TaskTimeLimit.swift @@ -9,9 +9,9 @@ // Copyright © 2024 Philipp Gabriel. Original code licensed under MIT. // -private enum TaskTimeLimit { +private enum TaskTimeLimit { - enum Event { + enum Event { case taskFinished(Result) case parentTaskCancelled @@ -26,12 +26,12 @@ internal func withTimeLimit( // swiftlint:disable:t clock: C, priority: TaskPriority?, isolation: isolated (any Actor)?, - operation: sending @escaping @isolated(any) () async throws -> Success + operation: sending @escaping () async throws -> Success ) async throws -> Success { var transfer = SingleUseTransfer(operation) let result = await withTaskGroup( - of: TaskTimeLimit.Event.self, + of: TaskTimeLimit.Event.self, returning: Result.self, isolation: isolation, body: { group in @@ -39,7 +39,9 @@ internal func withTimeLimit( // swiftlint:disable:t group.addTask(priority: priority) { do { - // Review after closure isolation control gets implemented + // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0461-async-function-isolation.md + // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0472-task-start-synchronously-on-caller-context.md + // https://forums.swift.org/t/explicitly-captured-isolated-parameter-does-not-change-isolation-of-sendable-sending-closures/79502 // https://forums.swift.org/t/closure-isolation-control/70378 let success = try await transfer.finalize()() return .taskFinished(.success(success)) diff --git a/Sources/PrincipleConcurrency/TimeoutError.swift b/Sources/PrincipleConcurrency/TimeoutError.swift index 136785c..bf039c2 100644 --- a/Sources/PrincipleConcurrency/TimeoutError.swift +++ b/Sources/PrincipleConcurrency/TimeoutError.swift @@ -33,7 +33,7 @@ public func withTimeout( clock: C, priority: TaskPriority? = nil, isolation: isolated (any Actor)? = #isolation, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success ) async throws -> Success { try await withTimeLimit( throwing: TimeoutError(), @@ -65,7 +65,7 @@ public func withTimeout( tolerance: Duration? = nil, priority: TaskPriority? = nil, isolation: isolated (any Actor)? = #isolation, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping () async throws -> Success ) async throws -> Success { try await withTimeout( duration, diff --git a/Tests/PrincipleConcurrencyTests/CustomActor.swift b/Tests/PrincipleConcurrencyTests/CustomActor.swift new file mode 100644 index 0000000..12445cf --- /dev/null +++ b/Tests/PrincipleConcurrencyTests/CustomActor.swift @@ -0,0 +1,13 @@ +// +// CustomActor.swift +// Principle +// +// Created by Kamil Strzelecki on 24/04/2025. +// Copyright © 2025 Kamil Strzelecki. All rights reserved. +// + +@globalActor +internal actor CustomActor { + + static let shared = CustomActor() +} diff --git a/Tests/PrincipleConcurrencyTests/TaskTimeLimitTests.swift b/Tests/PrincipleConcurrencyTests/TaskTimeLimitTests.swift index f333706..f57511f 100644 --- a/Tests/PrincipleConcurrencyTests/TaskTimeLimitTests.swift +++ b/Tests/PrincipleConcurrencyTests/TaskTimeLimitTests.swift @@ -54,6 +54,16 @@ internal struct TaskTimeLimitTests { try await task.value } } + + @Test + func testIsolation() async throws { + let task = Task { @CustomActor in + try await withDeadline(until: .now + .seconds(1)) { + CustomActor.shared.assertIsolated() + } + } + try await task.value + } } struct Timeout { @@ -99,6 +109,16 @@ internal struct TaskTimeLimitTests { try await task.value } } + + @Test + func testIsolation() async throws { + let task = Task { @CustomActor in + try await withTimeout(.seconds(1)) { + CustomActor.shared.assertIsolated() + } + } + try await task.value + } } }