Skip to content

Commit e1ee443

Browse files
authored
Merge pull request #537 from LPCIC/fix-renaming
when renaming, give precedence to recent context entries over old ones
2 parents 2f7f589 + 54e54ad commit e1ee443

File tree

2 files changed

+86
-26
lines changed

2 files changed

+86
-26
lines changed

src/coq_elpi_HOAS.ml

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ let in_coq_fresh ~id_only =
399399
let mk_fresh dbl =
400400
Id.of_string_soft
401401
(Printf.sprintf "elpi_ctx_entry_%d_" dbl) in
402-
fun ~depth dbl name ~coq_ctx:{names}->
402+
fun ~depth dbl name ~names ->
403403
match in_coq_name ~depth name with
404404
| Name.Anonymous when id_only -> Name.Name (mk_fresh dbl)
405405
| Name.Anonymous as x -> x
@@ -409,11 +409,11 @@ fun ~depth dbl name ~coq_ctx:{names}->
409409
let in_coq_annot ~depth t = Context.make_annot (in_coq_name ~depth t) Sorts.Relevant
410410

411411
let in_coq_fresh_annot_name ~depth ~coq_ctx dbl t =
412-
Context.make_annot (in_coq_fresh ~id_only:false ~depth ~coq_ctx dbl t) Sorts.Relevant
412+
Context.make_annot (in_coq_fresh ~id_only:false ~depth ~names:coq_ctx.names dbl t) Sorts.Relevant
413413

414-
let in_coq_fresh_annot_id ~depth ~coq_ctx dbl t =
414+
let in_coq_fresh_annot_id ~depth ~names dbl t =
415415
let get_name = function Name.Name x -> x | Name.Anonymous -> assert false in
416-
Context.make_annot (in_coq_fresh ~id_only:true ~depth ~coq_ctx dbl t |> get_name) Sorts.Relevant
416+
Context.make_annot (in_coq_fresh ~id_only:true ~depth ~names dbl t |> get_name) Sorts.Relevant
417417

418418
let unspec2opt = function Elpi.Builtin.Given x -> Some x | Elpi.Builtin.Unspec -> None
419419
let opt2unspec = function Some x -> Elpi.Builtin.Given x | None -> Elpi.Builtin.Unspec
@@ -874,6 +874,34 @@ module UVMap = struct
874874
let ruv = UVRawMap.elpi ev (S.get UVRawMap.uvmap s) in
875875
f ev ruv uv sol acc)
876876
(S.get UVElabMap.uvmap s) acc
877+
878+
exception Return of Evar.t
879+
880+
let rec morally_same_uvar ~depth uv bo =
881+
match E.look ~depth bo with
882+
| E.Lam x -> morally_same_uvar ~depth:(depth+1) uv x
883+
| E.UnifVar(ev,_) -> F.Elpi.equal ev uv
884+
| _ -> false
885+
886+
let host_upto_assignment f s =
887+
try
888+
UVElabMap.fold (fun ev _ sol _ ->
889+
match sol with
890+
| None -> () (* the fast lookup can only fail if the uvar was instantiated (as is expanded or pruned)*)
891+
| Some sol ->
892+
if f ev sol then raise (Return ev) else ())
893+
(S.get UVElabMap.uvmap s) ();
894+
raise Not_found
895+
with Return a -> a
896+
897+
let host_failsafe elab s =
898+
try
899+
UVElabMap.host elab (S.get UVElabMap.uvmap s)
900+
with Not_found ->
901+
try
902+
UVRawMap.host elab (S.get UVRawMap.uvmap s)
903+
with Not_found ->
904+
host_upto_assignment (fun evar bo -> morally_same_uvar ~depth:0 elab bo) s
877905

878906
let remove_host evar s =
879907
let s = S.update UVRawMap.uvmap s (UVRawMap.remove_host evar) in
@@ -1716,40 +1744,53 @@ let is_global_or_pglobal ~depth t =
17161744
let rec of_elpi_ctx ~calldepth syntactic_constraints depth dbl2ctx state initial_coq_ctx =
17171745

