Skip to content

Commit 229ca86

Browse files
committed
Add support for mutually recursive types with type parameters
1 parent f0c542b commit 229ca86

3 files changed

Lines changed: 177 additions & 15 deletions

File tree

elab.ml

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,27 @@ and paths_row ta ps = function
122122
ts1 @ ts2
123123

124124

125+
let rec_from_extyp typ label s =
126+
match s with
127+
| ExT([], t) ->
128+
let rec find_rec = function
129+
| AppT(t, ts) ->
130+
let rec_t, unroll_t, roll_t, ak = find_rec t in
131+
rec_t, AppT(unroll_t, ts), AppT(roll_t, ts), ak
132+
| RecT(ak, unroll_t) as rec_t ->
133+
rec_t, unroll_t, rec_t, ak
134+
| DotT(t, lab) ->
135+
let rec_t, unroll_t, roll_t, ak = find_rec t in
136+
rec_t, DotT(unroll_t, lab), DotT(roll_t, lab), ak
137+
| _ ->
138+
error typ.at ("non-recursive type for " ^ label ^ ":"
139+
^ " " ^ Types.string_of_extyp s) in
140+
find_rec t
141+
| _ ->
142+
error typ.at ("non-recursive type for " ^ label ^ ":"
143+
^ " " ^ Types.string_of_extyp s)
144+
145+
125146
(* Instantiation *)
126147

