module Js_of_ocaml = struct
  module Js = struct
    class type js_string = object end

    type +'a t

    type (-'a, +'b) meth_callback

    type +'a opt

    type +'a optdef

    type +'a meth

    type +'a gen_prop

    type 'a readonly_prop = < get : 'a > gen_prop

    type 'a writeonly_prop = < set : 'a -> unit > gen_prop

    type 'a prop = < get : 'a ; set : 'a -> unit > gen_prop

    type 'a optdef_prop = < get : 'a optdef ; set : 'a -> unit > gen_prop

    type +'a constr

    (****)

    type 'a callback = (unit, 'a) meth_callback

    module Unsafe = struct
      type any

      type any_js_array = any

      let inject : 'a -> any = fun _ -> assert false

      let get : 'a -> 'b -> 'c = fun _ _ -> assert false

      let set : 'a -> 'b -> 'c -> unit = fun _ _ _ -> assert false

      let meth_call : 'a -> string -> any array -> 'b = fun _ _ _ -> assert false

      let obj : (string * any) array -> 'a = fun _ -> assert false
    end

    let wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback = fun _ -> assert false

    let string : string -> js_string t = fun _ -> assert false

    let undefined : unit -> 'a optdef = fun () -> assert false

    let def : 'a -> 'a optdef = fun _ -> assert false
  end
end
;;

#directory "+compiler-libs"

let () = Clflags.dump_source := true

[%%expect
{|
module Js_of_ocaml :
  sig
    module Js :
      sig
        class type js_string = object  end
        type +'a t
        type (-'a, +'b) meth_callback
        type +'a opt
        type +'a optdef
        type +'a meth
        type +'a gen_prop
        type 'a readonly_prop = < get : 'a > gen_prop
        type 'a writeonly_prop = < set : 'a -> unit > gen_prop
        type 'a prop = < get : 'a; set : 'a -> unit > gen_prop
        type 'a optdef_prop = < get : 'a optdef; set : 'a -> unit > gen_prop
        type +'a constr
        type 'a callback = (unit, 'a) meth_callback
        module Unsafe :
          sig
            type any
            type any_js_array = any
            val inject : 'a -> any
            val get : 'a -> 'b -> 'c
            val set : 'a -> 'b -> 'c -> unit
            val meth_call : 'a -> string -> any array -> 'b
            val obj : (string * any) array -> 'a
          end
        val wrap_meth_callback : ('a -> 'b) -> ('a, 'b) meth_callback
        val string : string -> js_string t
        val undefined : unit -> 'a optdef
        val def : 'a -> 'a optdef
      end
  end
|}]

let o () =
  object%js
    method m1 a b = a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t0) (type t1) (type t2)
     (t2 : res Js_of_ocaml.Js.t -> t0 -> t1 -> t2)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t0 -> t1 -> t2 Js_of_ocaml.Js.meth) -> res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t2)))|])
    (fun _ a b -> a + b) ((fun self m1 -> object method m1 = m1 self end)
    [@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 a = fun b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t3) (type t4) (type t5)
     (t5 : res Js_of_ocaml.Js.t -> t3 -> t4 -> t5)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t3 -> t4 -> t5 Js_of_ocaml.Js.meth) -> res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t5)))|])
    (fun _ a -> fun b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 = fun a b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t6) (type t7) (type t8)
     (t8 : res Js_of_ocaml.Js.t -> t6 -> t7 -> t8)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t6 -> t7 -> t8 Js_of_ocaml.Js.meth) -> res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t8)))|])
    (fun _ a b -> a + b) ((fun self m1 -> object method m1 = m1 self end)
    [@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 = fun a -> fun b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t9) (type t10) (type t11)
     (t11 : res Js_of_ocaml.Js.t -> t9 -> t10 -> t11)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t9 -> t10 -> t11 Js_of_ocaml.Js.meth) ->
           res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t11)))|])
    (fun _ a -> fun b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 a =
      function
      | b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t12) (type t13) (type t14)
     (t14 : res Js_of_ocaml.Js.t -> t12 -> t13 -> t14)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t12 -> t13 -> t14 Js_of_ocaml.Js.meth) ->
           res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t14)))|])
    (fun _ a -> function | b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 a =
      function
      | 0 -> a
      | b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t15) (type t16) (type t17)
     (t17 : res Js_of_ocaml.Js.t -> t15 -> t16 -> t17)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t15 -> t16 -> t17 Js_of_ocaml.Js.meth) ->
           res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t17)))|])
    (fun _ a -> function | 0 -> a | b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 (type b) a =
      function
      | 0 -> a
      | b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t18) (type t19) (type t20)
     (t20 : res Js_of_ocaml.Js.t -> t18 -> t19 -> t20)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t18 -> t19 -> t20 Js_of_ocaml.Js.meth) ->
           res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t20)))|])
    (fun _ (type b) a -> function | 0 -> a | b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]

