123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290(************************************************************************)(* * 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.Notationslettauto_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 compatibility for buggy detection of binary connective is on *)binary_mode_bugged_detection: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 *)strict_unit:bool;}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{optdepr=false;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->letflags=assoc_flagsistinlettest=ifflags.strict_unitthenis_unit_typeelseis_unit_or_eq_typeiniftestgenvsigma(assoc_var"X1"ist)thenidtacelsefailletbugged_is_binarysigmat=isAppsigmat&&let(hdapp,args)=decompose_appsigmatinmatchEConstr.kindsigmahdappwith|Ind(ind,u)->let(mib,mip)=Global.lookup_inductiveindinInt.equalmib.Declarations.mind_nparams2|_->false(** Dealing with conjunction *)letis_conj_ist=Proofview.tclENV>>=fungenv->Proofview.tclEVARMAP>>=funsigma->letflags=assoc_flagsistinletind=assoc_var"X1"istinif(notflags.binary_mode_bugged_detection||bugged_is_binarysigmaind)&&is_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->mkArrowaSorts.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"istinif(notflags.binary_mode_bugged_detection||bugged_is_binarysigmat)&&is_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=mkArrowargSorts.Relevantcinletci=Tactics.constructor_tacfalseNone(succi)Tactypes.NoBindingsinletby=tclTHENLIST[intro;applyhyp;ci;assumption]inassert_~bytypinlettacs=List.mapimapargsinlettac0=clear(destVarsigmahyp)intclTHEN(tclTHENLISTtacs)tac0|_->failletevalglobref_of_globref=letopenTacredinfunction|GlobRef.VarRefv->EvalVarRefv|GlobRef.ConstRefc->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;binary_mode_bugged_detection=false;strict_in_contravariant_hyp=true;strict_in_hyp_and_ccl=true;strict_unit=false}(* This is the compatibility mode (not used) *)let_tauto_legacy_flags={binary_mode=true;binary_mode_bugged_detection=true;strict_in_contravariant_hyp=true;strict_in_hyp_and_ccl=false;strict_unit=false}(* This is the improved mode *)lettauto_power_flags={binary_mode=false;(* support n-ary connectives *)binary_mode_bugged_detection=false;strict_in_contravariant_hyp=false;(* supports non-regular connectives *)strict_in_hyp_and_ccl=false;strict_unit=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:"deprecated"Pp.(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()endletregister_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"[]