(* TEST
   * expect
*)

module M = struct
  type t
end;;
[%%expect{|
module M : sig type t end
|}]

module type Accepted = sig
  type t := int

  type 'a u := 'a list

  type 'a v := (string * 'a) list

  module T := M

  type _ w := T.t

  val f : t u -> char w v
end;;
[%%expect{|
module type Accepted = sig val f : int list -> (string * M.t) list end
|}]

module F(X : sig type t end) = struct
  type t = X.t
end;;
[%%expect{|
module F : functor (X : sig type t end) -> sig type t = X.t end
|}]

module type Accepted2 = sig
  module N := F(M)

  val foo : N.t -> int
end;;
[%%expect{|
module type Accepted2 = sig val foo : F(M).t -> int end
|}]

module type Reject1 = sig
  module M := Funct(M)
end;;
[%%expect{|
Line 2, characters 14-22:
2 |   module M := Funct(M)
                  ^^^^^^^^
Error: Unbound module Funct
Hint: Did you mean Fun?
|}]

module type Reject2 = sig
  module M := F(N)
end;;
[%%expect{|
Line 2, characters 14-18:
2 |   module M := F(N)
                  ^^^^
Error: Unbound module N
|}]

module type Reject3 = sig
  type t := u
end;;
[%%expect{|
Line 2, characters 12-13:
2 |   type t := u
                ^
Error: Unbound type constructor u
|}]

module type RejectRec = sig
  type t := [ `Foo of t | `Nil ]
end;;
[%%expect{|
Line 2, characters 22-23:
2 |   type t := [ `Foo of t | `Nil ]
                          ^
Error: Unbound type constructor t
|}]

module type AcceptAnd = sig
  type t := int
  and u := int * int
end;;
[%%expect{|
module type AcceptAnd = sig  end
|}]

module type RejectAnd = sig
  type t := int
  and u := t * int
end;;
[%%expect{|
Line 3, characters 11-12:
3 |   and u := t * int
               ^
Error: Unbound type constructor t
|}]

(** MPR7905, PR2231:
    We want to reject invalid right-hand side
    before typing the type declaration.
*)
module type Rejected = sig
  type cycle = A of cycle
  type t := cycle = A of t
  (** this type declaration is purposefully erroneous *)
end

[%%expect{|
Line 3, characters 2-26:
3 |   type t := cycle = A of t
      ^^^^^^^^^^^^^^^^^^^^^^^^
Error: Only type synonyms are allowed on the right of :=
|}]
