diff options
Diffstat (limited to 'tactics/extratactics.ml4')
-rw-r--r-- | tactics/extratactics.ml4 | 730 |
1 files changed, 467 insertions, 263 deletions
diff --git a/tactics/extratactics.ml4 b/tactics/extratactics.ml4 index 6fd95f16..f3482c31 100644 --- a/tactics/extratactics.ml4 +++ b/tactics/extratactics.ml4 @@ -1,26 +1,29 @@ (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) -(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2014 *) +(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2015 *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) -(*i camlp4deps: "parsing/grammar.cma" i*) +(*i camlp4deps: "grammar/grammar.cma" i*) open Pp -open Pcoq open Genarg open Extraargs open Mod_subst open Names open Tacexpr -open Glob_term +open Glob_ops open Tactics +open Errors open Util open Evd open Equality -open Compat +open Misctypes +open Proofview.Notations + +DECLARE PLUGIN "extratactics" (**********************************************************************) (* admit, replace, discriminate, injection, simplify_eq *) @@ -30,76 +33,46 @@ TACTIC EXTEND admit [ "admit" ] -> [ admit_as_an_axiom ] END - - -let classes_dirpath = - make_dirpath (List.map id_of_string ["Classes";"Coq"]) - -let init_setoid () = - if Libnames.is_dirpath_prefix_of classes_dirpath (Lib.cwd ()) then () - else Coqlib.check_required_library ["Coq";"Setoids";"Setoid"] - - -let occurrences_of occs = - let loccs = match occs with - | n::_ as nl when n < 0 -> (false,List.map (fun n -> ArgArg (abs n)) nl) - | nl -> - if List.exists (fun n -> n < 0) nl then - error "Illegal negative occurrence number."; - (true, List.map (fun n -> (ArgArg n)) nl) - in - init_setoid (); - {onhyps = Some []; concl_occs =loccs} - -let replace_in_clause_maybe_by (sigma1,c1) c2 cl tac = - Refiner.tclWITHHOLES false +let replace_in_clause_maybe_by (sigma,c1) c2 cl tac = + Proofview.Unsafe.tclEVARS sigma <*> (replace_in_clause_maybe_by c1 c2 cl) - sigma1 (Option.map Tacinterp.eval_tactic tac) -let replace_multi_term dir_opt (sigma,c) in_hyp = - Refiner.tclWITHHOLES false - (replace_multi_term dir_opt c) - sigma - (glob_in_arg_hyp_to_clause in_hyp) +let replace_term dir_opt (sigma,c) cl = + Proofview.Unsafe.tclEVARS sigma <*> + (replace_term dir_opt c) cl TACTIC EXTEND replace - ["replace" open_constr(c1) "with" constr(c2) in_arg_hyp(in_hyp) by_arg_tac(tac) ] --> [ replace_in_clause_maybe_by c1 c2 (glob_in_arg_hyp_to_clause in_hyp) tac ] -END - -TACTIC EXTEND replace_at - ["replace" open_constr(c1) "with" constr(c2) "at" occurrences(occs) by_arg_tac(tac) ] --> [ replace_in_clause_maybe_by c1 c2 (occurrences_of occs) tac ] + ["replace" open_constr(c1) "with" constr(c2) clause(cl) by_arg_tac(tac) ] +-> [ replace_in_clause_maybe_by c1 c2 cl tac ] END - TACTIC EXTEND replace_term_left - [ "replace" "->" open_constr(c) in_arg_hyp(in_hyp) ] - -> [ replace_multi_term (Some true) c in_hyp] + [ "replace" "->" open_constr(c) clause(cl) ] + -> [ replace_term (Some true) c cl ] END TACTIC EXTEND replace_term_right - [ "replace" "<-" open_constr(c) in_arg_hyp(in_hyp) ] - -> [replace_multi_term (Some false) c in_hyp] + [ "replace" "<-" open_constr(c) clause(cl) ] + -> [ replace_term (Some false) c cl ] END TACTIC EXTEND replace_term - [ "replace" open_constr(c) in_arg_hyp(in_hyp) ] - -> [ replace_multi_term None c in_hyp ] + [ "replace" open_constr(c) clause(cl) ] + -> [ replace_term None c cl ] END let induction_arg_of_quantified_hyp = function - | AnonHyp n -> ElimOnAnonHyp n - | NamedHyp id -> ElimOnIdent (Util.dummy_loc,id) + | AnonHyp n -> None,ElimOnAnonHyp n + | NamedHyp id -> None,ElimOnIdent (Loc.ghost,id) (* Versions *_main must come first!! so that "1" is interpreted as a ElimOnAnonHyp and not as a "constr", and "id" is interpreted as a ElimOnIdent and not as "constr" *) let elimOnConstrWithHoles tac with_evars c = - Refiner.tclWITHHOLES with_evars (tac with_evars) - c.sigma (Some (ElimOnConstr c.it)) + Tacticals.New.tclWITHHOLES with_evars (tac with_evars) + c.sigma (Some (None,ElimOnConstr c.it)) TACTIC EXTEND simplify_eq_main | [ "simplify_eq" constr_with_bindings(c) ] -> @@ -120,9 +93,11 @@ TACTIC EXTEND esimplify_eq [ dEq true (Some (induction_arg_of_quantified_hyp h)) ] END +let discr_main c = elimOnConstrWithHoles discr_tac false c + TACTIC EXTEND discriminate_main | [ "discriminate" constr_with_bindings(c) ] -> - [ elimOnConstrWithHoles discr_tac false c ] + [ discr_main c ] END TACTIC EXTEND discriminate | [ "discriminate" ] -> [ discr_tac false None ] @@ -139,49 +114,55 @@ TACTIC EXTEND ediscriminate [ discr_tac true (Some (induction_arg_of_quantified_hyp h)) ] END -let h_discrHyp id gl = - h_discriminate_main {it = Term.mkVar id,NoBindings; sigma = Refiner.project gl} gl +open Proofview.Notations +let discrHyp id = + Proofview.tclEVARMAP >>= fun sigma -> + discr_main {it = Term.mkVar id,NoBindings; sigma = sigma;} + +let injection_main c = + elimOnConstrWithHoles (injClause None) false c TACTIC EXTEND injection_main | [ "injection" constr_with_bindings(c) ] -> - [ elimOnConstrWithHoles (injClause []) false c ] + [ injection_main c ] END TACTIC EXTEND injection -| [ "injection" ] -> [ injClause [] false None ] +| [ "injection" ] -> [ injClause None false None ] | [ "injection" quantified_hypothesis(h) ] -> - [ injClause [] false (Some (induction_arg_of_quantified_hyp h)) ] + [ injClause None false (Some (induction_arg_of_quantified_hyp h)) ] END TACTIC EXTEND einjection_main | [ "einjection" constr_with_bindings(c) ] -> - [ elimOnConstrWithHoles (injClause []) true c ] + [ elimOnConstrWithHoles (injClause None) true c ] END TACTIC EXTEND einjection -| [ "einjection" ] -> [ injClause [] true None ] -| [ "einjection" quantified_hypothesis(h) ] -> [ injClause [] true (Some (induction_arg_of_quantified_hyp h)) ] +| [ "einjection" ] -> [ injClause None true None ] +| [ "einjection" quantified_hypothesis(h) ] -> [ injClause None true (Some (induction_arg_of_quantified_hyp h)) ] END TACTIC EXTEND injection_as_main | [ "injection" constr_with_bindings(c) "as" simple_intropattern_list(ipat)] -> - [ elimOnConstrWithHoles (injClause ipat) false c ] + [ elimOnConstrWithHoles (injClause (Some ipat)) false c ] END TACTIC EXTEND injection_as | [ "injection" "as" simple_intropattern_list(ipat)] -> - [ injClause ipat false None ] + [ injClause (Some ipat) false None ] | [ "injection" quantified_hypothesis(h) "as" simple_intropattern_list(ipat) ] -> - [ injClause ipat false (Some (induction_arg_of_quantified_hyp h)) ] + [ injClause (Some ipat) false (Some (induction_arg_of_quantified_hyp h)) ] END TACTIC EXTEND einjection_as_main | [ "einjection" constr_with_bindings(c) "as" simple_intropattern_list(ipat)] -> - [ elimOnConstrWithHoles (injClause ipat) true c ] + [ elimOnConstrWithHoles (injClause (Some ipat)) true c ] END TACTIC EXTEND einjection_as | [ "einjection" "as" simple_intropattern_list(ipat)] -> - [ injClause ipat true None ] + [ injClause (Some ipat) true None ] | [ "einjection" quantified_hypothesis(h) "as" simple_intropattern_list(ipat) ] -> - [ injClause ipat true (Some (induction_arg_of_quantified_hyp h)) ] + [ injClause (Some ipat) true (Some (induction_arg_of_quantified_hyp h)) ] END -let h_injHyp id gl = - h_injection_main { it = Term.mkVar id,NoBindings; sigma = Refiner.project gl } gl +let injHyp id = + Proofview.tclEVARMAP >>= fun sigma -> + injection_main { it = Term.mkVar id,NoBindings; sigma = sigma; } TACTIC EXTEND dependent_rewrite | [ "dependent" "rewrite" orient(b) constr(c) ] -> [ rewriteInConcl b c ] @@ -189,6 +170,10 @@ TACTIC EXTEND dependent_rewrite -> [ rewriteInHyp b c id ] END +(** To be deprecated?, "cutrewrite (t=u) as <-" is equivalent to + "replace u with t" or "enough (t=u) as <-" and + "cutrewrite (t=u) as ->" is equivalent to "enough (t=u) as ->". *) + TACTIC EXTEND cut_rewrite | [ "cutrewrite" orient(b) constr(eqn) ] -> [ cutRewriteInConcl b eqn ] | [ "cutrewrite" orient(b) constr(eqn) "in" hyp(id) ] @@ -196,6 +181,17 @@ TACTIC EXTEND cut_rewrite END (**********************************************************************) +(* Decompose *) + +TACTIC EXTEND decompose_sum +| [ "decompose" "sum" constr(c) ] -> [ Elim.h_decompose_or c ] +END + +TACTIC EXTEND decompose_record +| [ "decompose" "record" constr(c) ] -> [ Elim.h_decompose_and c ] +END + +(**********************************************************************) (* Contradiction *) open Contradiction @@ -206,7 +202,7 @@ END let onSomeWithHoles tac = function | None -> tac None - | Some c -> Refiner.tclWITHHOLES false tac c.sigma (Some c.it) + | Some c -> Proofview.Unsafe.tclEVARS c.sigma <*> tac (Some c.it) TACTIC EXTEND contradiction [ "contradiction" constr_with_bindings_opt(c) ] -> @@ -230,22 +226,19 @@ ARGUMENT EXTEND orient_string TYPED AS (bool * string) PRINTED BY pr_orient_stri END TACTIC EXTEND autorewrite -| [ "autorewrite" "with" ne_preident_list(l) in_arg_hyp(cl) ] -> - [ auto_multi_rewrite l (glob_in_arg_hyp_to_clause cl) ] -| [ "autorewrite" "with" ne_preident_list(l) in_arg_hyp(cl) "using" tactic(t) ] -> +| [ "autorewrite" "with" ne_preident_list(l) clause(cl) ] -> + [ auto_multi_rewrite l ( cl) ] +| [ "autorewrite" "with" ne_preident_list(l) clause(cl) "using" tactic(t) ] -> [ - let cl = glob_in_arg_hyp_to_clause cl in auto_multi_rewrite_with (Tacinterp.eval_tactic t) l cl - ] END TACTIC EXTEND autorewrite_star -| [ "autorewrite" "*" "with" ne_preident_list(l) in_arg_hyp(cl) ] -> - [ auto_multi_rewrite ~conds:AllMatches l (glob_in_arg_hyp_to_clause cl) ] -| [ "autorewrite" "*" "with" ne_preident_list(l) in_arg_hyp(cl) "using" tactic(t) ] -> - [ let cl = glob_in_arg_hyp_to_clause cl in - auto_multi_rewrite_with ~conds:AllMatches (Tacinterp.eval_tactic t) l cl ] +| [ "autorewrite" "*" "with" ne_preident_list(l) clause(cl) ] -> + [ auto_multi_rewrite ~conds:AllMatches l cl ] +| [ "autorewrite" "*" "with" ne_preident_list(l) clause(cl) "using" tactic(t) ] -> + [ auto_multi_rewrite_with ~conds:AllMatches (Tacinterp.eval_tactic t) l cl ] END (**********************************************************************) @@ -253,15 +246,8 @@ END let rewrite_star clause orient occs (sigma,c) (tac : glob_tactic_expr option) = let tac' = Option.map (fun t -> Tacinterp.eval_tactic t, FirstSolved) tac in - Refiner. tclWITHHOLES false - (general_rewrite_ebindings_clause clause orient occs ?tac:tac' true true (c,NoBindings)) sigma true - -let occurrences_of = function - | n::_ as nl when n < 0 -> (false,List.map abs nl) - | nl -> - if List.exists (fun n -> n < 0) nl then - error "Illegal negative occurrence number."; - (true,nl) + Proofview.Unsafe.tclEVARS sigma <*> + general_rewrite_ebindings_clause clause orient occs ?tac:tac' true true (c,NoBindings) true TACTIC EXTEND rewrite_star | [ "rewrite" "*" orient(o) open_constr(c) "in" hyp(id) "at" occurrences(occ) by_arg_tac(tac) ] -> @@ -269,45 +255,62 @@ TACTIC EXTEND rewrite_star | [ "rewrite" "*" orient(o) open_constr(c) "at" occurrences(occ) "in" hyp(id) by_arg_tac(tac) ] -> [ rewrite_star (Some id) o (occurrences_of occ) c tac ] | [ "rewrite" "*" orient(o) open_constr(c) "in" hyp(id) by_arg_tac(tac) ] -> - [ rewrite_star (Some id) o Termops.all_occurrences c tac ] + [ rewrite_star (Some id) o Locus.AllOccurrences c tac ] | [ "rewrite" "*" orient(o) open_constr(c) "at" occurrences(occ) by_arg_tac(tac) ] -> [ rewrite_star None o (occurrences_of occ) c tac ] | [ "rewrite" "*" orient(o) open_constr(c) by_arg_tac(tac) ] -> - [ rewrite_star None o Termops.all_occurrences c tac ] + [ rewrite_star None o Locus.AllOccurrences c tac ] END (**********************************************************************) (* Hint Rewrite *) -let add_rewrite_hint name ort t lcsr = +let add_rewrite_hint bases ort t lcsr = let env = Global.env() and sigma = Evd.empty in - let f c = Topconstr.constr_loc c, Constrintern.interp_constr sigma env c, ort, t in - add_rew_rules name (List.map f lcsr) - -VERNAC COMMAND EXTEND HintRewrite - [ "Hint" "Rewrite" orient(o) ne_constr_list(l) ":" preident(b) ] -> - [ add_rewrite_hint b o (Tacexpr.TacId []) l ] + let poly = Flags.is_universe_polymorphism () in + let f ce = + let c, ctx = Constrintern.interp_constr env sigma ce in + let ctx = + if poly then + Evd.evar_universe_context_set ctx + else + let cstrs = Evd.evar_universe_context_constraints ctx in + (Global.add_constraints cstrs; Univ.ContextSet.empty) + in + Constrexpr_ops.constr_loc ce, (c, ctx), ort, t in + let eqs = List.map f lcsr in + let add_hints base = add_rew_rules base eqs in + List.iter add_hints bases + +let classify_hint _ = Vernacexpr.VtSideff [], Vernacexpr.VtLater + +VERNAC COMMAND EXTEND HintRewrite CLASSIFIED BY classify_hint + [ "Hint" "Rewrite" orient(o) ne_constr_list(l) ":" preident_list(bl) ] -> + [ add_rewrite_hint bl o None l ] | [ "Hint" "Rewrite" orient(o) ne_constr_list(l) "using" tactic(t) - ":" preident(b) ] -> - [ add_rewrite_hint b o t l ] + ":" preident_list(bl) ] -> + [ add_rewrite_hint bl o (Some t) l ] | [ "Hint" "Rewrite" orient(o) ne_constr_list(l) ] -> - [ add_rewrite_hint "core" o (Tacexpr.TacId []) l ] + [ add_rewrite_hint ["core"] o None l ] | [ "Hint" "Rewrite" orient(o) ne_constr_list(l) "using" tactic(t) ] -> - [ add_rewrite_hint "core" o t l ] + [ add_rewrite_hint ["core"] o (Some t) l ] END (**********************************************************************) (* Hint Resolve *) open Term +open Vars open Coqlib -let project_hint pri l2r c = +let project_hint pri l2r r = + let gr = Smartlocate.global_with_alias r in let env = Global.env() in - let c = Constrintern.interp_constr Evd.empty env c in - let t = Retyping.get_type_of env Evd.empty c in + let sigma = Evd.from_env env in + let sigma, c = Evd.fresh_global env sigma gr in + let t = Retyping.get_type_of env sigma c in let t = - Tacred.reduce_to_quantified_ref env Evd.empty (Lazy.force coq_iff_ref) t in + Tacred.reduce_to_quantified_ref env sigma (Lazy.force coq_iff_ref) t in let sign,ccl = decompose_prod_assum t in let (a,b) = match snd (decompose_app ccl) with | [a;b] -> (a,b) @@ -317,82 +320,91 @@ let project_hint pri l2r c = let c = Reductionops.whd_beta Evd.empty (mkApp (c,Termops.extended_rel_vect 0 sign)) in let c = it_mkLambda_or_LetIn (mkApp (p,[|mkArrow a (lift 1 b);mkArrow b (lift 1 a);c|])) sign in - (pri,true,Auto.PathAny,c) + let id = + Nameops.add_suffix (Nametab.basename_of_global gr) ("_proj_" ^ (if l2r then "l2r" else "r2l")) + in + let ctx = Evd.universe_context_set sigma in + let c = Declare.declare_definition ~internal:Declare.KernelSilent id (c,ctx) in + (pri,false,true,Hints.PathAny, Hints.IsGlobRef (Globnames.ConstRef c)) let add_hints_iff l2r lc n bl = - Auto.add_hints true bl - (Auto.HintsResolveEntry (List.map (project_hint n l2r) lc)) + Hints.add_hints true bl + (Hints.HintsResolveEntry (List.map (project_hint n l2r) lc)) -VERNAC COMMAND EXTEND HintResolveIffLR - [ "Hint" "Resolve" "->" ne_constr_list(lc) natural_opt(n) +VERNAC COMMAND EXTEND HintResolveIffLR CLASSIFIED AS SIDEFF + [ "Hint" "Resolve" "->" ne_global_list(lc) natural_opt(n) ":" preident_list(bl) ] -> [ add_hints_iff true lc n bl ] -| [ "Hint" "Resolve" "->" ne_constr_list(lc) natural_opt(n) ] -> +| [ "Hint" "Resolve" "->" ne_global_list(lc) natural_opt(n) ] -> [ add_hints_iff true lc n ["core"] ] END -VERNAC COMMAND EXTEND HintResolveIffRL - [ "Hint" "Resolve" "<-" ne_constr_list(lc) natural_opt(n) +VERNAC COMMAND EXTEND HintResolveIffRL CLASSIFIED AS SIDEFF + [ "Hint" "Resolve" "<-" ne_global_list(lc) natural_opt(n) ":" preident_list(bl) ] -> [ add_hints_iff false lc n bl ] -| [ "Hint" "Resolve" "<-" ne_constr_list(lc) natural_opt(n) ] -> +| [ "Hint" "Resolve" "<-" ne_global_list(lc) natural_opt(n) ] -> [ add_hints_iff false lc n ["core"] ] END (**********************************************************************) (* Refine *) -open Refine +let refine_tac {Glob_term.closure=closure;term=term} = + Proofview.Goal.nf_enter begin fun gl -> + let concl = Proofview.Goal.concl gl in + let env = Proofview.Goal.env gl in + let flags = Pretyping.all_no_fail_flags in + let tycon = Pretyping.OfType concl in + let lvar = { Pretyping.empty_lvar with + Pretyping.ltac_constrs = closure.Glob_term.typed; + Pretyping.ltac_uconstrs = closure.Glob_term.untyped; + Pretyping.ltac_idents = closure.Glob_term.idents; + } in + let update evd = Pretyping.understand_ltac flags env evd lvar tycon term in + Tactics.New.refine ~unsafe:false update + end TACTIC EXTEND refine - [ "refine" casted_open_constr(c) ] -> [ refine c ] + [ "refine" uconstr(c) ] -> [ refine_tac c ] END -let refine_tac = h_refine - (**********************************************************************) (* Inversion lemmas (Leminv) *) open Inv open Leminv -VERNAC COMMAND EXTEND DeriveInversionClear - [ "Derive" "Inversion_clear" ident(na) hyp(id) ] - -> [ inversion_lemma_from_goal 1 na id Term.prop_sort false inv_clear_tac ] - -| [ "Derive" "Inversion_clear" natural(n) ident(na) hyp(id) ] - -> [ inversion_lemma_from_goal n na id Term.prop_sort false inv_clear_tac ] +let seff id = Vernacexpr.VtSideff [id], Vernacexpr.VtLater +VERNAC COMMAND EXTEND DeriveInversionClear | [ "Derive" "Inversion_clear" ident(na) "with" constr(c) "Sort" sort(s) ] + => [ seff na ] -> [ add_inversion_lemma_exn na c s false inv_clear_tac ] -| [ "Derive" "Inversion_clear" ident(na) "with" constr(c) ] - -> [ add_inversion_lemma_exn na c (Glob_term.GProp Term.Null) false inv_clear_tac ] +| [ "Derive" "Inversion_clear" ident(na) "with" constr(c) ] => [ seff na ] + -> [ add_inversion_lemma_exn na c GProp false inv_clear_tac ] END open Term -open Glob_term VERNAC COMMAND EXTEND DeriveInversion | [ "Derive" "Inversion" ident(na) "with" constr(c) "Sort" sort(s) ] + => [ seff na ] -> [ add_inversion_lemma_exn na c s false inv_tac ] -| [ "Derive" "Inversion" ident(na) "with" constr(c) ] - -> [ add_inversion_lemma_exn na c (GProp Null) false inv_tac ] - -| [ "Derive" "Inversion" ident(na) hyp(id) ] - -> [ inversion_lemma_from_goal 1 na id Term.prop_sort false inv_tac ] - -| [ "Derive" "Inversion" natural(n) ident(na) hyp(id) ] - -> [ inversion_lemma_from_goal n na id Term.prop_sort false inv_tac ] +| [ "Derive" "Inversion" ident(na) "with" constr(c) ] => [ seff na ] + -> [ add_inversion_lemma_exn na c GProp false inv_tac ] END VERNAC COMMAND EXTEND DeriveDependentInversion | [ "Derive" "Dependent" "Inversion" ident(na) "with" constr(c) "Sort" sort(s) ] + => [ seff na ] -> [ add_inversion_lemma_exn na c s true dinv_tac ] - END +END VERNAC COMMAND EXTEND DeriveDependentInversionClear | [ "Derive" "Dependent" "Inversion_clear" ident(na) "with" constr(c) "Sort" sort(s) ] + => [ seff na ] -> [ add_inversion_lemma_exn na c s true dinv_clear_tac ] END @@ -401,14 +413,14 @@ END TACTIC EXTEND subst | [ "subst" ne_var_list(l) ] -> [ subst l ] -| [ "subst" ] -> [ fun gl -> subst_all gl ] +| [ "subst" ] -> [ subst_all () ] END let simple_subst_tactic_flags = { only_leibniz = true; rewrite_dependent_proof = false } TACTIC EXTEND simple_subst -| [ "simple" "subst" ] -> [ subst_all ~flags:simple_subst_tactic_flags ] +| [ "simple" "subst" ] -> [ subst_all ~flags:simple_subst_tactic_flags () ] END open Evar_tactics @@ -416,29 +428,28 @@ open Evar_tactics (**********************************************************************) (* Evar creation *) +(* TODO: add support for some test similar to g_constr.name_colon so that + expressions like "evar (list A)" do not raise a syntax error *) TACTIC EXTEND evar [ "evar" "(" ident(id) ":" lconstr(typ) ")" ] -> [ let_evar (Name id) typ ] | [ "evar" constr(typ) ] -> [ let_evar Anonymous typ ] END -open Tacexpr open Tacticals TACTIC EXTEND instantiate - [ "instantiate" "(" integer(i) ":=" glob(c) ")" hloc(hl) ] -> - [instantiate i c hl ] -| [ "instantiate" ] -> [ tclNORMEVAR ] + [ "instantiate" "(" ident(id) ":=" lglob(c) ")" ] -> + [ Tacticals.New.tclTHEN (instantiate_tac_by_name id c) Proofview.V82.nf_evar_goals ] +| [ "instantiate" "(" integer(i) ":=" lglob(c) ")" hloc(hl) ] -> + [ Tacticals.New.tclTHEN (instantiate_tac i c hl) Proofview.V82.nf_evar_goals ] +| [ "instantiate" ] -> [ Proofview.V82.nf_evar_goals ] END - (**********************************************************************) (** Nijmegen "step" tactic for setoid rewriting *) open Tactics -open Tactics -open Libnames open Glob_term -open Summary open Libobject open Lib @@ -447,8 +458,8 @@ open Lib x R y -> x == z -> z R y (in the left table) *) -let transitivity_right_table = ref [] -let transitivity_left_table = ref [] +let transitivity_right_table = Summary.ref [] ~name:"transitivity-steps-r" +let transitivity_left_table = Summary.ref [] ~name:"transitivity-steps-l" (* [step] tries to apply a rewriting lemma; then apply [tac] intended to complete to proof of the last hypothesis (assumed to state an equality) *) @@ -456,12 +467,12 @@ let transitivity_left_table = ref [] let step left x tac = let l = List.map (fun lem -> - tclTHENLAST - (apply_with_bindings (lem, ImplicitBindings [x])) + Tacticals.New.tclTHENLAST + (apply_with_bindings (lem, ImplicitBindings [x])) tac) !(if left then transitivity_left_table else transitivity_right_table) in - tclFIRST l + Tacticals.New.tclFIRST l (* Main function to push lemmas in persistent environment *) @@ -476,59 +487,43 @@ let subst_transitivity_lemma (subst,(b,ref)) = (b,subst_mps subst ref) let inTransitivity : bool * constr -> obj = declare_object {(default_object "TRANSITIVITY-STEPS") with cache_function = cache_transitivity_lemma; - open_function = (fun i o -> if i=1 then cache_transitivity_lemma o); + open_function = (fun i o -> if Int.equal i 1 then cache_transitivity_lemma o); subst_function = subst_transitivity_lemma; classify_function = (fun o -> Substitute o) } -(* Synchronisation with reset *) - -let freeze () = !transitivity_left_table, !transitivity_right_table - -let unfreeze (l,r) = - transitivity_left_table := l; - transitivity_right_table := r - -let init () = - transitivity_left_table := []; - transitivity_right_table := [] - -let _ = - declare_summary "transitivity-steps" - { freeze_function = freeze; - unfreeze_function = unfreeze; - init_function = init } - (* Main entry points *) let add_transitivity_lemma left lem = - let lem' = Constrintern.interp_constr Evd.empty (Global.env ()) lem in + let lem',ctx (*FIXME*) = Constrintern.interp_constr (Global.env ()) Evd.empty lem in add_anonymous_leaf (inTransitivity (left,lem')) (* Vernacular syntax *) TACTIC EXTEND stepl | ["stepl" constr(c) "by" tactic(tac) ] -> [ step true c (Tacinterp.eval_tactic tac) ] -| ["stepl" constr(c) ] -> [ step true c tclIDTAC ] +| ["stepl" constr(c) ] -> [ step true c (Proofview.tclUNIT ()) ] END TACTIC EXTEND stepr | ["stepr" constr(c) "by" tactic(tac) ] -> [ step false c (Tacinterp.eval_tactic tac) ] -| ["stepr" constr(c) ] -> [ step false c tclIDTAC ] +| ["stepr" constr(c) ] -> [ step false c (Proofview.tclUNIT ()) ] END -VERNAC COMMAND EXTEND AddStepl +VERNAC COMMAND EXTEND AddStepl CLASSIFIED AS SIDEFF | [ "Declare" "Left" "Step" constr(t) ] -> [ add_transitivity_lemma true t ] END -VERNAC COMMAND EXTEND AddStepr +VERNAC COMMAND EXTEND AddStepr CLASSIFIED AS SIDEFF | [ "Declare" "Right" "Step" constr(t) ] -> [ add_transitivity_lemma false t ] END -VERNAC COMMAND EXTEND ImplicitTactic +VERNAC COMMAND EXTEND ImplicitTactic CLASSIFIED AS SIDEFF | [ "Declare" "Implicit" "Tactic" tactic(tac) ] -> [ Pfedit.declare_implicit_tactic (Tacinterp.interp tac) ] +| [ "Clear" "Implicit" "Tactic" ] -> + [ Pfedit.clear_implicit_tactic () ] END @@ -537,10 +532,10 @@ END (**********************************************************************) (*spiwack : Vernac commands for retroknowledge *) -VERNAC COMMAND EXTEND RetroknowledgeRegister +VERNAC COMMAND EXTEND RetroknowledgeRegister CLASSIFIED AS SIDEFF | [ "Register" constr(c) "as" retroknowledge_field(f) "by" constr(b)] -> - [ let tc = Constrintern.interp_constr Evd.empty (Global.env ()) c in - let tb = Constrintern.interp_constr Evd.empty (Global.env ()) b in + [ let tc,ctx = Constrintern.interp_constr (Global.env ()) Evd.empty c in + let tb,ctx(*FIXME*) = Constrintern.interp_constr (Global.env ()) Evd.empty b in Global.register f tc tb ] END @@ -567,7 +562,7 @@ END during dependent induction. For internal use. *) TACTIC EXTEND specialize_eqs -[ "specialize_eqs" hyp(id) ] -> [ specialize_eqs id ] +[ "specialize_eqs" hyp(id) ] -> [ Proofview.V82.tactic (specialize_eqs id) ] END (**********************************************************************) @@ -579,26 +574,36 @@ END (**********************************************************************) let subst_var_with_hole occ tid t = - let occref = if occ > 0 then ref occ else Termops.error_invalid_occurrence [occ] in + let occref = if occ > 0 then ref occ else Find_subterm.error_invalid_occurrence [occ] in let locref = ref 0 in let rec substrec = function | GVar (_,id) as x -> - if id = tid - then (decr occref; if !occref = 0 then x - else (incr locref; GHole (make_loc (!locref,0),Evd.QuestionMark(Evd.Define true)))) + if Id.equal id tid + then + (decr occref; + if Int.equal !occref 0 then x + else + (incr locref; + GHole (Loc.make_loc (!locref,0), + Evar_kinds.QuestionMark(Evar_kinds.Define true), + Misctypes.IntroAnonymous, None))) else x | c -> map_glob_constr_left_to_right substrec c in let t' = substrec t in - if !occref > 0 then Termops.error_invalid_occurrence [occ] else t' + if !occref > 0 then Find_subterm.error_invalid_occurrence [occ] else t' let subst_hole_with_term occ tc t = let locref = ref 0 in let occref = ref occ in let rec substrec = function - | GHole (_,Evd.QuestionMark(Evd.Define true)) -> - decr occref; if !occref = 0 then tc - else (incr locref; GHole (make_loc (!locref,0),Evd.QuestionMark(Evd.Define true))) + | GHole (_,Evar_kinds.QuestionMark(Evar_kinds.Define true),Misctypes.IntroAnonymous,s) -> + decr occref; + if Int.equal !occref 0 then tc + else + (incr locref; + GHole (Loc.make_loc (!locref,0), + Evar_kinds.QuestionMark(Evar_kinds.Define true),Misctypes.IntroAnonymous,s)) | c -> map_glob_constr_left_to_right substrec c in substrec t @@ -606,31 +611,38 @@ let subst_hole_with_term occ tc t = open Tacmach let out_arg = function - | ArgVar _ -> anomaly "Unevaluated or_var variable" + | ArgVar _ -> anomaly (Pp.str "Unevaluated or_var variable") | ArgArg x -> x -let hResolve id c occ t gl = - let sigma = project gl in - let env = Termops.clear_named_body id (pf_env gl) in +let hResolve id c occ t = + Proofview.Goal.nf_enter begin fun gl -> + let sigma = Proofview.Goal.sigma gl in + let env = Termops.clear_named_body id (Proofview.Goal.env gl) in + let concl = Proofview.Goal.concl gl in let env_ids = Termops.ids_of_context env in - let env_names = Termops.names_of_rel_context env in - let c_raw = Detyping.detype true env_ids env_names c in - let t_raw = Detyping.detype true env_ids env_names t in + let c_raw = Detyping.detype true env_ids env sigma c in + let t_raw = Detyping.detype true env_ids env sigma t in let rec resolve_hole t_hole = try - Pretyping.Default.understand sigma env t_hole - with - | Loc.Exc_located (loc,Pretype_errors.PretypeError (_,_,Pretype_errors.UnsolvableImplicit _)) -> - resolve_hole (subst_hole_with_term (fst (unloc loc)) c_raw t_hole) + Pretyping.understand env sigma t_hole + with + | Pretype_errors.PretypeError (_,_,Pretype_errors.UnsolvableImplicit _) as e -> + let (e, info) = Errors.push e in + let loc = match Loc.get_loc info with None -> Loc.ghost | Some loc -> loc in + resolve_hole (subst_hole_with_term (fst (Loc.unloc loc)) c_raw t_hole) in - let t_constr = resolve_hole (subst_var_with_hole occ id t_raw) in + let t_constr,ctx = resolve_hole (subst_var_with_hole occ id t_raw) in + let sigma = Evd.merge_universe_context sigma ctx in let t_constr_type = Retyping.get_type_of env sigma t_constr in - change_in_concl None (mkLetIn (Anonymous,t_constr,t_constr_type,pf_concl gl)) gl + Tacticals.New.tclTHEN + (Proofview.Unsafe.tclEVARS sigma) + (change_concl (mkLetIn (Anonymous,t_constr,t_constr_type,concl))) + end -let hResolve_auto id c t gl = +let hResolve_auto id c t = let rec resolve_auto n = try - hResolve id c n t gl + hResolve id c n t with | UserError _ as e -> raise e | e when Errors.noncritical e -> resolve_auto (n+1) @@ -646,18 +658,18 @@ END hget_evar *) -open Evar_refiner -open Sign - -let hget_evar n gl = - let sigma = project gl in - let evl = evar_list sigma (pf_concl gl) in +let hget_evar n = + Proofview.Goal.nf_enter begin fun gl -> + let sigma = Proofview.Goal.sigma gl in + let concl = Proofview.Goal.concl gl in + let evl = evar_list concl in if List.length evl < n then error "Not enough uninstantiated existential variables."; if n <= 0 then error "Incorrect existential variable index."; let ev = List.nth evl (n-1) in let ev_type = existential_type sigma ev in - change_in_concl None (mkLetIn (Anonymous,mkEvar ev,ev_type,pf_concl gl)) gl + change_concl (mkLetIn (Anonymous,mkEvar ev,ev_type,concl)) + end TACTIC EXTEND hget_evar | [ "hget_evar" int_or_var(n) ] -> [ hget_evar (out_arg n) ] @@ -673,12 +685,15 @@ END (* Contributed by Julien Forest and Pierre Courtieu (july 2010) *) (**********************************************************************) -exception Found of tactic +exception Found of unit Proofview.tactic -let rewrite_except h g = - tclMAP (fun id -> if id = h then tclIDTAC else - tclTRY (Equality.general_rewrite_in true Termops.all_occurrences true true id (mkVar h) false)) - (Tacmach.pf_ids_of_hyps g) g +let rewrite_except h = + Proofview.Goal.nf_enter begin fun gl -> + let hyps = Tacmach.New.pf_ids_of_hyps gl in + Tacticals.New.tclMAP (fun id -> if Id.equal id h then Proofview.tclUNIT () else + Tacticals.New.tclTRY (Equality.general_rewrite_in true Locus.AllOccurrences true true id (mkVar h) false)) + hyps + end let refl_equal = @@ -691,31 +706,39 @@ let refl_equal = (* This is simply an implementation of the case_eq tactic. this code should be replaced by a call to the tactic but I don't know how to call it before it is defined. *) -let mkCaseEq a : tactic = - (fun g -> - let type_of_a = Tacmach.pf_type_of g a in - tclTHENLIST - [Hiddentac.h_generalize [mkApp(delayed_force refl_equal, [| type_of_a; a|])]; - (fun g2 -> - change_in_concl None - (Tacred.pattern_occs [((false,[1]), a)] (Tacmach.pf_env g2) Evd.empty (Tacmach.pf_concl g2)) - g2); - simplest_case a] g);; - - -let case_eq_intros_rewrite x g = - let n = nb_prod (Tacmach.pf_concl g) in - Pp.msgnl (Printer.pr_lconstr x); - tclTHENLIST [ +let mkCaseEq a : unit Proofview.tactic = + Proofview.Goal.nf_enter begin fun gl -> + let type_of_a = Tacmach.New.of_old (fun g -> Tacmach.pf_type_of g a) gl in + Tacticals.New.tclTHENLIST + [Proofview.V82.tactic (Tactics.Simple.generalize [mkApp(delayed_force refl_equal, [| type_of_a; a|])]); + Proofview.Goal.nf_enter begin fun gl -> + let concl = Proofview.Goal.concl gl in + let env = Proofview.Goal.env gl in + change_concl + (snd (Tacred.pattern_occs [Locus.OnlyOccurrences [1], a] env Evd.empty concl)) + end; + simplest_case a] + end + + +let case_eq_intros_rewrite x = + Proofview.Goal.nf_enter begin fun gl -> + let n = nb_prod (Proofview.Goal.concl gl) in + (* Pp.msgnl (Printer.pr_lconstr x); *) + Tacticals.New.tclTHENLIST [ mkCaseEq x; - (fun g -> - let n' = nb_prod (Tacmach.pf_concl g) in - let h = fresh_id (Tacmach.pf_ids_of_hyps g) (id_of_string "heq") g in - tclTHENLIST [ (tclDO (n'-n-1) intro); - Tacmach.introduction h; - rewrite_except h] g - ) - ] g + Proofview.Goal.nf_enter begin fun gl -> + let concl = Proofview.Goal.concl gl in + let hyps = Tacmach.New.pf_ids_of_hyps gl in + let n' = nb_prod concl in + let h = Tacmach.New.of_old (fun g -> fresh_id hyps (Id.of_string "heq") g) gl in + Tacticals.New.tclTHENLIST [ + Tacticals.New.tclDO (n'-n-1) intro; + introduction h; + rewrite_except h] + end + ] + end let rec find_a_destructable_match t = match kind_of_term t with @@ -724,40 +747,52 @@ let rec find_a_destructable_match t = (* TODO check there is no rel n. *) raise (Found (Tacinterp.eval_tactic(<:tactic<destruct x>>))) else - let _ = Pp.msgnl (Printer.pr_lconstr x) in + (* let _ = Pp.msgnl (Printer.pr_lconstr x) in *) raise (Found (case_eq_intros_rewrite x)) | _ -> iter_constr find_a_destructable_match t let destauto t = try find_a_destructable_match t; - error "No destructable match found" + Proofview.tclZERO (UserError ("", str"No destructable match found")) with Found tac -> tac -let destauto_in id g = - let ctype = Tacmach.pf_type_of g (mkVar id) in - Pp.msgnl (Printer.pr_lconstr (mkVar id)); - Pp.msgnl (Printer.pr_lconstr (ctype)); - destauto ctype g +let destauto_in id = + Proofview.Goal.nf_enter begin fun gl -> + let ctype = Tacmach.New.of_old (fun g -> Tacmach.pf_type_of g (mkVar id)) gl in +(* Pp.msgnl (Printer.pr_lconstr (mkVar id)); *) +(* Pp.msgnl (Printer.pr_lconstr (ctype)); *) + destauto ctype + end TACTIC EXTEND destauto -| [ "destauto" ] -> [ (fun g -> destauto (Tacmach.pf_concl g) g) ] +| [ "destauto" ] -> [ Proofview.Goal.nf_enter (fun gl -> destauto (Proofview.Goal.concl gl)) ] | [ "destauto" "in" hyp(id) ] -> [ destauto_in id ] END (* ********************************************************************* *) +let eq_constr x y = + Proofview.Goal.enter (fun gl -> + let evd = Proofview.Goal.sigma gl in + if Evd.eq_constr_univs_test evd x y then Proofview.tclUNIT () + else Tacticals.New.tclFAIL 0 (str "Not equal")) + TACTIC EXTEND constr_eq -| [ "constr_eq" constr(x) constr(y) ] -> [ - if eq_constr x y then tclIDTAC else tclFAIL 0 (str "Not equal") ] +| [ "constr_eq" constr(x) constr(y) ] -> [ eq_constr x y ] +END + +TACTIC EXTEND constr_eq_nounivs +| [ "constr_eq_nounivs" constr(x) constr(y) ] -> [ + if eq_constr_nounivs x y then Proofview.tclUNIT () else Tacticals.New.tclFAIL 0 (str "Not equal") ] END TACTIC EXTEND is_evar | [ "is_evar" constr(x) ] -> [ match kind_of_term x with - | Evar _ -> tclIDTAC - | _ -> tclFAIL 0 (str "Not an evar") + | Evar _ -> Proofview.tclUNIT () + | _ -> Tacticals.New.tclFAIL 0 (str "Not an evar") ] END @@ -776,28 +811,36 @@ let rec has_evar x = has_evar t1 || has_evar t2 || has_evar_array ts | Fix ((_, tr)) | CoFix ((_, tr)) -> has_evar_prec tr + | Proj (p, c) -> has_evar c and has_evar_array x = - array_exists has_evar x + Array.exists has_evar x and has_evar_prec (_, ts1, ts2) = - array_exists has_evar ts1 || array_exists has_evar ts2 + Array.exists has_evar ts1 || Array.exists has_evar ts2 TACTIC EXTEND has_evar | [ "has_evar" constr(x) ] -> - [ if has_evar x then tclIDTAC else tclFAIL 0 (str "No evars") ] + [ if has_evar x then Proofview.tclUNIT () else Tacticals.New.tclFAIL 0 (str "No evars") ] END TACTIC EXTEND is_hyp | [ "is_var" constr(x) ] -> [ match kind_of_term x with - | Var _ -> tclIDTAC - | _ -> tclFAIL 0 (str "Not a variable or hypothesis") ] + | Var _ -> Proofview.tclUNIT () + | _ -> Tacticals.New.tclFAIL 0 (str "Not a variable or hypothesis") ] END TACTIC EXTEND is_fix | [ "is_fix" constr(x) ] -> [ match kind_of_term x with - | Fix _ -> Tacticals.tclIDTAC - | _ -> Tacticals.tclFAIL 0 (Pp.str "not a fix definition") ] + | Fix _ -> Proofview.tclUNIT () + | _ -> Tacticals.New.tclFAIL 0 (Pp.str "not a fix definition") ] +END;; + +TACTIC EXTEND is_cofix +| [ "is_cofix" constr(x) ] -> + [ match kind_of_term x with + | CoFix _ -> Proofview.tclUNIT () + | _ -> Tacticals.New.tclFAIL 0 (Pp.str "not a cofix definition") ] END;; (* Command to grab the evars left unresolved at the end of a proof. *) @@ -805,8 +848,169 @@ END;; the semantics of the LCF-style tactics, hence with the classic tactic mode. *) VERNAC COMMAND EXTEND GrabEvars -[ "Grab" "Existential" "Variables" ] -> - [ let p = Proof_global.give_me_the_proof () in - Proof.V82.grab_evars p; - Flags.if_verbose (fun () -> Pp.msg (Printer.pr_open_subgoals ())) () ] +[ "Grab" "Existential" "Variables" ] + => [ Vernacexpr.VtProofStep false, Vernacexpr.VtLater ] + -> [ Proof_global.simple_with_current_proof (fun _ p -> Proof.V82.grab_evars p) ] +END + +(* Shelves all the goals under focus. *) +TACTIC EXTEND shelve +| [ "shelve" ] -> + [ Proofview.shelve ] +END + +(* Shelves the unifiable goals under focus, i.e. the goals which + appear in other goals under focus (the unfocused goals are not + considered). *) +TACTIC EXTEND shelve_unifiable +| [ "shelve_unifiable" ] -> + [ Proofview.shelve_unifiable ] +END + +(* Command to add every unshelved variables to the focus *) +VERNAC COMMAND EXTEND Unshelve +[ "Unshelve" ] + => [ Vernacexpr.VtProofStep false, Vernacexpr.VtLater ] + -> [ Proof_global.simple_with_current_proof (fun _ p -> Proof.unshelve p) ] +END + +(* Gives up on the goals under focus: the goals are considered solved, + but the proof cannot be closed until the user goes back and solve + these goals. *) +TACTIC EXTEND give_up +| [ "give_up" ] -> + [ Proofview.give_up ] +END + +(* cycles [n] goals *) +TACTIC EXTEND cycle +| [ "cycle" int_or_var(n) ] -> [ Proofview.cycle (out_arg n) ] +END + +(* swaps goals number [i] and [j] *) +TACTIC EXTEND swap +| [ "swap" int_or_var(i) int_or_var(j) ] -> [ Proofview.swap (out_arg i) (out_arg j) ] +END + +(* reverses the list of focused goals *) +TACTIC EXTEND revgoals +| [ "revgoals" ] -> [ Proofview.revgoals ] +END + + +type cmp = + | Eq + | Lt | Le + | Gt | Ge + +type 'i test = + | Test of cmp * 'i * 'i + +let wit_cmp : (cmp,cmp,cmp) Genarg.genarg_type = Genarg.make0 None "cmp" +let wit_test : (int or_var test,int or_var test,int test) Genarg.genarg_type = + Genarg.make0 None "tactest" + +let pr_cmp = function + | Eq -> Pp.str"=" + | Lt -> Pp.str"<" + | Le -> Pp.str"<=" + | Gt -> Pp.str">" + | Ge -> Pp.str">=" + +let pr_cmp' _prc _prlc _prt = pr_cmp + +let pr_test_gen f (Test(c,x,y)) = + Pp.(f x ++ pr_cmp c ++ f y) + +let pr_test = pr_test_gen (Pptactic.pr_or_var Pp.int) + +let pr_test' _prc _prlc _prt = pr_test + +let pr_itest = pr_test_gen Pp.int + +let pr_itest' _prc _prlc _prt = pr_itest + + + +ARGUMENT EXTEND comparison TYPED AS cmp PRINTED BY pr_cmp' +| [ "=" ] -> [ Eq ] +| [ "<" ] -> [ Lt ] +| [ "<=" ] -> [ Le ] +| [ ">" ] -> [ Gt ] +| [ ">=" ] -> [ Ge ] + END + +let interp_test ist gls = function + | Test (c,x,y) -> + project gls , + Test(c,Tacinterp.interp_int_or_var ist x,Tacinterp.interp_int_or_var ist y) + +ARGUMENT EXTEND test + PRINTED BY pr_itest' + INTERPRETED BY interp_test + RAW_TYPED AS test + RAW_PRINTED BY pr_test' + GLOB_TYPED AS test + GLOB_PRINTED BY pr_test' +| [ int_or_var(x) comparison(c) int_or_var(y) ] -> [ Test(c,x,y) ] +END + +let interp_cmp = function + | Eq -> Int.equal + | Lt -> ((<):int->int->bool) + | Le -> ((<=):int->int->bool) + | Gt -> ((>):int->int->bool) + | Ge -> ((>=):int->int->bool) + +let run_test = function + | Test(c,x,y) -> interp_cmp c x y + +let guard tst = + if run_test tst then + Proofview.tclUNIT () + else + let msg = Pp.(str"Condition not satisfied:"++ws 1++(pr_itest tst)) in + Proofview.tclZERO (Errors.UserError("guard",msg)) + + +TACTIC EXTEND guard +| [ "guard" test(tst) ] -> [ guard tst ] +END + +let decompose l c = + Proofview.Goal.enter begin fun gl -> + let to_ind c = + if isInd c then Univ.out_punivs (destInd c) + else error "not an inductive type" + in + let l = List.map to_ind l in + Elim.h_decompose l c + end + +TACTIC EXTEND decompose +| [ "decompose" "[" ne_constr_list(l) "]" constr(c) ] -> [ decompose l c ] +END + +(** library/keys *) + +VERNAC COMMAND EXTEND Declare_keys CLASSIFIED AS SIDEFF +| [ "Declare" "Equivalent" "Keys" constr(c) constr(c') ] -> [ + let it c = snd (Constrintern.interp_open_constr (Global.env ()) Evd.empty c) in + let k1 = Keys.constr_key (it c) in + let k2 = Keys.constr_key (it c') in + match k1, k2 with + | Some k1, Some k2 -> Keys.declare_equiv_keys k1 k2 + | _ -> () ] +END + +VERNAC COMMAND EXTEND Print_keys CLASSIFIED AS QUERY +| [ "Print" "Equivalent" "Keys" ] -> [ msg_info (Keys.pr_keys Printer.pr_global) ] +END + + +VERNAC COMMAND EXTEND OptimizeProof +| [ "Optimize" "Proof" ] => [ Vernac_classifier.classify_as_proofstep ] -> + [ Proof_global.compact_the_proof () ] +| [ "Optimize" "Heap" ] => [ Vernac_classifier.classify_as_proofstep ] -> + [ Gc.compact () ] END |