123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413(************************************************************************)(* * 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) *)(************************************************************************)(* This file is (C) Copyright 2006-2015 Microsoft Corporation and Inria. *)openUtilopenNamesopenEvdopenTermopenConstropenContextopenTermopsopenPrinteropenLocusopsopenLtac_pluginopenProofview.NotationsopenLibnamesopenSsrmatching_pluginopenSsrmatchingopenSsrastopenSsrprintersmoduleRelDecl=Context.Rel.DeclarationmoduleNamedDecl=Context.Named.Declarationleterrorstrmx=CErrors.user_errxletallocc=Some(false,[])(** Bound assumption argument *)(* The Ltac API does have a type for assumptions but it is level-dependent *)(* and therefore impractical to use for complex arguments, so we substitute *)(* our own to have a uniform representation. Also, we refuse to intern *)(* idents that match global/section constants, since this would lead to *)(* fragile Ltac scripts. *)lethyp_id(SsrHyp(_,id))=idlethyp_err?locmsgid=CErrors.user_err?locPp.(strmsg++Id.printid)letnot_section_idid=not(Termops.is_section_variable(Global.env())id)lethyps_ids=List.maphyp_idletreccheck_hyps_uniqids=function|SsrHyp(loc,id)::_whenList.memidids->hyp_err?loc"Duplicate assumption "id|SsrHyp(_,id)::hyps->check_hyps_uniq(id::ids)hyps|[]->()letrecpf_check_hyps_uniqids=function|SsrHyp(loc,id)::_whenList.memidids->Tacticals.tclZEROMSG?locPp.(str"Duplicate assumption "++Id.printid)|SsrHyp(_,id)::hyps->pf_check_hyps_uniq(id::ids)hyps|[]->Proofview.tclUNIT()letcheck_hyp_existshyps(SsrHyp(_,id))=tryignore(Context.Named.lookupidhyps)withNot_found->errorstrmPp.(str"No assumption is named "++Id.printid)lettest_hyp_existshyps(SsrHyp(_,id))=tryignore(Context.Named.lookupidhyps);truewithNot_found->falselethoikf=functionHypx->fx|Idx->fxlethoi_id=hoikhyp_idletmk_hinttac=false,[Sometac]letmk_orhinttacs=true,tacsletnullhint=true,[]letnohint=false,[]openPpleterrorstrmx=CErrors.user_errxletanomalys=CErrors.anomaly(strs)(* Tentative patch from util.ml *)letarray_fold_right_fromnfva=letrecfoldn=ifn>=Array.lengthvthenaelsefv.(n)(fold(succn))infoldnletarray_app_tlvl=ifArray.lengthv=0theninvalid_arg"array_app_tl";array_fold_right_from1(funel->e::l)vlletarray_list_of_tlv=ifArray.lengthv=0theninvalid_arg"array_list_of_tl";array_fold_right_from1(funel->e::l)v[](* end patch *)letoption_assert_getomsg=matchowith|None->CErrors.anomalymsg|Somex->x(** Constructors for rawconstr *)openGlob_termletmkRHole=DAst.make@@GHole(GInternalHole)letrecmkRHolesn=ifn>0thenmkRHole::mkRHoles(n-1)else[]letrecisRHolescl=matchclwith|[]->true|c::l->matchDAst.getcwithGHole_->isRHolesl|_->falseletmkRAppfargs=ifargs=[]thenfelseDAst.make@@GApp(f,args)letmkRVarid=DAst.make@@GRef(GlobRef.VarRefid,None)letmkRltacVarid=DAst.make@@GVar(id)letmkRCastrcrt=DAst.make@@GCast(rc,SomeDEFAULTcast,rt)letmkRType=DAst.make@@GSortGlob_ops.glob_Type_sortletmkRProp=DAst.make@@GSortGlob_ops.glob_Prop_sortletmkRArrowrt1rt2=DAst.make@@GProd(Anonymous,None,Explicit,rt1,rt2)letmkRConstructc=DAst.make@@GRef(GlobRef.ConstructRefc,None)letmkRIndmind=DAst.make@@GRef(GlobRef.IndRefmind,None)letmkRLambdanst=DAst.make@@GLambda(n,None,Explicit,s,t)letrecmkRnatn=ifn<=0thenDAst.make@@GRef(Coqlib.lib_ref"num.nat.O",None)elsemkRApp(DAst.make@@GRef(Coqlib.lib_ref"num.nat.S",None))[mkRnat(n-1)]letglob_constristgenv=function|_,Somece->letvars=Id.Map.fold(funx_accu->Id.Set.addxaccu)ist.Tacinterp.lfunId.Set.emptyinletltacvars={Constrintern.empty_ltac_signwithConstrintern.ltac_vars=vars}inConstrintern.intern_genPretyping.WithoutTypeConstraint~ltacvarsgenvEvd.(from_envgenv)ce|rc,None->rcletintern_termistenv(_,c)=glob_constristenvc(* Estimate a bound on the number of arguments of a raw constr. *)(* This is not perfect, because the unifier may fail to *)(* typecheck the partial application, so we use a minimum of 5. *)(* Also, we don't handle delayed or iterated coercions to *)(* FUNCLASS, which is probably just as well since these can *)(* lead to infinite arities. *)letsplay_open_constrenv(sigma,c)=lett=Retyping.get_type_ofenvsigmacinReductionops.whd_decompose_prodenvsigmatletisAppIndenvsigmac=letc=Reductionops.clos_whd_flagsRedFlags.allenvsigmacinletc,_=EConstr.decompose_appsigmacinEConstr.isIndsigmac(** Generic argument-based globbing/typing utilities *)letinterp_refineenvsigmaist~conclrc=letconstrvars=Tacinterp.extract_ltac_constr_valuesistenvinletvars={Glob_ops.empty_lvarwithLtac_pretype.ltac_constrs=constrvars;ltac_genargs=ist.Tacinterp.lfun}inletkind=Pretyping.OfTypeconclinletflags=Pretyping.{use_coercions=true;use_typeclasses=UseTC;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;}inletsigma,c=Pretyping.understand_ltacflagsenvsigmavarskindrcin(* ppdebug(lazy(str"sigma@interp_refine=" ++ pr_evar_map None sigma)); *)debug_ssr(fun()->str"c@interp_refine="++Printer.pr_econstr_envenvsigmac);(sigma,c)letinterp_open_constrenvsigmaistgc=let(sigma,(c,_))=Tacinterp.interp_open_constr_with_bindingsistenvsigma(gc,Tactypes.NoBindings)in(sigma,c)letinterp_termenvsigmaist(_,c)=interp_open_constrenvsigmaistcletinterp_hypistenvsigma(SsrHyp(loc,id))=letid'=Tacinterp.interp_hypistenvsigmaCAst.(make?locid)inifnot_section_idid'thenSsrHyp(loc,id')elsehyp_err?loc"Can't clear section hypothesis "id'letinterp_hypsistenvsigmaghyps=lethyps=List.map(interp_hypistenvsigma)ghypsincheck_hyps_uniq[]hyps;hyps(* Old terms *)letmk_termkc=k,(mkRHole,Somec)letmk_ltermc=mk_termNoFlagc(* New terms *)letmk_ast_closure_termat={annotation=a;body=t;interp_env=None;glob_env=None;}letglob_ast_closure_term(ist:Genintern.glob_sign)t=letist={ast_ltacvars=ist.Genintern.ltacvars;ast_intern_sign=ist.Genintern.intern_sign;ast_extra=ist.Genintern.extra;}in{twithglob_env=Someist}letsubst_ast_closure_term(_s:Mod_subst.substitution)t=(* _s makes sense only for glob constr *)tletinterp_ast_closure_term(ist:Geninterp.interp_sign)envsigmat=(* sigma is only useful if we want to interp *now*, later we have
* a potentially different gl.sigma *){twithinterp_env=Someist}letssrterm_of_ast_closure_term{body;annotation}=letc=matchannotationwith|`Parens->InParens|`At->WithAt|_->NoFlaginmk_termcbodyletssrdgens_of_parsed_dgens=function|[],clr->{dgens=[];gens=[];clr}|[gens],clr->{dgens=[];gens;clr}|[dgens;gens],clr->{dgens;gens;clr}|_->assertfalseletnbargs_open_constrenvoc=letpl,_=splay_open_constrenvocinList.lengthplletpf_nbargsenvsigmac=nbargs_open_constrenv(sigma,c)letinternal_names=ref[]letadd_internal_namept=internal_names:=pt::!internal_namesletis_internal_names=List.exists(funp->ps)!internal_namesletmk_internal_ids=lets'=Printf.sprintf"_%s_"sinlets'=String.map(func->ifc=' 'then'_'elsec)s'inadd_internal_name((=)s');Id.of_strings'letsame_prefixstn=letrecloopi=i=n||s.[i]=t.[i]&&loop(i+1)inloop0letskip_digitss=letn=String.lengthsinletrecloopi=ifi<n&&is_digits.[i]thenloop(i+1)elseiinloopletmk_tagged_idti=Id.of_string(Printf.sprintf"%s%d_"ti)letis_taggedts=letn=String.lengths-1andm=String.lengthtinm<n&&s.[n]='_'&&same_prefixstm&&skip_digitssm=nletevar_tag="_evar_"let_=add_internal_name(is_taggedevar_tag)letmk_evar_namen=Name(mk_tagged_idevar_tagn)letssr_anon_hyp="Hyp"letwildcard_tag="_the_"letwildcard_post="_wildcard_"lethas_wildcard_tags=letn=String.lengthsinletm=String.lengthwildcard_taginletm'=String.lengthwildcard_postinn<m+m'+2&&same_prefixswildcard_tagm&&String.subs(n-m')m'=wildcard_post&&skip_digitssm=n-m'-2let_=add_internal_namehas_wildcard_tagletdischarged_tag="_discharged_"letmk_discharged_idid=Id.of_string(Printf.sprintf"%s%s_"discharged_tag(Id.to_stringid))lethas_discharged_tags=letm=String.lengthdischarged_tagandn=String.lengths-1inm<n&&s.[n]='_'&&same_prefixsdischarged_tagmlet_=add_internal_namehas_discharged_tagletis_discharged_idid=has_discharged_tag(Id.to_stringid)letmax_suffixm(t,j0astj0)id=lets=Id.to_stringidinletn=String.lengths-1inletdn=String.lengtht-1-ninleti0=j0-dninifnot(i0>=m&&s.[n]='_'&&same_prefixstm)thentj0elseletrecloopi=ifi<i0&&s.[i]='0'thenloop(i+1)elseif(ifi<i0thenskip_digitssi=nelsele_s_ti)thens,ielsetj0andle_s_ti=letds=s.[i]anddt=t.[i+dn]inifds=dttheni=n||le_s_t(i+1)elsedt<ds&&skip_digitssi=ninloopm(** creates a fresh (w.r.t. `gl_ids` and internal names) inaccessible name of the form _tXX_ *)letmk_anon_idtgl_ids=letm,si0,id0=lets=ref(Printf.sprintf"_%s_"t)inifis_internal_name!sthens:="_"^!s;letn=String.length!s-1inletrecloopij=letd=!s.[i]inifnot(is_digitd)theni+1,jelseloop(i-1)(ifd='0'thenjelsei)inletm,j=loop(n-1)ninm,(!s,j),Id.of_string_soft!sinifnot(List.memid0gl_ids)thenid0elselets,i=List.fold_left(max_suffixm)si0gl_idsinletopenBytesinlets=of_stringsinletn=lengths-1inletrecloopi=ifgetsi='9'then(setsi'0';loop(i-1))elseifi<mthen(setsn'0';setsm'1';cats(of_string"_"))else(setsi(Char.chr(Char.code(getsi)+1));s)inId.of_string_soft(Bytes.to_string(loop(n-1)))letconvert_concl_no_checkt=Tactics.convert_concl~cast:false~check:falsetDEFAULTcastletconvert_concl~checkt=Tactics.convert_concl~cast:false~checktDEFAULTcast(* Reduction that preserves the Prod/Let spine of the "in" tactical. *)letinc_safen=ifn=0thennelsen+1letrecsafe_depthsc=matchEConstr.kindscwith|LetIn({binder_name=Namex},_,_,c')whenis_discharged_idx->safe_depthsc'+1|LetIn(_,_,_,c')|Prod(_,_,c')->inc_safe(safe_depthsc')|_->0letred_safe(r:Reductionops.reduction_function)esc0=letrecred_toecn=matchEConstr.kindscwith|Prod(x,t,c')whenn>0->lett'=restinlete'=EConstr.push_rel(RelDecl.LocalAssum(x,t'))einEConstr.mkProd(x,t',red_toe'c'(n-1))|LetIn(x,b,t,c')whenn>0->lett'=restinlete'=EConstr.push_rel(RelDecl.LocalAssum(x,t'))einEConstr.mkLetIn(x,resb,t',red_toe'c'(n-1))|_->rescinred_toec0(safe_depthsc0)letis_id_constrsigmac=matchEConstr.kindsigmacwith|Lambda(_,_,c)whenEConstr.isRelsigmac->1=EConstr.destRelsigmac|_->falseletred_product_skip_idenvsigmac=matchEConstr.kindsigmacwith|App(hd,args)whenArray.lengthargs=1&&is_id_constrsigmahd->args.(0)|_->matchTacred.red_productenvsigmacwithSomec->c|None->cletssrevaltacistgtac=Tacinterp.tactic_of_valueistgtac(** Open term to lambda-term coercion *)(* {{{ ************************************)(* This operation takes a goal gl and an open term (sigma, t), and *)(* returns a term t' where all the new evars in sigma are abstracted *)(* with the mkAbs argument, i.e., for mkAbs = mkLambda then there is *)(* some duplicate-free array args of evars of sigma such that the *)(* term mkApp (t', args) is convertible to t. *)(* This makes a useful shorthand for local definitions in proofs, *)(* i.e., pose succ := _ + 1 means pose succ := fun n : nat => n + 1, *)(* and, in context of the 4CT library, pose mid := maps id means *)(* pose mid := fun d : detaSet => @maps d d (@id (datum d)) *)(* Note that this facility does not extend to set, which tries *)(* instead to fill holes by matching a goal subterm. *)(* The argument to "have" et al. uses product abstraction, e.g. *)(* have Hmid: forall s, (maps id s) = s. *)(* stands for *)(* have Hmid: forall (d : dataSet) (s : seq d), (maps id s) = s. *)(* We also use this feature for rewrite rules, so that, e.g., *)(* rewrite: (plus_assoc _ 3). *)(* will execute as *)(* rewrite (fun n => plus_assoc n 3) *)(* i.e., it will rewrite some subterm .. + (3 + ..) to .. + 3 + ... *)(* The convention is also used for the argument of the congr tactic, *)(* e.g., congr (x + _ * 1). *)(* Replace new evars with lambda variables, retaining local dependencies *)(* but stripping global ones. We use the variable names to encode the *)(* the number of dependencies, so that the transformation is reversible. *)letenv_sizeenv=List.length(Environ.named_contextenv)letresolve_typeclassesenvsigma~where~fail=letfilter=letevset=Evarutil.undefined_evars_of_termsigmawhereinfunk_->Evar.Set.memkevsetinTypeclasses.resolve_typeclasses~filter~failenvsigmaletabs_evarsenvsigma0?(rigid=[])(sigma,c0)=letc0=Evarutil.nf_evarsigmac0inletsigma0,ucst=sigma0,Evd.evar_universe_contextsigmainletnenv=env_sizeenvinletabs_evarnk=letopenEConstrinletevi=Evd.find_undefinedsigmakinletconcl=Evd.evar_concleviinletdc=CList.firstnn(evar_filtered_contextevi)inletabs_dcc=function|NamedDecl.LocalDef(x,b,t)->mkNamedLetInsigmaxbt(mkArrowtx.binder_relevancec)|NamedDecl.LocalAssum(x,t)->mkNamedProdsigmaxtcinlett=Context.Named.fold_insideabs_dc~init:concldcinEvarutil.nf_evarsigmatinletrecputevlistc=matchEConstr.kindsigmacwith|Evar(k,a)->ifList.mem_assockevlist||Evd.memsigma0k||List.memkrigidthenevlistelseletn=max0(SList.lengtha-nenv)inlett=abs_evarnkin(k,(n,t))::putevlistt|_->EConstr.foldsigmaputevlistcinletevlist=put[]c0inifList.is_emptyevlistthenc0,[],ucstelseletopenEConstrinletreclookupki=function|[]->0,0|(k',(n,_))::evl->ifk=k'theni,nelselookupk(i+1)evlinletrecgetic=matchEConstr.kindsigmacwith|Evar(ev,a)->letj,n=lookupevievlistinifj=0thenEConstr.mapsigma(geti)celseifn=0thenmkReljelseleta=Array.of_list@@Evd.expand_existentialsigma(ev,a)inmkApp(mkRelj,Array.initn(funk->getia.(n-1-k)))|_->EConstr.map_with_binderssigma((+)1)geticinletrecloopci=function|(_,(n,t))::evl->loop(mkLambda(make_annot(mk_evar_namen)ERelevance.relevant,get(i-1)t,c))(i-1)evl|[]->cinloop(get1c0)1evlist,List.mapfstevlist,ucst(* As before but if (?i : T(?j)) and (?j : P : Prop), then the lambda for i
* looks like (fun evar_i : (forall pi : P. T(pi))) thanks to "loopP" and all
* occurrences of evar_i are replaced by (evar_i evar_j) thanks to "app".
*
* If P can be solved by ssrautoprop (that defaults to trivial), then
* the corresponding lambda looks like (fun evar_i : T(c)) where c is
* the solution found by ssrautoprop.
*)letssrautoprop_tac=ref(Proofview.Goal.enter(fungl->assertfalse))(* Thanks to Arnaud Spiwack for this snippet *)letcall_on_evarenvsigmatace=trylettac=Proofview.Unsafe.tclSETGOALS[Proofview.with_empty_statee]<*>tacinlet_,init=Proofview.initsigma[]inletname=Names.Id.of_string"legacy_pe"inlet(_,final,_,_)=Proofview.apply~name~poly:falseenvtacinitinlet(gs,final)=Proofview.proofviewfinalinlet()=if(gs<>[])thenerrorstrm(str"Should we tell the user?")infinalwithLogic_monad.TacticFailureeassrc->let(_,info)=Exninfo.capturesrcinExninfo.iraise(e,info)openPpmoduleIntset=Evar.Setletabs_evars_pirrelenvsigma0(sigma,c0)=letc0=Evarutil.nf_evarsigmac0inletnenv=env_sizeenvinletabs_evarnk=letopenEConstrinletevi=Evd.find_undefinedsigmakinletconcl=Evd.evar_concleviinletdc=CList.firstnn(evar_filtered_contextevi)inletabs_dcc=function|NamedDecl.LocalDef(x,b,t)->mkNamedLetInsigmaxbt(mkArrowtx.binder_relevancec)|NamedDecl.LocalAssum(x,t)->mkNamedProdsigmaxtcinlett=Context.Named.fold_insideabs_dc~init:concldcinEvarutil.nf_evarsigmatinletrecputevlistc=matchEConstr.kindsigmacwith|Evar(k,a)->ifList.mem_assockevlist||Evd.memsigma0kthenevlistelseletn=max0(SList.lengtha-nenv)in(* FIXME? this is not the right environment in general *)letk_ty=Retyping.get_sort_family_ofenvsigma(Evd.evar_concl(Evd.find_undefinedsigmak))inletis_prop=k_ty=InPropinlett=abs_evarnkin(k,(n,t,is_prop))::putevlistt|_->EConstr.foldsigmaputevlistcinletevlist=put[]c0inifevlist=[]then0,c0elseletevplist=letdepev=List.fold_left(funevs(_,(_,t,_))->Intset.unionevs(Evarutil.undefined_evars_of_termsigmat))Intset.emptyevlistinList.filter(fun(i,(_,_,b))->b&&Intset.memidepev)evlistinletevlist,evplist,sigma=ifevplist=[]thenevlist,[],sigmaelseList.fold_left(fun(ev,evp,sigma)(i,(_,t,_)asp)->tryletsigma=call_on_evarenvsigma!ssrautoprop_taciinList.filter(fun(j,_)->j<>i)ev,evp,sigmawithewhenCErrors.noncriticale->ev,p::evp,sigma)(evlist,[],sigma)(List.revevplist)inletc0=Evarutil.nf_evarsigmac0inletnf(k,(n,t,p))=(k,(n,Evarutil.nf_evarsigmat,p))inletevlist=List.mapnfevlistinletevplist=List.mapnfevplistinletreclookupki=function|[]->0,0|(k',(n,_,_))::evl->ifk=k'theni,nelselookupk(i+1)evlinletopenEConstrinletrecgetevlistic=matchEConstr.kindsigmacwith|Evar(ev,a)->letj,n=lookupevievlistinifj=0thenEConstr.mapsigma(getevlisti)celseifn=0thenmkReljelseleta=Array.of_list@@Evd.expand_existentialsigma(ev,a)inmkApp(mkRelj,Array.initn(funk->getevlistia.(n-1-k)))|_->EConstr.map_with_binderssigma((+)1)(getevlist)icinletrecappextra_argsic=matchdecompose_app_listsigmacwith|hd,argswhenisRelsigmahd&&destRelsigmahd=i->letj=destRelsigmahdinmkApp(mkRelj,Array.of_list(List.map(Vars.lift(i-1))extra_args@args))|_->EConstr.map_with_binderssigma((+)1)(appextra_args)icinletrecloopPevlistaccui=function|[]->List.revaccu|(_,(n,t,_))::evl->lett=getevlist(i-1)tinletn=Name(Id.of_string(ssr_anon_hyp^string_of_intn))inloopPevlist(RelDecl.LocalAssum(make_annotnERelevance.relevant,t)::accu)(i-1)evlinletrecloopci=function|(_,(n,t,_))::evl->letevs=Evarutil.undefined_evars_of_termsigmatinlett_evplist=List.filter(fun(k,_)->Intset.memkevs)evplistinletctx_t=loopPt_evplist[]1t_evplistinlett=EConstr.it_mkProd_or_LetIn(gett_evplist1t)ctx_tinlett=getevlist(i-1)tinletextra_args=List.rev_map(fun(k,_)->mkRel(fst(lookupkievlist)))t_evplistinletc=ifextra_args=[]thencelseappextra_args1cinloop(mkLambda(make_annot(mk_evar_namen)ERelevance.relevant,t,c))(i-1)evl|[]->cinletres=loop(getevlist1c0)1evlistinList.lengthevlist,res(* Strip all non-essential dependencies from an abstracted term, generating *)(* standard names for the abstracted holes. *)letnb_evar_deps=function|Nameid->lets=Id.to_stringidinifnot(is_taggedevar_tags)then0elseletm=String.lengthevar_tagin(tryint_of_string(String.subsm(String.lengths-1-m))withewhenCErrors.noncriticale->0)|_->0lettype_idenvsigmat=Id.of_string(Namegen.hdcharenvsigmat)letpfe_type_relevance_ofenvsigmat=letsigma,ty=Typing.type_ofenvsigmatinsigma,ty,Retyping.relevance_of_termenvsigmatletabs_ctermenvsigmanc0=letopenEConstrinifn<=0thenc0elseletnoargs=[|0|]inleteva=Array.makennoargsinletrecstripic=matchEConstr.kindsigmacwith|App(f,a)whenisRelsigmaf->letj=i-destRelsigmafinifj>=n||eva.(j)=noargsthenmkApp(f,Array.map(stripi)a)elseletdp=eva.(j)inletnd=Array.lengthdp-1inletmkargk=stripia.(ifk<ndthendp.(k+1)-jelsek+dp.(0))inmkApp(f,Array.init(Array.lengtha-dp.(0))mkarg)|_->EConstr.map_with_binderssigma((+)1)stripicinletrecstrip_ndepsjic=matchEConstr.kindsigmacwith|Prod(x,t,c1)wheni<j->letdl,c2=strip_ndepsj(i+1)c1inifVars.noccurnsigma1c2thendl,Vars.lift(-1)c2elsei::dl,mkProd(x,stripit,c2)|LetIn(x,b,t,c1)wheni<j->let_,_,c1'=destProdsigmac1inletdl,c2=strip_ndepsj(i+1)c1'inifVars.noccurnsigma1c2thendl,Vars.lift(-1)c2elsei::dl,mkLetIn(x,stripib,stripit,c2)|_->[],stripicinletrecstrip_evarsic=matchEConstr.kindsigmacwith|Lambda(x,t1,c1)wheni<n->letna=nb_evar_depsx.binder_nameinletdl,t2=strip_ndeps(i+na)it1inletna'=List.lengthdlineva.(i)<-Array.of_list(na-na'::dl);letx'=ifna'=0thenName(type_idenvsigmat2)elsemk_evar_namena'inmkLambda({xwithbinder_name=x'},t2,strip_evars(i+1)c1)(* if noccurn 1 c2 then lift (-1) c2 else
mkLambda (Name (pf_type_id gl t2), t2, c2) *)|_->stripicinstrip_evars0c0(* }}} *)letrecconstr_namesigmac=matchEConstr.kindsigmacwith|Varid->Nameid|Cast(c',_,_)->constr_namesigmac'|Const(cn,_)->Name(Label.to_id(Constant.labelcn))|App(c',_)->constr_namesigmac'|_->Anonymousletpf_mkprodenvsigmac?(name=constr_namesigmac)cl=letsigma,t,r=pfe_type_relevance_ofenvsigmacinifname<>Anonymous||EConstr.Vars.noccurnsigma1clthensigma,EConstr.mkProd(make_annotnamer,t,cl)elsesigma,EConstr.mkProd(make_annot(Name(type_idenvsigmat))r,t,cl)(** look up a name in the ssreflect internals module *)letssrdirpath=DirPath.make[Id.of_string"ssreflect"]letssrqidname=Libnames.make_qualidssrdirpath(Id.of_stringname)letmkSsrRefname=letqn=Format.sprintf"plugins.ssreflect.%s"nameinifCoqlib.has_refqnthenCoqlib.lib_refqnelseCErrors.user_errPp.(str"Small scale reflection library not loaded ("++strname++str")")letmkSsrRRefname=(DAst.make@@GRef(mkSsrRefname,None)),NoneletmkSsrConstenvsigmaname=EConstr.fresh_globalenvsigma(mkSsrRefname)letmkProtenvsigmatc=letsigma,prot=mkSsrConstenvsigma"protect_term"insigma,EConstr.mkApp(prot,[|t;c|])letmkEtaAppcnimin=letopenEConstrinifn=0thencelseletnargs,mkarg=ifn<0then-n,(funi->mkRel(imin+i))elseletimax=imin+n-1inn,(funi->mkRel(imax-i))inmkApp(c,Array.initnargsmkarg)letmkReflenvsigmatc=let(sigma,refl)=EConstr.fresh_globalenvsigmaCoqlib.(lib_ref"core.eq.refl")insigma,EConstr.mkApp(refl,[|t;c|])letdischarge_hyp(id',(id,mode))=letopenEConstrinletopenTacmachinProofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletcl'=Vars.subst_varsigmaid(Tacmach.pf_conclgl)inletdecl=pf_get_hypidglinmatchdecl,modewith|NamedDecl.LocalAssum_,_|NamedDecl.LocalDef_,"("->letid'={(NamedDecl.get_annotdecl)withbinder_name=Nameid'}inTactics.apply_type~typecheck:true(mkProd(id',NamedDecl.get_typedecl,cl'))[mkVarid]|NamedDecl.LocalDef(_,v,t),_->letid'={(NamedDecl.get_annotdecl)withbinder_name=Nameid'}inconvert_concl~check:true(mkLetIn(id',v,t,cl'))endletview_errorsgv=Tacticals.tclZEROMSG(str("Cannot "^s^" view ")++pr_termgv)openLocus(****************************** tactics ***********************************)letrewritetac?(under=false)dirc=(* Due to the new optional arg ?tac, application shouldn't be too partial *)letopenProofview.NotationsinProofview.Goal.enterbeginfun_->Equality.general_rewrite~where:None~l2r:(dir=L2R)AllOccurrences~freeze:true~dep:false~with_evars:false(c,Tactypes.NoBindings)<*>ifunderthenProofview.cycle1elseProofview.tclUNIT()end(**********************`:********* hooks ************************************)typename_hint=(int*EConstr.typesarray)optionrefletabs_ssrterm?(resolve_typeclasses=false)istenvsigmat=letsigma0=sigmainletsigma,ct=interp_termenvsigmaisttinlett=ifnotresolve_typeclassesthen(sigma,ct)elseletsigma=Typeclasses.resolve_typeclasses~fail:falseenvsigmainsigma,Evarutil.nf_evarsigmactinletc,abstracted_away,ucst=abs_evarsenvsigma0tinletn=List.lengthabstracted_awayinlett=abs_ctermenvsigma0ncinletsigma=Evd.merge_universe_contextsigma0ucstinsigma,t,nlettop_id=mk_internal_id"top assumption"letssr_n_tacseedn=Proofview.Goal.enterbeginfungl->letname=ifn=-1thenseedelse("ssr"^seed^string_of_intn)inletfailmsg=CErrors.user_err(Pp.strmsg)inlettacname=tryTacenv.locate_tactic(Libnames.qualid_of_ident(Id.of_stringname))withNot_found->tryTacenv.locate_tactic(ssrqidname)withNot_found->ifn=-1thenfail"The ssreflect library was not loaded"elsefail("The tactic "^name^" was not found")inlettacexpr=Tacexpr.Reference(ArgArg(Loc.tag@@tacname))inTacinterp.eval_tactic@@CAst.make(Tacexpr.TacArgtacexpr)endletdonetacn=ssr_n_tac"done"nopenConstrexpropenUtil(** Constructors for constr_expr *)letmkCProploc=CAst.make?loc@@CSortConstrexpr_ops.expr_Prop_sortletmkCTypeloc=CAst.make?loc@@CSortConstrexpr_ops.expr_Type_sortletmkCVar?locid=CAst.make?loc@@CRef(qualid_of_ident?locid,None)letrecmkCHoles?locn=ifn<=0then[]else(CAst.make?loc@@CHole(None))::mkCHoles?loc(n-1)letmkCHoleloc=CAst.make?loc@@CHole(None)letmkCLambda?locnametyt=CAst.make?loc@@CLambdaN([CLocalAssum([CAst.make?locname],None,DefaultExplicit,ty)],t)letmkCArrow?loctyt=CAst.make?loc@@CProdN([CLocalAssum([CAst.makeAnonymous],None,DefaultExplicit,ty)],t)letmkCCast?loctty=CAst.make?loc@@CCast(t,SomeDEFAULTcast,ty)letrecisCHoles=function{CAst.v=CHole_}::cl->isCHolescl|cl->cl=[]letrecisCxHoles=function({CAst.v=CHole_},None)::ch->isCxHolesch|_->falseletpf_interp_ty?(resolve_typeclasses=false)envsigma0istty=letn_binders=ref0inletty=matchtywith|a,(t,None)->letrecforce_typety=DAst.(map(function|GProd(x,r,k,s,t)->incrn_binders;GProd(x,r,k,s,force_typet)|GLetIn(x,r,v,oty,t)->incrn_binders;GLetIn(x,r,v,oty,force_typet)|_->DAst.get(mkRCasttymkRType)))tyina,(force_typet,None)|_,(_,Somety)->letrecforce_typety=CAst.(map(function|CProdN(abs,t)->n_binders:=!n_binders+List.length(List.flatten(List.map(functionCLocalAssum(nal,_,_,_)->nal|CLocalDef(na,_,_,_)->[na]|CLocalPattern_->(* We count a 'pat for 1; TO BE CHECKED *)[CAst.makeName.Anonymous])abs));CProdN(abs,force_typet)|CLetIn(n,v,oty,t)->incrn_binders;CLetIn(n,v,oty,force_typet)|_->(mkCCastty(mkCTypeNone)).v))tyinmk_termNoFlag(force_typety)inletstrip_cast(sigma,t)=letopenEConstrinletrecauxt=matchkind_of_typesigmatwith|CastType(t,ty)when!n_binders=0&&isSortsigmaty->t|ProdType(n,s,t)->decrn_binders;mkProd(n,s,auxt)|LetInType(n,v,ty,t)->decrn_binders;mkLetIn(n,v,ty,auxt)|_->anomaly"pf_interp_ty: ssr Type cast deleted by typecheck"insigma,auxtinletsigma,ctyasty=strip_cast(interp_termenvsigma0istty)inletty=ifnotresolve_typeclassesthentyelseletsigma=Typeclasses.resolve_typeclasses~fail:falseenvsigmainsigma,Evarutil.nf_evarsigmactyinletc,evs,ucst=abs_evarsenvsigma0tyinletn=List.lengthevsinletlam_c=abs_ctermenvsigma0ncinletctx,c=EConstr.decompose_lambda_n_assumsigmanlam_cinletsigma0=Evd.merge_universe_contextsigma0ucstinsigma0,n,EConstr.it_mkProd_or_LetIncctx,lam_c(* TASSI: given (c : ty), generates (c ??? : ty[???/...]) with m evars *)exceptionNotEnoughProductsletsaturate?(beta=false)?(bi_types=false)envsigmac?(ty=Retyping.get_type_ofenvsigmac)m=letreclooptyargssigman=letopenEConstrinifn=0thenletargs=List.revargsin(ifbetathenReductionops.whd_betaenvsigmaelsefunx->x)(EConstr.mkApp(c,Array.of_list(List.mappi2args))),ty,args,sigmaelsematchkind_of_typesigmatywith|ProdType(_,src,tgt)->letsigma=create_evar_defssigmainletargty=ifbi_typesthenReductionops.nf_betaiotaenvsigmasrcelsesrcinlet(sigma,x)=Evarutil.new_evarenvsigmaargtyinloop(EConstr.Vars.subst1xtgt)((m-n,x,argty)::args)sigma(n-1)|CastType(t,_)->looptargssigman|LetInType(_,v,_,t)->loop(EConstr.Vars.subst1vt)argssigman|SortType_->raiseNotEnoughProducts|AtomicType_->letty=(* FIXME *)(Reductionops.whd_allenvsigma)tyinmatchkind_of_typesigmatywith|ProdType_->looptyargssigman|_->raiseNotEnoughProductsinloopty[]sigmamletdependent_apply_error=tryCErrors.user_err(Pp.str"Could not fill dependent hole in \"apply\"")witherr->err(* TASSI: Sometimes Coq's apply fails. According to my experience it may be
* related to goals that are products and with beta redexes. In that case it
* guesses the wrong number of implicit arguments for your lemma. What follows
* is just like apply, but with a user-provided number n of implicits.
*
* Refine.refine function that handles type classes and evars but fails to
* handle "dependently typed higher order evars".
*
* Assumes that the type of [t] is a telescope with [n] leading product types.
* This is always the case as the only caller of applyn uses it with the output
* of abs_evars_pirrel which starts with n lambdas generated by abstraction.
* It also assumes [t] starts with [n] Lambda nodes.
*
* Refiner.refiner that does not handle metas with a non ground type but works
* with dependently typed higher order metas. *)letapplyn?(beta=false)~with_evars?(first_goes_last=false)nt=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinifwith_evarsthenletrefine=Refine.refine~typecheck:falsebeginfunsigma->letrecsaturatecargssigman=ifn=0thenargs,sigmaelsematchEConstr.kindsigmacwith|Lambda(_,argty,c)->letargty=Reductionops.nf_betaiotaenvsigma(EConstr.Vars.substlargsargty)inlet(sigma,x)=Evarutil.new_evarenvsigmaargtyinsaturatec(x::args)sigma(n-1)|_->assertfalseinlet_,ty=EConstr.decompose_prod_n_declssigman(Retyping.get_type_ofenvsigmat)inletargs,sigma=saturatet[]sigmaninletty=EConstr.Vars.substlargstyinletargs=Array.rev_of_listargsinlett=EConstr.mkApp(t,args)inlett=ifbetathenReductionops.whd_betaenvsigmatelsetinletsigma=unify_HOenvsigmatyconclin(* Set our own set of goals. In theory saturate generates them in the
right order, so we could just return sigma directly, but explicit is
better than implicit. *)letsigma=Evd.push_future_goals(snd@@Evd.pop_future_goalssigma)inletfoldsigmae=matchEConstr.kindsigmaewith|Evar(evk,_)->Evd.declare_future_goalevksigma|_->sigmainletsigma=Array.fold_leftfoldsigmaargsin(sigma,t)endinTacticals.tclTHENLIST[refine;Proofview.shelve_unifiable;Proofview.(iffirst_goes_lastthencycle1elsetclUNIT())]elseletsigma=Evd.push_future_goalssigmainlethyps=Environ.named_context_valenvinletinst=EConstr.identity_subst_valhypsinlett,args,sigma=letrecloopsigmaboargs=function(* saturate with metas *)|0->(t,args,sigma)|n->matchEConstr.kindsigmabowith|Lambda(_,ty,bo)->let()=ifnot(EConstr.Vars.closed0sigmaty)thenraisedependent_apply_errorinletty=Reductionops.nf_betaiotaenvsigmatyinlet(sigma,evk)=Evarutil.new_pure_evar~typeclass_candidate:falsehypssigmatyinloopsigmabo(evk::args)(n-1)|_->assertfalseinloopsigmat[]ninlet_,sigma=Evd.pop_future_goalssigmainletmapevk=Proofview.goal_with_stateevk(Proofview.Goal.stategl)inletsgl=List.rev_mapmapargsinletans=EConstr.applist(t,List.rev_map(funevk->EConstr.mkEvar(evk,inst))args)inletevk=Proofview.Goal.goalglinlet_=ifnot(Evarutil.occur_evar_uptosigmaevkans)then()elsePretype_errors.error_occur_checkenvsigmaevkansinletsigma=Evd.defineevkanssigmainTacticals.tclTHENLIST[Proofview.Unsafe.tclEVARSsigma;Proofview.Unsafe.tclSETGOALSsgl;Proofview.(iffirst_goes_lastthencycle1elsetclUNIT())]endletrefine_with?(first_goes_last=false)?beta?(with_evars=true)oc=letopenProofview.NotationsinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletuct=Evd.evar_universe_context(fstoc)inletn,oc=abs_evars_pirrelenvsigmaocinProofview.Unsafe.tclEVARS(Evd.set_universe_contextsigmauct)<*>Proofview.tclORELSE(applyn~with_evars~first_goes_last?betanoc)(fun_->Proofview.tclZEROdependent_apply_error)end(** Basic tactics *)letrecfst_prodredtac=Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinmatchEConstr.kind(Proofview.Goal.sigmagl)conclwith|Prod(id,_,tgt)|LetIn(id,_,_,tgt)->tacid.binder_name|_->ifredthenTacticals.tclZEROMSG(str"No product even after head-reduction.")elseTacticals.tclTHENTactics.hnf_in_concl(fst_prodtruetac)endletintroid?(orig=refAnonymous)name=letopenProofview.NotationsinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletg=Proofview.Goal.conclglinmatchEConstr.kindsigmagwith|App(hd,_)whenEConstr.isLambdasigmahd->convert_concl_no_check(Reductionops.whd_betaenvsigmag)|_->Tacticals.tclIDTACend<*>(fst_prodfalse(funid->orig:=id;Tactics.intro_mustbe_forcename))letanontacdecl=Proofview.Goal.enterbeginfungl->letid=matchRelDecl.get_namedeclwith|Nameid->ifis_discharged_ididthenidelsemk_anon_id(Id.to_stringid)(Tacmach.pf_ids_of_hypsgl)|_->mk_anon_idssr_anon_hyp(Tacmach.pf_ids_of_hypsgl)inintroididendletrecintro_anon()=letopenTacmachinletopenProofview.NotationsinProofview.Goal.enterbeginfungl->letd=List.hd(fst(EConstr.decompose_prod_n_decls(projectgl)1(pf_conclgl)))inProofview.tclORELSE(anontacd)(fun(err0,info)->Proofview.tclORELSE(Tactics.red_in_concl<*>intro_anon())(fun_->Proofview.tclZERO~infoerr0))endletintro_anon=intro_anon()letis_pf_varsigmac=EConstr.isVarsigmac&¬_section_id(EConstr.destVarsigmac)lethyp_of_varsigmav=SsrHyp(Loc.tag@@EConstr.destVarsigmav)letinterp_clrsigma=function|Someclr,(k,c)when(k=NoFlag||k=WithAt)&&is_pf_varsigmac->hyp_of_varsigmac::clr|Someclr,_->clr|None,_->[](** Basic tacticals *)(** Multipliers *)(* {{{ ***********************************************************)(* tactical *)lettclIDtac=taclettclDOTRYntac=letopenTacticalsinifn<=0thentclIDTACelseletrecloopi=ifi=nthentclTRYtacelsetclTRY(tclTHENtac(loop(i+1)))inloop1lettclDOntac=letprefixi=str"At iteration "++inti++str": "inlettac_err_ati=Proofview.Goal.enterbeginfungl->Proofview.tclORELSEtacbeginfunction|(CErrors.UserErrors,info)->lete'=CErrors.UserError(prefixi++s)inProofview.tclZERO~infoe'|(e,info)->Proofview.tclZERO~infoeendendinletrecloopi=Proofview.Goal.enterbeginfungl->ifi=nthentac_err_atielseTacticals.tclTHEN(tac_err_ati)(loop(i+1))endinloop1lettclAT_LEAST_ONCEt=letopenTacticalsintclTHENt(tclREPEATt)lettclMULT=function|0,May->Tacticals.tclREPEAT|1,May->Tacticals.tclTRY|n,May->tclDOTRYn|0,Must->tclAT_LEAST_ONCE|n,Mustwhenn>1->tclDOn|_->tclIDletcleartacclr=Proofview.tclTHEN(pf_check_hyps_uniq[]clr)(Tactics.clear(hyps_idsclr))(* }}} *)letget_hypenvsigmaid=tryEConstr.of_named_decl(Environ.lookup_namedidenv)withNot_found->raise(Logic.RefinerError(env,sigma,Logic.NoSuchHypid))(** Generalize tactic *)(* XXX the k of the redex should percolate out *)letpf_interp_gen_auxenvsigma~conclto_ind((oclr,occ),t)=letpat=interp_cpatternenvsigmatNonein(* UGLY API *)letsigma=Evd.merge_universe_contextsigma(Evd.evar_universe_context@@pat.pat_sigma)inletsigma,c,cl=fill_rel_occ_patternenvsigmaconclpatoccinletclr=interp_clrsigma(oclr,(tag_of_cpatternt,c))inifnot(occur_existentialsigmac)theniftag_of_cpatternt=WithAtthenifnot(EConstr.isVarsigmac)thenerrorstrm(str"@ can be used with variables only")elsematchget_hypenvsigma(EConstr.destVarsigmac)with|NamedDecl.LocalAssum_->errorstrm(str"@ can be used with let-ins only")|NamedDecl.LocalDef(name,b,ty)->true,pat,EConstr.mkLetIn(map_annotName.mk_namename,b,ty,cl),c,clr,sigmaelseletsigma,ccl=pf_mkprodenvsigmacclinfalse,pat,ccl,c,clr,sigmaelseifto_ind&&occ=Nonethenletp,evs,ucst'=abs_evarsenvsigma(pat.pat_sigma,c)inletsigma=Evd.merge_universe_contextsigmaucst'inifList.is_emptyevsthenanomaly"occur_existential but no evars"elseletsigma,pty,rp=pfe_type_relevance_ofenvsigmapinfalse,pat,EConstr.mkProd(make_annot(constr_namesigmac)rp,pty,concl),p,clr,sigmaelseCErrors.user_err?loc:(loc_of_cpatternt)(str"generalized term didn't match")letgenclrtacclcsclr=letopenProofview.Notationsin(* apply_type may give a type error, but the useful message is
* the one of clear. You type "move: x" and you get
* "x is used in hyp H" instead of
* "The term H has type T x but is expected to have type T x0". *)(Proofview.tclORELSE(Tactics.apply_type~typecheck:trueclcs)(fun(type_err,info)->(Tactics.exfalso)<*>(cleartacclr)<*>(Proofview.tclZERO~infotype_err)))<*>(cleartacclr)letgentacgen=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglin(* ppdebug(lazy(str"sigma@gentac=" ++ pr_evar_map None (project gl))); *)letconv,_,cl,c,clr,sigma=pf_interp_gen_auxenvsigma~conclfalsegenindebug_ssr(fun()->str"c@gentac="++pr_econstr_envenvsigmac);Proofview.Unsafe.tclEVARSsigma<*>ifconvthenTacticals.tclTHEN(convert_concl~check:truecl)(cleartacclr)elsegenclrtaccl[c]clrendletgenstac(gens,clr)=Tacticals.tclTHENLIST(cleartacclr::List.rev_mapgentacgens)letinterp_genenvsigma~conclto_indgen=let_,_,a,b,c,sigma=pf_interp_gen_auxenvsigma~conclto_indgeninsigma,(a,b,c)letis_protecthdenvsigma=letprotectC=mkSsrRef"protect_term"inEConstr.isRefXenvsigmaprotectChdletabs_wgenenvsigmakeep_letfgen(args,c)=letevar_closedtp=ifoccur_existentialsigmatthenCErrors.user_err?loc:(loc_of_cpatternp)(pr_econstr_patenvsigmat++str" contains holes and matches no subterm of the goal.")inmatchgenwith|_,Some((x,mode),None)whenmode="@"||(mode=" "&&keep_let)->letx=hoi_idxinletdecl=get_hypenvsigmaxinsigma,(ifNamedDecl.is_local_defdeclthenargselseEConstr.mkVarx::args),EConstr.mkProd_or_LetIn(decl|>NamedDecl.to_rel_decl|>RelDecl.set_name(Name(fx)))(EConstr.Vars.subst_varsigmaxc)|_,Some((x,_),None)->letx=hoi_idxinlethyp=get_hypenvsigmaxinletx'=make_annot(Name(fx))(NamedDecl.get_relevancehyp)inletprod=EConstr.mkProd(x',NamedDecl.get_typehyp,EConstr.Vars.subst_varsigmaxc)insigma,EConstr.mkVarx::args,prod|_,Some((x,"@"),Somep)->letx=hoi_idxinletcp=interp_cpatternenvsigmapNoneinletsigma=Evd.merge_universe_contextsigma(Evd.evar_universe_contextcp.pat_sigma)inletsigma,t,c=fill_rel_occ_patternenvsigmaccpNoneinevar_closedtp;letut=red_product_skip_idenvsigmatinletsigma,ty,r=pfe_type_relevance_ofenvsigmatinsigma,args,EConstr.mkLetIn(make_annot(Name(fx))r,ut,ty,c)|_,Some((x,_),Somep)->letx=hoi_idxinletcp=interp_cpatternenvsigmapNoneinletsigma=Evd.merge_universe_contextsigma(Evd.evar_universe_contextcp.pat_sigma)inletsigma,t,c=fill_rel_occ_patternenvsigmaccpNoneinevar_closedtp;letsigma,ty,r=pfe_type_relevance_ofenvsigmatinsigma,t::args,EConstr.mkProd(make_annot(Name(fx))r,ty,c)|_->sigma,args,cletclr_of_wgengenclrs=matchgenwith|clr,Some((x,_),None)->letx=hoi_idxincleartacclr::cleartac[SsrHyp(Loc.tagx)]::clrs|clr,_->cleartacclr::clrsletreduct_in_concl~checkt=Tactics.reduct_in_concl~cast:false~check(t,DEFAULTcast)letunfoldcl=Proofview.tclEVARMAP>>=funsigma->letmoduleR=ReductionopsinletmoduleF=RedFlagsinletflags=F.mkflags[F.fBETA;F.fMATCH;F.fFIX;F.fCOFIX;F.fDELTA]inletfoldaccuc=F.red_addaccu(F.fCONST(fst(EConstr.destConstsigmac)))inletflags=List.fold_leftfoldflagsclinreduct_in_concl~check:false(R.clos_norm_flagsflags)openProofviewopenNotationsletpf_applyf=Proofview.Goal.enter_one~__LOC__beginfungl->f(Proofview.Goal.envgl)(Proofview.Goal.sigmagl)endlettclINTERP_AST_CLOSURE_TERM_AS_CONSTRc=tclINDEPENDENTL@@pf_applybeginfunenvsigma->letold_ssrterm=mkRHole,Somec.Ssrast.bodyinletist=option_assert_getc.Ssrast.interp_envPp.(str"tclINTERP_AST_CLOSURE_TERM_AS_CONSTR: term with no ist")inletsigma,t=Tacinterp.interp_constr_genPretyping.WithoutTypeConstraintistenvsigmaold_ssrterminUnsafe.tclEVARSsigma<*>tclUNITtendlettacEVAL_TO_QUANTIFIED_INDty=pf_applybeginfunenvsigma->trytclUNIT(Tacred.eval_to_quantified_indenvsigmaty)withewhenCErrors.noncriticale->tclZEROeendlettacTYPEOFc=Goal.enter_one~__LOC__(fung->letsigma,env=Goal.sigmag,Goal.envginletsigma,ty=Typing.type_ofenvsigmacinUnsafe.tclEVARSsigma<*>tclUNITty)(** This tactic creates a partial proof realizing the introduction rule, but
does not check anything. *)letunsafe_introenvdeclb=letopenContext.Named.DeclarationinRefine.refine~typecheck:falsebeginfunsigma->letctx=Environ.named_context_valenvinletnctx=EConstr.push_named_context_valdeclctxinletinst=EConstr.identity_subst_val(Environ.named_context_valenv)inletninst=SList.cons(EConstr.mkRel1)instinletnb=EConstr.Vars.subst1(EConstr.mkVar(get_iddecl))binletsigma,ev=Evarutil.new_pure_evar~principal:truenctxsigmanbinsigma,EConstr.mkNamedLambda_or_LetInsigmadecl(EConstr.mkEvar(ev,ninst))endletset_decl_idid=letopenContextinfunction|Rel.Declaration.LocalAssum(name,ty)->Named.Declaration.LocalAssum({namewithbinder_name=id},ty)|Rel.Declaration.LocalDef(name,ty,t)->Named.Declaration.LocalDef({namewithbinder_name=id},ty,t)letrecdecompose_assumenvsigmaorig_goal=letopenContextinmatchEConstr.kindsigmaorig_goalwith|Prod(name,ty,t)->Rel.Declaration.LocalAssum(name,ty),t,true|LetIn(name,ty,t1,t2)->Rel.Declaration.LocalDef(name,ty,t1),t2,true|_->letgoal=Reductionops.whd_allnoletenvsigmaorig_goalinmatchEConstr.kindsigmagoalwith|Prod(name,ty,t)->Rel.Declaration.LocalAssum(name,ty),t,false|LetIn(name,ty,t1,t2)->Rel.Declaration.LocalDef(name,ty,t1),t2,false|App(hd,args)whenEConstr.isLetInsigmahd->(* hack *)let_,v,_,b=EConstr.destLetInsigmahdinletctx,t,_=decompose_assumenvsigma(EConstr.mkApp(EConstr.Vars.subst1vb,args))inctx,t,false|_->CErrors.user_errPp.(str"No assumption in "++Printer.pr_econstr_envenvsigmagoal)lettclFULL_BETAIOTA=Goal.enterbeginfungl->letr,_=Redexpr.reduction_of_red_expr(Goal.envgl)Genredexpr.(Lazy{rBeta=true;rMatch=true;rFix=true;rCofix=true;rZeta=false;rDelta=false;rConst=[];rStrength=Norm})inTactics.e_reduct_in_concl~cast:false~check:false(r,Constr.DEFAULTcast)endtypeintro_id=|Anon|IdofId.t|Seedofstring(** [intro id k] introduces the first premise (product or let-in) of the goal
under the name [id], reducing the head of the goal (using beta, iota, delta
but not zeta) if necessary. If [id] is None, a name is generated, that will
not be user accessible. If the goal does not start with a product or a
let-in even after reduction, it fails. In case of success, the original name
and final id are passed to the continuation [k] which gets evaluated. *)lettclINTRO~id~conclusion:k=Goal.enterbeginfungl->letopenContextinletenv,sigma,g=Goal.(envgl,sigmagl,conclgl)inletdecl,t,no_red=decompose_assumenvsigmaginletoriginal_name=Rel.Declaration.get_namedeclinletalready_used=Tacmach.pf_ids_of_hypsglinletid=matchid,original_namewith|Idid,_->id|Seedid,_->mk_anon_ididalready_used|Anon,Nameid->ifis_discharged_ididthenidelsemk_anon_id(Id.to_stringid)already_used|Anon,Anonymous->letids=Tacmach.pf_ids_of_hypsglinmk_anon_idssr_anon_hypidsinifList.memidalready_usedthenerrorstrmPp.(Id.printid++str" already used");unsafe_introenv(set_decl_ididdecl)t<*>(ifno_redthentclUNIT()elsetclFULL_BETAIOTA)<*>k~orig_name:original_name~new_name:idendletreturn~orig_name:_~new_name:_=tclUNIT()lettclINTRO_IDid=tclINTRO~id:(Idid)~conclusion:returnlettclINTRO_ANON?seed()=matchseedwith|None->tclINTRO~id:Anon~conclusion:return|Someseed->tclINTRO~id:(Seedseed)~conclusion:returnlettclRENAME_HD_PRODname=Goal.enterbeginfungl->letconcl=Goal.conclglinletsigma=Goal.sigmaglinmatchEConstr.kindsigmaconclwith|Prod(x,src,tgt)->convert_concl_no_checkEConstr.(mkProd({xwithbinder_name=name},src,tgt))|_->CErrors.anomaly(Pp.str"rename_hd_prod: no head product")endlettcl0G~defaulttac=numgoals>>=funng->ifng=0thentclUNITdefaultelsetacletrectclFIRSTa=function|[]->Tacticals.tclZEROMSGPp.(str"No applicable tactic.")|tac::rest->tclORELSEtac(fun_->tclFIRSTarest)letrectclFIRSTitacn=ifn<0thenTacticals.tclZEROMSGPp.(str"tclFIRSTi")elsetclORELSE(tclFIRSTitac(n-1))(fun_->tacn)lettacCONSTR_NAME?namec=matchnamewith|Somen->tclUNITn|None->Goal.enter_one~__LOC__(fung->letsigma=Goal.sigmagintclUNIT(constr_namesigmac))lettacMKPRODc?namecl=tacTYPEOFc>>=funt->tacCONSTR_NAME?namec>>=funname->Goal.enter_one~__LOC__beginfung->letsigma,env=Goal.sigmag,Goal.envginletr=Retyping.relevance_of_termenvsigmacinifname<>Names.Name.Anonymous||EConstr.Vars.noccurnsigma1clthentclUNIT(EConstr.mkProd(make_annotnamer,t,cl))elseletname=Names.Id.of_string(Namegen.hdcharenvsigmat)intclUNIT(EConstr.mkProd(make_annot(Name.Namename)r,t,cl))endlettacINTERP_CPATTERNcp=pf_applybeginfunenvsigma->tclUNIT(Ssrmatching.interp_cpatternenvsigmacpNone)endlettacUNIFYab=pf_applybeginfunenvsigma->letsigma=Ssrmatching.unify_HOenvsigmaabinUnsafe.tclEVARSsigmaendlettclOPTIONod=matchowith|None->d>>=tclUNIT|Somex->tclUNITxlettacIS_INJECTION_CASE?tyt=begintclOPTIONty(tacTYPEOFt)>>=funty->tacEVAL_TO_QUANTIFIED_INDty>>=fun(mind,_)->tclUNIT(Coqlib.check_ref"core.eq.type"(GlobRef.IndRefmind))endlettclWITHTOPtac=Goal.enterbeginfungl->lettop=mk_anon_id"top_assumption"(Tacmach.pf_ids_of_hypsgl)intclINTRO_IDtop<*>tac(EConstr.mkVartop)<*>Tactics.clear[top]endlettacMK_SSR_CONSTname=Proofview.tclENV>>=funenv->Proofview.tclEVARMAP>>=funsigma->matchmkSsrConstenvsigmanamewith|sigma,c->Unsafe.tclEVARSsigma<*>tclUNITc|exceptionewhenCErrors.noncriticale->tclLIFT(Proofview.NonLogical.raise(e,Exninfo.null))lettacDEST_CONSTc=Proofview.tclEVARMAP>>=funsigma->matchEConstr.destConstsigmacwith|c,_->tclUNITc|exceptionewhenCErrors.noncriticale->tclLIFT(Proofview.NonLogical.raise(e,Exninfo.null))(* TASSI: This version of unprotects inlines the unfold tactic definition,
* since we don't want to wipe out let-ins, and it seems there is no flag
* to change that behaviour in the standard unfold code *)letunprotecttac=tacMK_SSR_CONST"protect_term">>=tacDEST_CONST>>=funprot->letopenRedFlagsinletflags=red_add_transparentallnoletTransparentState.emptyinletflags=red_addflags(fCONSTprot)inTacticals.onClause(funidopt->lethyploc=Option.map(funid->id,InHyp)idoptinTactics.reduct_option~check:false(Reductionops.clos_norm_flagsflags,DEFAULTcast)hyploc)allHypsAndConclmoduletypeStateType=sigtypestatevalinit:statevalname:stringendmoduleMakeState(S:StateType)=structletstate_field:S.stateProofview_monad.StateStore.field=Proofview_monad.StateStore.fieldS.name(* FIXME: should not inject fresh_state, but initialize it at the beginning *)letlift_upd_stateupds=letopenProofview_monad.StateStoreinletold_state=Option.defaultS.init(getsstate_field)inupdold_state>>=funnew_state->tclUNIT(setsstate_fieldnew_state)lettacUPDATEupd=Goal.enterbeginfungl->lets0=Goal.stateglinGoal.enter_one~__LOC__(fun_->lift_upd_stateupds0)>>=funs->Unsafe.tclGETGOALS>>=fungls->letgls=List.map(fungs->letg=Proofview_monad.drop_stategsinProofview_monad.goal_with_stategs)glsinUnsafe.tclSETGOALSglsendlettclGETk=Goal.enterbeginfungl->letopenProofview_monad.StateStoreink(Option.defaultS.init(get(Goal.stategl)state_field))endlettclGET1k=Goal.enter_onebeginfungl->letopenProofview_monad.StateStoreink(Option.defaultS.init(get(Goal.stategl)state_field))endlettclSETnew_s=letopenProofview_monad.StateStoreinUnsafe.tclGETGOALS>>=fungls->letgls=List.map(fungs->letg=Proofview_monad.drop_stategsinlets=Proofview_monad.get_stategsinProofview_monad.goal_with_stateg(setsstate_fieldnew_s))glsinUnsafe.tclSETGOALSglsletgetg=Option.defaultS.init(Proofview_monad.StateStore.get(Goal.stateg)state_field)endletis_construct_refenvsigmacr=EConstr.isConstructsigmac&&Environ.QGlobRef.equalenv(GlobRef.ConstructRef(fst(EConstr.destConstructsigmac)))rletis_ind_refenvsigmacr=EConstr.isIndsigmac&&Environ.QGlobRef.equalenv(GlobRef.IndRef(fst(EConstr.destIndsigmac)))rletis_const_refenvsigmacr=EConstr.isConstsigmac&&Environ.QGlobRef.equalenv(GlobRef.ConstRef(fst(EConstr.destConstsigmac)))r(* vim: set filetype=ocaml foldmethod=marker: *)