1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837(************************************************************************)(* * The Rocq Prover / The Rocq 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) *)(************************************************************************)openPpopenUtilopenCErrorsopenNamesopenConstropenContextopenEvdopenEConstropenVarsopenEnvironopenMod_substopenGlobnamesopenLibobjectopenNamegenopenLibnamesopenTermopsopenInductiveopsopenTypeclassesopenPatternopenPatternopsopenTacredopenPrintermoduleNamedDecl=Context.Named.Declaration(****************************************)(* General functions *)(****************************************)typedebug=Debug|Info|OffexceptionBoundletrechead_boundsigmat=matchEConstr.kindsigmatwith|Prod(_,_,b)->head_boundsigmab|LetIn(_,_,_,b)->head_boundsigmab|App(c,_)->head_boundsigmac|Case(_,_,_,_,_,c,_)->head_boundsigmac|Ind(ind,_)->GlobRef.IndRefind|Const(c,_)->GlobRef.ConstRefc|Construct(c,_)->GlobRef.ConstructRefc|Varid->GlobRef.VarRefid|Proj(p,_,_)->GlobRef.ConstRef(Projection.constantp)|Cast(c,_,_)->head_boundsigmac|Evar_|Rel_|Meta_|Sort_|Fix_|Lambda_|CoFix_|Int_|Float_|String_|Array_->raiseBoundlethead_constrsigmac=tryhead_boundsigmacwithBound->user_err(Pp.str"Head identifier must be a constant, section variable, \
(co)inductive type, (co)inductive type constructor, or projection.")letdecompose_app_boundsigmat=lett=strip_outer_castsigmatinlet_,ccl=decompose_prod_declssigmatinlethd,args=decompose_appsigmacclinletopenGlobRefinmatchEConstr.kindsigmahdwith|Const(c,u)->ConstRefc,args|Ind(i,u)->IndRefi,args|Construct(c,u)->ConstructRefc,args|Varid->VarRefid,args|Proj(p,_,c)->ConstRef(Projection.constantp),Array.conscargs|_->raiseBound(** Compute the set of section variables that remain in the named context.
Starts from the top to the bottom of the context, stops at the first
different declaration between the named hyps and the section context. *)letsecvars_of_hypshyps=letsecctx=Global.named_context()inletopenContext.Named.Declarationinletpred,all=List.fold_left(fun(pred,all)decl->trylet_=Context.Named.lookup(get_iddecl)hypsin(* Approximation, it might be an hypothesis reintroduced with same name and unconvertible types,
we must allow it currently, as comparing the declarations for syntactic equality is too
strong a check (e.g. an unfold in a section variable would make it unusable). *)(Id.Pred.add(get_iddecl)pred,all)withNot_found->(pred,false))(Id.Pred.empty,true)secctxinifallthenId.Pred.full(* If the whole section context is available *)elsepredletempty_hint_info={hint_priority=None;hint_pattern=None}(************************************************************************)(* The Type of Constructions Autotactic Hints *)(************************************************************************)type'ahint_ast=|Res_pfof'a(* Hint Apply *)|ERes_pfof'a(* Hint EApply *)|Give_exactof'a|Res_pf_THEN_trivial_failof'a(* Hint Immediate *)|Unfold_nthofEvaluable.t(* Hint Unfold *)|ExternofPattern.constr_patternoption*Gentactic.glob_generic_tactic(* Hint Extern *)type'ahints_path_atom_gen=|PathHintsof'alist(* For forward hints, their names is the list of projections *)|PathAnytypehints_path_atom=GlobRef.thints_path_atom_gentype'ahints_path_gen=|PathAtomof'ahints_path_atom_gen|PathStarof'ahints_path_gen|PathSeqof'ahints_path_gen*'ahints_path_gen|PathOrof'ahints_path_gen*'ahints_path_gen|PathEmpty|PathEpsilontypepre_hints_path=Libnames.qualidhints_path_gentypehints_path=GlobRef.thints_path_gentypehint_term=|IsGlobRefofGlobRef.t|IsConstrofconstr*UnivGen.sort_context_setoption(* None if monomorphic *)type'awith_uid={obj:'a;uid:KerName.t;}typeraw_hint={rhint_term:constr;rhint_type:types;rhint_uctx:UnivGen.sort_context_setoption;rhint_arty:int;(* Number of goals generated by the intended tactic *)}typehint={hint_term:constr;hint_type:types;hint_uctx:UnivGen.sort_context_setoption;(* None if monomorphic *)hint_clnv:Clenv.clausenv;hint_arty:int;(* Number of goals generated by the intended tactic *)}typehint_pattern=|DefaultPattern|ConstrPatternofconstr_pattern|SyntacticPatternofconstr_patterntype('a,'db)with_metadata={pri:int(** A number lower is higher priority *);pat:hint_patternoption(** A pattern for the concl of the Goal *);name:GlobRef.toption(** A potential name to refer to the hint *);db:'db(** The database from which the hint comes *);secvars:Id.Pred.t(** The set of section variables the hint depends on *);code:'a(** the tactic to apply when the concl matches pat *)}typehint_db_name=string(* db = None for local database (ie built from goal hyps) *)typefull_hint=(hinthint_astwith_uid,hint_db_nameoption)with_metadatatypehint_entry=GlobRef.toption*(raw_hinthint_astwith_uid,unit)with_metadatatypehint_mode=|ModeInput(* No evars *)|ModeNoHeadEvar(* No evar at the head *)|ModeOutput(* Anything *)moduleModes=structtypet=hint_modearraylistGlobRef.Map.tletempty=GlobRef.Map.emptyletunionm1m2=GlobRef.Map.union(fun_m1m2->Some(m1@m2))m1m2endtype'ahints_transparency_target=|HintsVariables|HintsConstants|HintsProjections|HintsReferencesof'alistlethint_as_termh=(h.hint_uctx,h.hint_term)letfresh_key=letid=Summary.ref~name:"HINT-COUNTER"0infun()->letcur=incrid;!idinletlbl=Id.of_string("_"^string_of_intcur)inletkn=Lib.make_knlblinlet(mp,_)=KerName.reprknin(* We embed the full path of the kernel name in the label so that
the identifier should be unique. This ensures that including
two modules together won't confuse the corresponding labels. *)letlbl=Id.of_string_soft(Printf.sprintf"%s#%i"(ModPath.to_stringmp)cur)inKerName.makemplblletpri_order_int(id1,{pri=pri1})(id2,{pri=pri2})=letd=Int.comparepri1pri2inifInt.equald0thenInt.compareid2id1elsedletget_default_pattern(h:hinthint_ast)=matchhwith|Give_exacth->h.hint_type|Res_pfh|ERes_pfh|Res_pf_THEN_trivial_failh->Clenv.clenv_typeh.hint_clnv|Unfold_nth_|Extern_->(* These hints cannot contain DefaultPattern *)assertfalse(* Nov 98 -- Papageno *)(* Les Hints sont ré-organisés en plusieurs databases.
La table impérative "searchtable", de type "hint_db_table",
associe une database (hint_db) à chaque nom.
Une hint_db est une table d'association fonctionelle constr -> search_entry
Le constr correspond à la constante de tête de la conclusion.
Une search_entry est un triplet comprenant :
- la liste des tactiques qui n'ont pas de pattern associé
- la liste des tactiques qui ont un pattern
- un discrimination net borné (Btermdn.t) constitué de tous les
patterns de la seconde liste de tactiques *)typestored_data=int*full_hint(* First component is the index of insertion in the table, to keep most recent first semantics. *)moduleStored=structtypet=stored_dataletcompare=pri_order_intendmoduleStoredSet=Set.Make(Stored)letmerge_setsl=List.mergeStored.compare(StoredSet.elementss)lmoduleBounded_net:sigtypetvalempty:TransparentState.toption->tvalbuild:TransparentState.toption->StoredSet.t->tvaladd:t->hint_pattern->stored_data->tvallookup:Environ.env->Evd.evar_map->t->EConstr.constr->stored_datalistend=structmoduleBnet=Btermdn.Make(Stored)typediff=hint_pattern*stored_datatypedata=|Bnetof(TransparentState.toption*Bnet.t)|Diffofdiff*dataref|BuildofTransparentState.toption*StoredSet.ttypet=datarefletemptyst=ref(Bnet(st,Bnet.empty))letaddnetpv=ref(Diff((p,v),net))letbuildstdata=ref(Build(st,data))letadd0envsigmastpvdn=(* Feedback.msg_debug (let v1 = v in Pp.(str "add0: " ++ Pp.pr_opt Names.GlobRef.print (snd v1).name)); *)letp=matchpwith|ConstrPatternp->Bnet.patternenvstp|SyntacticPatternp->Bnet.pattern_syntacticenvp|DefaultPattern->letc=get_default_pattern(sndv).code.objinBnet.constr_patternenvsigmastcinBnet.adddnpvletrecforceenvsigmanet=match!netwith|Bnetdn->dn|Diff((p,v),rem)->letst,dn=forceenvsigmareminletdn=add0envsigmastpvdninlet()=net:=(Bnet(st,dn))inst,dn|Build(st,data)->letfoldvdn=add0envsigmast(Option.get(sndv).pat)vdninletans=StoredSet.foldfolddataBnet.emptyinlet()=net:=Bnet(st,ans)inst,ansletlookupenvsigmanetp=letst,dn=forceenvsigmanetinBnet.lookupenvsigmastdnpendmoduleStoredData:sigtypetvalempty:tvalmem:KerName.t->t->boolvaladd:stored_data->t->tvalremove:Environ.env->GlobRef.Set_env.t->t->tvalelements:t->StoredSet.tend=structtypet={data:StoredSet.t;set:KerName.Set.t;}letempty={data=StoredSet.empty;set=KerName.Set.empty}letmemknsd=KerName.Set.memknsd.setletaddtsd={data=StoredSet.addtsd.data;set=KerName.Set.add(sndt).code.uidsd.set;}letremoveenvgrssd=letfold((_,h)asv)(accu,ans)=letkeep=matchh.namewith|Somegr->not(GlobRef.Set_env.mem(Environ.QGlobRef.canonizeenvgr)grs)|None->trueinifkeepthen(accu,StoredSet.addvans)else(KerName.Set.removeh.code.uidaccu,ans)inletset,data=StoredSet.foldfoldsd.data(sd.set,StoredSet.empty)inifset==sd.setthensdelse{data=data;set}letelementsv=v.dataendtypesearch_entry={sentry_nopat:StoredData.t;sentry_pat:StoredData.t;sentry_bnet:Bounded_net.t;sentry_mode:hint_modearraylist;}letempty_sest={sentry_nopat=StoredData.empty;sentry_pat=StoredData.empty;sentry_bnet=Bounded_net.emptyst;sentry_mode=[];}letadd_tacpattse=matchpatwith|None->letuid=(sndt).code.uidinifStoredData.memuidse.sentry_nopatthenseelse{sewithsentry_nopat=StoredData.addtse.sentry_nopat}|Somepat->letuid=(sndt).code.uidinifStoredData.memuidse.sentry_patthenseelse{sewithsentry_pat=StoredData.addtse.sentry_pat;sentry_bnet=Bounded_net.addse.sentry_bnetpatt;}letrebuild_dnstse=letdn'=Bounded_net.buildst(StoredData.elementsse.sentry_pat)in{sewithsentry_bnet=dn'}letlookup_tacsenvsigmaconclse=letl'=Bounded_net.lookupenvsigmase.sentry_bnetconclinletsl'=List.stable_sortpri_order_intl'inmerge_set(StoredData.elementsse.sentry_nopat)sl'letmerge_context_set_optsigmactx=matchctxwith|None->sigma|Somectx->Evd.merge_sort_context_setEvd.univ_flexible~src:UState.Internalsigmactxletinstantiate_hintenvsigmap=letmk_clenv{rhint_term=c;rhint_type=cty;rhint_uctx=ctx;rhint_arty=ar}=letsigma=merge_context_set_optsigmactxinletcl=Clenv.mk_clenv_fromenvsigma(c,cty)inletcl=Clenv.clenv_strip_proj_paramsclin{hint_term=c;hint_type=cty;hint_uctx=ctx;hint_clnv=cl;hint_arty=ar}inletcode=matchp.code.objwith|Res_pfc->Res_pf(mk_clenvc)|ERes_pfc->ERes_pf(mk_clenvc)|Res_pf_THEN_trivial_failc->Res_pf_THEN_trivial_fail(mk_clenvc)|Give_exactc->Give_exact(mk_clenvc)|(Unfold_nth_|Extern_)ash->hin{pwithcode={p.codewithobj=code}}lethint_mode_eqm1m2=matchm1,m2with|ModeInput,ModeInput->true|ModeNoHeadEvar,ModeNoHeadEvar->true|ModeOutput,ModeOutput->true|(ModeInput|ModeNoHeadEvar|ModeOutput),_->falselethints_path_atom_eqenvh1h2=matchh1,h2with|PathHintsl1,PathHintsl2->List.equal(fungr1gr2->QGlobRef.equalenvgr1gr2)l1l2|PathAny,PathAny->true|_->falseletrechints_path_eqenvh1h2=matchh1,h2with|PathAtomh1,PathAtomh2->hints_path_atom_eqenvh1h2|PathStarh1,PathStarh2->hints_path_eqenvh1h2|PathSeq(l1,r1),PathSeq(l2,r2)->hints_path_eqenvl1l2&&hints_path_eqenvr1r2|PathOr(l1,r1),PathOr(l2,r2)->hints_path_eqenvl1l2&&hints_path_eqenvr1r2|PathEmpty,PathEmpty->true|PathEpsilon,PathEpsilon->true|_->falseletpath_matchesenvhphints=letrecauxhphintsk=matchhp,hintswith|PathAtom_,[]->false|PathAtomPathAny,(_::hints')->khints'|PathAtomp,(h::hints')->ifhints_path_atom_eqenvphthenkhints'elsefalse|PathStarhp',hints->khints||auxhp'hints(funhints'->auxhphints'k)|PathSeq(hp,hp'),hints->auxhphints(funhints'->auxhp'hints'k)|PathOr(hp,hp'),hints->auxhphintsk||auxhp'hintsk|PathEmpty,_->false|PathEpsilon,hints->khintsinauxhphints(funhints'->true)letrecmatches_epsilon=function|PathAtom_->false|PathStar_->true|PathSeq(p,p')->matches_epsilonp&&matches_epsilonp'|PathOr(p,p')->matches_epsilonp||matches_epsilonp'|PathEmpty->false|PathEpsilon->trueletpath_matches_epsilon=matches_epsilonletrecis_empty=function|PathAtom_->false|PathStar_->false|PathSeq(p,p')->is_emptyp||is_emptyp'|PathOr(p,p')->matches_epsilonp&&matches_epsilonp'|PathEmpty->true|PathEpsilon->falseletpath_seqpp'=matchp,p'with|PathEpsilon,p'->p'|p,PathEpsilon->p|p,p'->PathSeq(p,p')letrecpath_derivateenvhphint=letrecderivate_atomsenvhintshints'=matchhints,hints'with|gr::grs,gr'::grs'whenQGlobRef.equalenvgrgr'->derivate_atomsenvgrsgrs'|[],[]->PathEpsilon|[],hints->PathEmpty|grs,[]->PathAtom(PathHintsgrs)|_,_->PathEmptyinmatchhpwith|PathAtomPathAny->PathEpsilon|PathAtom(PathHintsgrs)->(matchgrs,hintwith|h::_,PathAny->PathEmpty|hints,PathHintshints'->derivate_atomsenvhintshints'|_,_->assertfalse)|PathStarp->ifpath_matchesenvp[hint]thenhpelsePathEpsilon|PathSeq(hp,hp')->lethpder=path_derivateenvhphintinifmatches_epsilonhpthenPathOr(path_seqhpderhp',path_derivateenvhp'hint)elseifis_emptyhpderthenPathEmptyelsepath_seqhpderhp'|PathOr(hp,hp')->PathOr(path_derivateenvhphint,path_derivateenvhp'hint)|PathEmpty->PathEmpty|PathEpsilon->PathEmptyletrecnormalize_pathenvh=matchhwith|PathStarPathEpsilon->PathEpsilon|PathOr(p,q)->(matchnormalize_pathenvpwith|PathEmpty->normalize_pathenvq|p'->matchnormalize_pathenvqwith|PathEmpty->p'|q'->ifhints_path_eqenvp'q'thenp'elsePathOr(p',q'))|PathSeq(p,q)->(matchnormalize_pathenvpwith|PathEmpty->PathEmpty|PathEpsilon->normalize_pathenvq|p'->matchnormalize_pathenvqwith|PathEmpty->PathEmpty|PathEpsilon->p'|q'->PathSeq(p',q'))|_->hletpath_derivateenvhphint=lethint=matchhintwith|None->PathAny|Somegr->PathHints[gr]innormalize_pathenv(path_derivateenvhphint)letpp_hints_path_atomprga=matchawith|PathAny->str"_"|PathHintsgrs->pr_sequenceprggrsletpp_hints_path_genprg=letrecaux=function|PathAtompa->pp_hints_path_atomprgpa|PathStar(PathAtomPathAny)->str"_*"|PathStarp->str"("++auxp++str")*"|PathSeq(p,p')->auxp++spc()++auxp'|PathOr(p,p')->str"("++auxp++spc()++str"|"++cut()++spc()++auxp'++str")"|PathEmpty->str"emp"|PathEpsilon->str"eps"inauxletpp_hints_path=pp_hints_path_genpr_globalletglob_hints_path_atomp=matchpwith|PathHintsg->PathHints(List.mapNametab.globalg)|PathAny->PathAnyletglob_hints_path=letrecaux=function|PathAtompa->PathAtom(glob_hints_path_atompa)|PathStarp->PathStar(auxp)|PathSeq(p,p')->PathSeq(auxp,auxp')|PathOr(p,p')->PathOr(auxp,auxp')|PathEmpty->PathEmpty|PathEpsilon->PathEpsiloninauxletsubst_path_atomsubstp=matchpwith|PathAny->p|PathHintsgrs->letgr'gr=fst(subst_globalsubstgr)inletgrs'=List.Smart.mapgr'grsinifgrs'==grsthenpelsePathHintsgrs'letrecsubst_hints_pathsubsthp=matchhpwith|PathAtomp->letp'=subst_path_atomsubstpinifp'==pthenhpelsePathAtomp'|PathStarp->letp'=subst_hints_pathsubstpinifp'==pthenhpelsePathStarp'|PathSeq(p,q)->letp'=subst_hints_pathsubstpinletq'=subst_hints_pathsubstqinifp'==p&&q'==qthenhpelsePathSeq(p',q')|PathOr(p,q)->letp'=subst_hints_pathsubstpinletq'=subst_hints_pathsubstqinifp'==p&&q'==qthenhpelsePathOr(p',q')|_->hptypemode_match=|NoMode|WithModeofhint_modearraytype'awith_mode=|ModeMatchofmode_match*'a|ModeMismatchmoduleHint_db:sigtypetvalempty:?name:hint_db_name->TransparentState.t->bool->tvalmap_none:secvars:Id.Pred.t->t->full_hintlistvalmap_all:secvars:Id.Pred.t->GlobRef.t->t->full_hintlistvalmap_eauto:Environ.env->evar_map->secvars:Id.Pred.t->(GlobRef.t*constrarray)->constr->t->full_hintlistwith_modevalmap_auto:Environ.env->evar_map->secvars:Id.Pred.t->(GlobRef.t*constrarray)->constr->t->full_hintlistvaladd_list:env->evar_map->hint_entrylist->t->tvalremove_one:Environ.env->GlobRef.t->t->tvalremove_list:Environ.env->GlobRef.tlist->t->tvaliter:(GlobRef.toption->hint_modearraylist->full_hintlist->unit)->t->unitvaluse_dn:t->boolvaltransparent_state:t->TransparentState.tvalset_transparent_state:t->TransparentState.t->tvaladd_cut:Environ.env->hints_path->t->tvaladd_mode:GlobRef.t->hint_modearray->t->tvalcut:t->hints_pathvalunfolds:t->Id.Set.t*Cset.t*PRset.tvaladd_modes:hint_modearraylistGlobRef.Map.t->t->tvalmodes:t->hint_modearraylistGlobRef.Map.tvalfind_mode:env->GlobRef.t->t->hint_modearraylistvalfold:(GlobRef.toption->hint_modearraylist->full_hintlist->'a->'a)->t->'a->'aend=structtypet={hintdb_state:TransparentState.t;hintdb_cut:hints_path;hintdb_unfolds:Id.Set.t*Cset.t*PRset.t;hintdb_max_id:int;use_dn:bool;hintdb_map:search_entryGlobRef.Map.t;(* A list of unindexed entries with no associated pattern. *)hintdb_nopat:stored_datalist;hintdb_name:stringoption;}letnext_hint_iddb=leth=db.hintdb_max_idin{dbwithhintdb_max_id=succdb.hintdb_max_id},hletempty?namestuse_dn={hintdb_state=st;hintdb_cut=PathEmpty;hintdb_unfolds=(Id.Set.empty,Cset.empty,PRset.empty);hintdb_max_id=0;use_dn=use_dn;hintdb_map=GlobRef.Map.empty;hintdb_nopat=[];hintdb_name=name;}letdn_tsdb=ifdb.use_dnthen(Somedb.hintdb_state)elseNoneletfindkeydb=tryGlobRef.Map.findkeydb.hintdb_mapwithNot_found->empty_se(dn_tsdb)letrealize_tacsecvars(id,tac)=ifId.Pred.subsettac.secvarssecvarsthenSometacelse(* Warn about no longer typable hint? *)Nonelethas_no_head_evarsigmac=letrechrecc=matchEConstr.kindsigmacwith|Evar(evk,_)->false|App(c,_)->hrecc|Cast(c,_,_)->hrecc|_->trueinhreccletmatch_modesigmamarg=matchmwith|ModeInput->not(occur_existentialsigmaarg)|ModeNoHeadEvar->has_no_head_evarsigmaarg|ModeOutput->trueletmatches_modesigmaargsmode=ifArray.lengthmode==Array.lengthargs&&Array.for_all2(match_modesigma)modeargsthenSomemodeelseNoneletmatches_modessigmaargsmodes=ifList.is_emptymodesthenSomeNoModeelseOption.map(funx->WithModex)(List.find_map(matches_modesigmaargs)modes)letmerge_entrysecvarsdbnopatpat=leth=List.sortpri_order_intdb.hintdb_nopatinleth=List.mergepri_order_inthnopatinleth=List.mergepri_order_inthpatinList.map_filter(realize_tacsecvars)hletmap_none~secvarsdb=merge_entrysecvarsdb[][]letmap_all~secvarskdb=letse=findkdbinleth=List.sortpri_order_intdb.hintdb_nopatinleth=merge_set(StoredData.elementsse.sentry_nopat)hinleth=merge_set(StoredData.elementsse.sentry_pat)hinList.map_filter(realize_tacsecvars)h(* Precondition: concl has no existentials *)letmap_autoenvsigma~secvars(k,args)concldb=letse=findkdbinletpat=lookup_tacsenvsigmaconclseinmerge_entrysecvarsdb[]pat(* [c] contains an existential *)letmap_eautoenvsigma~secvars(k,args)concldb=letse=findkdbinmatchmatches_modessigmaargsse.sentry_modewith|Somem->letpat=lookup_tacsenvsigmaconclseinModeMatch(m,merge_entrysecvarsdb[]pat)|None->ModeMismatchletis_exact=function|Give_exact_->true|_->falseletaddkvgridvdb=letidv=id,{vwithdb=db.hintdb_name}inmatchgrwith|None->letis_present(_,v')=KerName.equalv.code.uidv'.code.uidinifnot(List.existsis_presentdb.hintdb_nopat)then(* FIXME *){dbwithhintdb_nopat=idv::db.hintdb_nopat}elsedb|Somegr->letpat=ifnotdb.use_dn&&is_exactv.code.objthenNoneelsev.patinletoval=findgrdbin{dbwithhintdb_map=GlobRef.Map.addgr(add_tacpatidvoval)db.hintdb_map}letrebuild_dbst'db=letdb'={dbwithhintdb_map=GlobRef.Map.map(rebuild_dn(Somest'))db.hintdb_map;hintdb_state=st';hintdb_nopat=[]}inList.fold_left(fundb(id,v)->addkvNoneidvdb)db'db.hintdb_nopatletadd_oneenvsigma(k,v)db=letv=instantiate_hintenvsigmavinletdb=matchv.code.objwith|Unfold_nthegr->letopenTransparentStateinletts=db.hintdb_stateinlet(ids,csts,prjs)=db.hintdb_unfoldsinletstate,unfs=matchegrwith|Evaluable.EvalVarRefid->{tswithtr_var=Id.Pred.addidts.tr_var},(Id.Set.addidids,csts,prjs)|Evaluable.EvalConstRefcst->{tswithtr_cst=Cpred.addcstts.tr_cst},(ids,Cset.addcstcsts,prjs)|Evaluable.EvalProjectionRefp->{tswithtr_prj=PRpred.addpts.tr_prj},(ids,csts,PRset.addpprjs)inletdb={dbwithhintdb_unfolds=unfs}inifdb.use_dnthenrebuild_dbstatedbelsedb|_->dbinletdb,id=next_hint_iddbinaddkvkidvdbletadd_listenvsigmaldb=List.fold_left(fundbk->add_oneenvsigmakdb)dblletremoveenvstgrsse=letfoldaccugr=GlobRef.Set_env.add(Environ.QGlobRef.canonizeenvgr)accuinletgrs=List.fold_leftfoldGlobRef.Set_env.emptygrsinletnopat=StoredData.removeenvgrsse.sentry_nopatinletpat=StoredData.removeenvgrsse.sentry_patinifpat==se.sentry_pat&&nopat==se.sentry_nopatthenseelseletse={sewithsentry_nopat=nopat;sentry_pat=pat}inrebuild_dnstseletremove_listenvgrsdb=leteqgr1gr2=QGlobRef.equalenvgr1gr2inletfilter(_,h)=matchh.namewithSomegr->not(List.mem_feqgrgrs)|None->trueinlethintmap=GlobRef.Map.map(fune->removeenv(dn_tsdb)grse)db.hintdb_mapinlethintnopat=List.filterfilterdb.hintdb_nopatin{dbwithhintdb_map=hintmap;hintdb_nopat=hintnopat}letremove_oneenvgrdb=remove_listenv[gr]dbletget_entryse=leth=merge_set(StoredData.elementsse.sentry_nopat)(merge_set(StoredData.elementsse.sentry_pat)[])inList.mapsndhletiterfdb=letiter_sekse=f(Somek)se.sentry_mode(get_entryse)infNone[](List.mapsnddb.hintdb_nopat);GlobRef.Map.iteriter_sedb.hintdb_mapletfoldfdbaccu=letaccu=fNone[](List.mapsnddb.hintdb_nopat)accuinGlobRef.Map.fold(funkse->f(Somek)se.sentry_mode(get_entryse))db.hintdb_mapacculettransparent_statedb=db.hintdb_stateletset_transparent_statedbst=ifdb.use_dnthenrebuild_dbstdbelse{dbwithhintdb_state=st}letadd_cutenvpathdb={dbwithhintdb_cut=normalize_pathenv(PathOr(db.hintdb_cut,path))}letadd_modegrmdb=letse=findgrdbinletse={sewithsentry_mode=m::List.remove(Array.equalhint_mode_eq)mse.sentry_mode}in{dbwithhintdb_map=GlobRef.Map.addgrsedb.hintdb_map}letcutdb=db.hintdb_cutletunfoldsdb=db.hintdb_unfoldsletadd_modesmodesdb=letfgreme=Some{ewithsentry_mode=me.sentry_mode@e.sentry_mode}inletmode_entries=GlobRef.Map.map(funm->{(empty_se(dn_tsdb))withsentry_mode=m})modesin{dbwithhintdb_map=GlobRef.Map.unionfdb.hintdb_mapmode_entries}letmodesdb=GlobRef.Map.map(funse->se.sentry_mode)db.hintdb_mapletfind_mode_envgrdb=(GlobRef.Map.findgrdb.hintdb_map).sentry_modeletuse_dndb=db.use_dnendmoduleHintdbmap=String.Maptypehint_db=Hint_db.tletsearchtable=Summary.ref~name:"searchtable"Hintdbmap.emptyletsearchtable_mapname=Hintdbmap.findname!searchtableletsearchtable_add(name,db)=(* XXX see #21114 *)(* let () = assert (Hintdbmap.mem name !searchtable) in *)searchtable:=Hintdbmap.addnamedb!searchtableletsearchtable_create(name,db)=(* let () = assert (not @@ Hintdbmap.mem name !searchtable) in *)searchtable:=Hintdbmap.addnamedb!searchtableletcurrent_db_names()=Hintdbmap.domain!searchtableletcurrent_db()=Hintdbmap.bindings!searchtableletcurrent_pure_db()=List.mapsnd(current_db())leterror_no_such_hint_databasex=user_err(str"No such Hint database: "++strx++str".")(**************************************************************************)(* Auxiliary functions to prepare AUTOHINT objects *)(**************************************************************************)(* adding and removing tactics in the search table *)letwith_uidc={obj=c;uid=fresh_key()}letsecvars_of_idsets=Id.Set.fold(funidp->ifis_section_variable(Global.env())idthenId.Pred.addidpelsep)sId.Pred.emptyletsecvars_of_constrenvsigmac=secvars_of_idset(Termops.global_vars_setenvsigmac)letsecvars_of_globalenvgr=secvars_of_idset(vars_of_globalenvgr)letmake_exact_entryenvsigmainfo?name(c,cty,ctx)=letsecvars=secvars_of_constrenvsigmacinletcty=strip_outer_castsigmactyinmatchEConstr.kindsigmactywith|Prod_->failwith"make_exact_entry"|_->lethd=tryhead_boundsigmactywithBound->failwith"make_exact_entry"inletpri=matchinfo.hint_prioritywithNone->0|Somep->pinletpat=matchinfo.hint_patternwith|Somepat->ConstrPattern(sndpat)|None->DefaultPatterninleth={rhint_term=c;rhint_type=cty;rhint_uctx=ctx;rhint_arty=0}in(Somehd,{pri;pat=Somepat;name;db=();secvars;code=with_uid(Give_exacth);})letname_of_hint=function|IsGlobRefgr->Somegr|IsConstr_->Noneletmake_apply_entryenvsigmahnfinfo?name(c,cty,ctx)=letcty=ifhnfthenhnf_constr0envsigmactyelsectyinmatchEConstr.kindsigmactywith|Prod_->letcty=ifhnfthenReductionops.nf_betaiotaenvsigmactyelsectyinletsigma'=merge_context_set_optsigmactxinletce=Clenv.mk_clenv_fromenvsigma'(c,cty)inletc'=Clenv.clenv_type(* ~reduce:false *)ceinlethd=tryhead_bound(Clenv.clenv_evdce)c'withBound->failwith"make_apply_entry"inletmiss,hyps=Clenv.clenv_missingceinletnmiss=List.lengthmissinletsecvars=secvars_of_constrenvsigmacinletpri=matchinfo.hint_prioritywithNone->hyps+nmiss|Somep->pinletpat=matchinfo.hint_patternwith|Somep->ConstrPattern(sndp)|None->DefaultPatterninleth={rhint_term=c;rhint_type=cty;rhint_uctx=ctx;rhint_arty=hyps;}inifInt.equalnmiss0then(Somehd,{pri;pat=Somepat;name;db=();secvars;code=with_uid(Res_pfh);})else(Somehd,{pri;pat=Somepat;name;db=();secvars;code=with_uid(ERes_pfh);})|_->failwith"make_apply_entry"(* flags is (e,h,v) with e=true if eapply and h=true if hnf and v=true if verbose
c is a constr
cty is the type of constr *)letfresh_global_or_constrenvsigmacr=matchcrwith|IsGlobRefgr->let(c,ctx)=UnivGen.fresh_global_instanceenvgrinletctx=ifEnviron.is_polymorphicenvgrthenSomectxelseNonein(EConstr.of_constrc,ctx)|IsConstr(c,ctx)->(c,ctx)letmake_resolvesenvsigma(eapply,hnf)info~checkcr=letname=name_of_hintcrinletc,ctx=fresh_global_or_constrenvsigmacrinletcty=Retyping.get_type_ofenvsigmacinlettry_applyf=trylet(_,hint)asans=f(c,cty,ctx)inmatchhint.code.objwith|ERes_pf_->ifnoteapplythenNoneelseSomeans|_->SomeanswithFailure_->Noneinletents=List.map_filtertry_apply[make_exact_entryenvsigmainfo?name;make_apply_entryenvsigmahnfinfo?name]inifcheck&&List.is_emptyentsthenuser_err(pr_leconstr_envenvsigmac++spc()++(ifeapplythenstr"cannot be used as a hint."elsestr"can be used as a hint only for eauto."));ents(* used to add an hypothesis to the local hint database *)letmake_resolve_hypenvsigmahname=letdecl=EConstr.lookup_namedhnameenvinletc=mkVarhnameintry[make_apply_entryenvsigmatrueempty_hint_info~name:(GlobRef.VarRefhname)(c,NamedDecl.get_typedecl,None)]with|Failure_->[]|ewhennoncriticale->anomaly(Pp.str"make_resolve_hyp.")(* REM : in most cases hintname = id *)letmake_unfolderef=letg=global_of_evaluable_referenceerefin(Someg,{pri=4;pat=None;name=Someg;db=();secvars=secvars_of_global(Global.env())g;code=with_uid(Unfold_ntheref)})letmake_externpripattacast=lethdconstr=matchpatwith|None->None|Somec->trySome(head_pattern_boundc)withBoundPattern->user_err(Pp.str"Head pattern or sub-pattern must be a global constant, a section variable, \
an if, case, or let expression, an application, or a projection.")in(hdconstr,{pri=pri;pat=Option.map(funp->SyntacticPatternp)pat;name=None;db=();secvars=Id.Pred.empty;(* Approximation *)code=with_uid(Extern(pat,tacast))})letmake_moderefm=letopenTerminletty,_=Typeops.type_of_global_in_context(Global.env())refinletctx,t=decompose_prod_declstyinletn=Context.Rel.nhypsctxinletm'=Array.of_listminifnot(n==Array.lengthm')thenuser_err(pr_globalref++str" has "++intn++str" arguments while the mode declares "++int(Array.lengthm')++str".")elsem'letmake_trivialenvsigmar=letname=Somerinletc,ctx=fresh_global_or_constrenvsigma(IsGlobRefr)inletsigma=merge_context_set_optsigmactxinlett=hnf_constrenvsigma(Retyping.get_type_ofenvsigmac)inlethd=head_constrsigmatinleth={rhint_term=c;rhint_type=t;rhint_uctx=ctx;rhint_arty=0}in(Somehd,{pri=1;pat=SomeDefaultPattern;name=name;db=();secvars=secvars_of_constrenvsigmac;code=with_uid(Res_pf_THEN_trivial_failh)})(**************************************************************************)(* declaration of the AUTOHINT library object *)(**************************************************************************)(* If the database does not exist, it is created *)(* TODO: should a warning be printed in this case ?? *)letget_dbdbname=trysearchtable_mapdbnamewithNot_found->Hint_db.empty~name:dbnameTransparentState.emptyfalseletadd_hintdbnamehintlist=letdb=get_dbdbnameinletenv=Global.env()inletsigma=Evd.from_envenvinletdb'=Hint_db.add_listenvsigmahintlistdbinsearchtable_add(dbname,db')letadd_transparencydbnametargetb=letopenTransparentStateinletdb=get_dbdbnameinletst=Hint_db.transparent_statedbinletst'=matchtargetwith|HintsVariables->{stwithtr_var=(ifbthenId.Pred.fullelseId.Pred.empty)}|HintsConstants->{stwithtr_cst=(ifbthenCpred.fullelseCpred.empty)}|HintsProjections->{stwithtr_prj=(ifbthenPRpred.fullelsePRpred.empty)}|HintsReferencesgrs->List.fold_left(funstgr->matchgrwith|Evaluable.EvalConstRefc->{stwithtr_cst=(ifbthenCpred.addelseCpred.remove)cst.tr_cst}|Evaluable.EvalVarRefv->{stwithtr_var=(ifbthenId.Pred.addelseId.Pred.remove)vst.tr_var}|Evaluable.EvalProjectionRefp->{stwithtr_prj=(ifbthenPRpred.addelsePRpred.remove)pst.tr_prj})stgrsinsearchtable_add(dbname,Hint_db.set_transparent_statedbst')letremove_hintdbnamegrs=letenv=Global.env()inletdb=get_dbdbnameinletdb'=Hint_db.remove_listenvgrsdbinsearchtable_add(dbname,db')letadd_cutdbnamepath=letenv=Global.env()inletdb=get_dbdbnameinletdb'=Hint_db.add_cutenvpathdbinsearchtable_add(dbname,db')letadd_modedbnamelm=letdb=get_dbdbnameinletdb'=Hint_db.add_modelmdbinsearchtable_add(dbname,db')typedb_obj={db_local:bool;db_name:string;db_use_dn:bool;db_ts:TransparentState.t;}letwarn_mismatch_create_hintdb=CWarnings.create~name:"mismatched-hint-db"~category:CWarnings.CoreCategories.automationPp.(fun{db_name;db_use_dn}->str"Hint Db "++strdb_name++str" already exists and "++(ifdb_use_dnthenstr"is not"elsestr"is")++str" discriminated.")letcache_db({db_name=name;db_use_dn=b;db_ts=ts}aso)=matchsearchtable_mapnamewith|exceptionNot_found->searchtable_create(name,Hint_db.empty~nametsb)|db->(* Explicit DBs start with full TS, implicit DBs start with empty TS
This should probably be controllable in Create Hint Db,
otherwise we have to do eg "Create HintDb foo. Hint Constants Opaque : foo."
and if someone else creates foo and puts some transparency hints they will be overwritten. *)ifHint_db.use_dndb<>bthenwarn_mismatch_create_hintdboletload_db_x=cache_dbxletclassify_dbdb=ifdb.db_localthenDisposeelseSubstituteletinDB:db_obj->obj=declare_object{(default_object"AUTOHINT_DB")withcache_function=cache_db;load_function=load_db;subst_function=(fun(_,x)->x);classify_function=classify_db;}letcreate_hint_dblntsb=lethint={db_local=l;db_name=n;db_use_dn=b;db_ts=ts}inLib.add_leaf(inDBhint)typehint_action=|AddTransparencyof{grefs:Evaluable.thints_transparency_target;state:bool;}|AddHintsofhint_entrylist|RemoveHintsofGlobRef.tlist|AddCutofhints_path|AddModeof{gref:GlobRef.t;mode:hint_modearray}typehint_locality=Libobject.locality=Local|Export|SuperGlobaltypehint_obj={hint_local:hint_locality;hint_name:string;hint_action:hint_action;}letis_trivial_action=function|AddTransparency{grefs}->beginmatchgrefswith|HintsVariables|HintsConstants|HintsProjections->false|HintsReferencesl->List.is_emptylend|AddHintsl->List.is_emptyl|RemoveHintsl->List.is_emptyl|AddCut_|AddMode_->falseletrecis_section_path=function|PathAtomPathAny->false|PathAtom(PathHintsgrs)->letcheckc=isVarRefc&&Global.is_in_sectioncinList.existscheckgrs|PathStarp->is_section_pathp|PathSeq(p,q)|PathOr(p,q)->is_section_pathp||is_section_pathq|PathEmpty|PathEpsilon->falseletsuperglobalh=matchh.hint_localwith|SuperGlobal->true|Local|Export->falseletload_autohint_h=letname=h.hint_nameinletsuperglobal=superglobalhinmatchh.hint_actionwith|AddTransparency{grefs;state}->ifsuperglobalthenadd_transparencynamegrefsstate|AddHintshints->ifsuperglobalthenadd_hintnamehints|RemoveHintshints->ifsuperglobalthenremove_hintnamehints|AddCutpaths->ifsuperglobalthenadd_cutnamepaths|AddMode{gref;mode}->ifsuperglobalthenadd_modenamegrefmodeletopen_autohinth=letsuperglobal=superglobalhinmatchh.hint_actionwith|AddHintshints->ifnotsuperglobalthenadd_hinth.hint_namehints|AddCutpaths->ifnotsuperglobalthenadd_cuth.hint_namepaths|AddTransparency{grefs;state}->ifnotsuperglobalthenadd_transparencyh.hint_namegrefsstate|RemoveHintshints->ifnotsuperglobalthenremove_hinth.hint_namehints|AddMode{gref;mode}->ifnotsuperglobalthenadd_modeh.hint_namegrefmodeletcache_autohinto=load_autohint1o;open_autohintoletsubst_autohint(subst,obj)=letsubst_keygr=let(gr',t)=subst_globalsubstgrinmatchtwith|None->gr'|Somet->(tryhead_boundEvd.empty(EConstr.of_constrt.UVars.univ_abstracted_value)withBound->gr')inletsubst_mpssubstc=EConstr.of_constr(subst_mpssubst(EConstr.Unsafe.to_constrc))inletsubst_aux({rhint_term=c;rhint_type=t;rhint_uctx=ctx;rhint_arty=ar}ash)=letc'=subst_mpssubstcinlett'=subst_mpssubsttinifc==c'&&t'==tthenhelse{rhint_term=c';rhint_type=t';rhint_uctx=ctx;rhint_arty=ar}inletsubst_hint(k,dataashint)=letk'=Option.Smart.mapsubst_keykinletenv=Global.env()inletsigma=Evd.from_envenvinletsubst_hint_pattern=function|DefaultPattern->DefaultPattern|ConstrPatternpasp0->letp'=subst_patternenvsigmasubstpinifp'==pthenp0elseConstrPatternp'|SyntacticPatternpasp0->letp'=subst_patternenvsigmasubstpinifp'==pthenp0elseSyntacticPatternp'inletpat'=Option.Smart.mapsubst_hint_patterndata.patinletcode'=matchdata.code.objwith|Res_pfh->leth'=subst_auxhinifh==h'thendata.code.objelseRes_pfh'|ERes_pfh->leth'=subst_auxhinifh==h'thendata.code.objelseERes_pfh'|Give_exacth->leth'=subst_auxhinifh==h'thendata.code.objelseGive_exacth'|Res_pf_THEN_trivial_failh->leth'=subst_auxhinifh==h'thendata.code.objelseRes_pf_THEN_trivial_failh'|Unfold_nthref->letref'=subst_evaluable_referencesubstrefinifref==ref'thendata.code.objelseUnfold_nthref'|Extern(pat,tac)->letpat'=Option.Smart.map(subst_patternenvsigmasubst)patinlettac'=Gentactic.substsubsttacinifpat==pat'&&tac==tac'thendata.code.objelseExtern(pat',tac')inletname'=Option.Smart.map(subst_global_referencesubst)data.nameinletuid'=subst_knsubstdata.code.uidinletdata'=ifdata.code.uid==uid'&&data.pat==pat'&&data.name==name'&&data.code.obj==code'thendataelse{datawithpat=pat';name=name';code={obj=code';uid=uid'}}inifk'==k&&data'==datathenhintelse(k',data')inletaction=matchobj.hint_actionwith|AddTransparency{grefs=target;state=b}->lettarget'=matchtargetwith|HintsVariables->target|HintsConstants->target|HintsProjections->target|HintsReferencesgrs->letgrs'=List.Smart.map(subst_evaluable_referencesubst)grsinifgrs==grs'thentargetelseHintsReferencesgrs'iniftarget'==targetthenobj.hint_actionelseAddTransparency{grefs=target';state=b}|AddHintshints->lethints'=List.Smart.mapsubst_hinthintsinifhints'==hintsthenobj.hint_actionelseAddHintshints'|RemoveHintsgrs->letgrs'=List.Smart.map(subst_global_referencesubst)grsinifgrs==grs'thenobj.hint_actionelseRemoveHintsgrs'|AddCutpath->letpath'=subst_hints_pathsubstpathinifpath'==paththenobj.hint_actionelseAddCutpath'|AddMode{gref=l;mode=m}->letl'=subst_global_referencesubstlinifl'==lthenobj.hint_actionelseAddMode{gref=l';mode=m}inifaction==obj.hint_actionthenobjelse{objwithhint_action=action}letis_hint_local=functionLocal->true|Export|SuperGlobal->falseletclassify_autohintobj=ifis_hint_localobj.hint_local||is_trivial_actionobj.hint_actionthenDisposeelseSubstituteletdischarge_autohintobj=ifis_hint_localobj.hint_localthenNoneelseletaction=matchobj.hint_actionwith|AddTransparency{grefs;state}->letgrefs=matchgrefswith|HintsVariables|HintsConstants|HintsProjections->grefs|HintsReferencesgrs->letfiltere=matchewith|Evaluable.EvalConstRefc->Somee|Evaluable.EvalProjectionRefp->letp=Global.discharge_proj_reprpinSome(Evaluable.EvalProjectionRefp)|Evaluable.EvalVarRefid->ifGlobal.is_in_section(GlobRef.VarRefid)thenNoneelseSomeeinletgrs=List.filter_mapfiltergrsinHintsReferencesgrsinAddTransparency{grefs;state}|AddHints_|RemoveHints_->(* not supported yet *)assertfalse|AddCutpath->ifis_section_pathpaththenAddHints[](* dummy *)elseobj.hint_action|AddMode{gref;mode}->ifGlobal.is_in_sectiongrefthenifisVarRefgrefthenAddHints[](* dummy *)elseletinst=Global.section_instancegrefin(* Default mode for discharged parameters is output *)letmode=Array.append(Array.make(Array.lengthinst)ModeOutput)modeinAddMode{gref;mode}elseobj.hint_actioninifis_trivial_actionactionthenNoneelseSome{objwithhint_action=action}lethint_cat=create_category"hints"letinAutoHint:hint_obj->obj=declare_object{(default_object"AUTOHINT")withcache_function=cache_autohint;load_function=load_autohint;open_function=simple_open~cat:hint_catopen_autohint;subst_function=subst_autohint;classify_function=classify_autohint;discharge_function=discharge_autohint;}letcheck_localitylocality=letnot_localwhat=CErrors.user_errPp.(str"This command does not support the "++strwhat++str" attribute in sections.")inifLib.sections_are_opened()thenmatchlocalitywith|Local->()|SuperGlobal->not_local"global"|Export->not_local"export"letmake_hint~localitynameaction={hint_local=locality;hint_name=name;hint_action=action;}letremove_hints~localitydbnamesgrs=let()=check_localitylocalityinletdbnames=ifList.is_emptydbnamesthen["core"]elsedbnamesinList.iter(fundbname->lethint=make_hint~localitydbname(RemoveHintsgrs)inLib.add_leaf(inAutoHinthint))dbnames(**************************************************************************)(* The "Hint" vernacular command *)(**************************************************************************)letadd_resolvesenvsigmaclist~localitydbnames=List.iter(fundbname->letr=List.flatten(List.map(fun(pri,hnf,gr)->make_resolvesenvsigma(true,hnf)pri~check:true(IsGlobRefgr))clist)inletcheck(_,hint)=matchhint.code.objwith|ERes_pf{rhint_term=c;rhint_type=cty;rhint_uctx=ctx}->letsigma'=merge_context_set_optsigmactxinletce=Clenv.mk_clenv_fromenvsigma'(c,cty)inletmiss,_=Clenv.clenv_missingceinletnmiss=List.lengthmissinletvariables=str(CString.pluralnmiss"variable")inFeedback.msg_info(strbrk"The hint "++pr_leconstr_envenvsigma'c++strbrk" will only be used by eauto, because applying "++pr_leconstr_envenvsigma'c++strbrk" would leave "++variables++Pp.spc()++Pp.prlist_with_sepPp.pr_commaName.printmiss++strbrk" as unresolved existential "++variables++str".")|_->()inlet()=ifnot!Flags.quietthenList.itercheckrinlethint=make_hint~localitydbname(AddHintsr)inLib.add_leaf(inAutoHinthint))dbnamesletadd_unfoldsl~localitydbnames=List.iter(fundbname->lethint=make_hint~localitydbname(AddHints(List.mapmake_unfoldl))inLib.add_leaf(inAutoHinthint))dbnamesletadd_cutsl~localitydbnames=List.iter(fundbname->lethint=make_hint~localitydbname(AddCutl)inLib.add_leaf(inAutoHinthint))dbnamesletadd_modelm~localitydbnames=List.iter(fundbname->letm'=make_modelminlethint=make_hint~localitydbname(AddMode{gref=l;mode=m'})inLib.add_leaf(inAutoHinthint))dbnamesletadd_transparencylb~localitydbnames=List.iter(fundbname->lethint=make_hint~localitydbname(AddTransparency{grefs=l;state=b})inLib.add_leaf(inAutoHinthint))dbnamesletadd_externinfotacast~localitydbname=letpat=matchinfo.hint_patternwith|None->None|Some(_,pat)->Somepatinlethint=make_hint~localitydbname(AddHints[make_extern(Option.getinfo.hint_priority)pattacast])inLib.add_leaf(inAutoHinthint)letadd_externsinfotacast~localitydbnames=List.iter(add_externinfotacast~locality)dbnamesletadd_trivialsenvsigmal~localitydbnames=List.iter(fundbname->letl=List.map(func->make_trivialenvsigmac)linlethint=make_hint~localitydbname(AddHintsl)inLib.add_leaf(inAutoHinthint))dbnamestypehnf=booltypenonrechint_info=hint_infotypehints_entry=|HintsResolveEntryof(hint_info*hnf*GlobRef.t)list|HintsImmediateEntryofGlobRef.tlist|HintsCutEntryofhints_path|HintsUnfoldEntryofEvaluable.tlist|HintsTransparencyEntryofEvaluable.thints_transparency_target*bool|HintsModeEntryofGlobRef.t*hint_modelist|HintsExternEntryofhint_info*Gentactic.glob_generic_tacticletdefault_prepare_hint_ident=Id.of_string"H"exceptionFoundofconstr*typesletprepare_hintenvinit(sigma,c)=letsigma=Typeclasses.resolve_typeclasses~fail:falseenvsigmain(* We re-abstract over uninstantiated evars and universes.
It is actually a bit stupid to generalize over evars since the first
thing make_resolves will do is to re-instantiate the products *)letc=Evarutil.nf_evarsigmacinletc=drop_extra_implicit_argssigmacinletvars=ref(collect_varssigmac)inletsubst=ref[]inletrecfind_next_evarc=matchEConstr.kindsigmacwith|Evar(evk,argsasev)->(* We skip the test whether args is the identity or not *)lett=Evarutil.nf_evarsigma(existential_typesigmaev)inlett=List.fold_right(fun(e,id)c->replace_termsigmaeidc)!substtinifnot(closed0sigmac)thenuser_errPp.(str"Hints with holes dependent on a bound variable not supported.");ifoccur_existentialsigmatthen(* Not clever enough to construct dependency graph of evars *)user_errPp.(str"Not clever enough to deal with evars dependent in other evars.");raise(Found(c,t))|_->EConstr.itersigmafind_next_evarcinletreciterc=tryfind_next_evarc;cwithFound(evar,t)->letid=next_ident_away_fromdefault_prepare_hint_ident(funid->Id.Set.memid!vars)invars:=Id.Set.addid!vars;subst:=(evar,mkVarid)::!subst;mkNamedLambdasigma(make_annotidERelevance.relevant)t(iter(replace_termsigmaevar(mkVarid)c))inletc'=itercinletdiff=UnivGen.diff_sort_context(Evd.sort_context_setsigma)(Evd.sort_context_setinit)in(c',diff)letwarn_non_local_section_hint=CWarnings.create~name:"non-local-section-hint"~category:CWarnings.CoreCategories.automation(fun()->strbrk"This hint is not local but depends on a section variable. It will disappear when the section is closed.")letis_notlocal=function|Local->false|Export|SuperGlobal->trueletadd_hints~localitydbnamesh=let()=matchhwith|HintsResolveEntry_|HintsImmediateEntry_|HintsUnfoldEntry_|HintsExternEntry_->check_localitylocality|HintsTransparencyEntry((HintsVariables|HintsConstants|HintsProjections),_)->()|HintsTransparencyEntry(HintsReferencesgrs,_)->letitergr=letgr=global_of_evaluable_referencegrinifis_notlocallocality&&isVarRefgr&&Global.is_in_sectiongrthenwarn_non_local_section_hint()inList.iteritergrs|HintsCutEntryp->ifis_notlocallocality&&is_section_pathpthenwarn_non_local_section_hint()|HintsModeEntry(gr,_)->ifis_notlocallocality&&isVarRefgr&&Global.is_in_sectiongrthenwarn_non_local_section_hint()inifString.List.mem"nocore"dbnamesthenuser_errPp.(str"The hint database \"nocore\" is meant to stay empty.");assert(not(List.is_emptydbnames));letenv=Global.env()inletsigma=Evd.from_envenvinmatchhwith|HintsResolveEntrylhints->add_resolvesenvsigmalhints~localitydbnames|HintsImmediateEntrylhints->add_trivialsenvsigmalhints~localitydbnames|HintsCutEntrylhints->add_cutslhints~localitydbnames|HintsModeEntry(l,m)->add_modelm~localitydbnames|HintsUnfoldEntrylhints->add_unfoldslhints~localitydbnames|HintsTransparencyEntry(lhints,b)->add_transparencylhintsb~localitydbnames|HintsExternEntry(info,tacexp)->add_externsinfotacexp~localitydbnamesletwarn_non_reference_hint_using=CWarnings.create~name:"non-reference-hint-using"~category:CWarnings.CoreCategories.deprecatedPp.(fun(env,sigma,c)->str"Use of the non-reference term "++pr_leconstr_envenvsigmac++str" in \"using\" clauses is deprecated")letexpand_constructor_hintsenvsigmalems=List.map_append(funlem->letevd,lem=lemenvsigmainletlem0=drop_extra_implicit_argsevdleminmatchEConstr.kindevdlem0with|Ind(ind,u)->List.init(nconstructorsenvind)(funi->IsGlobRef(GlobRef.ConstructRef((ind,i+1))))|Const(cst,_)->[IsGlobRef(GlobRef.ConstRefcst)]|Varid->[IsGlobRef(GlobRef.VarRefid)]|Construct(cstr,_)->[IsGlobRef(GlobRef.ConstructRefcstr)]|_->let()=warn_non_reference_hint_using(env,evd,lem)inlet(c,ctx)=prepare_hintenvsigma(evd,lem)inletctx=ifUnivGen.is_empty_sort_contextctxthenNoneelseSomectxin[IsConstr(c,ctx)])lems(* builds a hint database from a constr signature *)(* typically used with (lid, ltyp) = pf_hyps_types <some goal> *)letconstructor_hintsenvsigmaeapplylems=letlems=expand_constructor_hintsenvsigmalemsinList.map_append(funlem->make_resolvesenvsigma(eapply,true)empty_hint_info~check:truelem)lemsletmake_local_hint_dbenvsigmatseapplylems=letsign=EConstr.named_contextenvinletts=matchtswith|None->Hint_db.transparent_state(searchtable_map"core")|Somets->tsinlethintlist=List.map_append(fundecl->make_resolve_hypenvsigma(Named.Declaration.get_iddecl))signinHint_db.emptytsfalse|>Hint_db.add_listenvsigmahintlist|>Hint_db.add_listenvsigma(constructor_hintsenvsigmaeapplylems)letmake_local_hint_dbenvsigma?tseapplylems=make_local_hint_dbenvsigmatseapplylemsletmake_db_listdbnames=letfold(core,nocore)db=ifString.equaldb"core"then(true,nocore)elseifString.equaldb"nocore"then(core,true)else(core,nocore)inlethas_core,has_nocore=List.fold_leftfold(false,false)dbnamesinletdbnames=matchhas_core,has_nocorewith|true,true->user_errPp.(str"The core and nocore databases are mutually exclusive")|true,false->dbnames|false,true->List.removeString.equal"nocore"dbnames|false,false->"core"::dbnamesinletlookupdb=trysearchtable_mapdbwithNot_found->error_no_such_hint_databasedbinList.maplookupdbnamesletpush_resolvesenvsigmahintdb=letentries=make_resolvesenvsigma(true,false)empty_hint_info~check:false(IsGlobRefhint)inHint_db.add_listenvsigmaentriesdbletpush_resolve_hypenvsigmadecldb=letentries=make_resolve_hypenvsigmadeclinHint_db.add_listenvsigmaentriesdb(**************************************************************************)(* Functions for printing the hints *)(**************************************************************************)letpr_hint_eltenvsigmah=pr_econstr_envenvsigmah.hint_termletpr_hintenvsigmah=matchh.objwith|Res_pfc->(str"simple apply "++pr_hint_eltenvsigmac)|ERes_pfc->(str"simple eapply "++pr_hint_eltenvsigmac)|Give_exactc->(str"exact "++pr_hint_eltenvsigmac)|Res_pf_THEN_trivial_failc->(str"simple apply "++pr_hint_eltenvsigmac++str" ; trivial")|Unfold_nthc->str"unfold "++pr_evaluable_referencec|Extern(_,tac)->str"(*external*) "++Gentactic.print_globenvsigma~level:(LevelLe0)tacletpr_default_patternenvsigma=function|Give_exacth->pr_leconstr_envenvsigmah.hint_type|Res_pfh|ERes_pfh|Res_pf_THEN_trivial_failh->letsigma,f=Clenv.replace_clenv_metasenvsigmah.hint_clnvinpr_leconstr_envenvsigma(f(Clenv.clenv_typeh.hint_clnv))|Unfold_nth_|Extern_->(* These hints cannot contain DefaultPattern *)assertfalseletpr_id_hintenvsigma(id,v)=letpr_patp=matchp.patwith|None->mt()|Some(ConstrPatternp|SyntacticPatternp)->str", pattern "++pr_lconstr_pattern_envenvsigmap|SomeDefaultPattern->str", pattern "++(pr_default_patternenvsigmav.code.obj)in(pr_hintenvsigmav.code++str" (cost "++intv.pri++pr_patv++str", id "++intid++str")")letpr_hint_listenvsigmahintlist=(str" "++hov0(prlist_with_sepfnl(pr_id_hintenvsigma)hintlist)++fnl())letpr_hints_dbenvsigma(name,db,hintlist)=(str"In the database "++strname++str":"++ifList.is_emptyhintlistthen(str" nothing"++fnl())else(fnl()++pr_hint_listenvsigmahintlist))(* Print all hints associated to head c in any database *)letpr_hint_list_for_headenvsigmac=letdbs=current_db()inletvalidate(name,db)=lethints=List.map(funv->0,v)(Hint_db.map_all~secvars:Id.Pred.fullcdb)in(name,db,hints)inletvalid_dbs=List.mapvalidatedbsinifList.is_emptyvalid_dbsthen(str"No hint declared for :"++pr_globalc)elsehov0(str"For "++pr_globalc++str" -> "++fnl()++hov0(prlist(pr_hints_dbenvsigma)valid_dbs))letpr_hint_refref=pr_hint_list_for_headref(* Print all hints associated to head id in any database *)letpr_hint_termenvsigmacl=tryletdbs=current_db()inletvalid_dbs=letfn=trylethdc=decompose_app_boundsigmaclinifoccur_existentialsigmaclthen(fundb->matchHint_db.map_eautoenvsigma~secvars:Id.Pred.fullhdccldbwith|ModeMatch(_,l)->l|ModeMismatch->[])elseHint_db.map_autoenvsigma~secvars:Id.Pred.fullhdcclwithBound->Hint_db.map_none~secvars:Id.Pred.fullinletfndb=List.map(funx->0,x)(fndb)inList.map(fun(name,db)->(name,db,fndb))dbsinifList.is_emptyvalid_dbsthen(str"No hint applicable for current goal")else(str"Applicable Hints :"++fnl()++hov0(prlist(pr_hints_dbenvsigma)valid_dbs))withMatch_failure_|Failure_->(str"No hint applicable for current goal")(* print all hints that apply to the concl of the current goal *)letpr_applicable_hintpf=letenv=Global.env()inletProof.{goals;sigma}=Proof.datapfinmatchgoalswith|[]->CErrors.user_errPp.(str"No focused goal.")|g::_->pr_hint_termenvsigma(Evd.evar_concl(Evd.find_undefinedsigmag))letparse_modes=matchswith|"+"->ModeInput|"-"->ModeOutput|"!"->ModeNoHeadEvar|_->CErrors.user_errPp.(str"Unrecognized hint mode "++strs)letparse_modess=letmodes=String.split_on_char' 'sinList.mapparse_modemodesletstring_of_mode=function|ModeInput->"+"|ModeOutput->"-"|ModeNoHeadEvar->"!"letpp_hint_modem=str(string_of_modem)(* displays the whole hint database db *)letpr_hint_db_envenvsigmadb=letpr_mode=prvect_with_sepspcpp_hint_modeinletpr_modesl=ifList.is_emptylthenmt()elsestr" (modes "++prlist_with_seppr_commapr_model++str")"inletcontent=letpr_one(head,modes,hintlist)=letgoal_descr=matchheadwith|None->str"For any goal"|Somehead->str"For "++pr_globalhead++pr_modesmodesin(* sort because db.hintdb_nopat isn't kept in priority sorted order;
"auto" sorts on priority before using the hintdb *)letsorted=List.stable_sort(funab->Int.comparea.prib.pri)hintlistin(* always prints "id 0" in Print HintDb *)lethints=pr_hint_listenvsigma(List.map(funx->(0,x))sorted)inhov0(goal_descr++str" -> "++hints)inlethints=letnamex=Nametab.shortest_qualid_of_globalId.Set.emptyxinletorder(h1,_,_)(h2,_,_)=Option.compare(funab->leta=nameaandb=namebinletrv=Id.compare(qualid_basenamea)(qualid_basenameb)inifrv<>0thenrvelseString.compare(string_of_qualida)(string_of_qualidb))h1h2inlethints=Hint_db.fold(funhmhll->(h,m,hl)::l)db[]inList.stable_sortorderhintsinPp.prlistpr_onehintsinlet{TransparentState.tr_var=ids;tr_cst=csts;tr_prj=ps}=Hint_db.transparent_statedbinhov0((ifHint_db.use_dndbthenstr"Discriminated database"elsestr"Non-discriminated database"))++fnl()++hov2(str"Unfoldable variable definitions: "++pr_idpredids)++fnl()++hov2(str"Unfoldable constant definitions: "++pr_cpredcsts)++fnl()++hov2(str"Unfoldable projection definitions: "++pr_prpredps)++fnl()++hov2(str"Cut: "++pp_hints_path(Hint_db.cutdb))++fnl()++contentletpr_hint_db_by_nameenvsigmadbname=tryletdb=searchtable_mapdbnameinpr_hint_db_envenvsigmadbwithNot_found->error_no_such_hint_databasedbname(* displays all the hints of all databases *)letpr_searchtableenvsigma=letfoldnamedbaccu=accu++str"In the database "++strname++str":"++fnl()++pr_hint_db_envenvsigmadb++fnl()inHintdbmap.foldfold!searchtable(mt())moduleFullHint=structtypet=full_hintletpriority(h:t)=h.priletdatabase(h:t)=h.dbletpattern(h:t)=matchh.patwith|None->None|Some(ConstrPatternp|SyntacticPatternp)->Somep|SomeDefaultPattern->Noneletrun(h:t)k=kh.code.objletprintenvsigma(h:t)=pr_hintenvsigmah.codeletname(h:t)=h.nameletsubgoals(h:t)=matchh.code.objwith|Res_pfh|ERes_pfh|Give_exacth|Res_pf_THEN_trivial_failh->Someh.hint_arty|Unfold_nth_->Some1|Extern_->Noneletrepr(h:t)=h.code.objendletconnect_hint_clenvhgl=let{hint_uctx=ctx;hint_clnv=clenv}=hin(* [clenv] has been generated by a hint-making function, so the only relevant
data in its evarmap is the set of metas. The function
below just replaces the metas of sigma by those coming from the clenv. *)letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinClenv.clenv_refreshenvsigmactxclenvletfresh_hintenvsigmah=let{hint_term=c;hint_uctx=ctx}=hinmatchh.hint_uctxwith|None->sigma,c|Somectx->(* Refresh the instance of the hint *)let(subst,ctx)=UnivGen.fresh_sort_context_instancectxinletc=Vars.subst_univs_level_constrsubstcinletsigma=Evd.merge_sort_context_setEvd.univ_flexible~src:UState.Internalsigmactxinsigma,clethint_res_pf?with_evars?with_classes?flagsh=Proofview.Goal.enterbeginfungl->letclenv=connect_hint_clenvhglinClenv.res_pf?with_evars?with_classes?flagsclenvend