let o () =
  object%js
    method m1 a (type b) =
      function
      | 0 -> a
      | b -> a + b
  end

[%%expect
{|
let o () =
  (fun (type res) (type t21) (type t22) (type t23)
     (t23 : res Js_of_ocaml.Js.t -> t21 -> t22 -> t23)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t21 -> t22 -> t23 Js_of_ocaml.Js.meth) ->
           res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t23)))|])
    (fun _ a (type b) -> function | 0 -> a | b -> a + b)
    ((fun self m1 -> object method m1 = m1 self end)[@merlin.hide ]);;
val o :
  unit -> < m1 : int -> int -> int Js_of_ocaml.Js.meth > Js_of_ocaml.Js.t =
  <fun>
|}]


let o () =
  object%js
    method m1 : 'a. 'a -> unit = fun a -> ignore a
  end

[%%expect {|
let o () = [%ocaml.error "Polymorphic method not supported."];;
Line _, characters 4-50:
Error: Polymorphic method not supported.
|}]

let o () =
  object%js
    method m1 : 'a. 'a -> unit = fun (type a) (a : a) -> ignore a
  end

[%%expect {|
let o () = [%ocaml.error "Polymorphic method not supported."];;
Line _, characters 4-65:
Error: Polymorphic method not supported.
|}]


let o () =
  object%js
    method m1 : 'a  -> unit = fun (type a) (a : a) -> ignore a
    method m2 : int -> unit = fun (type a) (a : a) -> ignore a
    method m3 : 'b -> unit = fun (a : 'b) -> ignore a
  end

[%%expect {|
let o () =
  (fun (type res) (type t26) (type t27) (type t28) (type t29) (type t30)
     (type t31) (t29 : res Js_of_ocaml.Js.t -> t26 -> t29)
     (t30 : res Js_of_ocaml.Js.t -> t27 -> t30)
     (t31 : res Js_of_ocaml.Js.t -> t28 -> t31)
     (_ :
       res Js_of_ocaml.Js.t ->
         (res Js_of_ocaml.Js.t -> t26 -> t29 Js_of_ocaml.Js.meth) ->
           (res Js_of_ocaml.Js.t -> t27 -> t30 Js_of_ocaml.Js.meth) ->
             (res Js_of_ocaml.Js.t -> t28 -> t31 Js_of_ocaml.Js.meth) -> res)
     : res Js_of_ocaml.Js.t->
     Js_of_ocaml.Js.Unsafe.obj
       [|("m1",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t29)));("m2",
                                                          (Js_of_ocaml.Js.Unsafe.inject
                                                             (Js_of_ocaml.Js.wrap_meth_callback
                                                                t30)));
         ("m3",
           (Js_of_ocaml.Js.Unsafe.inject
              (Js_of_ocaml.Js.wrap_meth_callback t31)))|])
    (fun _ : 'a -> unit-> fun (type a) (a : a) -> ignore a)
    (fun _ : int -> unit-> fun (type a) (a : a) -> ignore a)
    (fun _ : 'b -> unit-> fun (a : 'b) -> ignore a)
    ((fun self m1 m2 m3 ->
        object method m1 = m1 self method m2 = m2 self method m3 = m3 self
        end)[@merlin.hide ]);;
val o :
  unit ->
  < m1 : 't26 -> unit Js_of_ocaml.Js.meth;
    m2 : int -> unit Js_of_ocaml.Js.meth;
    m3 : 't28 -> unit Js_of_ocaml.Js.meth >
  Js_of_ocaml.Js.t = <fun>
|}]