Skip to content

Commit 88d4ee8

Browse files
committed
Recursively dependent signatures
1 parent 02859ac commit 88d4ee8

6 files changed

Lines changed: 195 additions & 21 deletions

File tree

elab.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,18 @@ Trace.debug (lazy ("[WithT] aks12 = " ^ string_of_norm_extyp (ExT(aks12, StrT []
275275
ExT(aks11, subst_typ (subst aks12 ts) t1),
276276
lift_warn typ.at t1 (add_typs aks11 env) (zs1 @ zs2 @ zs3)
277277

278+
| EL.RecT(var, typ1, typ2) ->
279+
let ExT(aks1, t1), zs1 = elab_typ env typ1 l in
280+
let env1 = add_val var.it t1 (add_typs aks1 env) in
281+
let ExT(aks2, t2), zs2 = elab_typ env1 typ2 l in
282+
let ts, zs3, e =
283+
try sub_typ env1 t2 t1 (varTs aks1) with Sub e -> error typ.at
284+
("recursive type does not match annotation: " ^ Sub.string_of_error e)
285+
in
286+
let aks' = freshen_vars env aks1 in
287+
let t3 = subst_typ (subst aks1 (varTs aks')) t2 in
288+
ExT(aks', t3), lift_warn typ.at t3 env (zs1 @ zs2 @ zs3)
289+
278290
and elab_dec env dec l =
279291
Trace.elab (lazy ("[elab_dec] " ^ EL.label_of_dec dec));
280292
(fun (s, zs) -> dec.at, env, s, zs, None, EL.label_of_dec dec) <<<

readme.1ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ p = f (fun x => x)
4646

4747

4848

49-
type stream = rec t => {hd : int, tl : () ~> opt t} ;; creates rec type
49+
...rec {type stream} => {type stream = {hd : int, tl : () ~> opt stream}} ;; creates rec type
5050
single x :@ stream = {hd = x, tl = fun () => none} ;; b :@ t rolls value into t
5151
({hd = n} :@ stream) = single 5 ;; p :@ t pattern matches on rec value
5252
do Int.print n ;; or:

regression.1ml

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ type DEC_PUNNING = {int, list}
3333

3434
;;
3535

36+
type RDS = rec (R: let type T'1 = {type t _} in {A: T'1, B: T'1}) => let
37+
type ONE (type this _) (type that _) = {
38+
t = this
39+
aThis 'a: this a
40+
ofThat 'a: that a -> this a
41+
}
42+
in {
43+
A: ONE R.A.t R.B.t
44+
B: ONE R.B.t R.A.t
45+
}
46+
47+
Rds :> RDS = let
48+
One = {
49+
type t _ = ()
50+
aThis = ()
51+
ofThat _ = ()
52+
}
53+
in {
54+
A = One
55+
B = One
56+
}
57+
58+
;;
59+
3660
Equivalence: {
3761
type t a b
3862

@@ -199,11 +223,27 @@ type_error rec (R: {}) => {
199223
kaboom () = R
200224
}
201225

202-
Kaboom = rec (R: rec R => {kaboom: () ~> R}) => {kaboom () = R} :@ (= R)
226+
;;Kaboom = rec (R: rec R => {kaboom: () ~> R}) => {kaboom () = R} :@ (= R)
203227

204228
;;
205229

206-
Mutually = let
230+
type MUTUALLY = rec (R: {
231+
Even: {type t _}
232+
Odd: {type t _}
233+
}) => {
234+
Even: {
235+
t = R.Even.t
236+
make 'x: x -> R.Odd.t x -> R.Even.t x
237+
size 'x: R.Even.t x ~> int
238+
}
239+
Odd: {
240+
t = R.Odd.t
241+
make 'x: opt (R.Even.t x) -> R.Odd.t x
242+
size 'x: R.Odd.t x ~> int
243+
}
244+
}
245+
246+
Mutually :> MUTUALLY = let
207247
T = rec (R: {
208248
Even: {type t _}
209249
Odd: {type t _}
@@ -267,7 +307,7 @@ type (a `>>` b) c = c
267307
;;
268308

269309
Hungry = {
270-
type eat a = rec eat_a => a ~> eat_a
310+
...rec {type eat a} => {type eat a = a ~> eat a}
271311

272312
eater 'a = rec (eater: eat a) => (fun a => eater) :@ eat a
273313

@@ -277,7 +317,7 @@ Hungry = {
277317
}
278318

279319
PolyRec = {
280-
type l a = rec (type t) => a | t
320+
...rec {type l a} => {type l a = a | l a}
281321
...rec {type t a} => {type t a = a | t (a, a)}
282322

283323
t_int = t int

sub.ml

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,25 @@ let lift_warn at t env zs =
9191

9292
(* Subtyping *)
9393

94+
let rec has_typs_typ ps = function
95+
| VarT(_) -> false
96+
| PrimT(_) -> false
97+
| StrT(tr) -> List.exists (fun (_, t) -> has_typs_typ ps t) tr
98+
| FunT(aks, td, ExT(_, tr), e) ->
99+
(match e with
100+
| Implicit | Explicit Pure ->
101+
has_typs_typ (List.map (fun p -> AppT(p, varTs aks)) ps) tr
102+
| Explicit Impure -> false)
103+
| TypT(ExT(_, p)) -> List.mem p ps
104+
| WrapT(_) -> false
105+
| LamT(_) -> false
106+
| AppT(_) -> false
107+
| TupT(_) -> false
108+
| DotT(_) -> false
109+
| RecT(_) -> false
110+
| InferT(_) -> false
111+
112+
94113
let resolve_typ z t =
95114
Trace.sub (lazy ("[resolve_typ] z = " ^ string_of_norm_typ (InferT(z))));
96115
Trace.sub (lazy ("[resolve_typ] t = " ^ string_of_norm_typ t));
@@ -101,12 +120,36 @@ let unify_typ t1 t2 =
101120
Trace.sub (lazy ("[unify_typ] t2 = " ^ string_of_norm_typ t2));
102121
unify_typ t1 t2
103122

123+
let rec psubst p t =
124+
match p with
125+
| VarT(a, k) -> a, t
126+
| AppT(p', ts) -> psubst p' (LamT(List.map unvarT ts, t))
127+
| _ -> assert false
128+
104129

105130
let rec sub_typ env t1 t2 ps =
106131
Trace.sub (lazy ("[sub_typ] t1 = " ^ string_of_norm_typ t1));
107132
Trace.sub (lazy ("[sub_typ] t2 = " ^ string_of_norm_typ t2));
108133
Trace.sub (lazy ("[sub_typ] ps = " ^
109134
String.concat ", " (List.map string_of_norm_typ ps)));
135+
let ts', zs', t2, ps =
136+
if ps <> [] then
137+
let su, zs' = match_typ env t1 t2 ps in
138+
Trace.sub (lazy ("[sub_typ] su = " ^
139+
String.concat ", " (List.map (fun (p, t) -> Printf.sprintf "[= %s] - [= %s]\n" (string_of_typ p) (string_of_typ t)) su)));
140+
let t2 = subst_typ (List.map (fun (p, t) -> psubst p t) su) t2 in
141+
let ps' = List.filter (fun p -> List.mem_assoc p su) ps in
142+
let ts' = List.map (fun p -> List.assoc p su) ps' in
143+
let ps = List.filter (fun p -> not (List.mem_assoc p su)) ps in
144+
if ps <> [] then begin
145+
Trace.sub (lazy ("[sub_typ] unmatched ps = " ^
146+
String.concat ", " (List.map string_of_norm_typ ps)));
147+
raise Not_found
148+
end;
149+
ts', zs', t2, ps
150+
else
151+
[], [], t2, ps
152+
in
110153
let e1 = IL.VarE("x") in
111154
let ts, zs, e =
112155
match norm_typ t1, freshen_typ env (norm_typ t2) with
@@ -267,7 +310,7 @@ let rec sub_typ env t1 t2 ps =
267310
Trace.sub (lazy ("[sub_typ] done ts = " ^
268311
String.concat ", " (List.map string_of_norm_typ ts)));
269312
Trace.sub (lazy ("[sub_typ] done x -> " ^ IL.string_of_exp e));
270-
ts, zs, IL.LamE("x", erase_typ t1, e)
313+
ts' @ ts, zs' @ zs, IL.LamE("x", erase_typ t1, e)
271314

272315
and sub_extyp env s1 s2 ps =
273316
Trace.sub (lazy ("[sub_extyp] s1 = " ^ string_of_norm_extyp s1));
@@ -306,12 +349,6 @@ and sub_row env tr1 tr2 ps =
306349
try sub_typ env t1 t2 ps with
307350
| Sub e -> raise (Sub (Struct(l, e)))
308351
in
309-
let rec psubst p t =
310-
match p with
311-
| VarT(a, k) -> a, t
312-
| AppT(p', ts) -> psubst p' (LamT(List.map unvarT ts, t))
313-
| _ -> assert false
314-
in
315352
let su = List.map2 psubst (Lib.List.take (List.length ts1) ps) ts1 in
316353
let ps' = Lib.List.drop (List.length ts1) ps in
317354
let ts2, zs2, fs = sub_row env tr1 (subst_row su tr2') ps' in
@@ -341,3 +378,86 @@ and equal_row env tr1 tr2 ps =
341378
let _, zs2, _ =
342379
try sub_row env tr2 tr1 ps with Sub e -> raise (Sub (Right e)) in
343380
zs1 @ zs2
381+
382+
and match_typ env t1 t2 ps =
383+
let t2 = norm_typ t2 in
384+
Trace.sub (lazy ("[match_typ] t1 = " ^ string_of_norm_typ t1));
385+
Trace.sub (lazy ("[match_typ] t2 = " ^ string_of_typ t2));
386+
Trace.sub (lazy ("[match_typ] ps = " ^
387+
String.concat ", " (List.map string_of_norm_typ ps)));
388+
if not (has_typs_typ ps t2) then [], [] else
389+
match norm_typ t1, freshen_typ env t2 with
390+
| t1, FunT(aks21, t21, ExT(aks22, t22), Implicit) ->
391+
assert (aks22 = []);
392+
let su, zs = match_typ (add_typs aks21 env) t1 t22 ps in
393+
List.map (fun (p, t) -> (p, LamT(aks21, t))) su, lift env zs
394+
395+
| FunT(aks11, t11, ExT(aks12, t12), Implicit), t2 ->
396+
assert (aks12 = []);
397+
let ts1, zs1 = guess_typs (Env.domain_typ env) aks11 in
398+
let t1' = subst_typ (subst aks11 ts1) t12 in
399+
let su, zs2 = match_typ env t1' t2 ps in
400+
su, zs1 @ zs2
401+
402+
| TypT(s1), TypT(s2) ->
403+
(match s1, s2 with
404+
| ExT(aks1, t), ExT([], p) when List.mem p ps ->
405+
if aks1 <> [] || not (!undecidable_flag || is_small_typ t) then
406+
raise (Sub (Mismatch (t1, t2)));
407+
[(p, t)], []
408+
| _ ->
409+
[], [])
410+
411+
| StrT(tr1), StrT(tr2) ->
412+
match_row env tr1 tr2 ps
413+
414+
| FunT(aks1, t11, s1, Explicit p1), FunT(aks2, t21, s2, Explicit p2) ->
415+
if p1 = Impure && p2 = Pure then raise (Sub (FunEffect(p1, p2)));
416+
if p1 <> Pure || p2 <> Pure then
417+
[], []
418+
else
419+
let env' = add_typs aks2 env in
420+
let ts1, zs1, f1 =
421+
try sub_typ env' t21 t11 (varTs aks1) with Sub e ->
422+
raise (Sub (FunParam e)) in
423+
let ps' = List.map (fun p -> AppT(p, varTs aks2)) ps in
424+
let su, zs2 =
425+
try match_extyp env' (subst_extyp (subst aks1 ts1) s1) s2 ps'
426+
with Sub e -> raise (Sub (FunResult e)) in
427+
List.map (function (AppT(p, _), t) -> (p, LamT(aks2, t))
428+
| _ -> assert false) su, lift env (zs1 @ zs2)
429+
430+
| _ ->
431+
[], []
432+
433+
and match_extyp env s1 s2 ps =
434+
let ExT(aks2, t2) = freshen_extyp env s2 in
435+
let ExT(aks1, t1) = freshen_extyp (add_typs aks2 env) s1 in
436+
match aks1, aks2 with
437+
| [], [] ->
438+
match_typ env t1 t2 ps
439+
| _ ->
440+
[], []
441+
442+
and match_row env tr1 tr2 ps =
443+
match tr2 with
444+
| [] ->
445+
[], []
446+
| (l, t2)::tr2' ->
447+
let t1, zs, app =
448+
try List.assoc l tr1, [], fun f l x -> IL.AppE(f, IL.DotE(x, l)) with
449+
| Not_found ->
450+
if is_base_typ t2 && is_small_typ t2
451+
then
452+
let t, zs = guess_typ (Env.domain_typ env) BaseK in
453+
let s = ExT([], t) in
454+
TypT(s), zs, fun f _ _ -> IL.AppE(f, IL.LamE("_", erase_extyp s, IL.TupE[]))
455+
else
456+
raise (Sub (Struct(l, Missing)));
457+
in
458+
let su1, zs1 =
459+
try match_typ env t1 t2 ps with
460+
| Sub e -> raise (Sub (Struct(l, e)))
461+
in
462+
let su2, zs2 = match_row env tr1 (subst_row (List.map (fun (p, t) -> psubst p t) su1) tr2') ps in
463+
su1 @ su2, zs @ zs1 @ zs2

syntax.ml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ and typ' =
2929
| EqT of exp
3030
| AsT of typ * typ
3131
| WithT of typ * var list * exp
32+
| RecT of var * typ * typ
3233

3334
and dec = (dec', unit) phrase
3435
and dec' =
@@ -228,13 +229,10 @@ type pat = {bind: bind; infer: typ option; annot: typ option}
228229

229230
let recT(p, t2) =
230231
let b, t1 = p.it in
231-
let e = typE(t2)@@t2.at in
232-
let e' =
233-
match b.it with
234-
| VarB(x, {it = VarE({it = "$"})}) -> RecE(x, t1, e)
235-
| EmptyB -> RecE("_"@@b.at, t1, e)
236-
| _ -> RecE("$"@@b.at, t1, letE(b, e)@@span[b.at; e.at])
237-
in PathT(e'@@span[p.at; t2.at])
232+
match b.it with
233+
| VarB(x, {it = VarE({it = "$"})}) -> RecT(x, t1, t2)
234+
| EmptyB -> RecT("_"@@b.at, t1, t2)
235+
| _ -> RecT("$"@@b.at, t1, letT(b, t2)@@span[b.at; t2.at])
238236

239237
let recE(p, e) =
240238
let b, t = p.it in
@@ -366,6 +364,7 @@ let label_of_typ t =
366364
| EqT _ -> "EqT"
367365
| AsT _ -> "AsT"
368366
| WithT _ -> "WithT"
367+
| RecT _ -> "RecT"
369368

370369
let label_of_dec d =
371370
match d.it with
@@ -422,6 +421,8 @@ let rec string_of_typ t =
422421
| AsT(t1, t2) -> node' [string_of_typ t1; string_of_typ t2]
423422
| WithT(t, xs, e) ->
424423
node' ([string_of_typ t] @ List.map string_of_var xs @ [string_of_exp e])
424+
| RecT(x, b, t) ->
425+
node' [string_of_var x; string_of_typ b; string_of_typ t]
425426

426427
and string_of_dec d =
427428
let node' = node (label_of_dec d) in
@@ -475,6 +476,7 @@ let rec imports_typ typ =
475476
| EqT exp -> imports_exp exp
476477
| AsT(typ1, typ2) -> imports_typ typ1 @ imports_typ typ2
477478
| WithT(typ, _, exp) -> imports_typ typ @ imports_exp exp
479+
| RecT(_, typ1, typ2) -> imports_typ typ1 @ imports_typ typ2
478480

479481
and imports_dec dec =
480482
match dec.it with

test.1ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,11 @@ in {
275275

276276

277277
type int = primitive "int"
278-
type t = rec a => int
278+
...rec {type t} => {type t = int}
279279
v = 3 :@ t
280280
n = v @: t
281281
(m :@ t) = v
282-
type u a = rec _ => a
282+
...rec {type u a} => {type u a = a}
283283
w = 4 :@ u int
284284
(x :@ u int) = w
285285
((x :@ t, y) :@ u (_, _)) = (6 :@ t, 7) :@ u (_, _)

0 commit comments

Comments
 (0)