(* TEST * expect *) type 'a tree = | Leaf of 'a | Node of 'a tree * 'a tree [%%expect{| type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree |}] module Ambiguous = struct let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (left, right) -> Node (map f left, map f right) end [%%expect{| Line 5, characters 4-34: 5 | Node (map f left, map f right) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: [@tail_mod_cons]: this constructor application may be TMC-transformed in several different ways. Please disambiguate by adding an explicit [@tailcall] attribute to the call that should be made tail-recursive, or a [@tailcall false] attribute on calls that should not be transformed. Line 5, characters 10-20: 5 | Node (map f left, map f right) ^^^^^^^^^^ This call could be annotated. Line 5, characters 22-33: 5 | Node (map f left, map f right) ^^^^^^^^^^^ This call could be annotated. |}] module Positive_disambiguation = struct let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (left, right) -> Node (map f left, (map [@tailcall]) f right) end [%%expect{| module Positive_disambiguation : sig val map : ('a -> 'b) -> 'a tree -> 'b tree end |}] module Negative_disambiguation = struct let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (left, right) -> Node ((map [@tailcall false]) f left, map f right) end [%%expect{| module Negative_disambiguation : sig val map : ('a -> 'b) -> 'a tree -> 'b tree end |}] module Positive_and_negative_disambiguation = struct (* in-depth disambiguations *) type 'a t = | N | C of 'a t * ('a t * 'a t) let[@tail_mod_cons] rec map1 f l = match l with | N -> N | C (a, (b, c)) -> C ((map1 [@tailcall]) f a, ((map1 [@tailcall false]) f b, map1 f c)) let[@tail_mod_cons] rec map2 f l = match l with | N -> N | C (a, (b, c)) -> C ((map2 [@tailcall false]) f a, ((map2 [@tailcall]) f b, map2 f c)) end [%%expect {| module Positive_and_negative_disambiguation : sig type 'a t = N | C of 'a t * ('a t * 'a t) val map1 : 'a -> 'b t -> 'c t val map2 : 'a -> 'b t -> 'c t end |}] module Long_before_and_after = struct type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree * 'a tree * 'a tree * 'a tree let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (t1, t2, t3, t4, t5) -> (* manual unfolding *) Node (map f t1, map f t2, (map[@tailcall]) f t3, map f t4, map f t5) let () = assert (map succ (Node (Leaf 0, Leaf 1, Leaf 2, Leaf 3, Leaf 4)) = Node (Leaf 1, Leaf 2, Leaf 3, Leaf 4, Leaf 5)) end [%%expect {| module Long_before_and_after : sig type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree * 'a tree * 'a tree * 'a tree val map : ('a -> 'b) -> 'a tree -> 'b tree end |}] module Deep_nesting_nonambiguous = struct type 'a tree = Leaf of 'a | Node of 'a tree * ('a tree * ('a tree * ('a tree * 'a tree))) let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (t1, (t2, (t3, (t4, t5)))) -> Node (map f t1, (map f t2, ((map[@tailcall]) f t3, (map f t4, map f t5)))) let () = assert (map succ (Node (Leaf 0, (Leaf 1, (Leaf 2, (Leaf 3, Leaf 4))))) = Node (Leaf 1, (Leaf 2, (Leaf 3, (Leaf 4, Leaf 5))))) end [%%expect {| module Deep_nesting_nonambiguous : sig type 'a tree = Leaf of 'a | Node of 'a tree * ('a tree * ('a tree * ('a tree * 'a tree))) val map : ('a -> 'b) -> 'a tree -> 'b tree end |}] module Deep_nesting_ambiguous = struct type 'a tree = Leaf of 'a | Node of 'a tree * ('a tree * ('a tree * ('a tree * 'a tree))) let[@tail_mod_cons] rec map f = function | Leaf v -> Leaf (f v) | Node (t1, (t2, (t3, (t4, t5)))) -> Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) let () = assert (map succ (Node (Leaf 0, (Leaf 1, (Leaf 2, (Leaf 3, Leaf 4))))) = Node (Leaf 1, (Leaf 2, (Leaf 3, (Leaf 4, Leaf 5))))) end [%%expect {| Line 7, characters 10-71: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error: [@tail_mod_cons]: this constructor application may be TMC-transformed in several different ways. Please disambiguate by adding an explicit [@tailcall] attribute to the call that should be made tail-recursive, or a [@tailcall false] attribute on calls that should not be transformed. Line 7, characters 16-24: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^ This call could be annotated. Line 7, characters 27-35: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^ This call could be annotated. Line 7, characters 38-46: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^ This call could be annotated. Line 7, characters 49-57: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^ This call could be annotated. Line 7, characters 59-67: 7 | Node (map f t1, (map f t2, (map f t3, (map f t4, map f t5)))) ^^^^^^^^ This call could be annotated. |}] module Disjunctions_ambiguous = struct type t = Leaf of int | Node of t * t (** [shift ~flip:false k t] shifts all the leaves of [t] by [k]. When [~flip:true], leaves of even level are shifted by k, leaves of odd level by (-k) *) let[@tail_mod_cons] rec shift ~flip k = function | Leaf n -> Leaf (n + k) | Node (left, right) -> (* This example contains several ambiguous TMC calls per constructor argument: the two subcalls of each arguments are *both* in TMC position, and annotating either of them is enough to fix the ambiguity error. *) Node ( (if flip then shift ~flip (- k) left else shift ~flip k left), (if flip then shift ~flip (- k) right else shift ~flip k right) ) end [%%expect {| Lines 13-20, characters 8-9: 13 | ........Node ( 14 | (if flip 15 | then shift ~flip (- k) left 16 | else shift ~flip k left), 17 | (if flip 18 | then shift ~flip (- k) right 19 | else shift ~flip k right) 20 | ) Error: [@tail_mod_cons]: this constructor application may be TMC-transformed in several different ways. Please disambiguate by adding an explicit [@tailcall] attribute to the call that should be made tail-recursive, or a [@tailcall false] attribute on calls that should not be transformed. Line 15, characters 16-38: 15 | then shift ~flip (- k) left ^^^^^^^^^^^^^^^^^^^^^^ This call could be annotated. Line 16, characters 16-34: 16 | else shift ~flip k left), ^^^^^^^^^^^^^^^^^^ This call could be annotated. Line 18, characters 16-39: 18 | then shift ~flip (- k) right ^^^^^^^^^^^^^^^^^^^^^^^ This call could be annotated. Line 19, characters 16-35: 19 | else shift ~flip k right) ^^^^^^^^^^^^^^^^^^^ This call could be annotated. |}] module Disjunctions_disambiguated = struct type t = Leaf of int | Node of t * t let[@tail_mod_cons] rec shift ~flip k = function | Leaf n -> Leaf (n + k) | Node (left, right) -> Node ( (if flip then shift ~flip (- k) left else shift ~flip k left), (if flip then shift ~flip (- k) right else (shift[@tailcall]) ~flip k right) ) end [%%expect {| module Disjunctions_disambiguated : sig type t = Leaf of int | Node of t * t val shift : flip:bool -> int -> t -> t end |}] module Disjunctions_ambiguous_again = struct type t = Leaf of int | Node of t * t let[@tail_mod_cons] rec shift ~flip k = function | Leaf n -> Leaf (n + k) | Node (left, right) -> Node ( (if flip then (shift[@tailcall]) ~flip (- k) left else shift ~flip k left), (if flip then shift ~flip (- k) right else (shift[@tailcall]) ~flip k right) ) end [%%expect {| Lines 7-14, characters 8-9: 7 | ........Node ( 8 | (if flip 9 | then (shift[@tailcall]) ~flip (- k) left 10 | else shift ~flip k left), 11 | (if flip 12 | then shift ~flip (- k) right 13 | else (shift[@tailcall]) ~flip k right) 14 | ) Error: [@tail_mod_cons]: this constructor application may be TMC-transformed in several different ways. Only one of the arguments may become a TMC call, but several arguments contain calls that are explicitly marked as tail-recursive. Please fix the conflict by reviewing and fixing the conflicting annotations. Line 9, characters 16-51: 9 | then (shift[@tailcall]) ~flip (- k) left ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call is explicitly annotated. Line 13, characters 16-48: 13 | else (shift[@tailcall]) ~flip k right) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call is explicitly annotated. |}]