diff --git a/src/IcedTasks/CancellableTaskBuilderBase.fs b/src/IcedTasks/CancellableTaskBuilderBase.fs
index b1fd3cd..ea92edc 100644
--- a/src/IcedTasks/CancellableTaskBuilderBase.fs
+++ b/src/IcedTasks/CancellableTaskBuilderBase.fs
@@ -371,6 +371,95 @@ module CancellableTaskBase =
sm.ResumptionDynamicInfo.ResumptionFunc <- cont
false
+
+ ///
+ /// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code.
+ ///
+ []
+ static member inline internal BindDynamicNoCancellation
+ (
+ sm:
+ byref>>,
+ awaiter: 'Awaiter,
+ continuation:
+ ('TResult1 -> CancellableTaskBaseCode<'TOverall, 'TResult2, 'Builder>)
+ ) : bool =
+ let mutable awaiter = awaiter
+
+ let cont =
+ (CancellableTaskBaseResumptionFunc<'TOverall, 'Builder>(fun sm ->
+ let result = Awaiter.GetResult awaiter
+ (continuation result).Invoke(&sm)
+ ))
+
+ // shortcut to continue immediately
+ if Awaiter.IsCompleted awaiter then
+ cont.Invoke(&sm)
+ else
+ sm.ResumptionDynamicInfo.ResumptionData <-
+ (awaiter :> ICriticalNotifyCompletion)
+
+ sm.ResumptionDynamicInfo.ResumptionFunc <- cont
+ false
+
+
+ /// Creates A CancellableTask that runs computation, and when
+ /// computation generates a result T, runs binder res.
+ ///
+ /// A cancellation check is performed when the computation is executed.
+ ///
+ /// The existence of this method permits the use of let! in the
+ /// cancellableTask { ... } computation expression syntax.
+ ///
+ /// The computation to provide an unbound result.
+ /// The function to bind the result of computation.
+ ///
+ /// A CancellableTask that performs a monadic bind on the result
+ /// of computation.
+ []
+ member inline internal _.BindNoCancellation
+ (
+ awaiter: 'Awaiter,
+ continuation:
+ ('TResult1 -> CancellableTaskBaseCode<'TOverall, 'TResult2, 'Builder>)
+ ) : CancellableTaskBaseCode<'TOverall, 'TResult2, 'Builder> =
+
+ CancellableTaskBaseCode<'TOverall, 'TResult2, 'Builder>(fun sm ->
+ if __useResumableCode then
+ //-- RESUMABLE CODE START
+ // Get an awaiter from the Awaiter
+ let mutable awaiter = awaiter
+
+ let mutable __stack_fin = true
+
+ if not (Awaiter.IsCompleted awaiter) then
+ // This will yield with __stack_yield_fin = false
+ // This will resume with __stack_yield_fin = true
+ let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm)
+ __stack_fin <- __stack_yield_fin
+
+ if __stack_fin then
+ let result = Awaiter.GetResult awaiter
+ (continuation result).Invoke(&sm)
+ else
+ let mutable awaiter = awaiter :> ICriticalNotifyCompletion
+
+ MethodBuilder.AwaitUnsafeOnCompleted(
+ &sm.Data.MethodBuilder,
+ &awaiter,
+ &sm
+ )
+
+ false
+ else
+ CancellableTaskBuilderBase.BindDynamicNoCancellation(
+ &sm,
+ awaiter,
+ continuation
+ )
+ //-- RESUMABLE CODE END
+ )
+
/// Creates A CancellableTask that runs computation, and when
/// computation generates a result T, runs binder res.
///
@@ -673,7 +762,9 @@ module CancellableTaskBase =
) : CancellableTaskBaseCode<'TOverall, 'T, 'Builder> =
ResumableCode.TryFinallyAsync(
computation,
- ResumableCode<_, _>(fun sm -> x.Bind((compensation ()), (x.Zero)).Invoke(&sm))
+ ResumableCode<_, _>(fun sm ->
+ x.BindNoCancellation((compensation ()), (x.Zero)).Invoke(&sm)
+ )
)
diff --git a/tests/IcedTasks.Tests/CancellablePoolingValueTaskTests.fs b/tests/IcedTasks.Tests/CancellablePoolingValueTaskTests.fs
index 05e25f1..78787f4 100644
--- a/tests/IcedTasks.Tests/CancellablePoolingValueTaskTests.fs
+++ b/tests/IcedTasks.Tests/CancellablePoolingValueTaskTests.fs
@@ -510,12 +510,12 @@ module CancellablePoolingValueTaskTests =
testCaseAsync "use IAsyncDisposable cancelled"
<| async {
let data = 42
- let mutable wasDisposed = TaskCompletionSource()
+ let mutable wasDisposed = false
let doDispose () =
task {
- do! Task.Yield()
- wasDisposed.SetResult true
+ do! Task.Delay(15)
+ wasDisposed <- true
}
|> ValueTask
@@ -537,14 +537,10 @@ module CancellablePoolingValueTaskTests =
timeProvider.ForwardTimeAsync(TimeSpan.FromMilliseconds(100))
|> Async.AwaitTask
- let! _ =
+ do!
Expect.CancellationRequested inProgress
|> Async.AwaitValueTask
- let! wasDisposed =
- wasDisposed.Task
- |> Async.AwaitTask
-
Expect.isTrue wasDisposed ""
}
diff --git a/tests/IcedTasks.Tests/CancellableTaskTests.fs b/tests/IcedTasks.Tests/CancellableTaskTests.fs
index 2651be2..9c76f63 100644
--- a/tests/IcedTasks.Tests/CancellableTaskTests.fs
+++ b/tests/IcedTasks.Tests/CancellableTaskTests.fs
@@ -470,7 +470,7 @@ module CancellableTaskTests =
<| async {
let doDispose () =
task {
- do! Task.Yield()
+ do! Task.Delay(15)
failwith "boom"
}
|> ValueTask
@@ -492,16 +492,18 @@ module CancellableTaskTests =
testCaseAsync "use IAsyncDisposable cancelled"
<| async {
let data = 42
- let mutable wasDisposed = TaskCompletionSource()
+ let mutable wasDisposed = false
+
+ let timeProvider = ManualTimeProvider()
let doDispose () =
task {
- do! Task.Yield()
- wasDisposed.SetResult true
+ do! Task.Delay(15)
+
+ wasDisposed <- true
}
|> ValueTask
- let timeProvider = ManualTimeProvider()
let actor data =
cancellableTask {
@@ -519,16 +521,19 @@ module CancellableTaskTests =
timeProvider.ForwardTimeAsync(TimeSpan.FromMilliseconds(100))
|> Async.AwaitTask
+ Expect.isFalse wasDisposed ""
- let! _ =
- Expect.CancellationRequested inProgress
+ do!
+ timeProvider.ForwardTimeAsync(TimeSpan.FromMilliseconds(100))
|> Async.AwaitTask
- let! wasDisposed =
- wasDisposed.Task
+ do!
+ Expect.CancellationRequested inProgress
|> Async.AwaitTask
+
Expect.isTrue wasDisposed ""
+
}
@@ -540,7 +545,7 @@ module CancellableTaskTests =
let doDispose () =
task {
Expect.isFalse wasDisposed ""
- do! Task.Yield()
+ do! Task.Delay(15)
wasDisposed <- true
}
|> ValueTask
@@ -565,7 +570,7 @@ module CancellableTaskTests =
let doDispose () =
task {
Expect.isFalse wasDisposed ""
- do! Task.Yield()
+ do! Task.Delay(15)
wasDisposed <- true
}
|> ValueTask
diff --git a/tests/IcedTasks.Tests/CancellableValueTaskTests.fs b/tests/IcedTasks.Tests/CancellableValueTaskTests.fs
index 48bf7ff..6865084 100644
--- a/tests/IcedTasks.Tests/CancellableValueTaskTests.fs
+++ b/tests/IcedTasks.Tests/CancellableValueTaskTests.fs
@@ -511,12 +511,12 @@ module CancellableValueTaskTests =
testCaseAsync "use IAsyncDisposable cancelled"
<| async {
let data = 42
- let mutable wasDisposed = TaskCompletionSource()
+ let mutable wasDisposed = false
let doDispose () =
task {
- do! Task.Yield()
- wasDisposed.SetResult true
+ do! Task.Delay(15)
+ wasDisposed <- true
}
|> ValueTask
@@ -538,14 +538,10 @@ module CancellableValueTaskTests =
timeProvider.ForwardTimeAsync(TimeSpan.FromMilliseconds(100))
|> Async.AwaitTask
- let! _ =
+ do!
Expect.CancellationRequested inProgress
|> Async.AwaitValueTask
- let! wasDisposed =
- wasDisposed.Task
- |> Async.AwaitTask
-
Expect.isTrue wasDisposed ""
}