123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300(************************************************************************)(* * 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) *)(************************************************************************)openConstropenEConstropenHipatternopenNamesopenGeninterpopenLtac_pluginopenTacexpropenTacinterpopenUtilopenTacticalsopenProofview.NotationsmoduleNamedDecl=Context.Named.Declarationlettauto_plugin="coq-core.plugins.tauto"let()=Mltop.add_known_moduletauto_pluginletassoc_varsist=letv=Id.Map.find(Names.Id.of_strings)ist.lfuninmatchValue.to_constrvwith|Somec->c|None->failwith"tauto: anomaly"(** Parametrization of tauto *)typetauto_flags={(* Whether conjunction and disjunction are restricted to binary connectives *)binary_mode:bool;(* Whether conjunction and disjunction are restricted to the connectives *)(* having the structure of "and" and "or" (up to the choice of sorts) in *)(* contravariant position in an hypothesis *)strict_in_contravariant_hyp:bool;(* Whether conjunction and disjunction are restricted to the connectives *)(* having the structure of "and" and "or" (up to the choice of sorts) in *)(* an hypothesis and in the conclusion *)strict_in_hyp_and_ccl:bool;(* Whether unit type includes equality types *)}lettag_tauto_flags:tauto_flagsVal.typ=Val.create"tauto_flags"letassoc_flagsist:tauto_flags=letVal.Dyn(tag,v)=Id.Map.find(Names.Id.of_string"tauto_flags")ist.lfuninmatchVal.eqtagtag_tauto_flagswith|None->assertfalse|SomeRefl->v(* Whether inner not are unfolded *)letnegation_unfolding=reftrueopenGoptionslet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Intuition";"Negation";"Unfolding"];optread=(fun()->!negation_unfolding);optwrite=(:=)negation_unfolding}(** Base tactics *)letidtac=Proofview.tclUNIT()letfail=Proofview.tclINDEPENDENT(tclFAIL(Pp.mt()))letintro=Tactics.introletassert_?byc=lettac=matchbywith|None->None|Sometac->Some(Sometac)inProofview.tclINDEPENDENT(Tactics.forwardtruetacNonec)letapplyc=Tactics.applycletclearid=Tactics.clear[id]letassumption=Tactics.assumptionletsplit=Tactics.split_with_bindingsfalse[Tactypes.NoBindings](** Test *)letis_empty_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->ifis_empty_typegenvsigma(assoc_var"X1"ist)thenidtacelsefail(* Strictly speaking, this exceeds the propositional fragment as it
matches also equality types (and solves them if a reflexivity) *)letis_unit_or_eq_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->ifis_unit_or_eq_typegenvsigma(assoc_var"X1"ist)thenidtacelsefail(** Dealing with conjunction *)letis_conj_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->letflags=assoc_flagsistinletind=assoc_var"X1"istinifis_conjunctiongenvsigma~strict:flags.strict_in_hyp_and_ccl~onlybinary:flags.binary_modeindthenidtacelsefailletflatten_contravariant_conj_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->letflags=assoc_flagsistinlettyp=assoc_var"X1"istinletc=assoc_var"X2"istinlethyp=assoc_var"id"istinmatchmatch_with_conjunctiongenvsigma~strict:flags.strict_in_contravariant_hyp~onlybinary:flags.binary_modetypwith|Some(_,args)->letnewtyp=List.fold_right(funab->mkArrowaERelevance.relevantb)argscinletintros=tclMAP(fun_->intro)argsinletby=tclTHENLIST[intros;applyhyp;split;assumption]intclTHENLIST[assert_~bynewtyp;clear(destVarsigmahyp)]|_->fail(** Dealing with disjunction *)letis_disj_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->letflags=assoc_flagsistinlett=assoc_var"X1"istinifis_disjunctiongenvsigma~strict:flags.strict_in_hyp_and_ccl~onlybinary:flags.binary_modetthenidtacelsefailletflatten_contravariant_disj_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->letflags=assoc_flagsistinlettyp=assoc_var"X1"istinletc=assoc_var"X2"istinlethyp=assoc_var"id"istinmatchmatch_with_disjunctiongenvsigma~strict:flags.strict_in_contravariant_hyp~onlybinary:flags.binary_modetypwith|Some(_,args)->letmapiarg=lettyp=mkArrowargERelevance.relevantcinletci=Tactics.constructor_tacfalseNone(succi)Tactypes.NoBindingsinletby=tclTHENLIST[intro;applyhyp;ci;assumption]inassert_~bytypinlettacs=List.mapimapargsinlettac0=clear(destVarsigmahyp)intclTHEN(tclTHENLISTtacs)tac0|_->failletevalglobref_of_globref=function|GlobRef.VarRefv->Evaluable.EvalVarRefv|GlobRef.ConstRefc->Evaluable.EvalConstRefc|GlobRef.IndRef_|GlobRef.ConstructRef_->assertfalseletmake_unfoldname=letconst=evalglobref_of_globref(Coqlib.lib_refname)inLocus.(AllOccurrences,ArgArg(const,None))letreduction_not_iff_ist=letmake_reducec=CAst.make@@TacAtom(TacReduce(Genredexpr.Unfoldc,Locusops.allHypsAndConcl))inlettac=match!negation_unfoldingwith|true->make_reduce[make_unfold"core.not.type"]|false->CAst.make(TacId[])ineval_tactic_ististtacletapply_nnpp_ist=letnnpp="core.nnpp.type"inProofview.tclBIND(Proofview.tclUNIT())beginfun()->ifCoqlib.has_refnnppthenTacticals.pf_constr_of_global(Coqlib.lib_refnnpp)>>=applyelsetclFAIL(Pp.mt())end(* This is the uniform mode dealing with ->, not, iff and types isomorphic to
/\ and *, \/ and +, False and Empty_set, True and unit, _and_ eq-like types.
For the moment not and iff are still always unfolded. *)lettauto_uniform_unit_flags={binary_mode=true;strict_in_contravariant_hyp=true;strict_in_hyp_and_ccl=true;}(* This is the improved mode *)lettauto_power_flags={binary_mode=false;(* support n-ary connectives *)strict_in_contravariant_hyp=false;(* supports non-regular connectives *)strict_in_hyp_and_ccl=false;}letwith_flagsflags_ist=letf=CAst.make@@Id.of_string"f"inletx=CAst.make@@Id.of_string"x"inletarg=Val.Dyn(tag_tauto_flags,flags)inletist={istwithlfun=Id.Map.addx.CAst.vargist.lfun}ineval_tactic_istist(CAst.make@@TacArg(TacCall(CAst.make(Locus.ArgVarf,[Reference(Locus.ArgVarx)]))))letwarn_auto_with_star=CWarnings.create~name:"intuition-auto-with-star"~category:Deprecation.Version.v8_17Pp.(fun()->str"\"auto with *\" was used through the default \"intuition_solver\" tactic."++spc()++str"This will be replaced by just \"auto\" in the future.")letwarn_auto_with_star_tac__=Proofview.tclBIND(Proofview.tclUNIT())beginfun()->warn_auto_with_star();Proofview.tclUNIT()endletval_of_idid=letopenGeninterpinletid=CAst.make@@Tactypes.IntroNaming(IntroIdentifierid)inVal.inject(val_tag@@Genarg.topwitTacarg.wit_intro_pattern)idletfind_cut_ist=letk=Id.Map.find(Names.Id.of_string"k")ist.lfuninProofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinlethyps0=Proofview.Goal.hypsglin(* Beware of the relative order of hypothesis picking! *)letrecfind_arg=function|[]->Tacticals.tclFAIL(Pp.str("No matching clause"))|arg::hyps->lettyp=NamedDecl.get_typearginletarg=NamedDecl.get_idarginletrecfind_fun=function|[]->Tacticals.tclFAIL(Pp.str("No matching clause"))|fnc::hyps->matchEConstr.kindsigma(NamedDecl.get_typefnc)with|Prod(na,dom,codom)whenEConstr.Vars.noccurnsigma1codom->letf=NamedDecl.get_idfncinifId.equalfargthenfind_funhypselseProofview.tclOR(Proofview.tclUNIT()>>=fun()->find_funhyps)(fun_->Tactics.convertdomtyp<*>Proofview.tclUNIT(f,arg,codom))|_->find_funhypsinProofview.tclOR(Proofview.tclUNIT()>>=fun()->find_arghyps)(fun_->find_funhyps0)inlettac=find_arghyps0>>=fun(f,arg,t)->Tacinterp.Value.applyk[val_of_idf;val_of_idarg;Value.of_constrt]inProofview.tclONCEtacendletregister_tauto_tactictacname0args=letids=List.map(funid->Id.of_stringid)argsinletids=List.map(funid->Nameid)idsinletname={mltac_plugin=tauto_plugin;mltac_tactic=name0;}inletentry={mltac_name=name;mltac_index=0}inlet()=Tacenv.register_ml_tacticname[|tac|]inlettac=CAst.make(TacFun(ids,CAst.make(TacML(entry,[]))))inletobj()=Tacenv.register_ltactruetrue(Id.of_stringname0)tacinMltop.declare_cache_objobjtauto_pluginlet()=register_tauto_tacticis_empty"is_empty"["tauto_flags";"X1"]let()=register_tauto_tacticis_unit_or_eq"is_unit_or_eq"["tauto_flags";"X1"]let()=register_tauto_tacticis_disj"is_disj"["tauto_flags";"X1"]let()=register_tauto_tacticis_conj"is_conj"["tauto_flags";"X1"]let()=register_tauto_tacticflatten_contravariant_disj"flatten_contravariant_disj"["tauto_flags";"X1";"X2";"id"]let()=register_tauto_tacticflatten_contravariant_conj"flatten_contravariant_conj"["tauto_flags";"X1";"X2";"id"]let()=register_tauto_tacticapply_nnpp"apply_nnpp"[]let()=register_tauto_tacticreduction_not_iff"reduction_not_iff"[]let()=register_tauto_tactic(with_flagstauto_uniform_unit_flags)"with_uniform_flags"["f"]let()=register_tauto_tactic(with_flagstauto_power_flags)"with_power_flags"["f"]let()=register_tauto_tacticwarn_auto_with_star_tac"warn_auto_with_star"[]let()=register_tauto_tacticfind_cut"find_cut"["k"]