diff --git a/src/whyml/mlw_dexpr.ml b/src/whyml/mlw_dexpr.ml
index 75bc6166257abac924385f040bc61012b8dd2caa..93cddc35895a09e49d5b373d693f174c3b5ac92a 100644
--- a/src/whyml/mlw_dexpr.ml
+++ b/src/whyml/mlw_dexpr.ml
@@ -248,7 +248,7 @@ let specialize_scheme tvs (argl,res) =
   and get_tv tv dity = try Htv.find htv tv with Not_found ->
     let v = dity_fresh () in
     (* can't return dity, might differ in regions *)
-    if Stv.mem tv tvs then dity_unify_weak v dity;
+    if not (Stv.mem tv tvs) then dity_unify_weak v dity;
     Htv.add htv tv v;
     v
   and get_reg tv dity = try Htv.find hreg tv with Not_found ->
@@ -390,7 +390,7 @@ and dexpr_node =
   | DEconst of Number.constant
   | DElet of dlet_defn * dexpr
   | DEfun of dfun_defn * dexpr
-  | DErec of dfun_defn list * dexpr
+  | DErec of drec_defn * dexpr
   | DEif of dexpr * dexpr * dexpr
   | DEcase of dexpr * (dpattern * dexpr) list
   | DEassign of plsymbol * dexpr * dexpr
@@ -416,6 +416,8 @@ and dlet_defn = preid * ghost * dexpr
 
 and dfun_defn = preid * ghost * dbinder list * dexpr * dspec later
 
+and drec_defn = { fds : dfun_defn list }
+
 type dval_decl = preid * ghost * dtype_v
 
 (** Environment *)
@@ -489,31 +491,10 @@ let denv_add_let denv (id,_,{de_dvty = dvty}) =
   denv_add_mono denv id dvty
 
 let denv_add_fun denv (id,_,bl,{de_dvty = (argl,res)},_) =
+  if bl = [] then invalid_arg "Mlw_dexpr.denv_add_fun: empty argument list";
   let argl = List.fold_right (fun (_,_,_,t) l -> t::l) bl argl in
   denv_add_poly denv id (argl, res)
 
-exception DupId of preid
-
-let denv_prepare_rec denv0 l =
-  let add s (id,_,_) =
-    Sstr.add_new (DupId id) id.pre_name s in
-  let _ = try List.fold_left add Sstr.empty l
-    with DupId id -> Loc.errorm ?loc:id.pre_loc
-      "duplicate function name %s" id.pre_name in
-  let add denv (id,bl,res) =
-    let argl = List.map (fun (_,_,_,t) -> t) bl in
-    denv_add_rec denv denv0.frozen id (argl,res) in
-  List.fold_left add denv0 l
-
-let denv_verify_rec { frozen = frozen; locals = locals } id =
-  let check tv = if is_frozen frozen tv then Loc.errorm ?loc:id.pre_loc
-    "This function is expected to be polymorphic in type variable %a"
-    Pretty.print_tv tv in
-  match Mstr.find_opt id.pre_name locals with
-    | Some (Some tvs, _) -> Stv.iter check tvs
-    | Some (None, _) -> assert false
-    | None -> assert false
-
 let denv_add_args { frozen = frozen; locals = locals } bl =
   let l = List.fold_left (fun l (_,_,_,t) -> t::l) frozen bl in
   let add s (id,_,_,t) = match id with
@@ -561,6 +542,39 @@ let dexpr_expected_type_weak {de_dvty = (al,res); de_loc = loc} dity =
     "This expression has type %a,@ but is expected to have type %a"
     print_dity res print_dity dity
 
+(** Generation of letrec blocks *)
+
+type pre_fun_defn =
+  preid * ghost * dbinder list * dity * (denv -> dexpr * dspec later)
+
+exception DupId of preid
+
+let drec_defn denv0 prel =
+  if prel = [] then invalid_arg "Mlw_dexpr.drec_defn: empty function list";
+  let add s (id,_,_,_,_) = Sstr.add_new (DupId id) id.pre_name s in
+  let _ = try List.fold_left add Sstr.empty prel with DupId id ->
+    Loc.errorm ?loc:id.pre_loc "duplicate function name %s" id.pre_name in
+  let add denv (id,_,bl,res,_) =
+    if bl = [] then invalid_arg "Mlw_dexpr.drec_defn: empty argument list";
+    let argl = List.map (fun (_,_,_,t) -> t) bl in
+    denv_add_rec denv denv0.frozen id (argl,res) in
+  let denv1 = List.fold_left add denv0 prel in
+  let parse (id,gh,bl,res,pre) =
+    let de, dsp = pre (denv_add_args denv1 bl) in
+    dexpr_expected_type_weak de res;
+    (id,gh,bl,de,dsp) in
+  let fdl = List.map parse prel in
+  let add denv ((id,_,_,_,_) as fd) =
+    let check tv = if is_frozen denv0.frozen tv then Loc.errorm ?loc:id.pre_loc
+      "This function is expected to be polymorphic in type variable %a"
+      Pretty.print_tv tv in
+    begin match Mstr.find_opt id.pre_name denv1.locals with
+    | Some (Some tvs, _) -> Stv.iter check tvs
+    | Some (None, _) | None -> assert false
+    end;
+    denv_add_fun denv fd in
+  List.fold_left add denv0 fdl, { fds = fdl }
+
 (** Constructors *)
 
 let dpattern ?loc node =
@@ -632,6 +646,8 @@ let dexpr ?loc node =
         [], dity_int
     | DEconst (Number.ConstReal _) ->
         [], dity_real
+    | DEfun ((_,_,[],_,_),_) ->
+        invalid_arg "Mlw_dexpr.dexpr: empty argument list in DEfun"
     | DElet (_,de)
     | DEfun (_,de)
     | DErec (_,de) ->
@@ -642,6 +658,8 @@ let dexpr ?loc node =
         dexpr_expected_type de2 res;
         dexpr_expected_type de3 res;
         de2.de_dvty
+    | DEcase (_,[]) ->
+        invalid_arg "Mlw_dexpr.dexpr: empty branch list in DEcase"
     | DEcase (de,bl) ->
         let ety = dity_fresh () in
         let res = dity_fresh () in
@@ -669,6 +687,8 @@ let dexpr ?loc node =
     | DEraise (xs,de) ->
         dexpr_expected_type de (specialize_xs xs);
         [], dity_fresh ()
+    | DEtry (_,[]) ->
+        invalid_arg "Mlw_dexpr.dexpr: empty branch list in DEtry"
     | DEtry (de,bl) ->
         let res = dity_fresh () in
         dexpr_expected_type de res;
@@ -1225,6 +1245,7 @@ and try_expr keep_loc uloc env (argl,res) node =
       e_ghost (get env de)
   | DEany dtyc ->
       let spec, result = comp_decl env dtyc in
+      (* no invariants on arbitrary computations *)
       e_any spec result
   | DEfun (fd,de) ->
       let fd = expr_fun ~keep_loc uloc env fd in
@@ -1237,7 +1258,7 @@ and try_expr keep_loc uloc env (argl,res) node =
   | DEcast _ | DEuloc _ | DElabel _ ->
       assert false (* already stripped *)
 
-and expr_rec ~keep_loc uloc env dfdl =
+and expr_rec ~keep_loc uloc env {fds = dfdl} =
   let step1 env (id, gh, bl, de, dsp) =
     let pvl = binders bl in
     if fst de.de_dvty <> [] then Loc.errorm ?loc:de.de_loc
diff --git a/src/whyml/mlw_dexpr.mli b/src/whyml/mlw_dexpr.mli
index 96e85ea8a034189685896531af74e93403936d3f..49a8cf436d0bb70f154f5ade627ead3322adaa89 100644
--- a/src/whyml/mlw_dexpr.mli
+++ b/src/whyml/mlw_dexpr.mli
@@ -106,7 +106,7 @@ and dexpr_node =
   | DEconst of Number.constant
   | DElet of dlet_defn * dexpr
   | DEfun of dfun_defn * dexpr
-  | DErec of dfun_defn list * dexpr
+  | DErec of drec_defn * dexpr
   | DEif of dexpr * dexpr * dexpr
   | DEcase of dexpr * (dpattern * dexpr) list
   | DEassign of plsymbol * dexpr * dexpr
@@ -132,6 +132,8 @@ and dlet_defn = preid * ghost * dexpr
 
 and dfun_defn = preid * ghost * dbinder list * dexpr * dspec later
 
+and drec_defn = private { fds : dfun_defn list }
+
 type dval_decl = preid * ghost * dtype_v
 
 (** Environment *)
@@ -146,20 +148,6 @@ val denv_add_let : denv -> dlet_defn -> denv
 
 val denv_add_fun : denv -> dfun_defn -> denv
 
-val denv_prepare_rec : denv -> (preid * dbinder list * dity) list -> denv
-  (* [denv_prepare_rec] adds to the environment the user-supplied
-     types of every function in a (mutually) recursive definition.
-     Functions with fully specified prototypes are generalized in
-     the recursive block (polymorphic recursion), except for the
-     type variables that appear in the upper context. *)
-
-val denv_verify_rec : denv -> preid -> unit
-  (* after a (mutually) recursive definition has been typechecked,
-     [denv_verify_rec] should be called for every function on the
-     [denv] before [denv_prepare_rec]. This function verifies that
-     the resulting functions are not less polymorphic than expected
-     according the user-supplied type annotations. *)
-
 val denv_add_args : denv -> dbinder list -> denv
 
 val denv_add_pat : denv -> dpattern -> denv
@@ -174,6 +162,11 @@ val dpattern : ?loc:Loc.position -> dpattern_node -> dpattern
 
 val dexpr : ?loc:Loc.position -> dexpr_node -> dexpr
 
+type pre_fun_defn =
+  preid * ghost * dbinder list * dity * (denv -> dexpr * dspec later)
+
+val drec_defn : denv -> pre_fun_defn list -> denv * drec_defn
+
 (** Final stage *)
 
 val expr : keep_loc:bool ->
@@ -186,7 +179,7 @@ val fun_defn : keep_loc:bool ->
   Decl.known_map -> Mlw_decl.known_map -> dfun_defn -> fun_defn
 
 val rec_defn : keep_loc:bool ->
-  Decl.known_map -> Mlw_decl.known_map -> dfun_defn list -> fun_defn list
+  Decl.known_map -> Mlw_decl.known_map -> drec_defn -> fun_defn list
 
 val val_decl : keep_loc:bool ->
   Decl.known_map -> Mlw_decl.known_map -> dval_decl -> let_sym