Skip to content

Commit 34921ef

Browse files
committed
Add support for type rec over types with type parameters
1 parent b82fed7 commit 34921ef

File tree

2 files changed

+105
-15
lines changed

2 files changed

+105
-15
lines changed

elab.ml

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,24 @@ 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+
| _ ->
135+
error typ.at ("non-recursive type for " ^ label ^ ":\n"
136+
^ " " ^ Types.string_of_extyp s) in
137+
find_rec t
138+
| _ ->
139+
error typ.at ("non-recursive type for " ^ label ^ ":\n"
140+
^ " " ^ Types.string_of_extyp s)
141+
142+
125143
(* Instantiation *)
126144

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

387405
| EL.RollE(var, typ) ->
388406
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
407+
let rec_t, unroll_t, roll_t, ak = rec_from_extyp typ "rolling" s in
408+
let var_t = lookup_var env var in
409+
let unroll_t = subst_typ (subst [ak] [rec_t]) unroll_t in
393410
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)
411+
try sub_typ env var_t unroll_t []
412+
with Sub e ->
413+
error var.at ("rolled value does not match annotation:\n"
414+
^ " " ^ Types.string_of_typ var_t ^ "\n"
415+
^ "vs\n"
416+
^ " " ^ Types.string_of_typ unroll_t) in
417+
ExT([], roll_t), Pure, zs1 @ zs2,
418+
IL.RollE(IL.AppE(f, IL.VarE(var.it)), erase_typ roll_t)
398419

399420
| EL.IfE(var, exp1, exp2, typ) ->
400421
let t0, zs0, ex = elab_instvar env var in
@@ -489,13 +510,15 @@ Trace.debug (lazy ("[UnwrapE] s2 = " ^ string_of_norm_extyp s2));
489510

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

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

regression.1ml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,70 @@ Pure : () => {type t = bool; existentials: t} = fun () =>
2929

3030
;; Impure : () => {type t; existentials: t} = fun () =>
3131
;; {type t = bool; existentials = true} :> {type t = bool; existentials: t};
32+
33+
;;
34+
35+
Hungry = {
36+
type eat a = rec eat_a => a -> eat_a;
37+
38+
eater 'a: eat a = rec (eater: eat a) => @(eat a) (fun a => eater);
39+
40+
(<+) eater x = eater.@(eat _) x;
41+
42+
do eater <+ 1 <+ 2;
43+
};
44+
45+
PolyRec = {
46+
type l a = rec (type t) => alt a t;
47+
t = rec (type t a) => fun (type a) => alt a (t (type (a, a)));
48+
49+
t_int = t int;
50+
51+
hmm (x: t int) = casealt (x.@(t int));
52+
53+
t0 = @(t int) (right (@(t (type (int, int))) (left (0, 0))));
54+
};
55+
56+
N :> {
57+
type Z;
58+
type S _;
59+
} = {
60+
type Z = {};
61+
type S _ = {};
62+
};
63+
64+
ListN = let
65+
type I (type x) (type p _ _) (type t _ _) = {
66+
nil : p x N.Z;
67+
(::) 'n : x -> t x n -> p x (N.S n);
68+
};
69+
type T x n (type t _ _) = (type p _ _) => I x p t -> p x n;
70+
in {
71+
t = rec (type t _ _) => fun (type x) (type n) => type wrap T x n t;
72+
73+
case 'x 'n (p: {type t _ _}) (cs: I x p.t t) e =
74+
(unwrap e.@(t _ _): wrap T x n t) p.t cs;
75+
76+
local
77+
mk 'x 'n (c: T x n t) = @(t x n) (wrap c: wrap T x n t);
78+
in
79+
nil 'x = mk (fun (type p _ _) (r: I x p t) => r.nil);
80+
(::) 'x 'n (v: x) (vs: t x n) = mk (fun (type p _ _) (r: I x p t) => r.:: v vs);
81+
end;
82+
} :> {
83+
type t _ _;
84+
85+
case 'x 'n: (p: {type t _ _}) => I x p.t t => t x n -> p.t x n;
86+
87+
nil 'x : t x N.Z;
88+
(::) 'x 'n : x => t x n => t x (N.S n);
89+
};
90+
91+
ListN = {
92+
...ListN;
93+
map 'x 'y 'n (xy: x -> y) = rec (map: 'n => t x n -> t y n) =>
94+
case {type t _ n = t y n} {
95+
nil = nil;
96+
(::) x xs = xy x :: map xs;
97+
};
98+
};

0 commit comments

Comments
 (0)