17181746
let aux coq_ctx depth state t =
1719-
lp2constr ~calldepth syntactic_constraints coq_ctx ~depth state t in
1720-
1721-
let of_elpi_ctx_entry dbl coq_ctx ~depth e state =
1747+
lp2constr ~calldepth syntactic_constraints coq_ctx ~depth state t
1748+
in
1749+
let of_elpi_ctx_entry id dbl coq_ctx ~depth e state =
17221750
match e with
1723-
| `Decl(name,ty) ->
1724-
debug Pp.(fun () -> str "decl name: " ++ str(pp2string (P.term depth) name));
1751+
| `Decl(name_hint,ty) ->
1752+
debug Pp.(fun () -> str "decl name (hint/actual): " ++ str(pp2string (P.term depth) name_hint) ++ spc () ++ Id.print (Context.binder_name id));
17251753
debug Pp.(fun () -> str "decl ty: " ++ str(pp2string (P.term depth) ty));
1726-
let id = in_coq_fresh_annot_id ~depth ~coq_ctx dbl name in
17271754
let state, ty, gls = aux coq_ctx depth state ty in
17281755
state, Context.Named.Declaration.LocalAssum(id,ty), gls
1729-
| `Def(name,ty,bo) ->
1730-
debug Pp.(fun () -> str "def name: " ++ str(pp2string (P.term depth) name));
1756+
| `Def(name_hint,ty,bo) ->
1757+
debug Pp.(fun () -> str "def name (hint/actual): " ++ str(pp2string (P.term depth) name_hint) ++ spc () ++ Id.print (Context.binder_name id));
17311758
debug Pp.(fun () -> str "def ty: " ++ str(pp2string (P.term depth) ty));
17321759
debug Pp.(fun () -> str "def bo: " ++ str(pp2string (P.term depth) bo));
1733-
let id = in_coq_fresh_annot_id ~depth ~coq_ctx dbl name in
17341760
let state, ty, gl1 = aux coq_ctx depth state ty in
17351761
let state, bo, gl2 = aux coq_ctx depth state bo in
17361762
state, Context.Named.Declaration.LocalDef(id,bo,ty), gl1 @ gl2
17371763
in
1738-
1739-
let rec ctx_entries coq_ctx state gls i =
1740-
if i = depth then state, coq_ctx, List.(concat (rev gls))
1764+
let of_elpi_ctx_entry_name dbl names ~depth e =
1765+
match e with
1766+
| `Decl(name_hint,_) -> in_coq_fresh_annot_id ~depth ~names dbl name_hint
1767+
| `Def(name_hint,_,_) -> in_coq_fresh_annot_id ~depth ~names dbl name_hint
1768+
in
1769+
let rec build_ctx_entry coq_ctx state gls = function
1770+
| [] -> state, coq_ctx, List.(concat (rev gls))
1771+
| (i,id,d,e) :: rest ->
1772+
debug Pp.(fun () -> str "<<< context entry for DBL "++ int i ++ str" at depth" ++ int d);
1773+
let state, e, gl1 = of_elpi_ctx_entry id i coq_ctx ~depth:d e state in
1774+
debug Pp.(fun () -> str "<<< context entry for DBL "++ int i ++ str" at depth" ++ int d);
1775+
let coq_ctx = push_coq_ctx_proof i e coq_ctx in
1776+
build_ctx_entry coq_ctx state (gl1 :: gls) rest
1777+
in
1778+
(* we go from the bottom (most recent addition) to the top in order to
1779+
give precedence to the name recently introduced *)
1780+
let rec ctx_entries_names names i =
1781+
if i < 0 then []
17411782
else (* context entry for the i-th variable *)
17421783
if not (Int.Map.mem i dbl2ctx)
1743-
then ctx_entries coq_ctx state gls (i+1)
1784+
then ctx_entries_names names (i - 1)
17441785
else
17451786
let d, e = Int.Map.find i dbl2ctx in
1746-
debug Pp.(fun () -> str "<<< context entry for DBL "++ int i ++ str" at depth" ++ int d);
1747-
let state, e, gl1 = of_elpi_ctx_entry i coq_ctx ~depth:d e state in
1748-
debug Pp.(fun () -> str "context entry >>>");
1749-
let coq_ctx = push_coq_ctx_proof i e coq_ctx in
1750-
ctx_entries coq_ctx state (gl1 :: gls) (i+1)
1787+
let id = of_elpi_ctx_entry_name i names ~depth:d e in
1788+
let names = Id.Set.add (Context.binder_name id) names in
1789+
(i,id,d,e) :: ctx_entries_names names (i - 1)
17511790
in
1752-
ctx_entries initial_coq_ctx state [] 0
1791+
ctx_entries_names Id.Set.empty (depth-1) |>
1792+
List.rev |> (* we need to readback the context from top to bottom *)
1793+
build_ctx_entry initial_coq_ctx state []
17531794

17541795
(* ***************************************************************** *)
17551796
(* <-- depth --> *)
@@ -2236,8 +2277,10 @@ let get_goal_ref ~depth syntactic_constraints state t =
22362277
| E.UnifVar(ev,scope) ->
22372278
begin try
22382279
let uv = find_evar ev syntactic_constraints in
2239-
Open {ctx; evar = UVMap.host uv state; scope; args = U.lp_list_to_list ~depth i}
2240-
with Not_found -> Not_a_goal
2280+
let evar = UVMap.host_failsafe uv state in
2281+
Open {ctx; evar; scope; args = U.lp_list_to_list ~depth i}
2282+
with Not_found ->
2283+
Not_a_goal
22412284
end
22422285
| _ -> Closed_by_side_effect
22432286
end
@@ -3362,7 +3405,8 @@ let get_global_env_current_sigma ~depth hyps constraints state =
33623405

33633406
let lp2goal ~depth hyps syntactic_constraints state t =
33643407
match get_goal_ref ~depth (E.constraints syntactic_constraints) state t with
3365-
| Closed_by_side_effect | Not_a_goal -> assert false
3408+
| Closed_by_side_effect -> assert false
3409+
| Not_a_goal -> assert false
33663410
| Open {ctx; evar = k; scope; args} ->
33673411
let state, _, changed, gl1 =
33683412
elpi_solution_to_coq_solution ~calldepth:depth syntactic_constraints state in

tests/test_tactic.v

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
From elpi Require Import elpi.
22

3+
Elpi Tactic double_open.
4+
Elpi Accumulate lp:{{
5+
solve (goal _Ctx _Trigger Type _Proof [] as G) GL :-
6+
@no-tc! => refine {{ id _ }} G [G2],
7+
coq.ltac.open (refine {{ id _ }}) G2 GL,
8+
coq.say G2.
9+
}}.
10+
Elpi Typecheck.
11+
12+
Lemma foo (P : Prop) :
13+
P -> P.
14+
Proof.
15+
elpi double_open.
16+
match goal with |- P -> P => idtac end. (* no renaming *)
17+
Abort.
18+
319
Elpi Command foo.
420
Elpi Print foo.
521
Elpi Tactic foobar.

0 commit comments

Comments
 (0)