123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374(************************************************************************)(* * 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) *)(************************************************************************)openPpopenUtilopenNamesopenTermopenConstropenTermopsopenEConstropenTacticsopenTypeclassesopenEvdopenLocusopenProofview.NotationsopenHintsmoduleNamedDecl=Context.Named.Declaration(** Hint database named "typeclass_instances", created in prelude *)lettypeclasses_db="typeclass_instances"(** Options handling *)lettypeclasses_depth_opt_name=["Typeclasses";"Depth"]let{Goptions.get=get_typeclasses_depth}=Goptions.declare_intopt_option_and_ref~key:typeclasses_depth_opt_name~value:None()letset_typeclasses_depth=Goptions.set_int_option_valuetypeclasses_depth_opt_name(** When this flag is enabled, the resolution of type classes tries to avoid
useless introductions. This is no longer useful since we have eta, but is
here for compatibility purposes. Another compatibility issues is that the
cost (in terms of search depth) can differ. *)let{Goptions.get=get_typeclasses_limit_intros}=Goptions.declare_bool_option_and_ref~key:["Typeclasses";"Limit";"Intros"]~value:true()let{Goptions.get=get_typeclasses_dependency_order}=Goptions.declare_bool_option_and_ref~key:["Typeclasses";"Dependency";"Order"]~value:false()letiterative_deepening_opt_name=["Typeclasses";"Iterative";"Deepening"]let{Goptions.get=get_typeclasses_iterative_deepening}=Goptions.declare_bool_option_and_ref~key:iterative_deepening_opt_name~value:false()moduleDebug:sigvalppdebug:int->(unit->Pp.t)->unitvalget_debug:unit->intvalset_typeclasses_debug:bool->unitend=structlettypeclasses_debug=ref0letset_typeclasses_debugd=(:=)typeclasses_debug(ifdthen1else0)letget_typeclasses_debug()=if!typeclasses_debug>0thentrueelsefalseletset_typeclasses_verbose=function|None->typeclasses_debug:=0|Somen->typeclasses_debug:=nletget_typeclasses_verbose()=if!typeclasses_debug=0thenNoneelseSome!typeclasses_debuglet()=letopenGoptionsindeclare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Typeclasses";"Debug"];optread=get_typeclasses_debug;optwrite=set_typeclasses_debug;}let()=letopenGoptionsindeclare_int_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Typeclasses";"Debug";"Verbosity"];optread=get_typeclasses_verbose;optwrite=set_typeclasses_verbose;}letppdebuglvlpp=if!typeclasses_debug>lvlthenFeedback.msg_debug(pp())letget_debug()=!typeclasses_debugendopenDebugletset_typeclasses_debug=set_typeclasses_debugtypesearch_strategy=Dfs|Bfsletset_typeclasses_strategy=function|Dfs->Goptions.set_bool_option_valueiterative_deepening_opt_namefalse|Bfs->Goptions.set_bool_option_valueiterative_deepening_opt_nametrueletpr_evevsev=letevi=Evd.find_undefinedevsevinletenv=Evd.evar_filtered_env(Global.env())eviinPrinter.pr_econstr_envenvevs(Evd.evar_conclevi)letpr_ev_with_idevsev=Evar.printev++str" : "++pr_evevsev(** Typeclasses instance search tactic / eauto *)openAutoopenUnificationletauto_core_unif_flagsstallowed_evars={modulo_conv_on_closed_terms=Somest;use_metas_eagerly_in_conv_on_closed_terms=true;use_evars_eagerly_in_conv_on_closed_terms=false;modulo_delta=st;modulo_delta_types=st;check_applied_meta_types=false;use_pattern_unification=true;use_meta_bound_pattern_unification=true;allowed_evars;restrict_conv_on_strict_subterms=false;(* ? *)modulo_betaiota=true;modulo_eta=false;}letauto_unif_flags?(allowed_evars=Evarsolve.AllowedEvars.all)st=letfl=auto_core_unif_flagsstallowed_evarsin{core_unify_flags=fl;merge_unify_flags=fl;subterm_unify_flags=fl;allow_K_in_toplevel_higher_order_unification=false;resolve_evars=false}lete_give_exactflagsh=letopenTacmachinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=projectglinletsigma,c=Hints.fresh_hintenvsigmahinlet(sigma,t1)=Typing.type_of(pf_envgl)sigmacinProofview.Unsafe.tclEVARSsigma<*>Clenv.unify~flags~cv_pb:CUMULt1<*>exact_no_checkcendletunify_resolve~with_evarsflagshdiff=matchdiffwith|None->Hints.hint_res_pf~with_evars~with_classes:false~flagsh|Some(diff,ty)->let()=assert(Option.is_empty(fst@@hint_as_term@@h))inProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletsigma,c=Hints.fresh_hintenvsigmahinletclenv=Clenv.mk_clenv_from_nenvsigmadiff(c,ty)inClenv.res_pf~with_evars~with_classes:false~flagsclenvend(** Dealing with goals of the form A -> B and hints of the form
C -> A -> B.
*)letwith_prodsnprodshf=ifget_typeclasses_limit_intros()thenProofview.Goal.enterbeginfungl->ifOption.has_some(fst@@hint_as_termh)||Int.equalnprods0thenfNoneelseletsigma=Tacmach.projectglinletty=Retyping.get_type_of(Proofview.Goal.envgl)sigma(snd@@hint_as_termh)inletdiff=nb_prodsigmaty-nprodsinif(>=)diff0thenf(Some(diff,ty))elseTacticals.tclZEROMSG(str"Not enough premisses")endelseProofview.Goal.enterbeginfungl->ifInt.equalnprods0thenfNoneelseTacticals.tclZEROMSG(str"Not enough premisses")end(** Semantics of type class resolution lemma application:
- Use unification to find a well-typed substitution. There might
be evars in the goal and the lemma. Evars in the goal can get refined.
- Independent evars are turned into goals, whatever their kind is.
- Dependent evars of the lemma corresponding to arguments which appear
in independent goals or the conclusion are turned into subgoals iff
they are of typeclass kind.
- The remaining dependent evars not of typeclass type are shelved,
and resolution must fill them for it to succeed, otherwise we
backtrack.
*)letpr_glssigmagls=prlist_with_sepspc(funev->int(Evar.reprev)++spc()++pr_evsigmaev)gls(** Ensure the dependent subgoals are shelved after an apply/eapply. *)letshelve_dependenciesgls=letopenProofviewinifCList.is_emptyglsthentclUNIT()elsetclEVARMAP>>=funsigma->ppdebug1(fun()->str" shelving dependent subgoals: "++pr_glssigmagls);shelve_goalsglslethintmap_ofenvsigmahdcsecvarsconcl=matchhdcwith|None->fundb->ModeMatch(NoMode,Hint_db.map_none~secvarsdb)|Somehdc->fundb->Hint_db.map_eautoenvsigma~secvarshdcconcldb(** Hack to properly solve dependent evars that are typeclasses *)letrece_trivial_fail_dbonly_classesdb_listlocal_dbsecvars=letopenTacticalsinletopenTacmachinlettrivial_fail=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletd=NamedDecl.get_id@@pf_last_hypglinlethints=push_resolve_hypenvsigmadlocal_dbine_trivial_fail_dbonly_classesdb_listhintssecvarsendinlettrivial_resolve=Proofview.Goal.enterbeginfungl->lettacs=e_trivial_resolvedb_listlocal_dbsecvarsonly_classes(pf_envgl)(projectgl)(pf_conclgl)intclFIRST(List.map(fun(x,_,_,_,_)->x)tacs)endinlettacl=Eauto.e_assumption::(tclTHENTactics.introtrivial_fail::[trivial_resolve])intclSOLVEtaclande_my_find_searchdb_listlocal_dbsecvarshdccompleteonly_classesenvsigmaconcl0=letprods,concl=EConstr.decompose_prod_declssigmaconcl0inletnprods=List.lengthprodsinletallowed_evars=letall=Evarsolve.AllowedEvars.allinmatchhdcwith|Some(hd,_)whenonly_classes->beginmatchTypeclasses.class_infohdwith|Somecl->ifcl.cl_strictthenletundefined=lazy(Evarutil.undefined_evars_of_termsigmaconcl)inletallowedevk=not(Evar.Set.memevk(Lazy.forceundefined))inEvarsolve.AllowedEvars.from_predallowedelseall|None->allend|_->allinlettac_of_hint=fun(flags,h)->letname=FullHint.namehinlettac=function|Res_pfh->lettac=with_prodsnprodsh(unify_resolve~with_evars:falseflagsh)inProofview.tclBIND(Proofview.with_shelftac)(fun(gls,())->shelve_dependenciesgls)|ERes_pfh->lettac=with_prodsnprodsh(unify_resolve~with_evars:trueflagsh)inProofview.tclBIND(Proofview.with_shelftac)(fun(gls,())->shelve_dependenciesgls)|Give_exacth->e_give_exactflagsh|Res_pf_THEN_trivial_failh->letfst=with_prodsnprodsh(unify_resolve~with_evars:trueflagsh)inletsnd=ifcompletethenTacticals.tclIDTACelsee_trivial_fail_dbonly_classesdb_listlocal_dbsecvarsinTacticals.tclTHENfstsnd|Unfold_nthc->Proofview.tclPROGRESS(unfold_in_concl[AllOccurrences,c])|Extern(p,tacast)->conclPatternconcl0ptacastinlettac=FullHint.runhtacinlettac=ifcompletethenTacticals.tclCOMPLETEtacelsetacinletextern=matchFullHint.reprhwith|Extern_->true|_->falsein(tac,FullHint.priorityh,extern,name,lazy(FullHint.printenvsigmah))inlethint_of_db=hintmap_ofenvsigmahdcsecvarsconclinlethintl=List.map_filter(fundb->matchhint_of_dbdbwith|ModeMatch(m,l)->Some(db,m,l)|ModeMismatch->None)(local_db::db_list)in(* In case there is a mode mismatch in all the databases we get stuck.
Otherwise we consider the hints that match.
Recall the local database uses the union of all the modes in the other databases. *)ifList.is_emptyhintlthenNoneelselethintl=CList.map(fun(db,m,tacs)->letflags=auto_unif_flags~allowed_evars(Hint_db.transparent_statedb)inm,List.map(funx->tac_of_hint(flags,x))tacs)hintlinletmodes,hintl=List.splithintlinletall_mode_match=List.for_all(funm->m!=NoMode)modesinlethintl=matchhintlwith(* Optim: only sort if multiple hint sources were involved *)|[hintl]->hintl|_->lethintl=List.flattenhintlinlethintl=List.stable_sort(fun(_,pri1,_,_,_)(_,pri2,_,_,_)->Int.comparepri1pri2)hintlinhintlinSome(all_mode_match,hintl)ande_trivial_resolvedb_listlocal_dbsecvarsonly_classesenvsigmaconcl=lethd=trySome(decompose_app_boundsigmaconcl)withBound->Noneintry(matche_my_find_searchdb_listlocal_dbsecvarshdtrueonly_classesenvsigmaconclwith|Some(_,l)->l|None->[])withNot_found->[]lete_possible_resolvedb_listlocal_dbsecvarsonly_classesenvsigmaconcl=lethd=trySome(decompose_app_boundsigmaconcl)withBound->Noneintrye_my_find_searchdb_listlocal_dbsecvarshdfalseonly_classesenvsigmaconclwithNot_found->Some(true,[])letcut_of_hintsh=List.fold_left(funcutdb->PathOr(Hint_db.cutdb,cut))PathEmptyhletpr_depthl=letrecfmtelts=matcheltswith|[]->[]|[n]->[string_of_intn]|n1::n2::rest->(string_of_intn1^"."^string_of_intn2)::fmtrestinprlist_with_sep(fun()->str"-")str(fmt(List.revl))letis_Propenvsigmaconcl=letty=Retyping.get_type_ofenvsigmaconclinmatchEConstr.kindsigmatywith|Sorts->beginmatchESorts.kindsigmaswith|Prop->true|_->falseend|_->falseletis_uniqueenvsigmaconcl=trylet(cl,u),args=dest_class_appenvsigmaconclincl.cl_uniquewithewhenCErrors.noncriticale->false(** Sort the undefined variables from the least-dependent to most dependent. *)lettop_sortevmundefs=letl'=ref[]inlettosee=refundefsinletcache=Evarutil.create_undefined_evars_cache()inletrecvisitevevi=letevs=Evarutil.filtered_undefined_evars_of_evar_info~cacheevmeviintosee:=Evar.Set.removeev!tosee;Evar.Set.iter(funev->ifEvar.Set.memev!toseethenvisitev(Evd.find_undefinedevmev))evs;l':=ev::!l';inwhilenot(Evar.Set.is_empty!tosee)doletev=Evar.Set.choose!toseeinvisitev(Evd.find_undefinedevmev)done;List.rev!l'(** We transform the evars that are concerned by this resolution
(according to predicate p) into goals.
Invariant: function p only manipulates and returns undefined evars
*)letevars_to_goalspevm=letgoals,nongoals=Evar.Set.partition(pevm)(Evd.get_typeclass_evarsevm)inifEvar.Set.is_emptygoalsthenNoneelseSome(goals,nongoals)(** Making local hints *)letmake_resolve_hypenvsigmastonly_classesdecldb=letid=NamedDecl.get_iddeclinletcty=Evarutil.nf_evarsigma(NamedDecl.get_typedecl)inletisclenvty=letctx,ar=decompose_prod_declssigmatyinmatchEConstr.kindsigma(fst(decompose_appsigmaar))with|Const(c,_)->is_class(GlobRef.ConstRefc)|Ind(i,_)->is_class(GlobRef.IndRefi)|_->falseinletis_class=isclenvctyinletkeep=notonly_classes||is_classinifkeepthenletid=GlobRef.VarRefidinpush_resolvesenvsigmaiddbelsedbletmake_hintsenvsigma(modes,st)only_classessign=letdb=Hint_db.add_modesmodes@@Hint_db.emptysttrueinList.fold_right(funhyphints->letconsider=notonly_classes||trylett=hyp|>NamedDecl.get_id|>Global.lookup_named|>NamedDecl.get_typein(* Section variable, reindex only if the type changed *)not(EConstr.eq_constrsigma(EConstr.of_constrt)(NamedDecl.get_typehyp))withNot_found->trueinifconsiderthenmake_resolve_hypenvsigmastonly_classeshyphintselsehints)signdbmoduleIntpart=Unionfind.Make(Evar.Set)(Evar.Map)typesolver={solver:Environ.env->Evd.evar_map->depth:intoption->unique:bool->best_effort:bool->goals:Evar.tlist->(bool*Evd.evar_map)}moduleSearch=structtypeautoinfo={search_depth:intlist;last_tac:Pp.tLazy.t;search_dep:bool;search_only_classes:bool;search_cut:hints_path;search_hints:hint_db;search_best_effort:bool;}(** Local hints *)letautogoal_cache=Summary.ref~name:"autogoal_cache"(DirPath.empty,true,Context.Named.empty,GlobRef.Map.empty,Hint_db.emptyTransparentState.fulltrue)letmake_autogoal_hintsonly_classes(modes,stasmst)gl=letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletsign=EConstr.named_contextenvinlet(dir,onlyc,sign',cached_modes,cached_hints)=!autogoal_cacheinletcwd=Lib.cwd()inleteqc1c2=EConstr.eq_constrsigmac1c2inifDirPath.equalcwddir&&(onlyc==only_classes)&&Context.Named.equal(ERelevance.equalsigma)eqsignsign'&&cached_modes==modesthencached_hintselselethints=make_hintsenvsigmamstonly_classessigninautogoal_cache:=(cwd,only_classes,sign,modes,hints);hintsletmake_autogoalmstonly_classesdepcutbest_effortig=lethints=make_autogoal_hintsonly_classesmstgin{search_hints=hints;search_depth=[i];last_tac=lazy(str"none");search_dep=dep;search_only_classes=only_classes;search_cut=cut;search_best_effort=best_effort}(** In the proof engine failures are represented as exceptions *)exceptionReachedLimitexceptionNoApplicableHintexceptionStuckGoal(** ReachedLimit has priority over NoApplicableHint to handle
iterative deepening: it should fail when no hints are applicable,
but go to a deeper depth otherwise. *)letmerge_exceptionsee'=matchfste,fste'with|ReachedLimit,_->e|_,ReachedLimit->e'|_,_->e(** Determine if backtracking is needed for this goal.
We generally backtrack except in the following (possibly
overlapping) cases:
- [unique_instances] is [true].
This is the case when the goal's class has [Unique Instances].
- [indep] is [true] and the current goal has no evars.
[indep] is generally [true] and only gets set to [false] if the
current goal's evar is mentioned in other goals.
([indep] is the negation of [search_dep].)
- The current goal is a [Prop] and has no evars. *)letneeds_backtrackenvevd~unique_instances~indepconcl=ifunique_instancesthenfalseelseifindep||is_Propenvevdconclthenoccur_existentialevdconclelsetrueexceptionNonStuckFailure(* exception Backtrack *)letpr_goalss=letopenProofviewinifget_debug()>1thentclEVARMAP>>=funsigma->Unsafe.tclGETGOALS>>=fungls->letgls=CList.mapProofview.drop_stateglsinletj=List.lengthglsinletpr_goalgl=pr_ev_with_idsigmaglinFeedback.msg_debug(s++intj++str" goals:"++spc()++prlist_with_sepPp.fnlpr_goalgls);tclUNIT()elsetclUNIT()letpr_internal_exceptionie=matchfstiewith|ReachedLimit->str"Proof-search reached its limit."|NoApplicableHint->str"Proof-search failed."|StuckGoal|NonStuckFailure->str"Proof-search got stuck."|e->CErrors.iprintie(* XXX Is this handler needed for something? *)let()=CErrors.register_handlerbeginfunction|NonStuckFailure->Some(str"NonStuckFailure")|NoApplicableHint->Some(str"NoApplicableHint")|_->Noneend(**
For each success of tac1 try tac2.
If tac2 raises NonStuckFailure, try the next success of tac1 until depleted.
If tac1 finally fails, returns the result of the first tac1 success, if any.
*)typegoal_status=|IsInitial|IsStuckGoal|IsNonStuckFailureletpr_goal_status=function|IsInitial->str"initial"|IsStuckGoal->str"stuck"|IsNonStuckFailure->str"stuck failure"letpr_search_goalsigma(glid,ev,status,_)=str"Goal "++intglid++str" evar: "++Evar.printev++str" status: "++pr_goal_statusstatusletpr_search_goalssigma=prlist_with_sepfnl(pr_search_goalsigma)letsearch_fixpoint~best_effort~allow_out_of_ordertacs=letopenPpinletopenProofviewinletopenProofview.Notationsinletrecfixpointprogresstacsstuckfk=letnext(glid,ev,status,tac)tacsstuck=let()=ppdebug1(fun()->str"considering goal "++intglid++str" of status "++pr_goal_statusstatus)inletreckont=function|Fail((NonStuckFailure|StuckGoalasexn),info)whenallow_out_of_order->let()=ppdebug1(fun()->str"Goal "++intglid++str" is stuck or failed without being stuck, trying other tactics.")inletstatus=matchexnwith|NonStuckFailure->IsNonStuckFailure|StuckGoal->IsStuckGoal|_->assertfalseincycle1(* Puts the first goal last *)<*>fixpointprogresstacs((glid,ev,status,tac)::stuck)fk(* Launches the search on the rest of the goals *)|Failie->let()=ppdebug1(fun()->str"Goal "++intglid++str" has no more solutions, returning exception: "++pr_internal_exceptionie)infkie|Next(res,fk')->let()=ppdebug1(fun()->str"Goal "++intglid++str" has a success, continuing resolution")in(* We try to solve the rest of the constraints, and if that fails
we backtrack to the next result of tac, etc.... Ultimately if none of the solutions
for tac work, we will come back to the failure continuation fk in one of
the above cases *)fixpointtruetacsstuck(fune->tclCASE(fk'e)>>=kont)intclCASEtac>>=kontintclEVARMAP>>=funsigma->let()=ppdebug1(fun()->letstuck,failed=List.partition(fun(_,_,status,_)->status=IsStuckGoal)stuckinstr"Calling fixpoint on : "++int(List.lengthtacs)++str" initial goals"++str", "++int(List.lengthstuck)++str" stuck goals"++str" and "++int(List.lengthfailed)++str" non-stuck failures kept"++str" with "++str(ifprogressthen""else"no ")++str"progress made in this run."++fnl()++str"Stuck: "++pr_search_goalssigmastuck++fnl()++str"Failed: "++pr_search_goalssigmafailed++fnl()++str"Initial: "++pr_search_goalssigmatacs)intclCHECKINTERRUPT<*>matchtacswith|tac::tacs->nexttactacsstuck|[]->(* All remaining goals are stuck *)matchstuckwith|[]->(* We found a solution! Great, but in case it's not good for the rest of the proof search,
we might have other solutions available through fk. *)tclOR(tclUNIT())fk|stuck->ifprogressthenfixpointfalsestuck[]fkelse(* No progress can be made on the stuck goals arising from this resolution,
try a different solution on the non-stuck goals, if any. *)begintclORELSE(fk(NoApplicableHint,Exninfo.null))(fun(e,info)->let()=ppdebug1(fun()->int(List.lengthstuck)++str" remaining goals left, no progress, calling continuation failed")in(* We keep the stuck goals to display to the user *)ifbest_effortthenletstuckgls,failedgls=List.partition(fun(_,_,status,_)->matchstatuswith|IsStuckGoal->true|IsNonStuckFailure->false(* There should remain no initial goals at this point *)|IsInitial->assertfalse)stuckinpr_goals(str"best_effort is on and remaining goals are: ")<*>(* We shelve the stuck goals but we keep the non-stuck failures in the goal list.
This is for compat with Coq 8.12 but might not be the wisest choice in the long run.
*)letto_shelve=List.map(fun(glid,ev,_,_)->ev)stuckglsinlet()=ppdebug1(fun()->str"Shelving subgoals: "++prlist_with_sepspcEvar.printto_shelve)inUnsafe.tclNEWSHELVEDto_shelveelsetclZERO~infoe)endinpr_goals(str"Launching resolution fixpoint on ")<*>Unsafe.tclGETGOALS>>=fungls->(* We wrap all goals with their associated tactic.
It might happen that an initial goal is solved during the resolution of another goal,
hence the `tclUNIT` in case there is no goal for the tactic to apply anymore. *)lettacs=List.map2_i(funiglstac->(succi,Proofview.drop_stategls,IsInitial,tclFOCUS~nosuchgoal:(tclUNIT())11tac))0glstacsinfixpointfalsetacs[](fun(e,info)->tclZERO~infoe)<*>pr_goals(str"Result goals after fixpoint: ")(** The general hint application tactic.
tac1 + tac2 .... The choice of OR or ORELSE is determined
depending on the dependencies of the goal and the unique/Prop
status *)lethints_tac_glhintsinfokontgl:unitProofview.tactic=letopenProofviewinletopenProofview.Notationsinletenv=Goal.envglinletconcl=Goal.conclglinletsigma=Goal.sigmaglinletunique_instances=is_uniqueenvsigmaconclinletindep=notinfo.search_depinletbacktrack=needs_backtrackenvsigma~unique_instances~indepconclinlet()=ppdebug0(fun()->pr_depthinfo.search_depth++str": looking for "++Printer.pr_econstr_env(Goal.envgl)sigmaconcl++(ifbacktrackthenstr" with backtracking"elsestr" without backtracking"))inletsecvars=compute_secvarsglinmatche_possible_resolvehintsinfo.search_hintssecvarsinfo.search_only_classesenvsigmaconclwith|None->Proofview.tclZEROStuckGoal|Some(all_mode_match,poss)->(* If no goal depends on the solution of this one or the
instances are irrelevant/assumed to be unique, then
we don't need to backtrack, as long as no evar appears in the goal
This is an overapproximation. Evars could appear in this goal only
and not any other *)letortac=ifbacktrackthenProofview.tclORelseProofview.tclORELSEinletidx=ref1inletfoundone=reffalseinletreconetace(tac,pat,b,name,pp)tl=letderivs=path_derivateinfo.search_cutnameinletpr_errorie=ppdebug1(fun()->letidx=iffstie==NoApplicableHintthenpred!idxelse!idxinletheader=pr_depth(idx::info.search_depth)++str": "++Lazy.forcepp++(if!foundone!=truethenstr" on"++spc()++pr_evsigma(Proofview.Goal.goalgl)elsemt())in(header++str" failed with: "++pr_internal_exceptionie))inlettac_ofglsij=Goal.enterbeginfungl'->letsigma'=Goal.sigmagl'inlet()=ppdebug0(fun()->pr_depth(succj::i::info.search_depth)++str" : "++pr_evsigma'(Proofview.Goal.goalgl'))inleteqc1c2=EConstr.eq_constrsigma'c1c2inlethints'=ifb&¬(Context.Named.equal(ERelevance.equalsigma)eq(Goal.hypsgl')(Goal.hypsgl))thenletst=Hint_db.transparent_stateinfo.search_hintsinletmodes=Hint_db.modesinfo.search_hintsinmake_autogoal_hintsinfo.search_only_classes(modes,st)gl'elseinfo.search_hintsinletdep'=info.search_dep||Proofview.unifiablesigma'(Goal.goalgl')glsinletinfo'={search_depth=succj::i::info.search_depth;last_tac=pp;search_dep=dep';search_only_classes=info.search_only_classes;search_hints=hints';search_cut=derivs;search_best_effort=info.search_best_effort}inkontinfo'endinletrecresult(shelf,())ik=foundone:=true;Proofview.Unsafe.tclGETGOALS>>=fungls->letgls=CList.mapProofview.drop_stateglsinletj=List.lengthglsinlet()=ppdebug0(fun()->pr_depth(i::info.search_depth)++str": "++Lazy.forcepp++str" on"++spc()++pr_evsigma(Proofview.Goal.goalgl)++str", "++intj++str" subgoal(s)"++(Option.cata(funk->str" in addition to the first "++intk)(mt())k))inletres=ifj=0thentclUNIT()elsesearch_fixpoint~best_effort:false~allow_out_of_order:false(List.initj(funj'->(tac_ofglsi(Option.default0k+j'))))inletfinishnestedshelfsigma=letfilterev=tryletevi=Evd.find_undefinedsigmaevinifinfo.search_only_classesthenSome(ev,not(is_class_evarsigmaevi))elseSome(ev,true)withNot_found->Noneinletremaining=CList.map_filterfiltershelfinlet()=ppdebug1(fun()->letprunsolved(ev,_)=int(Evar.reprev)++spc()++pr_evsigmaevinletunsolved=prlist_with_sepspcprunsolvedremaininginpr_depth(i::info.search_depth)++str": after "++Lazy.forcepp++str" finished, "++int(List.lengthremaining)++str" goals are shelved and unsolved ( "++unsolved++str")")inbegin(* Some existentials produced by the original tactic were not solved
in the subgoals, turn them into subgoals now. *)letshelved,goals=List.partition(fun(ev,s)->s)remaininginletshelved=List.mapfstshelved@nestedshelfandgoals=List.mapfstgoalsinlet()=ifnot(List.is_emptyshelved&&List.is_emptygoals)thenppdebug1(fun()->str"Adding shelved subgoals to the search: "++prlist_with_sepspc(pr_evsigma)goals++str" while shelving "++prlist_with_sepspc(pr_evsigma)shelved)inshelve_goalsshelved<*>ifList.is_emptygoalsthentclUNIT()elseletmake_unresolvables=tclEVARMAP>>=funsigma->letsigma=make_unresolvables(funx->List.mem_fEvar.equalxgoals)sigmainUnsafe.tclEVARSsigmainletgoals=CList.mapProofview.with_empty_stategoalsinwith_shelf(make_unresolvables<*>Unsafe.tclNEWGOALSgoals)>>=funs->resultsi(Some(Option.default0k+j))endinwith_shelfres>>=fun(sh,())->tclEVARMAP>>=finishshinifpath_matches_epsilonderivsthenauxetlelseortac(with_shelftac>>=funs->leti=!idxinincridx;resultsiNone)(fune'->(pr_errore';aux(merge_exceptionsee')tl))andauxe=function|tac::tacs->onetacetactacs|[]->let()=if!foundone==falsethenppdebug0(fun()->pr_depthinfo.search_depth++str": no match for "++Printer.pr_econstr_env(Goal.envgl)sigmaconcl++str", "++int(List.lengthposs)++str" possibilities")inmatchewith|(ReachedLimit,ie)->Proofview.tclZERO~info:ieReachedLimit|(StuckGoal,ie)->Proofview.tclZERO~info:ieStuckGoal|(NoApplicableHint,ie)->(* If the constraint abides by the (non-trivial) modes but no
solution could be found, we consider it a failed goal, and let
proof search proceed on the rest of the
constraints, thus giving a more precise error message. *)ifall_mode_match&&info.search_best_effortthenProofview.tclZERO~info:ieNonStuckFailureelseProofview.tclZERO~info:ieNoApplicableHint|(_,ie)->Proofview.tclZERO~info:ieNoApplicableHintinifbacktrackthenaux(NoApplicableHint,Exninfo.null)posselsetclONCE(aux(NoApplicableHint,Exninfo.null)poss)lethints_tachintsinfokont:unitProofview.tactic=Proofview.Goal.enter(fungl->hints_tac_glhintsinfokontgl)letintro_tacinfokontgl=letopenProofviewinletenv=Goal.envglinletsigma=Goal.sigmaglinletdecl=Tacmach.pf_last_hypglinletldb=make_resolve_hypenvsigma(Hint_db.transparent_stateinfo.search_hints)info.search_only_classesdeclinfo.search_hintsinletinfo'={infowithsearch_hints=ldb;last_tac=lazy(str"intro");search_depth=1::1::info.search_depth}inkontinfo'letintroinfokont=Proofview.tclBINDTactics.intro(fun_->Proofview.Goal.enter(fungl->intro_tacinfokontgl))letrecsearch_tachintslimitdepth=letkontinfo=Proofview.numgoals>>=funi->let()=ppdebug1(fun()->str"calling eauto recursively at depth "++int(succdepth)++str" on "++inti++str" subgoals")insearch_tachintslimit(succdepth)infoinfuninfo->ifInt.equaldepth(succlimit)thenletinfo=Exninfo.reify()inProofview.tclZERO~infoReachedLimitelseProofview.tclOR(hints_tachintsinfokont)(fune->Proofview.tclOR(introinfokont)(fune'->let(e,info)=merge_exceptionsee'inProofview.tclZERO~infoe))letsearch_tac_glmstonly_classesdephintsbest_effortdepthisigmaglsgl:unitProofview.tactic=letopenProofviewinletdep=dep||Proofview.unifiablesigma(Goal.goalgl)glsinletinfo=make_autogoalmstonly_classesdep(cut_of_hintshints)best_effortiglinsearch_tachintsdepth1infoletsearch_tacmstonly_classesbest_effortdephintsdepth=letopenProofviewinlettacsigmaglsi=Goal.enterbeginfungl->search_tac_glmstonly_classesdephintsbest_effortdepth(succi)sigmaglsglendinProofview.Unsafe.tclGETGOALS>>=fungls->letgls=CList.mapProofview.drop_stateglsinProofview.tclEVARMAP>>=funsigma->letj=List.lengthglsinsearch_fixpoint~best_effort~allow_out_of_order:true(List.initj(funi->tacsigmaglsi))letfix_iterativet=letrecauxdepth=Proofview.tclOR(tdepth)(function|(ReachedLimit,_)->aux(succdepth)|(e,ie)->Proofview.tclZERO~info:iee)inaux1letfix_iterative_limitlimitt=letopenProofviewinletrecauxdepth=ifInt.equaldepth(succlimit)thenletinfo=Exninfo.reify()intclZERO~infoReachedLimitelsetclOR(tdepth)(function|(ReachedLimit,_)->aux(succdepth)|(e,ie)->Proofview.tclZERO~info:iee)inaux1leteauto_tac_stuckmst?(unique=false)~only_classes~best_effort?strategy~depth~dephints=letopenProofviewinlettac=letsearch=search_tacmstonly_classesbest_effortdephintsinletdfs=matchstrategywith|None->not(get_typeclasses_iterative_deepening())|SomeDfs->true|SomeBfs->falseinifdfsthenletdepth=matchdepthwithNone->-1|Somed->dinsearchdepthelsematchdepthwith|None->fix_iterativesearch|Somel->fix_iterative_limitlsearchinleterror(e,info)=matchewith|ReachedLimit->Tacticals.tclFAIL~info(str"Proof search reached its limit")|NoApplicableHint->Tacticals.tclFAIL~info(str"Proof search failed"++(ifOption.is_emptydepththenmt()elsestr" without reaching its limit"))|Proofview.MoreThanOneSuccess->Tacticals.tclFAIL~info(str"Proof search failed: "++str"more than one success found")|e->Proofview.tclZERO~infoeinlettac=Proofview.tclORtacerrorinlettac=ifuniquethenProofview.tclEXACTLY_ONCEProofview.MoreThanOneSuccesstacelsetacinwith_shelfnumgoals>>=fun(initshelf,i)->let()=ppdebug1(fun()->str"Starting resolution with "++inti++str" goal(s) under focus and "++int(List.lengthinitshelf)++str" shelved goal(s)"++(ifonly_classesthenstr" in only_classes mode"elsestr" in regular mode")++matchdepthwith|None->str", unbounded"|Somei->str", with depth limit "++inti)intac<*>pr_goals(str"after eauto_tac_stuck: ")leteauto_tacmst?unique~only_classes~best_effort?strategy~depth~dephints=Hints.wrap_hint_warning@@eauto_tac_stuckmst?unique~only_classes~best_effort?strategy~depth~dephintsletpreprocess_goalsevmgoals=letsorted_goals=ifget_typeclasses_dependency_order()thentop_sortevmgoalselseEvar.Set.elementsgoalsinletevm=Evd.set_typeclass_evarsevmEvar.Set.emptyinletevm=Evd.push_future_goalsevminevm,Evd.meta_listevm,sorted_goalsletrun_on_goalsenvevmtac~goals=letgoalsl=List.mapProofview.with_empty_stategoalsinlettac=Proofview.Unsafe.tclNEWGOALSgoalsl<*>tacinlet_,pv=Proofview.initevm[]in(* Instance may try to call this before a proof is set up!
Thus, give_me_the_proof will fail. Beware! *)letname,poly=(* try
* let Proof.{ name; poly } = Proof.data Proof_global.(give_me_the_proof ()) in
* name, poly
* with | Proof_global.NoCurrentProof -> *)Id.of_string"instance",falseinlettac=ifget_debug()>1thenProofview.Trace.record_info_tracetacelsetacinlet(),pv',unsafe,info=tryProofview.apply~name~polyenvtacpvwithLogic_monad.TacticFailure_->raiseNot_foundinlet()=ppdebug1(fun()->str"The tactic trace is: "++hov0(Proofview.Trace.pr_infoenvevm~lvl:1info))inletfinished=Proofview.finishedpv'inletevm'=Proofview.returnpv'in(finished,evm')letpost_process_goals~goals~nongoals~old_metas~sigma~finished=let_,sigma=Evd.pop_future_goalssigmainlettc_evars=Evd.get_typeclass_evarssigmainlet()=ppdebug1(fun()->str"Finished resolution with "++str(iffinishedthen"a complete"else"an incomplete")++str" solution."++fnl()++str"Old typeclass evars not concerned by this resolution = "++hov0(prlist_with_sepspc(pr_ev_with_idsigma)(Evar.Set.elementstc_evars))++fnl()++str"Shelf = "++hov0(prlist_with_sepspc(pr_ev_with_idsigma)(Evar.Set.elementstc_evars)))inletnongoals=Evar.Set.fold(funevacc->matchEvarutil.advancesigmaevwith|Someev->Evar.Set.addevacc|None->acc)(Evar.Set.uniongoalsnongoals)tc_evarsin(* FIXME: the need to merge metas seems to come from this being called
internally from Unification. It should be handled there instead. *)letsigma=Evd.meta_mergeold_metas(Evd.clear_metassigma)inletsigma=Evd.set_typeclass_evarssigmanongoalsinlet()=ppdebug1(fun()->str"New typeclass evars are: "++hov0(prlist_with_sepspc(pr_ev_with_idsigma)(Evar.Set.elementsnongoals)))insigma(** Typeclasses eauto is an eauto which tries to resolve only
goals of typeclass type, and assumes that the initially selected
evars in evd are independent of the rest of the evars *)lettypeclasses_eautoenvevd~goals?depth~unique~best_effortsthints=letonly_classes=trueinletdep=uniqueinNewProfile.profile"typeclass search"(fun()->run_on_goalsenvevd(eauto_tac_stuckst~unique~only_classes~best_effort~depth~dephints)~goals)()lettypeclasses_resolve:solver={solver=funenvevd~depth~unique~best_effort~goals->letdb=searchtable_maptypeclasses_dbinletst=Hint_db.transparent_statedbinletmodes=Hint_db.modesdbintypeclasses_eautoenvevd~goals?depth~best_effort~unique(modes,st)[db]}endlettypeclasses_eauto?(only_classes=false)?(best_effort=false)?(st=TransparentState.full)?strategy~depthdbs=letdbs=List.map_filter(fundb->trySome(searchtable_mapdb)withewhenCErrors.noncriticale->None)dbsinletst=matchdbswithx::_->Hint_db.transparent_statex|_->stinletmodes=List.mapHint_db.modesdbsinletmodes=List.fold_left(GlobRef.Map.union(fun_m1m2->Some(m1@m2)))GlobRef.Map.emptymodesinletdepth=matchdepthwithNone->get_typeclasses_depth()|Somel->SomelinProofview.tclIGNORE(Search.eauto_tac(modes,st)~only_classes?strategy~best_effort~depth~dep:truedbs)(* Stuck goals can remain here, we could shelve them, but this way
the user can use `solve [typeclasses eauto]` to check there are
no stuck goals remaining, or use [typeclasses eauto; shelve] himself. *)(** We compute dependencies via a union-find algorithm.
Beware of the imperative effects on the partition structure,
it should not be shared, but only used locally. *)letdeps_of_constraintscstrsevmp=List.iter(fun(_,_,x,y)->letevx=Evarutil.undefined_evars_of_termevmxinletevy=Evarutil.undefined_evars_of_termevmyinIntpart.union_set(Evar.Set.unionevxevy)p)cstrsletevar_dependenciespredevmp=letcache=Evarutil.create_undefined_evars_cache()inEvd.fold_undefined(funevevi_->ifEvd.is_typeclass_evarevmev&&predevmevevithenletevars=Evar.Set.addev(Evarutil.filtered_undefined_evars_of_evar_info~cacheevmevi)inIntpart.union_setevarspelse())evm()(** [split_evars] returns groups of undefined evars according to dependencies *)letsplit_evarspredevm=letp=Intpart.create()inevar_dependenciespredevmp;deps_of_constraints(snd(extract_all_conv_pbsevm))evmp;Intpart.partitionpletis_inference_forcedpevdev=tryifEvar.Set.memev(Evd.get_typeclass_evarsevd)&&pevthenlet(loc,k)=evar_source(Evd.find_undefinedevdev)inmatchkwith|Evar_kinds.ImplicitArg(_,_,b)->b|Evar_kinds.QuestionMark_->false|_->trueelsetruewithNot_found->assertfalseletis_mandatorypcompevd=Evar.Set.exists(is_inference_forcedpevd)comp(** Check if an evar is concerned by the current resolution attempt,
(and in particular is in the current component).
Invariant : this should only be applied to undefined evars. *)letselect_and_update_evarspoevdin_compevdev=tryifEvd.is_typeclass_evaroevdevthen(in_compev&&pevdev(Evd.find_undefinedevdev))elsefalsewithNot_found->false(** Do we still have unresolved evars that should be resolved ? *)lethas_undefinedpoevdevd=letcheckevevi=poevdevinEvar.Map.existscheck(Evd.undefined_mapevd)letfind_undefinedpoevdevd=letcheckevevi=poevdevinEvar.Map.domain(Evar.Map.filtercheck(Evd.undefined_mapevd))exceptionUnresolvedofevar_maptypecondition=Environ.env->evar_map->Evar.Set.t->booltypetc_solver=solver*conditionletclass_solvers=ref(CString.Map.empty:tc_solverCString.Map.t)letregister_solver~name?(override=false)h=ifnotoverride&&CString.Map.memname!class_solversthenCErrors.anomaly~label:"Class_tactics.register_solver"Pp.(str(Printf.sprintf{|Solver "%s" is already registered|}name));class_solvers:=CString.Map.addnameh!class_solversletactive_solvers=Summary.ref~name:"typeclass_solvers"([]:stringlist)letdeactivate_solver~name=active_solvers:=List.filter(funs->not(String.equalsname))!active_solversletactivate_solver~name=assert(CString.Map.memname!class_solvers);deactivate_solver~name;active_solvers:=name::!active_solversletfind_solverenvevd(s:Intpart.set)=letrecfind_solver=function|[]->Search.typeclasses_resolve|hd::tl->trylet(solver,cond)=CString.Map.findhd!class_solversinifcondenvevdsthensolverelsefind_solvertlwithNot_found->find_solvertlinfind_solver!active_solvers(** If [do_split] is [true], we try to separate the problem in
several components and then solve them separately *)letresolve_all_evarsdepthuniqueenvpoevdfail=let()=ppdebug0(fun()->str"Calling typeclass resolution with flags: "++str"depth = "++(matchdepthwithNone->str"∞"|Somed->intd)++str","++str"unique = "++boolunique++str","++str"fail = "++boolfail);ppdebug2(fun()->str"Initial evar map: "++Termops.pr_evar_map~with_univs:!Detyping.print_universesNoneenvoevd)inletsplit=split_evarspoevdinletin_compcompev=Evar.Set.memevcompinletrecdocompevd=function|[]->let()=ppdebug2(fun()->str"Final evar map: "++Termops.pr_evar_map~with_univs:!Detyping.print_universesNoneenvevd)inevd|comp::comps->letp=select_and_update_evarspoevd(in_compcomp)intry(try(* evars_to_goals p evd gives none when there's no evar having p *)matchevars_to_goalspevdwith|Some(goals,nongoals)->letsolver=find_solverenvevdcompinletevd,old_metas,sorted_goals=Search.preprocess_goalsevdgoalsinletfinished,evd=solver.solverenvevd~goals:sorted_goals~best_effort:true~depth~uniqueinletevd=Search.post_process_goals~goals~nongoals~old_metas~sigma:evd~finishedinifhas_undefinedpoevdevdthenlet()=iffinishedthenppdebug1(fun()->str"Proof is finished but there remain undefined evars: "++prlist_with_sepspc(pr_evevd)(Evar.Set.elements(find_undefinedpoevdevd)))inraise(Unresolvedevd)elsedocompevdcomps|None->docompevdcomps(* No typeclass evars left in this component *)withNot_found->(* Typeclass resolution failed *)raise(Unresolvedevd))withUnresolvedevd'->iffail&&is_mandatory(pevd')compevd'then(* Unable to satisfy the constraints. *)error_unresolvableenvevd'compelse(* Best effort: use the best found solution on this component *)docompevd'compsindocompoevdsplitletinitial_select_evarsfilter=funevdevevi->filterev(Lazy.from_val(snd(Evd.evar_sourceevi)))&&(* Typeclass evars can contain evars whose conclusion is not
yet determined to be a class or not. *)Typeclasses.is_class_evarevdeviletclasses_transparent_state()=tryHint_db.transparent_state(searchtable_maptypeclasses_db)withNot_found->TransparentState.emptyletresolve_typeclass_evarsdepthuniqueenvevdfilterfail=letevd=tryEvarconv.solve_unif_constraints_with_heuristics~flags:(Evarconv.default_flags_of(classes_transparent_state()))envevdwithewhenCErrors.noncriticale->evdinresolve_all_evarsdepthuniqueenv(initial_select_evarsfilter)evdfailletsolve_instenvevdfilteruniquefail=let((),sigma)=Hints.wrap_hint_warning_funenvevdbeginfunevd->(),resolve_typeclass_evars(get_typeclasses_depth())uniqueenvevdfilterfailendinsigmalet()=Typeclasses.set_solve_all_instancessolve_instletresolve_one_typeclassenv?(sigma=Evd.from_envenv)conclunique=let(term,sigma)=Hints.wrap_hint_warning_funenvsigmabeginfunsigma->lethints=searchtable_maptypeclasses_dbinletst=Hint_db.transparent_statehintsinletmodes=Hint_db.modeshintsinletdepth=get_typeclasses_depth()inlettac=Tacticals.tclCOMPLETE(Search.eauto_tac(modes,st)~only_classes:true~best_effort:false~depth[hints]~dep:true)inletentry,pv=Proofview.initsigma[env,concl]inletpv=letname=Names.Id.of_string"legacy_pe"inmatchProofview.apply~name~poly:false(Global.env())tacpvwith|(_,final,_,_)->final|exception(Logic_monad.TacticFailure(Tacticals.FailError_))->raiseNot_foundinletevd=Proofview.returnpvinletterm=matchProofview.partial_proofentrypvwith[t]->t|_->assertfalseinterm,evdendin(sigma,term)let()=Typeclasses.set_solve_one_instance(funxyzw->resolve_one_typeclassx~sigma:yzw)(** Take the head of the arity of a constr.
Used in the partial application tactic. *)letrechead_of_constrsigmat=lett=strip_outer_castsigmatinmatchEConstr.kindsigmatwith|Prod(_,_,c2)->head_of_constrsigmac2|LetIn(_,_,_,c2)->head_of_constrsigmac2|App(f,args)->head_of_constrsigmaf|_->tlethead_of_constrhc=Proofview.tclEVARMAP>>=funsigma->letc=head_of_constrsigmacinletin_tacNone(Nameh)cNoneLocusops.allHypsletnot_evarc=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmacwith|Evar_->Tacticals.tclFAIL(str"Evar")|_->Proofview.tclUNIT()letis_groundc=letopenTacticalsinProofview.tclEVARMAP>>=funsigma->ifEvarutil.is_ground_termsigmacthentclIDTACelsetclFAIL(str"Not ground")letautoapplyci=letopenProofview.NotationsinHints.wrap_hint_warning@@Proofview.Goal.enterbeginfungl->lethintdb=tryHints.searchtable_mapiwithNot_found->CErrors.user_err(Pp.str("Unknown hint database "^i^"."))inletflags=auto_unif_flags(Hints.Hint_db.transparent_statehintdb)inletcty=Tacmach.pf_get_type_ofglcinletenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletce=Clenv.mk_clenv_fromenvsigma(c,cty)inClenv.res_pf~with_evars:true~with_classes:false~flagsce<*>Proofview.tclEVARMAP>>=(funsigma->letsigma=Typeclasses.make_unresolvables(funev->Typeclasses.all_goalsev(Lazy.from_val(snd(Evd.evar_source(Evd.find_undefinedsigmaev)))))sigmainProofview.Unsafe.tclEVARSsigma)endletresolve_tcc=letopenProofview.NotationsinProofview.tclENV>>=funenv->Proofview.tclEVARMAP>>=funsigma->letdepth=get_typeclasses_depth()inletunique=get_typeclasses_unique_solutions()inletevars=Evarutil.undefined_evars_of_termsigmacinletfilter=(funev_->Evar.Set.memevevars)inletfail=trueinletsigma=resolve_all_evarsdepthuniqueenv(initial_select_evarsfilter)sigmafailinProofview.Unsafe.tclEVARSsigma