From 054ca8434b1b9be9b89f83193da877a5b26f2ba5 Mon Sep 17 00:00:00 2001
From: Gabriel Scherer <gabriel.scherer@gmail.com>
Date: Mon, 20 Feb 2023 18:35:57 +0100
Subject: [PATCH] client/F: support "let rec"

---
 client/F.ml            |  8 +++++---
 client/F.mli           |  4 +++-
 client/FPrinter.ml     |  8 ++++++--
 client/FTypeChecker.ml | 12 ++++++++----
 client/Infer.ml        |  4 ++--
 5 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/client/F.ml b/client/F.ml
index a064d0c..5fc2eb8 100644
--- a/client/F.ml
+++ b/client/F.ml
@@ -87,7 +87,7 @@ type ('a, 'b) term =
   | Annot of loc * ('a, 'b) term * ('a, 'b) typ
   | Abs of loc * tevar * ('a, 'b) typ * ('a, 'b) term
   | App of loc * ('a, 'b) term * ('a, 'b) term
-  | Let of loc * tevar * ('a, 'b) typ * ('a, 'b) term * ('a, 'b) term
+  | Let of loc * rec_status * tevar * ('a, 'b) typ * ('a, 'b) term * ('a, 'b) term
   | TyAbs of loc * 'b * ('a, 'b) term
   | TyApp of loc * ('a, 'b) term * ('a, 'b) typ
   | Tuple of loc * ('a, 'b) term list
@@ -99,6 +99,8 @@ type ('a, 'b) term =
   | Refl of loc * ('a,'b) typ
   | Use of loc * ('a,'b) term * ('a,'b) term
 
+and rec_status = Recursive | Non_recursive
+
 and ('a,'b) branch = ('a,'b) pattern * ('a,'b) term
 
 and ('a,'b) pattern =
@@ -222,11 +224,11 @@ module TypeInTerm : DeBruijn.TRAVERSE
         let t1' = trav env t1
         and t2' = trav env t2 in
         App (pos, t1', t2')
-    | Let (pos, x, ty, t1, t2) ->
+    | Let (pos, rec_, x, ty, t1, t2) ->
         let ty' = trav_ty env ty in
         let t1' = trav env t1
         and t2' = trav env t2 in
-        Let (pos, x, ty', t1', t2')
+        Let (pos, rec_, x, ty', t1', t2')
     | TyAbs (pos, x, t) ->
         let env, x = extend env x in
         let t' = trav env t in
diff --git a/client/F.mli b/client/F.mli
index 1ceb0a4..eed4d7f 100644
--- a/client/F.mli
+++ b/client/F.mli
@@ -88,7 +88,7 @@ type ('a, 'b) term =
   | Annot of loc * ('a, 'b) term * ('a, 'b) typ
   | Abs of loc * tevar * ('a, 'b) typ * ('a, 'b) term
   | App of loc * ('a, 'b) term * ('a, 'b) term
-  | Let of loc * tevar * ('a, 'b) typ * ('a, 'b) term * ('a, 'b) term
+  | Let of loc * rec_status * tevar * ('a, 'b) typ * ('a, 'b) term * ('a, 'b) term
   | TyAbs of loc * 'b * ('a, 'b) term
   | TyApp of loc * ('a, 'b) term * ('a, 'b) typ
   | Tuple of loc * ('a, 'b) term list
@@ -100,6 +100,8 @@ type ('a, 'b) term =
   | Refl of loc * ('a,'b) typ
   | Use of loc * ('a,'b) term * ('a,'b) term
 
+and rec_status = Recursive | Non_recursive
+
 and ('a,'b) branch = ('a,'b) pattern * ('a,'b) term
 
 and ('a,'b) pattern =
diff --git a/client/FPrinter.ml b/client/FPrinter.ml
index 21bfcbe..7d5b922 100644
--- a/client/FPrinter.ml
+++ b/client/FPrinter.ml
@@ -61,9 +61,13 @@ let rec translate_term env (t : F.nominal_term) : P.term =
       P.Abs (x_annot, self env t)
   | F.App (_, t1, t2) ->
       P.App (self env t1, self env t2)
-  | F.Let (_, x, ty, t, u) ->
+  | F.Let (_, rec_, x, ty, t, u) ->
+      let rec_ = match rec_ with
+      | F.Recursive -> P.Recursive
+      | F.Non_recursive -> P.Non_recursive
+      in
       let x_annot = P.PAnnot (P.PVar x, annot env ty) in
-      P.Let (P.Non_recursive, x_annot, self env t, self env u)
+      P.Let (rec_, x_annot, self env t, self env u)
   | F.TyAbs (_, x, t) ->
       let alpha = new_tyvar () in
       P.TyAbs (alpha, self ((x, alpha) :: env) t)
diff --git a/client/FTypeChecker.ml b/client/FTypeChecker.ml
index 76f1052..332d1c7 100644
--- a/client/FTypeChecker.ml
+++ b/client/FTypeChecker.ml
@@ -384,10 +384,14 @@ let rec typeof datatype_env env (t : debruijn_term) : debruijn_type =
       let ty1, ty2 = as_arrow ~loc (typeof env t) in
       enforce_equal ~loc env (typeof env u) ty1;
       ty2
-  | Let (loc, x, ty, t, u) ->
-      enforce_equal ~loc env (typeof env t) ty;
-      let env = extend_with_tevar env x ty in
-      typeof env u
+  | Let (loc, rec_, x, ty, t, u) ->
+      let env_with_x = extend_with_tevar env x ty in
+      let def_env = match rec_ with
+        | Non_recursive -> env
+        | Recursive -> env_with_x
+      in
+      enforce_equal ~loc def_env (typeof def_env t) ty;
+      typeof env_with_x u
   | TyAbs (_, (), t) ->
       TyForall ((), typeof (extend_with_tyvar env) t)
   | TyApp (loc, t, ty2) ->
diff --git a/client/Infer.ml b/client/Infer.ml
index 742a71b..0e57b3d 100644
--- a/client/Infer.ml
+++ b/client/Infer.ml
@@ -130,7 +130,7 @@ let flet ~loc (x, ty, t, u) =
   | F.Var (_, y) when smart && x = y ->
       u
   | t ->
-      F.Let (loc, x, ty, t, u)
+      F.Let (loc, F.Non_recursive, x, ty, t, u)
 
 (* -------------------------------------------------------------------------- *)
 
@@ -372,7 +372,7 @@ let hastype (typedecl_env : ML.datatype_env) (t : ML.term) (w : variable) : F.no
          produced. *)
       let sch tyvars =
         List.fold_right (fun alpha sch -> F.TyForall (alpha, sch)) tyvars ty in
-      F.Let (loc, x, sch a, F.ftyabs ~loc a t',
+      F.Let (loc, F.Non_recursive, x, sch a, F.ftyabs ~loc a t',
              flet ~loc (x, sch b, coerce ~loc a b (F.Var (loc, x)),
                         u'))
 
-- 
GitLab