diff --git a/src/Fable.Transforms/Rust/Replacements.fs b/src/Fable.Transforms/Rust/Replacements.fs index 7a7b3c824..861aeb076 100644 --- a/src/Fable.Transforms/Rust/Replacements.fs +++ b/src/Fable.Transforms/Rust/Replacements.fs @@ -3023,6 +3023,9 @@ let asyncBuilder (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | "Return", _, _ -> Helper.LibCall(com, "AsyncBuilder", "r_return", t, args, i.SignatureArgTypes, ?loc = r) |> Some + | "ReturnFrom", _, _ -> + Helper.LibCall(com, "AsyncBuilder", "return_from", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "Zero", _, _ -> Helper.LibCall(com, "AsyncBuilder", "zero", t, args, i.SignatureArgTypes, ?loc = r) |> Some diff --git a/src/fable-library-rust/src/Async.rs b/src/fable-library-rust/src/Async.rs index c9e4b9f0b..b04f3eab4 100644 --- a/src/fable-library-rust/src/Async.rs +++ b/src/fable-library-rust/src/Async.rs @@ -129,6 +129,10 @@ pub mod AsyncBuilder_ { }) } + pub fn return_from(computation: Arc>) -> Arc> { + computation + } + pub fn zero() -> Arc> { r_return(()) } diff --git a/tests/Rust/tests/src/AsyncTests.fs b/tests/Rust/tests/src/AsyncTests.fs index 4c00c4f7e..2e69a91ea 100644 --- a/tests/Rust/tests/src/AsyncTests.fs +++ b/tests/Rust/tests/src/AsyncTests.fs @@ -33,6 +33,55 @@ let shouldConvertTaskToASyncAndEvalCorrectly () = let t = task { return 1 } |> Async.AwaitTask t |> Async.RunSynchronously |> equal 1 +[] +let ``return! should compile in async CE`` () = + let inner () = async { return 42 } + let outer () = async { return! inner () } + let result = Async.RunSynchronously (outer ()) + result |> equal 42 + +[] +let ``return! works in recursive async CE`` () = + let rec loop n = async { + if n <= 0 then return 0 + else return! loop (n - 1) + } + let result = Async.RunSynchronously (loop 5) + result |> equal 0 + +[] +let ``return! is transparent through multiple layers`` () = + // Verifies return_from is identity: chaining return! does not double-wrap the computation + // or alter the value in any way. + let inner () = async { return 7 } + let passthrough (comp: Async) = async { return! comp } + let result = + inner () + |> passthrough + |> passthrough + |> passthrough + |> Async.RunSynchronously + result |> equal 7 + +[] +let ``return! propagates value from async built with bind`` () = + // Verifies that a computation produced via let! / return is correctly + // passed through return!, not just a literal return value. + let doubled x = async { + let! v = async { return x } + return v * 2 + } + let outer () = async { return! doubled 21 } + Async.RunSynchronously (outer ()) |> equal 42 + +[] +let ``return! propagates error Result from inner async`` () = + // Both Ok and Error variants must flow through return! unchanged. + let inner (result: Result) = async { return result } + let outer (result: Result) = async { return! inner result } + Async.RunSynchronously (outer (Ok 99)) |> equal (Ok 99) + Async.RunSynchronously (outer (Error "oops")) |> equal (Error "oops") + // [] // let shouldExecAsParallelStructurallyCorrect () = // let t = Async.Parallel [