(* TEST * expect *) let rec x = (x; ());; [%%expect{| val x : unit = () |}];; let rec x = "x";; [%%expect{| val x : string = "x" |}];; let rec x = let x = () in x;; [%%expect{| val x : unit = () |}];; let rec x = let y = (x; ()) in y;; [%%expect{| val x : unit = () |}];; let rec x = let y = () in x;; [%%expect{| Line 1, characters 12-27: 1 | let rec x = let y = () in x;; ^^^^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = [y] and y = let x = () in x;; [%%expect{| val x : unit list = [()] val y : unit = () |}];; let rec x = [y] and y = let rec x = () in x;; [%%expect{| val x : unit list = [()] val y : unit = () |}];; let rec x = let a = x in fun () -> a () and y = [x];; [%%expect{| val x : unit -> 'a = val y : (unit -> 'a) list = [] |}];; let rec x = [|y|] and y = 0;; [%%expect{| val x : int array = [|0|] val y : int = 0 |}];; let rec x = (y, y) and y = fun () -> ignore x;; [%%expect{| val x : (unit -> unit) * (unit -> unit) = (, ) val y : unit -> unit = |}];; let rec x = Some y and y = fun () -> ignore x ;; [%%expect{| val x : (unit -> unit) option = Some val y : unit -> unit = |}];; let rec x = ignore x;; [%%expect{| Line 1, characters 12-20: 1 | let rec x = ignore x;; ^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = y 0 and y _ = ();; [%%expect{| Line 1, characters 12-15: 1 | let rec x = y 0 and y _ = ();; ^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec b = if b then true else false;; [%%expect{| Line 1, characters 12-37: 1 | let rec b = if b then true else false;; ^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = function Some _ -> ignore (y []) | None -> ignore (y []) and y = function [] -> ignore (x None) | _ :: _ -> ignore (x None) ;; [%%expect{| val x : 'a option -> unit = val y : 'a list -> unit = |}];; (* used to be accepted, see PR#7696 *) let rec x = { x with contents = 3 } [@ocaml.warning "-23"];; [%%expect{| Line 1, characters 12-35: 1 | let rec x = { x with contents = 3 } [@ocaml.warning "-23"];; ^^^^^^^^^^^^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; (* this is rejected as `c` will be dereferenced during the copy, and is not yet fully defined *) let rec c = { c with Complex.re = 1.0 };; [%%expect{| Line 1, characters 12-39: 1 | let rec c = { c with Complex.re = 1.0 };; ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = `A y and y = fun () -> ignore x ;; [%%expect{| val x : [> `A of unit -> unit ] = `A val y : unit -> unit = |}];; let rec x = { contents = y } and y = fun () -> ignore x;; [%%expect{| val x : (unit -> unit) ref = {contents = } val y : unit -> unit = |}];; let r = ref (fun () -> ()) let rec x = fun () -> r := x;; [%%expect{| val r : (unit -> unit) ref = {contents = } val x : unit -> unit = |}];; let rec x = fun () -> y.contents and y = { contents = 3 };; [%%expect{| val x : unit -> int = val y : int ref = {contents = 3} |}];; let r = ref () let rec x = r := x;; [%%expect{| val r : unit ref = {contents = ()} Line 2, characters 12-18: 2 | let rec x = r := x;; ^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = for i = 0 to 1 do let z = y in ignore z done and y = x; ();; [%%expect{| Lines 2-4, characters 2-6: 2 | ..for i = 0 to 1 do 3 | let z = y in ignore z 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = for i = 0 to y do () done and y = 10;; [%%expect{| Lines 2-4, characters 2-6: 2 | ..for i = 0 to y do 3 | () 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = for i = y to 10 do () done and y = 0;; [%%expect{| Lines 2-4, characters 2-6: 2 | ..for i = y to 10 do 3 | () 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = while false do let y = x in ignore y done and y = x; ();; [%%expect{| Lines 2-4, characters 2-6: 2 | ..while false do 3 | let y = x in ignore y 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = while y do () done and y = false;; [%%expect{| Lines 2-4, characters 2-6: 2 | ..while y do 3 | () 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = while y do let y = x in ignore y done and y = false;; [%%expect{| Lines 2-4, characters 2-6: 2 | ..while y do 3 | let y = x in ignore y 4 | done Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = y.contents and y = { contents = 3 };; [%%expect{| Line 1, characters 12-22: 1 | let rec x = y.contents and y = { contents = 3 };; ^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = assert y and y = true;; [%%expect{| Line 1, characters 12-20: 1 | let rec x = assert y and y = true;; ^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; (* Recursively constructing arrays of known non-float type is permitted *) let rec deep_cycle : [`Tuple of [`Shared of 'a] array] as 'a = `Tuple [| `Shared deep_cycle |];; [%%expect{| val deep_cycle : [ `Tuple of [ `Shared of 'a ] array ] as 'a = `Tuple [|`Shared |] |}];; (* Constructing float arrays was disallowed altogether at one point by an overzealous check. Constructing float arrays in recursive bindings is fine when they don't partake in the recursion. *) let rec _x = let _ = [| 1.0 |] in 1. in ();; [%%expect{| - : unit = () |}];; (* The builtin Stdlib.ref is currently treated as a constructor. Other functions of the same name should not be so treated. *) let _ = let module Stdlib = struct let ref _ = assert false end in let rec x = Stdlib.ref y and y = fun () -> ignore x in (x, y) ;; [%%expect{| Line 6, characters 14-26: 6 | let rec x = Stdlib.ref y ^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; (* An example, from Leo White, of let rec bindings that allocate values of unknown size *) let foo p x = let rec f = if p then (fun y -> x + g y) else (fun y -> g y) and g = if not p then (fun y -> x - f y) else (fun y -> f y) in (f, g) ;; [%%expect{| Line 3, characters 4-52: 3 | if p then (fun y -> x + g y) else (fun y -> g y) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; let rec x = match let _ = y in raise Not_found with _ -> "x" | exception Not_found -> "z" and y = match x with z -> ("y", z);; [%%expect{| Lines 2-4, characters 2-30: 2 | ..match let _ = y in raise Not_found with 3 | _ -> "x" 4 | | exception Not_found -> "z" Error: This kind of expression is not allowed as right-hand side of `let rec' |}];; (* To compute the dependencies of mutually-recursive bindings, transitive dependencies must be taken into account. The example below was causing a segfault in 4.08+dev. *) let rec wrong = (* x depends on y, and y depends on wrong, so it is important to notice that x transitively depends on wrong; an earlier version of our letrec analysis would only report that y depends on wrong, which seems safe as y is not used in the body. *) let rec x = ref y and y = ref wrong in ref ("foo" ^ ! ! !x);; [%%expect{| Lines 10-12, characters 2-25: 10 | ..let rec x = ref y 11 | and y = ref wrong 12 | in ref ("foo" ^ ! ! !x).. Error: This kind of expression is not allowed as right-hand side of `let rec' |}] (* in this case, x does not depend on y, so everything is fine *) let rec okay = let rec x = ref "bar" and _y = ref okay in ref ("foo" ^ ! x);; [%%expect{| val okay : string ref = {contents = "foobar"} |}]