Skip to content

Commit

Permalink
Tac2externals: wrap last application of the closure to make it pure
Browse files Browse the repository at this point in the history
otherwise it can be quite footgunny (even though it's hard to get a
visible bug without the ltac2 compiler), for instance the current
implementation of Array.set is incorrect without this.

See also SkySkimmer/coq-ltac2-compiler#17
and https://coq.zulipchat.com/#narrow/stream/278935-Ltac2/topic/thunking.20and.20.60thaw.60
  • Loading branch information
SkySkimmer committed Dec 19, 2023
1 parent 9ac72c5 commit 641ee19
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
7 changes: 5 additions & 2 deletions plugins/ltac2/tac2externals.ml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ let define : type v f. _ -> (v,f) spec -> f -> unit = fun n ar v ->
match ar with
| S (V tr) -> tr v
| S (F _) ->
let cl = Tac2ffi.mk_closure (arity_of ar) (interp_spec ar v) in
Tac2ffi.of_closure cl
let arity = arity_of ar in
let v = interp_spec ar v in
let v = Tac2ffi.purify_closure arity v in
let cl = Tac2ffi.mk_closure arity v in
Tac2ffi.of_closure cl
| _ -> invalid_arg "Tac2def.define: not a pure value"
in
Tac2env.define_primitive n v
5 changes: 5 additions & 0 deletions plugins/ltac2/tac2ffi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,8 @@ let app_fun1 cls r0 r1 x =
let annotate_closure fr (MLTactic (arity, fr0, f)) =
assert (Option.is_empty fr0);
MLTactic (arity, Some fr, f)

let rec purify_closure : type a. a arity -> a -> a = fun arity f ->
match arity with
| OneAty -> (fun x -> Proofview.tclUNIT () >>= fun () -> f x)
| AddAty a -> (fun x -> purify_closure a (f x))
7 changes: 7 additions & 0 deletions plugins/ltac2/tac2ffi.mli
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,19 @@ val arity_one : (valexpr -> valexpr Proofview.tactic) arity
val arity_suc : 'a arity -> (valexpr -> 'a) arity

val mk_closure : 'v arity -> 'v -> closure
(** The arrows in ['v] should be pure. Use [tclLIFT] or do
[tclUNIT () >>= fun () -> f args] when you need effects. *)

val mk_closure_val : 'v arity -> 'v -> valexpr
(** Composition of [mk_closure] and [ValCls] *)

val annotate_closure : Tac2expr.frame -> closure -> closure
(** The closure must not be already annotated *)

val purify_closure : 'v arity -> 'v -> 'v
(** For internal use (Tac2externals). Wraps the last application of the ['v] argument
to make it pure. *)

module Valexpr :
sig
type t = valexpr
Expand Down

0 comments on commit 641ee19

Please sign in to comment.