(* TEST
 expect;
*)

type t = < x : 'a. int as 'a >
[%%expect {|
Line 1, characters 15-28:
1 | type t = < x : 'a. int as 'a >
                   ^^^^^^^^^^^^^
Error: The universal type variable "'a" cannot be generalized: it is bound to
       "int".
|}]
type u = < x : 'a 'b. 'a as 'b >
[%%expect {|
Line 1, characters 15-30:
1 | type u = < x : 'a 'b. 'a as 'b >
                   ^^^^^^^^^^^^^^^
Error: The universal type variable "'b" cannot be generalized:
       it is already bound to another variable.
|}]
type v = 'b -> < x : 'a. 'b as 'a >
[%%expect {|
Line 1, characters 21-33:
1 | type v = 'b -> < x : 'a. 'b as 'a >
                         ^^^^^^^^^^^^
Error: The universal type variable "'a" cannot be generalized:
       it escapes its scope.
|}]


(** Check that renaming universal type variable is properly tracked
    in printtyp *)

let f (x:<a:'a; b:'a. 'a>) (y:<a:'a;b:'a>) = x = y
[%%expect {|
Line 4, characters 49-50:
4 | let f (x:<a:'a; b:'a. 'a>) (y:<a:'a;b:'a>) = x = y
                                                     ^
Error: This expression has type "< a : 'a; b : 'a >"
       but an expression was expected of type "< a : 'a; b : 'a0. 'a0 >"
       The method "b" has type "'a", but the expected method type was "'a0. 'a0"
       The universal variable "'a0" would escape its scope
|}]


(** MPR 7565 *)
class type t_a = object
    method f: 'a. 'a -> int
  end
let f (o:t_a) = o # f 0
let _ = f (object
    method f _ = 0
 end);;
[%%expect {|
class type t_a = object method f : 'a -> int end
val f : t_a -> int = <fun>
Lines 5-7, characters 10-5:
5 | ..........(object
6 |     method f _ = 0
7 |  end)..
Error: This expression has type "< f : 'b -> int >"
       but an expression was expected of type "t_a"
       The method "f" has type "'b -> int", but the expected method type was
       "'a. 'a -> int"
       The universal variable "'a" would escape its scope
|}
]

type uv = [ `A of <f: 'a. 'a -> int > ]
type 'a v = [ `A of <f: 'a -> int > ]
let f (`A o:uv) = o # f 0
let () = f ( `A (object method f _ = 0 end): _ v);;
[%%expect {|
type uv = [ `A of < f : 'a. 'a -> int > ]
type 'a v = [ `A of < f : 'a -> int > ]
val f : uv -> int = <fun>
Line 4, characters 11-49:
4 | let () = f ( `A (object method f _ = 0 end): _ v);;
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type "'b v" but an expression was expected of type
         "uv"
       The method "f" has type "'b -> int", but the expected method type was
       "'a. 'a -> int"
       The universal variable "'a" would escape its scope
|}]

(* Issue #8702: row types unified with universally quantified types*)

let f: 'a. ([> `A ] as 'a) -> [ `A ] = fun x -> x
[%%expect {|
Line 1, characters 48-49:
1 | let f: 'a. ([> `A ] as 'a) -> [ `A ] = fun x -> x
                                                    ^
Error: This expression has type "[> `A ]"
       but an expression was expected of type "[ `A ]"
       The first variant type is bound to the universal type variable "'a",
       it cannot be closed
|}]

let f: 'a. [ `A ] -> ([> `A ] as 'a) = fun x -> x
[%%expect {|
Line 1, characters 48-49:
1 | let f: 'a. [ `A ] -> ([> `A ] as 'a) = fun x -> x
                                                    ^
Error: This expression has type "[ `A ]" but an expression was expected of type
         "[> `A ]"
       The second variant type is bound to the universal type variable "'a",
       it cannot be closed
|}]


let f: 'a. [ `A | `B ] -> ([> `A ] as 'a) = fun x -> x
[%%expect {|
Line 1, characters 53-54:
1 | let f: 'a. [ `A | `B ] -> ([> `A ] as 'a) = fun x -> x
                                                         ^
Error: This expression has type "[ `A | `B ]"
       but an expression was expected of type "[> `A ]"
       The second variant type is bound to the universal type variable "'a",
       it cannot be closed
|}]


let f: 'a. [> `A | `B | `C ] -> ([> `A ] as 'a) = fun x -> x
[%%expect {|
Line 1, characters 59-60:
1 | let f: 'a. [> `A | `B | `C ] -> ([> `A ] as 'a) = fun x -> x
                                                               ^
Error: This expression has type "[> `A | `B | `C ]"
       but an expression was expected of type "[> `A ]"
       The second variant type is bound to the universal type variable "'a",
       it may not allow the tag(s) "`B", "`C"
|}]
