Skip to content

Commit 708e5a9

Browse files
committed
Add tests
1 parent c609eee commit 708e5a9

File tree

1 file changed

+359
-0
lines changed

1 file changed

+359
-0
lines changed
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
(* TEST
2+
* expect
3+
*)
4+
5+
let poly1 (id : 'a. 'a -> 'a) = id 3, id "three"
6+
[%%expect {|
7+
val poly1 : ('a. 'a -> 'a) -> int * string = <fun>
8+
|}];;
9+
10+
let _ = poly1 (fun x -> x)
11+
[%%expect {|
12+
- : int * string = (3, "three")
13+
|}];;
14+
15+
let _ = poly1 (fun x -> x + 1)
16+
[%%expect {|
17+
Line 1, characters 14-30:
18+
1 | let _ = poly1 (fun x -> x + 1)
19+
^^^^^^^^^^^^^^^^
20+
Error: This argument has type int -> int which is less general than
21+
'a. 'a -> 'a
22+
|}];;
23+
24+
let id x = x
25+
let _ = poly1 id
26+
[%%expect {|
27+
val id : 'a -> 'a = <fun>
28+
- : int * string = (3, "three")
29+
|}];;
30+
31+
let _ = poly1 (id (fun x -> x))
32+
[%%expect {|
33+
Line 1, characters 14-31:
34+
1 | let _ = poly1 (id (fun x -> x))
35+
^^^^^^^^^^^^^^^^^
36+
Error: This argument has type 'b -> 'b which is less general than
37+
'a. 'a -> 'a
38+
|}];;
39+
40+
let _ = poly1 (let r = ref None in fun x -> r := Some x; x)
41+
[%%expect {|
42+
Line 1, characters 14-59:
43+
1 | let _ = poly1 (let r = ref None in fun x -> r := Some x; x)
44+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45+
Error: This argument has type 'b -> 'b which is less general than
46+
'a. 'a -> 'a
47+
|}];;
48+
49+
let escape f = poly1 (fun x -> f x; x)
50+
[%%expect {|
51+
Line 1, characters 21-38:
52+
1 | let escape f = poly1 (fun x -> f x; x)
53+
^^^^^^^^^^^^^^^^^
54+
Error: This argument has type 'b -> 'b which is less general than
55+
'a. 'a -> 'a
56+
|}];;
57+
58+
let poly2 : ('a. 'a -> 'a) -> int * string =
59+
fun id -> id 3, id "three"
60+
[%%expect {|
61+
val poly2 : ('a. 'a -> 'a) -> int * string = <fun>
62+
|}];;
63+
64+
let _ = poly2 (fun x -> x)
65+
[%%expect {|
66+
- : int * string = (3, "three")
67+
|}];;
68+
69+
let _ = poly2 (fun x -> x + 1)
70+
[%%expect {|
71+
Line 1, characters 14-30:
72+
1 | let _ = poly2 (fun x -> x + 1)
73+
^^^^^^^^^^^^^^^^
74+
Error: This argument has type int -> int which is less general than
75+
'a. 'a -> 'a
76+
|}];;
77+
78+
let poly3 : 'b. ('a. 'a -> 'a) -> 'b -> 'b * 'b option =
79+
fun id x -> id x, id (Some x)
80+
[%%expect {|
81+
val poly3 : ('a. 'a -> 'a) -> 'b -> 'b * 'b option = <fun>
82+
|}];;
83+
84+
let _ = poly3 (fun x -> x) 8
85+
[%%expect {|
86+
- : int * int option = (8, Some 8)
87+
|}];;
88+
89+
let _ = poly3 (fun x -> x + 1) 8
90+
[%%expect {|
91+
Line 1, characters 14-30:
92+
1 | let _ = poly3 (fun x -> x + 1) 8
93+
^^^^^^^^^^^^^^^^
94+
Error: This argument has type int -> int which is less general than
95+
'a. 'a -> 'a
96+
|}];;
97+
98+
let rec poly4 p (id : 'a. 'a -> 'a) =
99+
if p then poly4 false id else id 4, id "four"
100+
[%%expect {|
101+
val poly4 : bool -> ('a. 'a -> 'a) -> int * string = <fun>
102+
|}];;
103+
104+
let _ = poly4 true (fun x -> x)
105+
[%%expect {|
106+
- : int * string = (4, "four")
107+
|}];;
108+
109+
let _ = poly4 true (fun x -> x + 1)
110+
[%%expect {|
111+
Line 1, characters 19-35:
112+
1 | let _ = poly4 true (fun x -> x + 1)
113+
^^^^^^^^^^^^^^^^
114+
Error: This argument has type int -> int which is less general than
115+
'a. 'a -> 'a
116+
|}];;
117+
118+
let rec poly5 : bool -> ('a. 'a -> 'a) -> int * string =
119+
fun p id ->
120+
if p then poly5 false id else id 5, id "five"
121+
[%%expect {|
122+
val poly5 : bool -> ('a. 'a -> 'a) -> int * string = <fun>
123+
|}];;
124+
125+
let _ = poly5 true (fun x -> x)
126+
[%%expect {|
127+
- : int * string = (5, "five")
128+
|}];;
129+
130+
let _ = poly5 true (fun x -> x + 1)
131+
[%%expect {|
132+
Line 1, characters 19-35:
133+
1 | let _ = poly5 true (fun x -> x + 1)
134+
^^^^^^^^^^^^^^^^
135+
Error: This argument has type int -> int which is less general than
136+
'a. 'a -> 'a
137+
|}];;
138+
139+
140+
let rec poly6 : 'b. bool -> ('a. 'a -> 'a) -> 'b -> 'b * 'b option =
141+
fun p id x ->
142+
if p then poly6 false id x else id x, id (Some x)
143+
[%%expect {|
144+
val poly6 : bool -> ('a. 'a -> 'a) -> 'b -> 'b * 'b option = <fun>
145+
|}];;
146+
147+
let _ = poly6 true (fun x -> x) 8
148+
[%%expect {|
149+
- : int * int option = (8, Some 8)
150+
|}];;
151+
152+
let _ = poly6 true (fun x -> x + 1) 8
153+
[%%expect {|
154+
Line 1, characters 19-35:
155+
1 | let _ = poly6 true (fun x -> x + 1) 8
156+
^^^^^^^^^^^^^^^^
157+
Error: This argument has type int -> int which is less general than
158+
'a. 'a -> 'a
159+
|}];;
160+
161+
let needs_magic (magic : 'a 'b. 'a -> 'b) = (magic 5 : string)
162+
let _ = needs_magic (fun x -> x)
163+
[%%expect {|
164+
val needs_magic : ('a 'b. 'a -> 'b) -> string = <fun>
165+
Line 2, characters 20-32:
166+
2 | let _ = needs_magic (fun x -> x)
167+
^^^^^^^^^^^^
168+
Error: This argument has type 'c. 'c -> 'c which is less general than
169+
'a 'b. 'a -> 'b
170+
|}];;
171+
172+
let with_id (f : ('a. 'a -> 'a) -> 'b) = f (fun x -> x)
173+
[%%expect {|
174+
val with_id : (('a. 'a -> 'a) -> 'b) -> 'b = <fun>
175+
|}];;
176+
177+
let _ = with_id (fun id -> id 4, id "four")
178+
[%%expect {|
179+
- : int * string = (4, "four")
180+
|}];;
181+
182+
let non_principal1 p f =
183+
if p then with_id f
184+
else f (fun x -> x)
185+
[%%expect {|
186+
val non_principal1 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b = <fun>
187+
|}, Principal{|
188+
Line 3, characters 7-21:
189+
3 | else f (fun x -> x)
190+
^^^^^^^^^^^^^^
191+
Warning 18 [not-principal]: applying a higher-rank function here is not principal.
192+
val non_principal1 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b = <fun>
193+
|}];;
194+
195+
let non_principal2 p f =
196+
if p then f (fun x -> x)
197+
else with_id f
198+
[%%expect {|
199+
Line 3, characters 15-16:
200+
3 | else with_id f
201+
^
202+
Error: This expression has type ('b -> 'b) -> 'c
203+
but an expression was expected of type ('a. 'a -> 'a) -> 'd
204+
The universal variable 'a would escape its scope
205+
|}];;
206+
207+
let principal1 p (f : ('a. 'a -> 'a) -> 'b) =
208+
if p then f (fun x -> x)
209+
else with_id f
210+
[%%expect {|
211+
val principal1 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b = <fun>
212+
|}];;
213+
214+
let principal2 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b =
215+
fun p f ->
216+
if p then f (fun x -> x)
217+
else with_id f
218+
[%%expect {|
219+
val principal2 : bool -> (('a. 'a -> 'a) -> 'b) -> 'b = <fun>
220+
|}];;
221+
222+
type poly = ('a. 'a -> 'a) -> int * string
223+
224+
let principal3 : poly option list = [ None; Some (fun x -> x 5, x "hello") ]
225+
[%%expect {|
226+
type poly = ('a. 'a -> 'a) -> int * string
227+
val principal3 : poly option list = [None; Some <fun>]
228+
|}];;
229+
230+
let non_principal3 =
231+
[ (Some (fun x -> x 5, x "hello") : poly option);
232+
Some (fun y -> y 6, y "goodbye") ]
233+
[%%expect {|
234+
val non_principal3 : poly option list = [Some <fun>; Some <fun>]
235+
|}, Principal{|
236+
Line 3, characters 9-36:
237+
3 | Some (fun y -> y 6, y "goodbye") ]
238+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
239+
Warning 18 [not-principal]: this higher-rank function is not principal.
240+
val non_principal3 : poly option list = [Some <fun>; Some <fun>]
241+
|}];;
242+
243+
let non_principal4 =
244+
[ Some (fun y -> y 6, y "goodbye");
245+
(Some (fun x -> x 5, x "hello") : poly option) ]
246+
[%%expect {|
247+
Line 2, characters 26-35:
248+
2 | [ Some (fun y -> y 6, y "goodbye");
249+
^^^^^^^^^
250+
Error: This expression has type string but an expression was expected of type
251+
int
252+
|}];;
253+
254+
(* Functions with polymorphic parameters are separate from other functions *)
255+
type 'a arg = 'b
256+
constraint 'a = 'b -> 'c
257+
type really_poly = (('a. 'a -> 'a) -> string) arg
258+
[%%expect {|
259+
type 'a arg = 'b constraint 'a = 'b -> 'c
260+
Line 3, characters 20-44:
261+
3 | type really_poly = (('a. 'a -> 'a) -> string) arg
262+
^^^^^^^^^^^^^^^^^^^^^^^^
263+
Error: This type ('a. 'a -> 'a) -> string should be an instance of type
264+
'b -> 'c
265+
The universal variable 'a would escape its scope
266+
|}];;
267+
268+
(* Polymorphic parameters are (mostly) treated as invariant *)
269+
type p1 = ('a. 'a -> 'a) -> int
270+
type p2 = ('a 'b. 'a -> 'b) -> int
271+
[%%expect {|
272+
type p1 = ('a. 'a -> 'a) -> int
273+
type p2 = ('a 'b. 'a -> 'b) -> int
274+
|}];;
275+
276+
let foo (f : p1) : p2 = f
277+
[%%expect {|
278+
Line 1, characters 24-25:
279+
1 | let foo (f : p1) : p2 = f
280+
^
281+
Error: This expression has type p1 = ('a. 'a -> 'a) -> int
282+
but an expression was expected of type p2 = ('a 'b. 'a -> 'b) -> int
283+
Type 'a is not compatible with type 'b
284+
|}];;
285+
286+
let foo f = (f : p1 :> p2)
287+
[%%expect {|
288+
Line 1, characters 12-26:
289+
1 | let foo f = (f : p1 :> p2)
290+
^^^^^^^^^^^^^^
291+
Error: Type p1 = ('a. 'a -> 'a) -> int is not a subtype of
292+
p2 = ('a 'b. 'a -> 'b) -> int
293+
Type 'b is not a subtype of 'a
294+
|}];;
295+
296+
module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
297+
[%%expect {|
298+
Line 1, characters 59-60:
299+
1 | module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
300+
^
301+
Error: Signature mismatch:
302+
Modules do not match:
303+
sig val f : p1 end
304+
is not included in
305+
sig val f : p2 end
306+
Values do not match: val f : p1 is not included in val f : p2
307+
The type p1 = ('a. 'a -> 'a) -> int is not compatible with the type
308+
p2 = ('a 'b. 'a -> 'b) -> int
309+
Type 'a is not compatible with type 'b
310+
|}];;
311+
312+
let foo (f : p1) : p2 = (fun id -> f id)
313+
[%%expect {|
314+
val foo : p1 -> p2 = <fun>
315+
|}];;
316+
317+
(* Following the existing behaviour for polymorphic methods, you can
318+
subtype from a polymorphic parameter to a monomorphic
319+
parameter. Elsewhere it still behaves as invariant. *)
320+
type p1 = (bool -> bool) -> int
321+
type p2 = ('a. 'a -> 'a) -> int
322+
323+
let foo (x : p1) : p2 = x
324+
[%%expect {|
325+
type p1 = (bool -> bool) -> int
326+
type p2 = ('a. 'a -> 'a) -> int
327+
Line 4, characters 24-25:
328+
4 | let foo (x : p1) : p2 = x
329+
^
330+
Error: This expression has type p1 = (bool -> bool) -> int
331+
but an expression was expected of type p2 = ('a. 'a -> 'a) -> int
332+
Type bool is not compatible with type 'a
333+
|}];;
334+
335+
let foo x = (x : p1 :> p2)
336+
[%%expect {|
337+
val foo : p1 -> p2 = <fun>
338+
|}];;
339+
340+
module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
341+
[%%expect {|
342+
Line 1, characters 59-60:
343+
1 | module Foo (X : sig val f : p1 end) : sig val f : p2 end = X
344+
^
345+
Error: Signature mismatch:
346+
Modules do not match:
347+
sig val f : p1 end
348+
is not included in
349+
sig val f : p2 end
350+
Values do not match: val f : p1 is not included in val f : p2
351+
The type p1 = (bool -> bool) -> int is not compatible with the type
352+
p2 = ('a. 'a -> 'a) -> int
353+
Type bool is not compatible with type 'a
354+
|}];;
355+
356+
let foo (f : p1) : p2 = (fun id -> f id)
357+
[%%expect {|
358+
val foo : p1 -> p2 = <fun>
359+
|}];;

0 commit comments

Comments
 (0)