123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437(************************************************************************)(* * 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) *)(************************************************************************)openPpopenUtilopenNamesopenTermopsopenTacticsopenProofview.NotationsopenHints(**************************************************************************)(* Automatic tactics *)(**************************************************************************)(**************************************************************************)(* tactics with a trace mechanism for automatic search *)(**************************************************************************)letcompute_secvarsgl=lethyps=Proofview.Goal.hypsglinsecvars_of_hypshyps(* tell auto not to reuse already instantiated metas in unification (for
compatibility, since otherwise, apply succeeds oftener) *)openUnificationletauto_core_unif_flags_ofst1st2={modulo_conv_on_closed_terms=Somest1;use_metas_eagerly_in_conv_on_closed_terms=true;use_evars_eagerly_in_conv_on_closed_terms=false;modulo_delta=st2;modulo_delta_types=TransparentState.full;check_applied_meta_types=false;use_pattern_unification=false;use_meta_bound_pattern_unification=true;allowed_evars=Evarsolve.AllowedEvars.all;restrict_conv_on_strict_subterms=false;(* Compat *)modulo_betaiota=false;modulo_eta=true;}letauto_unif_flags_ofst1st2=letflags=auto_core_unif_flags_ofst1st2in{core_unify_flags=flags;merge_unify_flags=flags;subterm_unify_flags={flagswithmodulo_delta=TransparentState.empty};allow_K_in_toplevel_higher_order_unification=false;resolve_evars=true}letauto_unif_flags=auto_unif_flags_ofTransparentState.fullTransparentState.empty(* Try unification with the precompiled clause, then use registered Apply *)letunify_resolveflagsh=Hints.hint_res_pf~flagshletunify_resolve_nodeltah=Hints.hint_res_pf~flags:auto_unif_flagshletexacth=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletsigma,c=Hints.fresh_hintenvsigmahinletsigma,t=Typing.type_ofenvsigmacinletconcl=Proofview.Goal.conclglinifoccur_existentialsigmat||occur_existentialsigmaconclthenletsigma=Evd.clear_metassigmaintryletsigma=Unification.w_unifyenvsigmaCONV~flags:auto_unif_flagsconcltinProofview.Unsafe.tclEVARSADVANCEsigma<*>exact_no_checkcwithewhenCErrors.noncriticale->Proofview.tclZEROeelseProofview.Unsafe.tclEVARSsigma<*>exact_checkcend(* Util *)(* Serait-ce possible de compiler d'abord la tactique puis de faire la
substitution sans passer par bdize dont l'objectif est de préparer un
terme pour l'affichage ? (HH) *)(* Si on enlève le dernier argument (gl) conclPattern est calculé une
fois pour toutes : en particulier si Pattern.somatch produit une UserError
Ce qui fait que si la conclusion ne matche pas le pattern, Auto échoue, même
si après Intros la conclusion matche le pattern.
*)(* conclPattern doit échouer avec error car il est rattraper par tclFIRST *)letconclPatternconclpattac=letconstr_bindingsenvsigma=matchpatwith|None->Proofview.tclUNITId.Map.empty|Somepat->tryProofview.tclUNIT(Constr_matching.matchesenvsigmapatconcl)withConstr_matching.PatternMatchingFailureasexn->let_,info=Exninfo.captureexninTacticals.tclZEROMSG~info(str"pattern-matching failed")inProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinconstr_bindingsenvsigma>>=funconstr_bindings->Proofview.tclProofInfo[@ocaml.warning"-3"]>>=fun(_name,poly)->letopenGenarginletopenGeninterpinletinjc=matchval_tag(topwitStdarg.wit_constr)with|Val.Basetag->Val.Dyn(tag,c)|_->assertfalseinletfoldidcaccu=Id.Map.addid(injc)accuinletlfun=Id.Map.foldfoldconstr_bindingsId.Map.emptyinletist={lfun;poly;extra=TacStore.empty}inmatchtacwith|GenArg(Glbwitwit,tac)->Ftactic.run(Geninterp.interpwitisttac)(fun_->Proofview.tclUNIT())end(***********************************************************)(** A debugging / verbosity framework for trivial and auto *)(***********************************************************)(** The following options allow to trigger debugging/verbosity
without having to adapt the scripts.
Note: if Debug and Info are both activated, Debug take precedence. *)letglobal_debug_trivial=reffalseletglobal_debug_auto=reffalseletglobal_info_trivial=reffalseletglobal_info_auto=reffalseletadd_optionlsrefe=Goptions.(declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=ls;optread=(fun()->!refe);optwrite=(:=)refe})let()=add_option["Debug";"Trivial"]global_debug_trivial;add_option["Debug";"Auto"]global_debug_auto;add_option["Info";"Trivial"]global_info_trivial;add_option["Info";"Auto"]global_info_autotypedebug_kind=ReportForTrivial|ReportForAutoletno_dbg(_,whatfor,_,_)=(Off,whatfor,0,ref[])letmk_trivial_dbgdebug=letd=ifdebug==Debug||!global_debug_trivialthenDebugelseifdebug==Info||!global_info_trivialthenInfoelseOffin(d,ReportForTrivial,0,ref[])letmk_auto_dbgdebug=letd=ifdebug==Debug||!global_debug_autothenDebugelseifdebug==Info||!global_info_autothenInfoelseOffin(d,ReportForAuto,0,ref[])letincr_dbg=function(dbg,whatfor,depth,trace)->(dbg,whatfor,depth+1,trace)(** A tracing tactic for debug/info trivial/auto *)lettclLOG(dbg,_,depth,trace)pptac=matchdbgwith|Off->tac|Debug->(* For "debug (trivial/auto)", we directly output messages *)lets=String.make(depth+1)'*'inProofview.(tclIFCATCH(tac>>=funv->tclENV>>=funenv->tclEVARMAP>>=funsigma->Feedback.msg_notice(strs++spc()++ppenvsigma++str". (*success*)");tclUNITv)tclUNIT(fun(exn,info)->tclENV>>=funenv->tclEVARMAP>>=funsigma->Feedback.msg_notice(strs++spc()++ppenvsigma++str". (*fail*)");tclZERO~infoexn))|Info->(* For "info (trivial/auto)", we store a log trace *)Proofview.(tclIFCATCH(tac>>=funv->trace:=(depth,Somepp)::!trace;tclUNITv)Proofview.tclUNIT(fun(exn,info)->trace:=(depth,None)::!trace;tclZERO~infoexn))(** For info, from the linear trace information, we reconstitute the part
of the proof tree we're interested in. The last executed tactic
comes first in the trace (and it should be a successful one).
[depth] is the root depth of the tree fragment we're visiting.
[keep] means we're in a successful tree fragment (the very last
tactic has been successful). *)letreccleanup_info_tracedepthacc=function|[]->acc|(d,Somepp)::l->cleanup_info_traced((d,pp)::acc)l|l->cleanup_info_tracedepthacc(erase_subtreedepthl)anderase_subtreedepth=function|[]->[]|(d,_)::l->ifInt.equalddepththenlelseerase_subtreedepthlletpr_info_atomenvsigma(d,pp)=str(String.maked' ')++ppenvsigma++str"."letpr_info_traceenvsigma=function|(Info,_,_,{contents=(d,Somepp)::l})->Feedback.msg_notice(prlist_with_sepfnl(pr_info_atomenvsigma)(cleanup_info_traced[(d,pp)]l))|_->()letpr_info_nop=function|(Info,_,_,_)->Feedback.msg_notice(str"idtac.")|_->()letpr_dbg_header=function|(Off,_,_,_)->()|(Debug,ReportForTrivial,_,_)->Feedback.msg_notice(str"(* debug trivial: *)")|(Debug,ReportForAuto,_,_)->Feedback.msg_notice(str"(* debug auto: *)")|(Info,ReportForTrivial,_,_)->Feedback.msg_notice(str"(* info trivial: *)")|(Info,ReportForAuto,_,_)->Feedback.msg_notice(str"(* info auto: *)")lettclTRY_dbgdtac=letdelayf=Proofview.tclUNIT()>>=fun()->f()inlettac=delay(fun()->pr_dbg_headerd;tac)>>=fun()->Proofview.tclENV>>=funenv->Proofview.tclEVARMAP>>=funsigma->pr_info_traceenvsigmad;Proofview.tclUNIT()inletafter=delay(fun()->pr_info_nopd;Proofview.tclUNIT())inTacticals.tclORELSE0tacafter(**************************************************************************)(* The Trivial tactic *)(**************************************************************************)(* local_db is a Hint database containing the hypotheses of current goal *)(* Papageno : cette fonction a été pas mal simplifiée depuis que la base
de Hint impérative a été remplacée par plusieurs bases fonctionnelles *)letauto_flags_of_statest=auto_unif_flags_ofTransparentState.fullstlethintmap_ofenvsigmasecvarshdcconcl=matchhdcwith|None->Hint_db.map_none~secvars|Somehdc->ifoccur_existentialsigmaconclthen(fundb->matchHint_db.map_eautoenvsigma~secvarshdcconcldbwith|ModeMatch(_,l)->l|ModeMismatch->[])elseHint_db.map_autoenvsigma~secvarshdcconclletexists_evaluable_referenceenv=function|Evaluable.EvalConstRef_->true|Evaluable.EvalProjectionRef_->true|Evaluable.EvalVarRefv->tryignore(Environ.lookup_namedvenv);truewithNot_found->falseletdbg_introdbg=tclLOGdbg(fun__->str"intro")introletdbg_assumptiondbg=tclLOGdbg(fun__->str"assumption")assumptionletintro_registerdbgkontdb=Proofview.tclTHEN(dbg_introdbg)@@Proofview.Goal.enterbeginfungl->letextend_local_dbdecldb=letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinpush_resolve_hypenvsigma(Context.Named.Declaration.get_iddecl)dbinTacticals.onLastDecl(fundecl->kont(extend_local_dbdecldb))endletrectrivial_fail_dbdbgdb_listlocal_db=Proofview.tclINDEPENDENT@@Tacticals.tclORELSE0(dbg_assumptiondbg)@@Tacticals.tclORELSE0(intro_registerdbg(trivial_fail_dbdbgdb_list)local_db)@@Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletsecvars=compute_secvarsglinlethdc=trySome(decompose_app_boundsigmaconcl)withBound->Noneinlethintmap=hintmap_ofenvsigmasecvarshdcconclinlethinttac=tac_of_hintdbgdb_listlocal_dbconclin(local_db::db_list)|>List.map_append(fundb->tryhintmapdbwithNot_found->[])|>List.filter_mapbeginfunh->ifInt.equal(FullHint.priorityh)0thenSome(Tacticals.tclCOMPLETE(hinttach))elseNoneend|>Tacticals.tclFIRSTendandtac_of_hintdbgdb_listlocal_dbconcl=lettactic=function|Res_pfh->unify_resolve_nodeltah|ERes_pf_->Proofview.Goal.enter(fungl->letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"eres_pf"))|Give_exacth->exacth|Res_pf_THEN_trivial_failh->Tacticals.tclTHEN(unify_resolve_nodeltah)(* With "(debug) trivial", we shouldn't end here, and
with "debug auto" we don't display the details of inner trivial *)(trivial_fail_db(no_dbgdbg)db_listlocal_db)|Unfold_nthc->Proofview.Goal.enterbeginfungl->ifexists_evaluable_reference(Proofview.Goal.envgl)cthenTacticals.tclPROGRESS(reduce(Unfold[AllOccurrences,c])Locusops.onConcl)elseletinfo=Exninfo.reify()inTacticals.tclFAIL~info(str"Unbound reference")end|Extern(p,tacast)->conclPatternconclptacastinletpr_hinthenvsigma=letorigin=matchFullHint.databasehwith|None->mt()|Somen->str" (in "++strn++str")"inFullHint.printenvsigmah++origininfunh->tclLOGdbg(pr_hinth)(FullHint.runhtactic)(** The use of the "core" database can be de-activated by passing
"nocore" amongst the databases. *)letgen_trivial?(debug=Off)lemsdbnames=Hints.wrap_hint_warning@@Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletdb_list=matchdbnameswith|Somedbnames->make_db_listdbnames|None->current_pure_db()inletd=mk_trivial_dbgdebuginletlocal_db=make_local_hint_dbenvsigmafalselemsintclTRY_dbgd(trivial_fail_dbddb_listlocal_db)end(**************************************************************************)(* The classical Auto tactic *)(**************************************************************************)exceptionSearchBound(* n is the max depth of search *)(* local_db contains the local Hypotheses *)letsearchdndb_listlems=letmake_local_dbgl=letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinmake_local_hint_dbenvsigmafalselemsinletrecsearchdnlocal_db=ifInt.equaln0thenletinfo=Exninfo.reify()inProofview.tclZERO~infoSearchBoundelseTacticals.tclORELSE0(dbg_assumptiond)@@Tacticals.tclORELSE0(intro_registerd(searchdn)local_db)@@Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinlethyps=Proofview.Goal.hypsglinletd'=incr_dbgdinletsecvars=compute_secvarsglinlethdc=trySome(decompose_app_boundsigmaconcl)withBound->Noneinlethintmap=hintmap_ofenvsigmasecvarshdcconclinlethinttac=tac_of_hintddb_listlocal_dbconclin(local_db::db_list)|>List.map_append(fundb->tryhintmapdbwithNot_found->[])|>List.mapbeginfunh->Proofview.tclTHEN(hinttach)@@Proofview.Goal.enterbeginfungl->lethyps'=Proofview.Goal.hypsglinletlocal_db'=(* update local_db if local hypotheses have changed *)ifhyps'==hypsthenlocal_dbelsemake_local_dbglinsearchd'(n-1)local_db'endend|>Tacticals.tclFIRSTendinProofview.Goal.enterbeginfungl->searchdn(make_local_dbgl)endletdefault_search_depth=5letgen_auto?(debug=Off)nlemsdbnames=Hints.wrap_hint_warning@@Proofview.Goal.enterbeginfungl->letn=matchnwithNone->default_search_depth|Somen->ninletdb_list=matchdbnameswith|Somedbnames->make_db_listdbnames|None->current_pure_db()inletd=mk_auto_dbgdebugintclTRY_dbgd(searchdndb_listlems)endletauto?(debug=Off)nlemsdbnames=gen_auto~debug(Somen)lems(Somedbnames)letdefault_auto=autodefault_search_depth[][]