1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
(* This test is extracted from the compiler's testsuite. *)
let poly1 (id : 'a. 'a -> 'a) = id 3, id "three"
let _ = poly1 (fun x -> x)
let _ = poly1 (fun x -> x + 1)
let id x = x
let _ = poly1 id
let _ = poly1 (id (fun x -> x))
let _ = poly1 (let r = ref None in fun x -> r := Some x; x)
let escape f = poly1 (fun x -> f x; x)
let poly2 : ('a. 'a -> 'a) -> int * string =
fun id -> id 3, id "three"
let _ = poly2 (fun x -> x)
let _ = poly2 (fun x -> x + 1)
let poly3 : 'b. ('a. 'a -> 'a) -> 'b -> 'b * 'b option =
fun id x -> id x, id (Some x)
let _ = poly3 (fun x -> x) 8
let _ = poly3 (fun x -> x + 1) 8
let rec poly4 p (id : 'a. 'a -> 'a) =
if p then poly4 false id else id 4, id "four"
let _ = poly4 true (fun x -> x)
let _ = poly4 true (fun x -> x + 1)
let rec poly5 : bool -> ('a. 'a -> 'a) -> int * string =
fun p id ->
if p then poly5 false id else id 5, id "five"
let _ = poly5 true (fun x -> x)
let _ = poly5 true (fun x -> x + 1)
let rec poly6 : 'b. bool -> ('a. 'a -> 'a) -> 'b -> 'b * 'b option =
fun p id x ->
if p then poly6 false id x else id x, id (Some x)
let _ = poly6 true (fun x -> x) 8
let _ = poly6 true (fun x -> x + 1) 8
let needs_magic (magic : 'a 'b. 'a -> 'b) = (magic 5 : string)
let _ = needs_magic (fun x -> x)
let with_id (f : ('a. 'a -> 'a) -> 'b) = f (fun x -> x)
let _ = with_id (fun id -> id 4, id "four")
let non_principal1 p f =
if p then with_id f
else f (fun x -> x)
let non_principal2 p f =
if p then f (fun x -> x)
else with_id f
let principal1 p (f : ('a. 'a -> 'a) -> 'b) =
if p then f (fun x -> x)
else with_id f
let principal2 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b =
fun p f ->
if p then f (fun x -> x)
else with_id f
type poly = ('a. 'a -> 'a) -> int * string
let principal3 : poly option list = [ None; Some (fun x -> x 5, x "hello") ]
let non_principal3 =
[ (Some (fun x -> x 5, x "hello") : poly option);
Some (fun y -> y 6, y "goodbye") ]
let non_principal4 =
[ Some (fun y -> y 6, y "goodbye");
(Some (fun x -> x 5, x "hello") : poly option) ]
(* Functions with polymorphic parameters are separate from other functions *)
type 'a arg = 'b
constraint 'a = 'b -> 'c
type really_poly = (('a. 'a -> 'a) -> string) arg
(* Polymorphic parameters are (mostly) treated as invariant *)
type p1 = ('a. 'a -> 'a) -> int
type p2 = ('a 'b. 'a -> 'b) -> int
let foo (f : p1) : p2 = f
let foo f = (f : p1 :> p2)
module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
let foo (f : p1) : p2 = (fun id -> f id)
(* Following the existing behaviour for polymorphic methods, you can
subtype from a polymorphic parameter to a monomorphic
parameter. Elsewhere it still behaves as invariant. *)
type p1 = (bool -> bool) -> int
type p2 = ('a. 'a -> 'a) -> int
let foo (x : p1) : p2 = x
let foo x = (x : p1 :> p2)
module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
let foo (f : p1) : p2 = (fun id -> f id)
class c (f: 'a. 'a -> 'a) = object
method m = f 0
method n = f "a"
end;;
class c' (f: 'a. int -> int) = object
method m = f 0
end;;
let poly1' ~(id : 'a. 'a -> 'a) = id 3, id "three"
let poly2' ?(id : 'a. 'a -> 'a) = id 3, id "three"
let poly3' ?(id : 'a. int -> int) = id 3
(* This test illustrate a new occurrence of the bug discussed in
https://github.com/ocaml/ocaml/pull/13984*)
module type T = sig type 'a t = 'a list end
let rec f (x : (module T)) =
let (module LocalModule) = x in (assert false : ('a. 'a LocalModule.t) -> unit)
(* The following test requires full translation in the [approx_type] function if
the annotation is partial. *)
let rec f () = g () Fun.id
and g () : ('a. 'a -> 'a) -> unit = fun _ -> () ;;
let rec f () = g () Fun.id
and g : unit -> ('a. 'a -> 'a) -> unit = fun () _ -> () ;;
(* Attempts at breaking type_pattern_approx *)
let rec f ([] : 'a. 'a list) = ()
let rec f () : ('a. 'a list) -> unit = fun [] -> ()
(* New expert trick: use 'a. to trigger "exact approximation" *)
let rec f () = g (module Map.Make(Int)) and g (m : (module Map.S)) = ();;
let rec f () = g (module Map.Make(Int)) and g (m : 'a. (module Map.S)) = ();;
(* Check that we are getting the right behaviour for polymorphic variants
in polymorphic parameters. *)
let poly_poly_var : [< `A | `B ] -> unit = function | `A -> () | `B -> ()
let accept_poly_poly_var (g : 'a. ([< `A | `B ] as 'a) -> unit) = g `A
let () = accept_poly_poly_var poly_poly_var
let f (`B|_) = ()
let h (f:'a. ([> `A ] as 'a) -> unit ) = f `B
let error = h f
let (let*) x (id : 'a. 'a -> 'a) = id x, id 1
let (let*) (x : 'a. 'a option) (id : 'a. 'a -> 'a) = id x, id 1
let y =
let* x = 3. in
x
let f ((g, x) : 'a. ('a -> int) * 'a) =
g 3, g "three"
let f (x: [< `A of ('a. 'a option) -> unit ]) = match x with `A f -> f None
let f: type a. unit -> (a, ('b. 'b -> 'b) -> int) Type.eq -> a =
fun () Equal f -> f 0
|