diff --git a/benches/numeric/fibonacci.ncl b/benches/numeric/fibonacci.ncl index 1cc55f6f..1971b4bd 100644 --- a/benches/numeric/fibonacci.ncl +++ b/benches/numeric/fibonacci.ncl @@ -1,9 +1,9 @@ { - run = { - f = fun n => - if n == 0 || n == 1 then - 1 - else - f (n - 1) + f (n - 2) - }.f + run = + let rec f = fun n => + if n == 0 || n == 1 then + 1 + else + f (n - 1) + f (n - 2) + in f } diff --git a/tests/free_vars.rs b/tests/free_vars.rs index a8d61069..30662520 100644 --- a/tests/free_vars.rs +++ b/tests/free_vars.rs @@ -163,3 +163,19 @@ fn nested_records() { HashMap::from([("a", vec!["c"]), ("b", vec!["a", "c"]), ("c", vec!["b"]),]) )); } + +#[test] +fn recursive_let() { + assert!(check_stat_vars( + "{ + a = let rec b = b + a + h in b, + b = let rec a = a + b in f (a + 1) z, + c = let rec foo = b in let rec bar = c in if a.r then [b] else {foo = c} + }", + HashMap::from([ + ("a", vec!["a"]), + ("b", vec!["b"]), + ("c", vec!["a", "b", "c"]) + ]) + )); +} diff --git a/tests/pass.rs b/tests/pass.rs index a2b15a97..91b51ec9 100644 --- a/tests/pass.rs +++ b/tests/pass.rs @@ -117,3 +117,8 @@ fn importing() { fn overriding() { check_file("overriding.ncl"); } + +#[test] +fn recursive_let() { + check_file("recursive_let.ncl"); +} diff --git a/tests/pass/recursive_let.ncl b/tests/pass/recursive_let.ncl new file mode 100644 index 00000000..1cb46f4e --- /dev/null +++ b/tests/pass/recursive_let.ncl @@ -0,0 +1,7 @@ +let Assert = fun l x => x || %blame% l in + +[ + let rec f = fun n => if n == 0 then n else f (n - 1) in f 10 == 0, + let rec fib = fun n => if n == 0 || n == 1 then 1 else fib (n - 1) + fib (n - 2) in fib 5 == 8, +] +|> array.foldl (fun x y => (x | Assert) && y) true diff --git a/tests/pass/typechecking.ncl b/tests/pass/typechecking.ncl index 12b8aa0d..9ffe18a8 100644 --- a/tests/pass/typechecking.ncl +++ b/tests/pass/typechecking.ncl @@ -74,6 +74,15 @@ let typecheck = [ fun x => switch {`blo => `bla, `ble => `bli, _ => `bla} x in f `bli, + # recursive let bindings + let rec f : forall a. a -> Num -> a = fun x n => + if n == 0 then x else if f "0" n == "1" then f x (n - 1) else f x (f 1 n) in + (f "0" 2 : Str), + let rec f : Num -> Num = fun x => if x == 0 then x else f (x - 1) in + (f 10 : Num), + let rec repeat : forall a. Num -> a -> Array a = fun n x => + if n <= 0 then [] else repeat (n - 1) x @ [x] in (repeat 3 "foo" : Array Str), + # static records ({bla = 1} : {bla : Num}), ({blo = true, bla = 1} : {bla : Num, blo : Bool}), diff --git a/tests/typecheck_fail.rs b/tests/typecheck_fail.rs index 165e633f..08c62f34 100644 --- a/tests/typecheck_fail.rs +++ b/tests/typecheck_fail.rs @@ -230,3 +230,10 @@ fn piecewise_signature() { Err(TypecheckError::TypeMismatch(..)) ); } +#[test] +fn recursive_let() { + assert_matches!( + type_check_expr("let rec f : Num -> Num = fun x => f \"hoi\" in null"), + Err(TypecheckError::TypeMismatch(..)) + ); +}