123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openConstropenEConstropenEConstr.VarsopenNamesopenTacexpropenCErrorsopenUtilopenTermopsopenTactypesopenTacticsopenProofview.Notationsletassert_succeedstac=letopenProofviewinletexceptionSucceededintclORELSE(tclONCEtac<*>tclZEROSucceeded)(function|Succeeded,_->tclUNIT()|exn,info->tclZERO~infoexn)letmytclWithHolestacwith_evarsc=Proofview.Goal.enterbeginfungl->letenv=Tacmach.pf_envglinletsigma=Tacmach.projectglinletsigma',c=Tactics.force_destruction_argwith_evarsenvsigmacinTacticals.tclWITHHOLESwith_evars(tacwith_evars(Somec))sigma'end(**********************************************************************)(* replace, discriminate, injection, simplify_eq *)(* dependent rewrite *)letwith_delayed_uconstristctac=letflags=Pretyping.{use_coercions=true;use_typeclasses=NoUseTC;solve_unification_constraints=true;fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;undeclared_evars_patvars=false;patvars_abstract=false;unconstrained_sorts=false;}inletc=Tacinterp.type_uconstr~flagsistcinTacticals.tclDELAYEDWITHHOLESfalsectacletreplace_in_clause_maybe_byistdir_optc1c2cltac=with_delayed_uconstristc1(func1->Equality.replace_in_clause_maybe_bydir_optc1c2cl(Option.map(Tacinterp.tactic_of_valueist)tac))letreplace_termistdir_optccl=with_delayed_uconstristc(func->Equality.replace_termdir_optccl)letelimOnConstrWithHolestacwith_evarsc=Tacticals.tclDELAYEDWITHHOLESwith_evarsc(func->tacwith_evars(Some(None,ElimOnConstrc)))letdiscr_mainc=elimOnConstrWithHolesEquality.discr_tacfalsecletdiscrHypid=Proofview.tclEVARMAP>>=funsigma->discr_main(funenvsigma->(sigma,(EConstr.mkVarid,NoBindings)))letinjection_mainwith_evarsc=elimOnConstrWithHoles(Equality.injClauseNoneNone)with_evarscletinjHypid=Proofview.tclEVARMAP>>=funsigma->injection_mainfalse(funenvsigma->(sigma,(EConstr.mkVarid,NoBindings)))letconstr_flags()=Pretyping.{use_coercions=true;use_typeclasses=UseTC;solve_unification_constraints=Proof.use_unification_heuristics();fail_evar=false;expand_evars=true;program_mode=false;polymorphic=false;undeclared_evars_patvars=false;patvars_abstract=false;unconstrained_sorts=false;}letrefine_tacist~simple~with_classesc=letwith_classes=ifwith_classesthenPretyping.UseTCelsePretyping.NoUseTCinProofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletflags={(constr_flags())withPretyping.use_typeclasses=with_classes}inletexpected_type=Pretyping.OfTypeconclinletc=Tacinterp.type_uconstr~flags~expected_typeistcinletupdate=beginfunsigma->cenvsigmaendinletrefine=Refine.refine~typecheck:falseupdateinifsimplethenrefineelserefine<*>Tactics.reduce_after_refine<*>Proofview.shelve_unifiableend(**********************************************************************)(**********************************************************************)(* A tactic that reduces one match t with ... by doing destruct t. *)(* if t is not a variable, the tactic does *)(* case_eq t;intros ... heq;rewrite heq in *|-. (but heq itself is *)(* preserved). *)(* Contributed by Julien Forest and Pierre Courtieu (july 2010) *)(**********************************************************************)letinduction_arg_of_quantified_hyp=function|AnonHypn->None,ElimOnAnonHypn|NamedHypid->None,ElimOnIdentidexceptionFoundofunitProofview.tacticletrewrite_excepth=Proofview.Goal.enterbeginfungl->lethyps=Tacmach.pf_ids_of_hypsglinTacticals.tclMAP(funid->ifId.equalidhthenProofview.tclUNIT()elseTacticals.tclTRY(Equality.general_rewrite~where:(Someid)~l2r:trueLocus.AllOccurrences~freeze:true~dep:true~with_evars:false(mkVarh,NoBindings)))hypsendletrefl_equal()=Coqlib.lib_ref"core.eq.type"(* 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. *)letmkCaseEqa:unitProofview.tactic=Proofview.Goal.enterbeginfungl->lettype_of_a=Tacmach.pf_get_type_ofglainTacticals.pf_constr_of_global(delayed_forcerefl_equal)>>=funreq->Tacticals.tclTHENLIST[Generalize.generalize[(mkApp(req,[|type_of_a;a|]))];Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglin(* FIXME: this looks really wrong. Does anybody really use
this tactic? *)let(_,c)=Tacred.pattern_occs[Locus.OnlyOccurrences[1],a]env(Evd.from_envenv)conclinchange_conclcend;simplest_casea]endletcase_eq_intros_rewritex=Proofview.Goal.enterbeginfungl->letn=nb_prod(Tacmach.projectgl)(Proofview.Goal.conclgl)in(* Pp.msgnl (Printer.pr_lconstr x); *)Tacticals.tclTHENLIST[mkCaseEqx;Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinlethyps=Tacmach.pf_ids_set_of_hypsglinletn'=nb_prod(Tacmach.projectgl)conclinleth=fresh_id_in_envhyps(Id.of_string"heq")(Proofview.Goal.envgl)inTacticals.tclTHENLIST[Tacticals.tclDO(n'-n-1)intro;introductionh;rewrite_excepth]end]endletrecfind_a_destructable_matchsigmat=letcl=induction_arg_of_quantified_hyp(NamedHyp(CAst.make@@Id.of_string"x"))inletcl=[cl,(None,None),None],Noneinletdest=CAst.make@@TacAtom(TacInductionDestruct(false,false,cl))inmatchEConstr.kindsigmatwith|Case(_,_,_,_,_,x,_)whenclosed0sigmax->ifisVarsigmaxthen(* TODO check there is no rel n. *)raise(Found(Tacinterp.eval_tacticdest))else(* let _ = Pp.msgnl (Printer.pr_lconstr x) in *)raise(Found(case_eq_intros_rewritex))|_->EConstr.itersigma(func->find_a_destructable_matchsigmac)tletdestauto0t=Proofview.tclEVARMAP>>=funsigma->tryfind_a_destructable_matchsigmat;Tacticals.tclZEROMSG(Pp.str"No destructable match found")withFoundtac->tacletdestauto=Proofview.Goal.enterbeginfungl->destauto0(Proofview.Goal.conclgl)endletdestauto_inid=Proofview.Goal.enterbeginfungl->letctype=Tacmach.pf_get_type_ofgl(mkVarid)in(* Pp.msgnl (Printer.pr_lconstr (mkVar id)); *)(* Pp.msgnl (Printer.pr_lconstr (ctype)); *)destauto0ctypeend(** Term introspection *)letis_evarx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Evar_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"Not an evar")lethas_evarx=Proofview.tclEVARMAP>>=funsigma->ifEvarutil.has_undefined_evarssigmaxthenProofview.tclUNIT()elseTacticals.tclFAIL(Pp.str"No evars")letis_varx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Var_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"Not a variable or hypothesis")letis_fixx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Fix_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not a fix definition")letis_cofixx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|CoFix_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not a cofix definition")letis_indx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Ind_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not an (co)inductive datatype")letis_constructorx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Construct_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not a constructor")letis_projx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Proj_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not a primitive projection")letis_constx=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmaxwith|Const_->Proofview.tclUNIT()|_->Tacticals.tclFAIL(Pp.str"not a constant")letunshelveistt=Proofview.with_shelf(Tacinterp.tactic_of_valueistt)>>=fun(gls,())->letgls=List.mapProofview.with_empty_stateglsinProofview.Unsafe.tclGETGOALS>>=funogls->Proofview.Unsafe.tclSETGOALS(gls@ogls)(** tactic analogous to "OPTIMIZE HEAP" *)lettclOPTIMIZE_HEAP=Proofview.tclLIFT(Proofview.NonLogical.make(fun()->Gc.compact()))letonSomeWithHolestac=function|None->tacNone|Somec->Tacticals.tclDELAYEDWITHHOLESfalsec(func->tac(Somec))letdecomposelc=Proofview.Goal.enterbeginfungl->letsigma=Tacmach.projectglinletto_indc=ifisIndsigmacthenfst(destIndsigmac)elseuser_errPp.(str"not an inductive type")inletl=List.mapto_indlinElim.h_decomposelcendletexactist(c:Ltac_pretype.closed_glob_constr)=letopenTacmachinProofview.Goal.enterbeginfungl->letexpected_type=Pretyping.OfType(pf_conclgl)inletsigma,c=Tacinterp.type_uconstr~expected_typeistc(pf_envgl)(projectgl)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tactics.exact_no_checkc)end(** ProofGeneral specific command *)(* Execute tac, show the names of new hypothesis names created by tac
in the "as" format and then forget everything. From the logical
point of view [infoH tac] is therefore equivalent to idtac,
except that it takes the time and memory of tac and prints "as"
information. The resulting (unchanged) goals are printed *after*
the as-expression, which forces pg to some gymnastic.
TODO: Have something similar (better?) in the xml protocol.
NOTE: some tactics delete hypothesis and reuse names (induction,
destruct), this is not detected by this tactical. *)letinfoH~pstate(tac:raw_tactic_expr):unit=let(_,oldhyps)=Declare.Proof.get_current_goal_contextpstateinletoldhyps=List.mapContext.Named.Declaration.get_id@@Environ.named_contextoldhypsinlettac=Tacinterp.interptacinlettac=letopenProofview.Notationsintac<*>Proofview.Unsafe.tclGETGOALS>>=fungls->Proofview.tclEVARMAP>>=funsigma->letmapgl=letgl=Proofview_monad.drop_stateglinlethyps=Evd.evar_filtered_context(Evd.find_undefinedsigmagl)inList.mapContext.Named.Declaration.get_id@@hypsinlethyps=List.mapmapglsinletnewhyps=List.map(funhypl->List.subtractNames.Id.equalhyploldhyps)hypsinlets=letfrst=reftrueinList.fold_left(funacclh->acc^(if!frstthen(frst:=false;"")else" | ")^(List.fold_left(funaccd->(Names.Id.to_stringd)^" "^acc)""lh))""newhypsinlet()=Feedback.msg_noticePp.(str"<infoH>"++(hov0(strs))++(str"</infoH>"))inProofview.tclUNIT()inignore(Declare.Proof.bytacpstate)letdeclare_equivalent_keyscc'=letget_keyc=letenv=Global.env()inletevd=Evd.from_envenvinlet(evd,c)=Constrintern.interp_open_constrenvevdcinletkindc=EConstr.kindevdcinKeys.constr_keyenvkindcinletk1=get_keycinletk2=get_keyc'inmatchk1,k2with|Somek1,Somek2->Keys.declare_equiv_keysk1k2|_->()