Skip to content

Commit

Permalink
[Rust] Fixed try finally handler (fable-compiler#3933)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave authored Oct 21, 2024
1 parent 33b501f commit 31019c8
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 68 deletions.
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

0 comments on commit 31019c8

Please sign in to comment.