@@ -259,6 +259,7 @@ type nontac_expr =
259259 | PrjV of nontac_expr * int (* non-mutable projection *)
260260 | Prim of ml_tactic_name
261261 | ValLetNoRec of (Name .t * nontac_expr ) list * nontac_expr
262+ | ValLetRec of (Id .t * (Name .t list * tac_expr )) list * nontac_expr
262263
263264(* * evaluates to a valexpr tactic *)
264265and tac_expr_head =
@@ -450,11 +451,11 @@ let rec is_nontac = function
450451 | GTacPrj (typ , sube , i ) ->
451452 not (is_mutable_proj typ i) && is_nontac sube
452453
453- | GTacLet (false , bnd , e ) ->
454+ | GTacLet (_ , bnd , e ) ->
454455 List. for_all (fun (_ , e ) -> is_nontac e) bnd
455456 && is_nontac e
456457
457- | GTacApp _ | GTacLet ( true , _, _) | GTacCse _
458+ | GTacApp _ | GTacCse _
458459 | GTacSet _ | GTacWth _ | GTacFullMatch _
459460 | GTacExt _
460461 -> false
@@ -495,6 +496,12 @@ let rec nontac_expr env ((cnt, nonvals) as acc) e = match e with
495496 acc, Ref (LocalKn (" Tac2compiledPrim." ^ ml.mltac_tactic, info))
496497 end
497498
499+ | GTacLet (true , bnd , sube ) when is_nontac e ->
500+ let envbnd, lets = letrec_bnd env bnd in
501+ let acc', sube = nontac_expr envbnd acc sube in
502+ assert (acc' == acc);
503+ acc, ValLetRec (lets, sube)
504+
498505 | GTacLet (false , bnd , sube ) when is_nontac e ->
499506 let envbnd, nas' = push_env push_user_names (List. map fst bnd) Valexpr env in
500507 let bnd = List. map2 (fun (_ , e ) na' ->
@@ -544,36 +551,16 @@ and tac_expr env e =
544551 let acc, args = List. fold_left_map (nontac_expr env) acc args in
545552 acc, App (h, args)
546553
547- | GTacLet (true , lets , e ) ->
548- let lets = lets |> List. filter_map (fun (na , e ) ->
549- match e with
550- | GTacFun (bnd , e ) ->
551- begin match na with
552- | Anonymous ->
553- (* "let rec _ := ..." seems good for nothing, just a syntax curiosity
554- lambda abstraction can't have effects so just drop it *)
555- None
556- | Name na ->
557- Some (na, (bnd, e))
558- end
559- | _ -> assert false )
560- in
561- let env, nas' =
562- List. fold_left_map (fun env (na , (bnd , _ )) ->
563- push_env push_user_id na (Function {arity= List. length bnd}) env)
564- env lets
565- in
566- let lets = List. map2 (fun (_ , (bnd , e )) na' ->
567- let env, bnd = push_env push_user_names bnd Valexpr env in
568- let e = tac_expr env e in
569- (na', (bnd, e)))
570- lets
571- nas'
572- in
573- let e = tac_expr env e in
574- acc, LetRec (lets, e)
554+ | GTacLet (true , lets , sube ) ->
555+ if is_nontac e then
556+ let acc', e = nontac_expr env acc e in
557+ assert (acc == acc');
558+ acc, Return e
559+ else
560+ let env, lets = letrec_bnd env lets in
561+ let sube = tac_expr env sube in
562+ acc, LetRec (lets, sube)
575563
576- (* XXX detect when a let can be nontac_expr *)
577564 | GTacLet (false , bnd , sube ) ->
578565 if is_nontac e then
579566 let acc', e = nontac_expr env acc e in
@@ -650,6 +637,34 @@ and tac_expr env e =
650637 { spilled_exprs = nonvals;
651638 head_expr = e; }
652639
640+ and letrec_bnd env lets =
641+ let lets = lets |> List. filter_map (fun (na , e ) ->
642+ match e with
643+ | GTacFun (bnd , e ) ->
644+ begin match na with
645+ | Anonymous ->
646+ (* "let rec _ := ..." seems good for nothing, just a syntax curiosity
647+ lambda abstraction can't have effects so just drop it *)
648+ None
649+ | Name na ->
650+ Some (na, (bnd, e))
651+ end
652+ | _ -> assert false )
653+ in
654+ let env, nas' =
655+ List. fold_left_map (fun env (na , (bnd , _ )) ->
656+ push_env push_user_id na (Function {arity= List. length bnd}) env)
657+ env lets
658+ in
659+ let lets = List. map2 (fun (_ , (bnd , e )) na' ->
660+ let env, bnd = push_env push_user_names bnd Valexpr env in
661+ let e = tac_expr env e in
662+ (na', (bnd, e)))
663+ lets
664+ nas'
665+ in
666+ env, lets
667+
653668let nontac_expr env state acc e =
654669 let state = ref state in
655670 let acc, e = nontac_expr {env;state} acc e in
@@ -799,7 +814,16 @@ let rec pp_nontac_expr = function
799814 str " in" ++ spc() ++
800815 pp_nontac_expr e ++
801816 str " )" )
802-
817+ | ValLetRec (lets , e ) ->
818+ let pr_one_let (na , (bnd , e )) =
819+ hov 1 (Id. print na ++ pp_binders bnd ++ str " =" ) ++ spc () ++
820+ pp_expr e ++ spc()
821+ in
822+ surround
823+ (hv 0
824+ (str " let rec " ++ prlist_with_sep (fun () -> str " and " ) pr_one_let lets ++
825+ str " in" ++ spc() ) ++
826+ pp_nontac_expr e)
803827
804828(* produce a ocaml term of type valexpr tactic *)
805829and pp_expr e =
0 commit comments