From b836eed1e11212d896f8a7f485727a4cef01eca5 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Thu, 19 Oct 2023 19:24:15 +0400 Subject: [PATCH] Changed `raise` to calling `Reraise()` extension method to preserve the call stack --- src/FSharp.Data.GraphQL.Shared/AsyncVal.fs | 12 ++++++------ src/FSharp.Data.GraphQL.Shared/Exception.fs | 16 ++++++++++++++++ .../FSharp.Data.GraphQL.Shared.fsproj | 1 + tests/FSharp.Data.GraphQL.Tests/Helpers.fs | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 src/FSharp.Data.GraphQL.Shared/Exception.fs diff --git a/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs b/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs index ab4ca3992..10e308bd3 100644 --- a/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs +++ b/src/FSharp.Data.GraphQL.Shared/AsyncVal.fs @@ -41,7 +41,7 @@ module AsyncVal = match x with | Value v -> v | Async a -> a |> Async.RunSynchronously - | Failure f -> raise f + | Failure f -> f.Reraise() /// Create new AsyncVal from Async computation. let inline ofAsync (a: Async<'T>) = Async(a) @@ -54,7 +54,7 @@ module AsyncVal = match x with | Value v -> async.Return v | Async a -> a - | Failure f -> async.Return (raise f) + | Failure f -> async.Return (f.Reraise()) /// Returns an empty AsyncVal with immediatelly executed value. let inline empty<'T> : AsyncVal<'T> = AsyncVal<'T>.Zero @@ -111,7 +111,7 @@ module AsyncVal = match bound with | Value v -> return v | Async a -> return! a - | Failure f -> return raise f + | Failure f -> return f.Reraise() }) | Failure f -> Failure(f) @@ -133,7 +133,7 @@ module AsyncVal = let! r = a results.[i] <- r | Failure f -> - results.[i] <- raise f + results.[i] <- f.Reraise() return results }) else Value (values |> Array.map (fun (Value v) -> v)) @@ -156,7 +156,7 @@ module AsyncVal = indexes.Add i continuations.Add a | Failure f -> - results.[i] <- raise f + results.[i] <- f.Reraise() if indexes.Count = 0 then Value(results) else Async(async { @@ -193,7 +193,7 @@ type AsyncValBuilder () = match bound with | Value v -> return v | Async a -> return! a - | Failure f -> return raise f }) + | Failure f -> return f.Reraise() }) [] diff --git a/src/FSharp.Data.GraphQL.Shared/Exception.fs b/src/FSharp.Data.GraphQL.Shared/Exception.fs new file mode 100644 index 000000000..df07a6983 --- /dev/null +++ b/src/FSharp.Data.GraphQL.Shared/Exception.fs @@ -0,0 +1,16 @@ +[] +[] +module System.Exception + +open System +open System.Diagnostics +open System.Runtime.ExceptionServices + +// Useful for reraising exceptions under an async {...} and task {...} contexts +// See this for more details: https://github.com/fsharp/fslang-suggestions/issues/660 +type internal Exception with + + [] + member __.Reraise () = + (ExceptionDispatchInfo.Capture __).Throw () + Unchecked.defaultof<_> diff --git a/src/FSharp.Data.GraphQL.Shared/FSharp.Data.GraphQL.Shared.fsproj b/src/FSharp.Data.GraphQL.Shared/FSharp.Data.GraphQL.Shared.fsproj index f1b33dc2d..de95a1b6d 100644 --- a/src/FSharp.Data.GraphQL.Shared/FSharp.Data.GraphQL.Shared.fsproj +++ b/src/FSharp.Data.GraphQL.Shared/FSharp.Data.GraphQL.Shared.fsproj @@ -49,6 +49,7 @@ + diff --git a/tests/FSharp.Data.GraphQL.Tests/Helpers.fs b/tests/FSharp.Data.GraphQL.Tests/Helpers.fs index d4193cc2a..5ac6626ab 100644 --- a/tests/FSharp.Data.GraphQL.Tests/Helpers.fs +++ b/tests/FSharp.Data.GraphQL.Tests/Helpers.fs @@ -146,7 +146,7 @@ type TestObserver<'T>(obs : IObservable<'T>, ?onReceived : TestObserver<'T> -> ' member _.OnCompleted() = isCompleted <- true mre.Set() |> ignore - member _.OnError(error) = raise error + member _.OnError(error) = error.Reraise() member _.OnNext(value) = received.Add(value) onReceived |> Option.iter (fun evt -> evt this value)