127148
let rec instantiate env t e =
@@ -386,15 +407,18 @@ Trace.debug (lazy ("[FunE] env =" ^ VarSet.fold (fun a s -> s ^ " " ^ a) (domain
386407

387408
| EL.RollE(var, typ) ->
388409
let s, zs1 = elab_typ env typ l in
389-
let t, ak, t' =
390-
match s with
391-
| ExT([], (RecT(ak, t') as t)) -> t, ak, t'
392-
| _ -> error typ.at "non-recursive type for rolling" in
410+
let rec_t, unroll_t, roll_t, ak = rec_from_extyp typ "rolling" s in
411+
let var_t = lookup_var env var in
412+
let unroll_t = subst_typ (subst [ak] [rec_t]) unroll_t in
393413
let _, zs2, f =
394-
try sub_typ env (lookup_var env var) (subst_typ (subst [ak] [t]) t') []
395-
with Sub e -> error var.at ("rolled value does not match annotation") in
396-
ExT([], t), Pure, zs1 @ zs2,
397-
IL.RollE(IL.AppE(f, IL.VarE(var.it)), erase_typ t)
414+
try sub_typ env var_t unroll_t []
415+
with Sub e ->
416+
error var.at ("rolled value does not match annotation:"
417+
^ " " ^ Types.string_of_typ var_t ^ " "
418+
^ "<"
419+
^ " " ^ Types.string_of_typ unroll_t) in
420+
ExT([], roll_t), Pure, zs1 @ zs2,
421+
IL.RollE(IL.AppE(f, IL.VarE(var.it)), erase_typ roll_t)
398422

399423
| EL.IfE(var, exp1, exp2, typ) ->
400424
let t0, zs0, ex = elab_instvar env var in
@@ -488,13 +512,15 @@ Trace.debug (lazy ("[UnwrapE] s2 = " ^ string_of_norm_extyp s2));
488512

489513
| EL.UnrollE(var, typ) ->
490514
let s, zs1 = elab_typ env typ l in
491-
let t, ak, t' =
492-
match s with
493-
| ExT([], (RecT(ak, t') as t)) -> t, ak, t'
494-
| _ -> error typ.at "non-recursive type for rolling" in
495-
let _, zs2, f = try sub_typ env (lookup_var env var) t [] with Sub e ->
496-
error var.at ("unrolled value does not match annotation") in
497-
ExT([], subst_typ (subst [ak] [t]) t'), Pure, zs1 @ zs2,
515+
let rec_t, unroll_t, roll_t, ak = rec_from_extyp typ "unrolling" s in
516+
let var_t = lookup_var env var in
517+
let _, zs2, f = try sub_typ env var_t roll_t [] with Sub e ->
518+
error var.at ("unrolled value does not match annotation:"
519+
^ " " ^ Types.string_of_typ var_t ^ " "
520+
^ "<"
521+
^ " " ^ Types.string_of_typ roll_t) in
522+
let unroll_t = subst_typ (subst [ak] [rec_t]) unroll_t in
523+
ExT([], unroll_t), Pure, zs1 @ zs2,
498524
IL.UnrollE(IL.AppE(f, IL.VarE(var.it)))
499525

500526
| EL.RecE(var, typ, exp1) ->

regression.1ml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,117 @@ type_error {
4646
Impure : () => {type t; existentials: t} = fun () =>
4747
{type t = bool; existentials = true} :> {type t = bool; existentials: t};
4848
};
49+
50+
;;
51+
52+
Mutually = {
53+
T = rec (R: {
54+
Even: {type t _};
55+
Odd: {type t _};
56+
}) => {
57+
Even = {
58+
type t x = {head: x; tail: R.Odd.t x};
59+
};
60+
Odd = {
61+
type t x = opt (R.Even.t x);
62+
};
63+
};
64+
65+
V = rec (R: {
66+
Even: {
67+
make 'x: x => T.Odd.t x => T.Even.t x;
68+
size 'x: T.Even.t x -> int;
69+
};
70+
Odd: {
71+
make 'x: opt (T.Even.t x) => T.Odd.t x;
72+
size 'x: T.Odd.t x -> int;
73+
};
74+
}) => {
75+
Even = {
76+
make 'x (head: x) (tail: T.Odd.t x) : T.Even.t x =
77+
@(T.Even.t x) {head; tail};
78+
size 'x (v: T.Even.t x) = 1 + R.Odd.size v.@(T.Even.t _).tail;
79+
};
80+
Odd = {
81+
make 'x (v: opt (T.Even.t x)) : T.Odd.t x = @(T.Odd.t x) v;
82+
size 'x (v: T.Odd.t x) =
83+
caseopt v.@(T.Odd.t x)
84+
(fun () => 0)
85+
(fun e => R.Even.size e);
86+
};
87+
};
88+
};
89+
90+
Mutually = {
91+
Even = {...Mutually.T.Even; ...Mutually.V.Even};
92+
Odd = {...Mutually.T.Odd; ...Mutually.V.Odd};
93+
94+
one = Odd.size (Odd.make (some (Even.make true (Odd.make none))));
95+
};
96+
97+
;;
98+
99+
Hungry = {
100+
type eat a = rec eat_a => a -> eat_a;
101+
102+
eater 'a: eat a = rec (eater: eat a) => @(eat a) (fun a => eater);
103+
104+
(<+) eater x = eater.@(eat _) x;
105+
106+
do eater <+ 1 <+ 2;
107+
};
108+
109+
PolyRec = {
110+
type l a = rec (type t) => alt a t;
111+
...rec {type t a} => {type t a = alt a (t (type (a, a)))};
112+
113+
t_int = t int;
114+
115+
hmm (x: t int) = casealt (x.@(t int));
116+
117+
t0 = @(t int) (right (@(t (type (int, int))) (left (0, 0))));
118+
};
119+
120+
N :> {
121+
type Z;
122+
type S _;
123+
} = {
124+
type Z = {};
125+
type S _ = {};
126+
};
127+
128+
ListN = let
129+
type I (type x) (type p _) (type t _ _) = {
130+
nil : p N.Z;
131+
(::) 'n : x -> t x n -> p (N.S n);
132+
};
133+
type T x n (type t _ _) = (type p _) => I x p t -> p n;
134+
in {
135+
...rec {type t _ _} => {type t x n = wrap T x n t};
136+
137+
case 'x 'n (type p _) (cs: I x p t) e =
138+
(unwrap e.@(t _ _): wrap T x n t) p cs;
139+
140+
local
141+
mk 'x 'n (c: T x n t) = @(t x n) (wrap c: wrap T x n t);
142+
in
143+
nil 'x = mk (fun (type p _) (r: I x p t) => r.nil);
144+
(::) 'x 'n (v: x) (vs: t x n) = mk (fun (type p _) (r: I x p t) => r.:: v vs);
145+
end;
146+
} :> {
147+
type t _ _;
148+
149+
case 'x 'n: (type p _) => I x p t => t x n -> p n;
150+
151+
nil 'x : t x N.Z;
152+
(::) 'x 'n : x => t x n => t x (N.S n);
153+
};
154+
155+
ListN = {
156+
...ListN;
157+
map 'x 'y (xy: x -> y) = rec (map: 'n => t x n -> t y n) =>
158+
case (t _) {
159+
nil = nil;
160+
(::) x xs = xy x :: map xs;
161+
};
162+
};

sub.ml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ let rec sub_typ env t1 t2 ps =
141141
ts, zs,
142142
IL.TupE(List.map2 (fun (l, _) f -> l, IL.AppE(f, IL.DotE(e1, l))) tr2 fs)
143143

144+
| TupT(tr1), TupT(tr2) ->
145+
let zs = equal_row env tr1 tr2 ps in
146+
[], zs, e1
147+
144148
| FunT(aks1, t11, s1, Explicit p1), FunT(aks2, t21, s2, Explicit p2) ->
145149
if p1 = Impure && p2 = Pure then raise (Sub (FunEffect(p1, p2)));
146150
let env' = add_typs aks2 env in
@@ -176,6 +180,17 @@ let rec sub_typ env t1 t2 ps =
176180
raise (Sub (Mismatch(t1, t2))) in
177181
[], zs, e1
178182

183+
| LamT(aks1, t1'), LamT(aks2, t2') ->
184+
if List.length aks1 <> List.length aks2 ||
185+
List.exists2 (fun ak1 ak2 -> snd ak1 <> snd ak2) aks1 aks2 then
186+
raise (Sub (Mismatch(t1, t2)));
187+
let zs = try
188+
equal_typ (add_typs aks2 env)
189+
(subst_typ (subst aks1 (varTs aks2)) t1') t2'
190+
with Sub e ->
191+
raise (Sub (Mismatch(t1, t2)))
192+
in [], lift env zs, e1
193+
179194
| RecT(ak1, t1'), RecT(ak2, t2') ->
180195
if snd ak1 <> snd ak2 then
181196
raise (Sub (Mismatch(t1, t2)));
@@ -309,3 +324,10 @@ and equal_extyp env s1 s2 =
309324
let _, zs2, _ =
310325
try sub_extyp env s2 s1 [] with Sub e -> raise (Sub (Right e)) in
311326
zs1 @ zs2
327+
328+
and equal_row env tr1 tr2 ps =
329+
let _, zs1, _ =
330+
try sub_row env tr1 tr2 ps with Sub e -> raise (Sub (Left e)) in
331+
let _, zs2, _ =
332+
try sub_row env tr2 tr1 ps with Sub e -> raise (Sub (Right e)) in
333+
zs1 @ zs2

0 commit comments

Comments
 (0)