Skip to content
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

[Rust] Fixed try finally handler #3933

Merged
merged 1 commit into from
Oct 21, 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
4 changes: 4 additions & 0 deletions src/Fable.Cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [Rust] Support more System.Array methods and tests (by @ncave)
* [JS] Add `System.String.Normalize` support (by @DashieTM)

### Fixed

* [Rust] Fixed try finally handler order of execution (by @ncave)

## 4.22.0 - 2024-10-02

### Added
Expand Down
2 changes: 1 addition & 1 deletion src/Fable.Transforms/FableTransforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ let isTailRecursive identName expr =
getSubExpressions e |> List.iter (loop false)
| Sequential exprs ->
let lastIndex = (List.length exprs) - 1
exprs |> List.iteri (fun i e -> loop (i = lastIndex) e)
exprs |> List.iteri (fun i e -> loop (inTailPos && i = lastIndex) e)
| Let(_, value, body) ->
loop false value
loop inTailPos body
Expand Down
17 changes: 9 additions & 8 deletions src/Fable.Transforms/Rust/Fable2Rust.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2829,10 +2829,12 @@ module Util =
// try...finally
match finalizer with
| Some finBody ->
let f = makeLocalLambda com ctx [] finBody
let finAlloc = makeLibCall com ctx None "Exception" "finally" [ f ]
let f = transformLambda com ctx None [] finBody
let finCall = makeLibCall com ctx None "Exception" "finally" [ f ]
let finPat = makeFullNameIdentPat "__finally__"
let letExpr = mkLetExpr finPat finCall
let bodyExpr = transformExpr com ctx body
[ finAlloc |> mkSemiStmt; bodyExpr |> mkExprStmt ] |> mkStmtBlockExpr
[ letExpr |> mkSemiStmt; bodyExpr |> mkExprStmt ] |> mkStmtBlockExpr
| _ ->
// no catch, no finalizer
transformExpr com ctx body
Expand Down Expand Up @@ -3635,11 +3637,10 @@ module Util =
TailCallOpportunity = tco
}

let isTailRecursive (name: string option) (body: Fable.Expr) =
if name.IsNone then
false, false
else
FableTransforms.isTailRecursive name.Value body
let isTailRecursive (nameOpt: string option) (body: Fable.Expr) =
match nameOpt with
| Some name -> FableTransforms.isTailRecursive name body
| None -> false, false

let transformFunctionBody com ctx (args: Fable.Ident list) (body: Fable.Expr) =
match ctx.TailCallOpportunity with
Expand Down
11 changes: 3 additions & 8 deletions src/fable-library-rust/src/Exception.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod Exception_ {
use crate::Native_::{Any, Box_, LrcPtr};
use crate::Native_::{Any, Box_, Func0, LrcPtr};
use crate::String_::{fromSlice, string};
use crate::System::Exception;
use crate::Util_::new_Exception;
Expand Down Expand Up @@ -41,14 +41,9 @@ pub mod Exception_ {
}
}

pub struct finally<F, R>(pub F)
where
F: FnMut() -> R;
pub struct finally<R: 'static>(pub Func0<R>);

