Skip to content

Commit de3bec9

Browse files
authored
Add subtyping between arrows of related modes (#20)
1 parent 93d8615 commit de3bec9

File tree

6 files changed

+95
-12
lines changed

6 files changed

+95
-12
lines changed

testsuite/tests/typing-local/local.ml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,3 +1864,56 @@ Error: This expression has type (local_ int list -> unit) -> int -> unit
18641864
Type local_ int list -> unit is not compatible with type
18651865
int list -> unit
18661866
|}]
1867+
1868+
(* Subtyping *)
1869+
1870+
let foo f = (f : local_ string -> float :> string -> float)
1871+
[%%expect{|
1872+
val foo : (local_ string -> float) -> string -> float = <fun>
1873+
|}]
1874+
1875+
let foo f = (f : string -> float :> string -> local_ float)
1876+
[%%expect{|
1877+
val foo : (string -> float) -> string -> local_ float = <fun>
1878+
|}]
1879+
1880+
let foo f = (f : string -> local_ float :> string -> float)
1881+
[%%expect{|
1882+
Line 1, characters 12-59:
1883+
1 | let foo f = (f : string -> local_ float :> string -> float)
1884+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1885+
Error: Type string -> local_ float is not a subtype of string -> float
1886+
|}]
1887+
1888+
let foo f = (f : string -> float :> local_ string -> local_ float)
1889+
[%%expect{|
1890+
Line 1, characters 12-66:
1891+
1 | let foo f = (f : string -> float :> local_ string -> local_ float)
1892+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1893+
Error: Type string -> float is not a subtype of local_ string -> local_ float
1894+
|}]
1895+
1896+
let foo f = ignore (f :> string -> float); ()
1897+
[%%expect{|
1898+
val foo : (string -> float) -> unit = <fun>
1899+
|}]
1900+
1901+
let use_local_to_global (f : local_ string -> float) = ()
1902+
1903+
let foo f = ignore (f :> string -> float); use_local_to_global f
1904+
[%%expect{|
1905+
val use_local_to_global : (local_ string -> float) -> unit = <fun>
1906+
val foo : (local_ string -> float) -> unit = <fun>
1907+
|}]
1908+
1909+
let use_global_to_local (f : string -> local_ float) = ()
1910+
1911+
let foo f = ignore (f :> string -> float); use_global_to_local f
1912+
[%%expect{|
1913+
val use_global_to_local : (string -> local_ float) -> unit = <fun>
1914+
Line 3, characters 63-64:
1915+
3 | let foo f = ignore (f :> string -> float); use_global_to_local f
1916+
^
1917+
Error: This expression has type string -> float
1918+
but an expression was expected of type string -> local_ float
1919+
|}]

testsuite/tests/typing-objects/Tests.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ Error: Multiple definition of the type name t.
715715

