File: poly_params.ml

package info (click to toggle)
ocamlformat 0.29.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,820 kB
  • sloc: ml: 65,176; pascal: 4,877; lisp: 229; sh: 217; makefile: 121
file content (191 lines) | stat: -rw-r--r-- 4,896 bytes parent folder | download
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