impl<F, R> Drop for finally<F, R>
where
F: FnMut() -> R,
{
impl<R: 'static> Drop for finally<R> {
fn drop(&mut self) {
(self.0)();
}
Expand Down
100 changes: 50 additions & 50 deletions tests/Rust/tests/src/TailCallTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -73,28 +73,28 @@ module Functions =
| 0 -> x
| _ -> iterate f (n - 1) (f x)

// let recWithFinally () =
// let mutable log = ""
// let rec test n =
// try
// log <- log + string "abcde"[n]
// if n < 4 then test (n+1)
// finally
// log <- log + string "ABCDE"[n]
// test 0
// log

// let recWithUse () =
// let mutable log = ""
// let disp(n) =
// { new System.IDisposable with
// member x.Dispose() = log <- log + string "ABCDE"[n] }
// let rec test n =
// use _disp = disp(n)
// log <- log + string "abcde"[n]
// if n < 4 then test (n+1) else 0
// test 0 |> ignore
// log
let recWithFinally () =
let mutable log = ""
let rec test n =
try
log <- log + string "abcde".[n]
if n < 4 then test (n+1)
finally
log <- log + string "ABCDE".[n]
test 0
log

let recWithUse () =
let mutable log = ""
let disp(n) =
{ new System.IDisposable with
member x.Dispose() = log <- log + string "ABCDE".[n] }
let rec test n =
use _disp = disp(n)
log <- log + string "abcde".[n]
if n < 4 then test (n+1) else 0
test 0 |> ignore
log

open Functions

Expand Down Expand Up @@ -133,13 +133,13 @@ and parseTokens tokens = function
| x::xs -> parseTokens tokens xs
| [] -> List.rev tokens

// type Element =
// | Element of action: (unit->unit) * children: Element list
// member this.Activate() =
// match this with
// | Element(action, children) ->
// action()
// for child in children do child.Activate()
type Element =
| Element of action: (unit->unit) * children: Element list
member this.Activate() =
match this with
| Element(action, children) ->
action()
for child in children do child.Activate()

[<Fact>]
let ``Tailcall works in tail position`` () =
Expand Down Expand Up @@ -204,13 +204,13 @@ let ``Tailcall optimization doesn't cause endless loops`` () = // See #675
|> tryFind "a"
|> equal None

// [<Fact>]
// let ``Recursive functions containing finally work`` () =
// recWithFinally () |> equal "abcdeEDCBA"
[<Fact>]
let ``Recursive functions containing finally work`` () =
recWithFinally () |> equal "abcdeEDCBA"

// [<Fact>]
// let ``Recursive functions containing use work`` () =
// recWithUse () |> equal "abcdeEDCBA"
[<Fact>]
let ``Recursive functions containing use work`` () =
recWithUse () |> equal "abcdeEDCBA"

[<Fact>]
let ``Function arguments can be optimized`` () = // See #681
Expand All @@ -220,22 +220,22 @@ let ``Function arguments can be optimized`` () = // See #681
let ``Function arguments can be optimized II`` () = // See #681
iterate ((*) 2) 5 10 |> equal 320

// // See https://github.com/fable-compiler/Fable/issues/1368#issuecomment-434142713
// [<Fact>]
// let ``State of internally mutated tail called function parameters is preserved properly`` () =
// let rec loop i lst =
// if i <= 0
// then lst
// else loop (i - 1) ((fun () -> i) :: lst)
// loop 3 [] |> List.map (fun f -> f()) |> equal [1;2;3]
// See https://github.com/fable-compiler/Fable/issues/1368#issuecomment-434142713
[<Fact>]
let ``State of internally mutated tail called function parameters is preserved properly`` () =
let rec loop i lst =
if i <= 0
then lst
else loop (i - 1) ((fun () -> i) :: lst)
loop 3 [] |> List.map (fun f -> f()) |> equal [1;2;3]

// [<Fact>]
// let ``State of internally mutated tail called function parameters is preserved properly II`` () =
// let rec loop lst i =
// if i <= 0
// then lst
// else loop ((fun () -> i) :: lst) (i - 1)
// loop [] 3 |> List.map (fun f -> f()) |> equal [1;2;3]
[<Fact>]
let ``State of internally mutated tail called function parameters is preserved properly II`` () =
let rec loop lst i =
if i <= 0
then lst
else loop ((fun () -> i) :: lst) (i - 1)
loop [] 3 |> List.map (fun f -> f()) |> equal [1;2;3]

// See https://github.com/fable-compiler/Fable/issues/1368#issuecomment-434142713
[<Fact>]
Expand Down
2 changes: 1 addition & 1 deletion tests/Rust/tests/src/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@ let ``copying struct records works`` () = // See #3371
// let ``reraise works`` () =
// try
// try
// Exception("Will I be reraised?") |> raise
// System.Exception("Will I be reraised?") |> raise
// with _ ->
// try
// reraise()
Expand Down
Loading