716716
fun x -> (x :> < m : 'a -> 'a > as 'a);;
717717
[%%expect{|
718-
- : < m : (< m : 'a > as 'b) -> 'b as 'a; .. > -> 'b = <fun>
718+
- : < m : (< m : 'a -> 'a > as 'a) -> 'a; .. > -> 'a = <fun>
719719
|}];;
720720

721721
fun x -> (x : int -> bool :> 'a -> 'a);;

typing/btype.ml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,11 +1075,18 @@ module Alloc_mode = struct
10751075
let newvar () = Amodevar (fresh ())
10761076

10771077
let newvar_below = function
1078-
| Amode Global -> Amode Global
1078+
| Amode Global -> Amode Global, false
10791079
| m ->
10801080
let v = newvar () in
10811081
submode_exn v m;
1082-
v
1082+
v, true
1083+
1084+
let newvar_above = function
1085+
| Amode Local -> Amode Local, false
1086+
| m ->
1087+
let v = newvar () in
1088+
submode_exn m v;
1089+
v, true
10831090

10841091
let check_const = function
10851092
| Amode m -> Some m

typing/btype.mli

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ module Alloc_mode : sig
290290

291291
val newvar : unit -> t
292292

293-
val newvar_below : t -> t
293+
val newvar_below : t -> t * bool
294+
295+
val newvar_above : t -> t * bool
294296

295297
val check_const : t -> const option
296298

typing/ctype.ml

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4147,6 +4147,17 @@ let find_cltype_for_path env p =
41474147
let has_constr_row' env t =
41484148
has_constr_row (expand_abbrev env t)
41494149

4150+
let build_submode posi m =
4151+
if posi then begin
4152+
let m', changed = Btype.Alloc_mode.newvar_below m in
4153+
let c = if changed then Changed else Unchanged in
4154+
m', c
4155+
end else begin
4156+
let m', changed = Btype.Alloc_mode.newvar_above m in
4157+
let c = if changed then Changed else Unchanged in
4158+
m', c
4159+
end
4160+
41504161
let rec build_subtype env visited loops posi level t =
41514162
let t = repr t in
41524163
match t.desc with
@@ -4160,14 +4171,19 @@ let rec build_subtype env visited loops posi level t =
41604171
(t, Unchanged)
41614172
else
41624173
(t, Unchanged)
4163-
| Tarrow(l, t1, t2, _) ->
4174+
| Tarrow((l,a,r) , t1, t2, _) ->
41644175
if memq_warn t visited then (t, Unchanged) else
41654176
let visited = t :: visited in
41664177
let (t1', c1) = build_subtype env visited loops (not posi) level t1 in
41674178
let (t2', c2) = build_subtype env visited loops posi level t2 in
4168-
let c = max c1 c2 in
4169-
(* FIXME update arrow modes *)
4170-
if c > Unchanged then (newty (Tarrow(l, t1', t2', Cok)), c)
4179+
let (a', c3) =
4180+
if level > 2 then build_submode (not posi) a else a, Unchanged
4181+
in
4182+
let (r', c4) =
4183+
if level > 2 then build_submode posi r else r, Unchanged
4184+
in
4185+
let c = max c1 (max c2 (max c3 c4)) in
4186+
if c > Unchanged then (newty (Tarrow((l,a',r'), t1', t2', Cok)), c)
41714187
else (t, Unchanged)
41724188
| Ttuple tlist ->
41734189
if memq_warn t visited then (t, Unchanged) else
@@ -4336,6 +4352,11 @@ let subtypes = TypePairs.create 17
43364352
let subtype_error env trace =
43374353
raise (Subtype (expand_trace env (List.rev trace), []))
43384354

4355+
let subtype_alloc_mode env trace a1 a2 =
4356+
match Btype.Alloc_mode.submode a1 a2 with
4357+
| Ok () -> ()
4358+
| Error () -> subtype_error env trace
4359+
43394360
let rec subtype_rec env trace t1 t2 cstrs =
43404361
let t1 = repr t1 in
43414362
let t2 = repr t2 in
@@ -4353,8 +4374,8 @@ let rec subtype_rec env trace t1 t2 cstrs =
43534374
(l1 = l2
43544375
|| !Clflags.classic && not (is_optional l1 || is_optional l2)) ->
43554376
let cstrs = subtype_rec env (Trace.diff t2 t1::trace) t2 t1 cstrs in
4356-
unify_alloc_mode a1 a2; (* FIXME *)
4357-
unify_alloc_mode r1 r2;
4377+
subtype_alloc_mode env trace a2 a1;
4378+
subtype_alloc_mode env trace r1 r2;
43584379
subtype_rec env (Trace.diff u1 u2::trace) u1 u2 cstrs;
43594380
| (Ttuple tl1, Ttuple tl2) ->
43604381
subtype_list env trace tl1 tl2 cstrs

typing/typecore.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5287,15 +5287,15 @@ and type_argument ?explanation ?recarg env (mode : expected_mode) sarg
52875287
and type_apply_arg env ~funct ~index ~position ~partial_app (lbl, arg) =
52885288
match arg with
52895289
| Arg (Unknown_arg { sarg; ty_arg; mode_arg }) ->
5290-
let mode = Alloc_mode.newvar_below mode_arg in
5290+
let mode, _ = Alloc_mode.newvar_below mode_arg in
52915291
let expected_mode =
52925292
mode_argument ~funct ~index ~position ~partial_app mode in
52935293
let arg = type_expect env expected_mode sarg (mk_expected ty_arg) in
52945294
if is_optional lbl then
52955295
unify_exp env arg (type_option(newvar()));
52965296
(lbl, Arg arg)
52975297
| Arg (Known_arg { sarg; ty_arg; ty_arg0; mode_arg; wrapped_in_some }) ->
5298-
let mode = Alloc_mode.newvar_below mode_arg in
5298+
let mode, _ = Alloc_mode.newvar_below mode_arg in
52995299
let expected_mode =
53005300
mode_argument ~funct ~index ~position ~partial_app mode in
53015301
let arg =

0 commit comments

Comments
 (0)