123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* This file is (C) Copyright 2006-2015 Microsoft Corporation and Inria. *)openLtac_pluginopenNamesopenPpopenGenargopenContextmoduleCoqConstr=ConstropenCoqConstropenLibnamesopenTacticsopenTermopsopenGlob_termopenUtilopenEvdopenTacexpropenTacinterpopenPretypingopenPpconstropenPrinteropenEvar_kindsopenConstrexpropenConstrexpr_opstypessrtermkind=|InParens|WithAt|NoFlag|Cpatternleterrorstrm=CErrors.user_errletloc_errorlocmsg=CErrors.user_err?loc(strmsg)letppnl=Feedback.msg_info(* 0 cost pp function. Active only if env variable SSRDEBUG is set *)(* or if SsrDebug is Set *)letpp_ref=ref(fun_->())letssr_pps=Feedback.msg_debug(str"SSR: "++Lazy.forces)let_=tryignore(Sys.getenv"SSRMATCHINGDEBUG");pp_ref:=ssr_ppwithNot_found->()letdebugb=ifbthenpp_ref:=ssr_ppelsepp_ref:=fun_->()let_=Goptions.declare_bool_option{Goptions.optstage=Summary.Stage.Interp;Goptions.optkey=["Debug";"SsrMatching"];Goptions.optdepr=None;Goptions.optread=(fun_->!pp_ref==ssr_pp);Goptions.optwrite=debug}letpps=!pp_refs(** Utils *)(* {{{ *****************************************************************)letenv_sizeenv=List.length(Environ.named_contextenv)letsafeDestAppsigmac=matchEConstr.kindsigmacwithApp(f,a)->f,a|_->c,[||](* Toplevel constr must be globalized twice ! *)letglob_constristgenvsigmat=matcht,istwith|(_,Somece),Someist->letvars=Id.Map.fold(funx_accu->Id.Set.addxaccu)ist.lfunId.Set.emptyinletltacvars={Constrintern.empty_ltac_signwithConstrintern.ltac_vars=vars}inConstrintern.intern_genWithoutTypeConstraint~ltacvars:ltacvarsgenvsigmace|(rc,None),_->rc|(_,Some_),None->CErrors.anomalyPp.(str"glob_constr: term with no ist")(* Term printing utilities functions for deciding bracketing. *)letpr_parenprxx=hov1(str"("++prxx++str")")(* String lexing utilities *)letskip_wscharss=letrecloopi=matchs.[i]with'\n'..' '->loop(i+1)|_->iinloop(* We also guard characters that might interfere with the ssreflect *)(* tactic syntax. *)letguard_termkindsi=matchs.[i]with|'('->false|'{'|'/'|'='->true|_->kind=InParens(* The call 'guard s i' should return true if the contents of s *)(* starting at i need bracketing to avoid ambiguities. *)letpr_guardedguardprcc=lets=Pp.string_of_ppcmds(prcc)^"$"inifguards(skip_wscharss0)thenpr_parenprccelseprcc(* More sensible names for constr printers *)letwith_global_env_evmfx=letenv=Global.env()inletsigma=Evd.from_envenvinfenvsigmaxletprl_glob_constr=with_global_env_evmpr_lglob_constr_envletpr_glob_constr=with_global_env_evmpr_glob_constr_envletprl_constr_expr=pr_lconstr_exprletpr_constr_expr=pr_constr_exprletprl_glob_constr_and_exprenvsigma=function|_,Somec->prl_constr_exprenvsigmac|c,None->prl_glob_constrcletpr_glob_constr_and_exprenvsigma=function|_,Somec->pr_constr_exprenvsigmac|c,None->pr_glob_constrc(** Adding a new uninterpreted generic argument type *)letadd_genargtagpr=letwit=Genarg.make0taginlettag=Geninterp.Val.createtaginletglobistx=(ist,x)inletsubst_x=xinletinterpistx=Ftactic.return(Geninterp.Val.Dyn(tag,x))inletgen_prenvsigma___=prenvsigmainlet()=Genintern.register_intern0witglobinlet()=Gensubst.register_subst0witsubstinlet()=Geninterp.register_interp0witinterpinlet()=Geninterp.register_val0wit(Some(Geninterp.Val.Basetag))inPptactic.declare_extra_genarg_pprulewitgen_prgen_prgen_pr;wit(** Constructors for constr_expr *)letisCVar=function{CAst.v=CRef(qid,_)}->qualid_is_identqid|_->falseletdestCVar=function|{CAst.v=CRef(qid,_)}whenqualid_is_identqid->qualid_basenameqid|_->CErrors.anomaly(str"not a CRef.")letisGLambdac=matchDAst.getcwithGLambda(Name_,_,_,_,_)->true|_->falseletdestGLambdac=matchDAst.getcwithGLambda(Nameid,_,_,_,c)->(id,c)|_->CErrors.anomaly(str"not a GLambda")letisGHolec=matchDAst.getcwithGHole_->true|_->falseletmkCHole~loc=CAst.make?loc@@CHole(None)letmkCLambda?locnametyt=CAst.make?loc@@CLambdaN([CLocalAssum([CAst.make?locname],None,DefaultExplicit,ty)],t)letmkCLetIn?locnamebot=CAst.make?loc@@CLetIn((CAst.make?locname),bo,None,t)letmkCCast?loctty=CAst.make?loc@@CCast(t,SomeDEFAULTcast,ty)(** Constructors for rawconstr *)letmkRHole=DAst.make@@GHole(GInternalHole)letmkRAppfargs=ifargs=[]thenfelseDAst.make@@GApp(f,args)letmkRCastrcrt=DAst.make@@GCast(rc,SomeDEFAULTcast,rt)letmkRLambdanst=DAst.make@@GLambda(n,None,Explicit,s,t)(* }}} *)exceptionNoProgress(** Unification procedures. *)(* To enforce the rigidity of the rooted match we always split *)(* top applications, so the unification procedures operate on *)(* arrays of patterns and terms. *)(* We perform three kinds of unification: *)(* EQ: exact conversion check *)(* FO: first-order unification of evars, without conversion *)(* HO: higher-order unification with conversion *)(* The subterm unification strategy is to find the first FO *)(* match, if possible, and the first HO match otherwise, then *)(* compute all the occurrences that are EQ matches for the *)(* relevant subterm. *)(* Additional twists: *)(* - If FO/HO fails then we attempt to fill evars using *)(* typeclasses before raising an outright error. We also *)(* fill typeclasses even after a successful match, since *)(* beta-reduction and canonical instances may leave *)(* undefined evars. *)(* - We do postchecks to rule out matches that are not *)(* closed or that assign to a global evar; these can be *)(* disabled for rewrite or dependent family matches. *)(* - We do a full FO scan before turning to HO, as the FO *)(* comparison can be much faster than the HO one. *)letunif_EQenvsigmapc=letenv=Environ.set_universes(Evd.universessigma)envinReductionops.is_convenvsigmapcletunif_EQ_argsenvsigmapaa=letn=Array.lengthpainletrecloopi=(i=n)||unif_EQenvsigmapa.(i)a.(i)&&loop(i+1)inloop0letunif_HOenvisepc=tryEvarconv.unify_delayenvisepcwithEvarconv.UnableToUnify(ise,err)->raisePretype_errors.(PretypeError(env,ise,CannotUnify(p,c,Someerr)))letunif_HO_argsenvise0paica=letn=Array.lengthpainletrecloopisej=ifj=ntheniseelseloop(unif_HOenvisepa.(j)(ca.(i+j)))(j+1)inloopise00(* FO unification should boil down to calling w_unify with no_delta, but *)(* alas things are not so simple: w_unify does partial type-checking, *)(* which breaks down when the no-delta flag is on (as the Coq type system *)(* requires full convertibility. The workaround here is to convert all *)(* evars into metas, since 8.2 does not TC metas. This means some lossage *)(* for HO evars, though hopefully Miller patterns can pick up some of *)(* those cases, and HO matching will mop up the rest. *)letflags_FOenv=letoracle=Environ.oracleenvinletts=Conv_oracle.get_transp_stateoracleinletflags={(Unification.default_no_delta_unify_flagsts).Unification.core_unify_flagswithUnification.modulo_conv_on_closed_terms=None;Unification.modulo_eta=true;Unification.modulo_betaiota=true;Unification.modulo_delta_types=ts}in{Unification.core_unify_flags=flags;Unification.merge_unify_flags=flags;Unification.subterm_unify_flags=flags;Unification.allow_K_in_toplevel_higher_order_unification=false;Unification.resolve_evars=(Unification.default_no_delta_unify_flagsts).Unification.resolve_evars}letunif_FOenvisemetaspc=letise=Metamap.fold(funmvtaccu->Evd.meta_declaremvtaccu)metasiseinlet_:Evd.evar_map=Unification.w_unifyenviseConversion.CONV~flags:(flags_FOenv)pcin()(* Perform evar substitution in main term and prune substitution. *)letnf_open_termsigma0isec=letopenEConstrinlets'=refsigma0inletrecnfc'=matchEConstr.kindisec'with|Evarex->letk,a=exinleta'=SList.Skip.mapnfainifnot(Evd.mem!s'k)thens':=Evd.add!s'k(Evarutil.nf_evar_infoise(Evd.find_undefinedisek));mkEvar(k,a')|_->mapisenfc'inletcopy_defk_()=letEvarInfoevi=Evd.findisekinmatchEvd.evar_bodyeviwith|Evar_definedc'->letc'=nfc'ins':=Evd.definekc'!s'|_->()inletc'=nfcinlet_=Evd.fold_undefinedcopy_defsigma0()inletchanged=sigma0!=!s'inchanged,!s',Evd.evar_universe_contextise,c'letunif_end?(solve_TC=true)envsigma0ise0ptok=letise=Evarconv.solve_unif_constraints_with_heuristicsenvise0inlettcs=Evd.get_typeclass_evarsiseinletc,s,uc,t=nf_open_termsigma0iseptinletise1=create_evar_defssinletise1=Evd.set_typeclass_evarsise1(Evar.Set.filter(funev->Evd.is_undefinedise1ev)tcs)inletise1=Evd.set_universe_contextise1ucinletise2=ifsolve_TCthenTypeclasses.resolve_typeclasses~fail:trueenvise1elseise1inifnot(okise)thenraiseNoProgresselseifise2==ise1then(c,s,uc,t)elseletc,s,uc',t=nf_open_termsigma0ise2tinc,s,UState.unionucuc',tletunify_HOenvsigma0t1t2=letsigma=unif_HOenvsigma0t1t2inlet_,sigma,uc,_=unif_end~solve_TC:falseenvsigma0sigmat2(fun_->true)inEvd.set_universe_contextsigmauc(* This is what the definition of iter_constr should be... *)letiter_constr_LRsigmafc=matchEConstr.kindsigmacwith|Evar(k,a)->SList.Skip.iterfa|Cast(cc,_,t)->fcc;ft|Prod(_,t,b)|Lambda(_,t,b)->ft;fb|LetIn(_,v,t,b)->fv;ft;fb|App(cf,a)->fcf;Array.iterfa|Case(_,_,pms,((_,p),_),iv,v,b)->fv;Array.iterfpms;fp;iter_invertfiv;Array.iter(fun(_,c)->fc)b|Fix(_,(_,t,b))|CoFix(_,(_,t,b))->fori=0toArray.lengtht-1doft.(i);fb.(i)done|Proj(_,_,a)->fa|Array(_u,t,def,ty)->Array.iterft;fdef;fty|(Rel_|Meta_|Var_|Sort_|Const_|Ind_|Construct_|Int_|Float_|String_)->()(* The comparison used to determine which subterms matches is KEYED *)(* CONVERSION. This looks for convertible terms that either have the same *)(* same head constant as pat if pat is an application (after beta-iota), *)(* or start with the same constr constructor (esp. for LetIn); this is *)(* disregarded if the head term is let x := ... in x, and casts are always *)(* ignored and removed). *)(* Record projections get special treatment: in addition to the projection *)(* constant itself, ssreflect also recognizes head constants of canonical *)(* projections. *)exceptionNoMatchtypessrdir=L2R|R2Lletpr_dir_side=functionL2R->str"LHS"|R2L->str"RHS"letinv_dir=functionL2R->R2L|R2L->L2Rtypepattern_class=|KpatFixed|KpatConst|KpatEvarofEvar.t|KpatLet|KpatLam|KpatRigid|KpatFlex|KpatProjofConstant.ttypetpattern={up_k:pattern_class;up_FO:EConstr.tMetamap.t*EConstr.t;up_f:EConstr.t;up_a:EConstr.tarray;up_t:EConstr.t;(* equation proof term or matched term *)up_dir:ssrdir;(* direction of the rule *)up_ok:EConstr.t->evar_map->bool;(* progress test for rewrite *)}typetpatterns={tpat_sigma:Evd.evar_map;tpat_pats:tpatternlist;}letempty_tpatternssigma={tpat_sigma=sigma;tpat_pats=[]}(* Technically we only care about the metas of [sigma] in the [tpatterns] type.
Should we [create_evar_defs] here? *)letall_ok__=trueletproj_nparamsc=try1+Structures.Structure.projection_nparamscwithNot_found->0letisRigidsigmac=matchEConstr.kindsigmacwith|(Prod_|Sort_|Lambda_|Case_|Fix_|CoFix_|Int_|Float_|String_|Array_)->true|(Rel_|Var_|Meta_|Evar(_,_)|Cast(_,_,_)|LetIn(_,_,_,_)|App(_,_)|Const(_,_)|Ind((_,_),_)|Construct(((_,_),_),_)|Proj_)->falselethole_var=mkVar(Id.of_string"_")letpr_constr_patenvsigmac0=letrecwipe_evarc=ifisEvarcthenhole_varelsemapwipe_evarcinpr_constr_envenvsigma(wipe_evarc0)letehole_var=EConstr.mkVar(Id.of_string"_")letpr_econstr_patenvsigmac0=letrecwipe_evarc=letopenEConstrinifisEvarsigmacthenehole_varelsemapsigmawipe_evarcinletdummy_decl=letdummy_prod=mkProd(make_annotAnonymousSorts.Relevant,mkProp,mkProp)inletna=make_annot(EConstr.destVarsigmaehole_var)Sorts.RelevantinContext.Named.Declaration.(LocalAssum(na,dummy_prod))inletenv=Environ.push_nameddummy_declenvinpr_econstr_envenvsigma(wipe_evarc0)(* Turn (new) evars into metas *)letevars_for_FO~hack~rigidenv(ise0:evar_map)c0=letopenEConstrinletmetas=refMetamap.emptyinletsigma=refise0inletnenv=env_sizeenv+ifhackthen1else0inletrecputc=matchEConstr.kind!sigmacwith|Evar(k,a)->ifrigidkthenmap!sigmaputcelseletevi=Evd.find_undefined!sigmakinletdc=List.firstn(max0(SList.lengtha-nenv))(evar_filtered_contextevi)inletabs_dc(d,c)=function|Context.Named.Declaration.LocalDef(x,b,t)->d,mkNamedLetIn!sigmax(putb)(putt)c|Context.Named.Declaration.LocalAssum(x,t)->mkVarx.binder_name::d,mkNamedProd!sigmax(putt)cinleta,t=Context.Named.fold_insideabs_dc~init:([],put(Evd.evar_conclevi))dcinletm=Evarutil.new_meta()inlet()=metas:=Metamap.addmt!metasinsigma:=Evd.definek(applistc(mkMetam)a)!sigma;putc|_->map!sigmaputcinletc1=putc0in!metas,c1(* Compile a match pattern from a term; t is the term to fill. *)(* p_origin can be passed to obtain a better error message *)letmk_tpattern?p_origin?(hack=false)?(ok=all_ok)~rigidenvtdirp{tpat_sigma=ise;tpat_pats=pats}=letopenEConstrinletk,f,a=letf,a=Reductionops.whd_betaiota_stackenvisepinmatchEConstr.kindisefwith|Const(p,_)->letnp=proj_nparamspinifnp=0||np>List.lengthathenKpatConst,f,aelseleta1,a2=List.chopnpainKpatProjp,(applistcfa1),a2|Proj(p,_,arg)->KpatProj(Projection.constantp),f,a|Var_|Ind_|Construct_->KpatFixed,f,a|Evar(k,_)->ifrigidkthenKpatEvark,f,aelseifa<>[]thenKpatFlex,f,aelse(matchp_originwithNone->CErrors.user_errPp.(str"indeterminate pattern")|Some(dir,rule)->errorstrm(str"indeterminate "++pr_dir_sidedir++str" in "++pr_econstr_patenviserule))|LetIn(_,v,_,b)->ifb<>mkRel1thenKpatLet,f,aelseKpatFlex,v,a|Lambda_->KpatLam,f,a|_->KpatRigid,f,ainletaa=Array.of_listainletp'=evars_for_FO~hack~rigidenvise(mkApp(f,aa))inletpat={up_k=k;up_FO=p';up_f=f;up_a=aa;up_ok=ok;up_dir=dir;up_t=t}in{tpat_sigma=ise;tpat_pats=pats@[pat]}(* Specialize a pattern after a successful match: assign a precise head *)(* kind and arity for Proj and Flex patterns. *)letungen_upatlhs(c,sigma,uc,t)u=letf,a=safeDestAppsigmalhsinletk=matchkind(EConstr.Unsafe.to_constrf)with|Var_|Ind_|Construct_->KpatFixed|Const_->KpatConst|Evar(k,_)->ifis_definedsigmakthenraiseNoMatchelseKpatEvark(* FIXME: why do we observe defined evars here? *)|LetIn_->KpatLet|Lambda_->KpatLam|_->KpatRigidinc,sigma,uc,{uwithup_k=k;up_FO=(Metamap.empty,lhs);up_f=f;up_a=a;up_t=t}letnb_cs_proj_argsenvisepcfu=letopenEConstrinletopenStructuresinletopenValuePatterninletnak=letopenCanonicalSolutioninlet_,{cvalue_arguments}=findenvise(GlobRef.ConstRefpc,k)inList.lengthcvalue_argumentsinletnargs_of_projt=matchEConstr.kindisetwith|App(_,args)->Array.lengthargs|Proj_->0(* if splay_app calls expand_projection, this has to be
the number of arguments including the projected *)|_->assertfalseintrymatchEConstr.kindisefwith|Prod_->naProd_cs|Sorts->na(Sort_cs(Sorts.family(ESorts.kindises)))|Const(c',_)whenEnviron.QConstant.equalenvc'pc->nargs_of_proju.up_f|Proj(c',_,_)whenEnviron.QConstant.equalenv(Names.Projection.constantc')pc->nargs_of_proju.up_f|Proj(c',_,_)->let_=na(Proj_cs(Names.Projection.reprc'))in0|Var_|Ind_|Construct_|Const_->na(Const_cs(fst@@destRefisef))|_->-1withNot_found->-1letisEvar_kisekf=matchEConstr.kindisefwithEvar(k',_)->k=k'|_->falseletnb_argssigmac=matchEConstr.kindsigmacwithApp(_,a)->Array.lengtha|_->0letmkSubArgia=ifi=Array.lengthathenaelseArray.suba0iletmkSubAppfia=letopenEConstrinifi=0thenfelsemkApp(f,mkSubArgia)letsplay_appise=letrecloopca=matchEConstr.kindisecwith|App(f,a')->loopf(Array.appenda'a)|Cast(c',_,_)->loopc'a|_->c,ainfunc->matchEConstr.kindisecwith|App(f,a)->loopfa|Cast_|Evar_->loopc[||]|_->c,[||]letfilter_upatenvsigmai0fnufpats=letopenEConstrinletna=Array.lengthu.up_ainifn<nathenfpatselseletnp=matchu.up_kwith|KpatConstwheneq_constr_nounivssigmau.up_ff->na|KpatFixedwheneq_constr_nounivssigmau.up_ff->na|KpatEvarkwhenisEvar_ksigmakf->na|KpatLetwhenisLetInsigmaf->na|KpatLamwhenisLambdasigmaf->na|KpatRigidwhenisRigidsigmaf->na|KpatFlex->na|KpatProjpc->letnp=na+nb_cs_proj_argsenvsigmapcfuinifn<npthen-1elsenp|_->-1inifnp<nathenfpatselselet()=if!i0<nptheni0:=nin(u,np)::fpatsleteq_prim_projenvsigmact=matchEConstr.kindsigmatwith|Proj(p,_,_)->Environ.QConstant.equalenv(Projection.constantp)c|_->falseletfilter_upat_FOenvsigmai0fnufpats=letopenEConstrinletnp=nb_argssigma(sndu.up_FO)inifn<npthenfpatselseletok=matchu.up_kwith|KpatConst->eq_constr_nounivssigmau.up_ff|KpatFixed->eq_constr_nounivssigmau.up_ff|KpatEvark->isEvar_ksigmakf|KpatLet->isLetInsigmaf|KpatLam->isLambdasigmaf|KpatRigid->isRigidsigmaf|KpatProjpc->isRefXenvsigma(ConstRefpc)f||eq_prim_projenvsigmapcf|KpatFlex->i0:=n;trueinifokthenbeginif!i0<nptheni0:=np;(u,np)::fpatsendelsefpatsexceptionFoundUnifof(bool*evar_map*UState.t*tpattern)(* Note: we don't update env as we descend into the term, as the primitive *)(* unification procedure always rejects subterms with bound variables. *)letdont_impact_evars_insigma0cl=letevs_in_cl=Evd.evars_of_termsigma0clinfunsigma->Evar.Set.for_all(funk->trylet_=Evd.find_undefinedsigmakintruewithNot_found->false)evs_in_cl(* We are forced to duplicate code between the FO/HO matching because we *)(* have to work around several kludges in unify.ml: *)(* - w_unify drops into second-order unification when the pattern is an *)(* application whose head is a meta. *)(* - w_unify tries to unify types without subsumption when the pattern *)(* head is an evar or meta (e.g., it fails on ?1 = nat when ?1 : Type). *)(* - w_unify expands let-in (zeta conversion) eagerly, whereas we want to *)(* match a head let rigidly. *)letmatch_upats_FOupatsenvsigma0iseorig_c=letdont_impact_evars=dont_impact_evars_insigma0orig_cinletrecloopc=letf,a=splay_appisecinleti0=ref(-1)inletfpats=List.fold_right(filter_upat_FOenvisei0f(Array.lengtha))upats[]inwhile!i0>=0doleti=!i0ini0:=-1;letc'=mkSubAppfiainletone_match(u,np)=letopenEConstrinletskip=ifi<=nptheni<npelseifu.up_k==KpatFlexthenbegini0:=i-1;falseendelsebeginif!i0<nptheni0:=np;trueendinifskip||not(EConstr.Vars.closed0isec')then()elsetrylet()=matchu.up_kwith|KpatFlex->letkludgev=mkLambda(make_annotAnonymousERelevance.relevant,mkProp,v)inlet(metas,p_FO)=u.up_FOinunif_FOenvisemetas(kludgep_FO)(kludgec')|KpatLet->letkludgevla=letvl,a=safeDestAppisevlainletx,v,t,b=destLetInisevlinmkApp(mkLambda(x,t,b),Array.consva)inlet(metas,p_FO)=u.up_FOinunif_FOenvisemetas(kludgep_FO)(kludgec')|_->let(metas,p_FO)=u.up_FOinunif_FOenvisemetasp_FOc'inletise'=(* Unify again using HO to assign evars *)letp=mkApp(u.up_f,u.up_a)intryunif_HOenvisepc'withewhenCErrors.noncriticale->raiseNoMatchinletlhs=mkSubAppfiainletpt'=unif_endenvsigma0ise'u.up_t(u.up_oklhs)inraise(FoundUnif(ungen_upatlhspt'u))withFoundUnif(_,s,_,_)assig_uwhendont_impact_evarss->raisesig_u|Not_found->CErrors.anomaly(str"incomplete ise in match_upats_FO.")|ewhenCErrors.noncriticale->()inList.iterone_matchfpatsdone;iter_constr_LRiseloopf;Array.iterloopaintrylooporig_cwithInvalid_argument_->CErrors.anomaly(str"IN FO.")letmatch_upats_HO~on_instanceupatsenvsigma0isec=letdont_impact_evars=dont_impact_evars_insigma0cinletit_did_match=reffalseinletfailed_because_of_TC=reffalseinletrecauxupatsenvsigma0isec=letf,a=splay_appisecinleti0=ref(-1)inletfpats=List.fold_right(filter_upatenvisei0f(Array.lengtha))upats[]inwhile!i0>=0doleti=!i0ini0:=-1;letone_match(u,np)=letskip=ifi<=nptheni<npelseifu.up_k==KpatFlexthenbegini0:=i-1;falseendelsebeginif!i0<nptheni0:=np;trueendinifskipthen()elsetryletise'=matchu.up_kwith|KpatFixed|KpatConst->ise|KpatEvar_->letopenEConstrinletpka=Evd.expand_existentialise@@destEvariseu.up_finletka=Evd.expand_existentialise@@destEvarisefinletfoldisepkk=unif_HOenvisepkkinList.fold_left2foldisepkaka|KpatLet->letopenEConstrinletx,v,t,b=destLetInisefinlet_,pv,_,pb=destLetIniseu.up_finletise'=unif_HOenvisepvvinunif_HO(EConstr.push_rel(Context.Rel.Declaration.LocalAssum(x,t))env)ise'pbb|KpatFlex|KpatProj_->letfa=mkSubAppf(i-Array.lengthu.up_a)ainletise=matchEConstr.kindisef,EConstr.kindiseu.up_fwith|Proj_,_|_,Proj_->(* with primitive projections we "lose" parameters so we unify
* the type of the arguments to retrieve that information *)lettuf=Retyping.get_type_of~lax:trueenviseu.up_finlettfa=Retyping.get_type_of~lax:trueenvisefainunif_HOenvisetuftfa|_->iseinunif_HOenviseu.up_ffa|_->unif_HOenviseu.up_ffinletise''=unif_HO_argsenvise'u.up_a(i-Array.lengthu.up_a)ainletlhs=mkSubAppfiainletpt'=unif_endenvsigma0ise''u.up_t(u.up_oklhs)inon_instance(ungen_upatlhspt'u)withFoundUnif(_,s,_,_)assig_uwhendont_impact_evarss->raisesig_u|NoProgress->it_did_match:=true|Pretype_errors.PretypeError(_,_,Pretype_errors.UnsatisfiableConstraints_)->failed_because_of_TC:=true|ewhenCErrors.noncriticale->()inList.iterone_matchfpatsdone;iter_constr_LRise(auxupatsenvsigma0ise)f;Array.iter(auxupatsenvsigma0ise)ainauxupatsenvsigma0isec;if!it_did_matchthenraiseNoProgress;!failed_because_of_TCletfixed_upatevd=function|{up_k=KpatFlex|KpatEvar_|KpatProj_}->false|{up_t=t}->not(occur_existentialevdt)letdo_oncerf=match!rwithSome_->()|None->r:=Some(f())letassert_doner=match!rwithSomex->x|None->CErrors.anomaly(str"do_once never called.")letassert_done_multiresr=match!rwith|None->CErrors.anomaly(str"do_once never called.")|Some(e,n,xs)->r:=Some(e,n+1,xs);tryList.nthxsnwithFailure_->raiseNoMatchtypesubst=Environ.env->EConstr.t->EConstr.t->int->EConstr.ttypefind_P=Environ.env->EConstr.t->int->k:subst->EConstr.ttypeconclude=unit->EConstr.t*ssrdir*(bool*Evd.evar_map*UState.t*EConstr.t)letrecuniquize=function|[]->[]|(_,sigma,_,{up_f=f;up_a=a;up_t=t}asx)::xs->letnf_evarsigmac=EConstr.Unsafe.to_constr(Evarutil.nf_evarsigmac)inletequalsigma1sigma2c1c2=Constr.equal(nf_evarsigma1c1)(nf_evarsigma2c2)inletneq(_,sigma1,_,{up_f=f1;up_a=a1;up_t=t1})=not(equalsigmasigma1tt1&&equalsigmasigma1ff1&&CArray.for_all2(equalsigmasigma1)aa1)inx::uniquize(List.filterneqxs)typeocc_state={max_occ:int;nocc:intref;occ_set:boolarray;use_occ:bool;skip_occ:boolref;}letcreate_occ_stateocc=letnocc=ref0andskip_occ=reffalseinletuse_occ,occ_list=matchoccwith|Some(true,ol)->ol=[],ol|Some(false,ol)->ol<>[],ol|None->false,[]inletmax_occ=List.fold_rightmaxocc_list0inletocc_set=Array.makemax_occ(notuse_occ)inlet_=List.iter(funi->occ_set.(i-1)<-use_occ)occ_listinlet_=ifmax_occ=0thenskip_occ:=use_occin{max_occ;nocc;occ_set;skip_occ;use_occ}letsubst_occ{nocc;max_occ;occ_set;use_occ;skip_occ}=incrnocc;if!nocc=max_occthenskip_occ:=use_occ;if!nocc<=max_occthenocc_set.(!nocc-1)elsenotuse_occletmatch_EQenvsigma(ise,u)=letopenEConstrinmatchu.up_kwith|KpatLet->letx,pv,t,pb=destLetInsigmau.up_finletenv'=EConstr.push_rel(Context.Rel.Declaration.LocalAssum(x,t))envinletmatch_letf=matchEConstr.kindisefwith|LetIn(_,v,_,b)->unif_EQenvsigmapvv&&unif_EQenv'sigmapbb|_->falseinmatch_let|KpatFixed->func->EConstr.eq_constr_nounivssigmau.up_fc|KpatConst->func->EConstr.eq_constr_nounivssigmau.up_fc|KpatLam->func->(matchEConstr.kindsigmacwith|Lambda_->unif_EQenvsigmau.up_fc|_->false)|_->unif_EQenvsigmau.up_fletp2tp=EConstr.mkApp(p.up_f,p.up_a)letsourceenviseupats_originupats=matchupats_origin,upatswith|None,[p]->(iffixed_upatisepthenstr"term "elsestr"partial term ")++pr_econstr_patenvise(p2tp)++spc()|Some(dir,rule),[p]->str"The "++pr_dir_sidedir++str" of "++pr_econstr_patenviserule++fnl()++ws4++pr_econstr_patenvise(p2tp)++fnl()|Some(dir,rule),_->str"The "++pr_dir_sidedir++str" of "++pr_econstr_patenviserule++spc()|_,[]|None,_::_::_->CErrors.anomaly(str"mk_tpattern_matcher with no upats_origin.")typessrmatching_failure=|SsrTCFail|SsrMatchFail|SsrProgressFail|SsrOccMissingofint*int*EConstr.tletpr_ssrmatching_failureenvsigmaupats_originupats=function|SsrTCFail->sourceenvsigmaupats_originupats++strbrk"matches but type classes inference fails"|SsrMatchFail->sourceenvsigmaupats_originupats++str"does not match any subterm of the goal"|SsrProgressFail->letdir=matchupats_originwithSome(d,_)->d|_->CErrors.anomaly(str"mk_tpattern_matcher with no upats_origin.")instr"all matches of "++sourceenvsigmaupats_originupats++str"are equal to the "++pr_dir_side(inv_dirdir)|SsrOccMissing(nocc,max_occ,p')->str"Only "++intnocc++str" < "++intmax_occ++str(String.pluralnocc" occurrence")++matchupats_originwith|None->str" of"++spc()++pr_econstr_patenvsigmap'|Some(dir,rule)->str" of the "++pr_dir_sidedir++fnl()++ws4++pr_econstr_patenvsigmap'++fnl()++str"of "++pr_econstr_patenvsigmaruleexceptionSsrMatchingFailureofEnviron.env*Evd.evar_map*(ssrdir*EConstr.t)option*tpatternlist*ssrmatching_failurelet_=CErrors.register_handlerbeginfunction|SsrMatchingFailure(env,sigma,upats_origin,upats,e)->Some(pr_ssrmatching_failureenvsigmaupats_originupatse)|_->Noneendletssrfailenvsigmaupats_originupatse=raise(SsrMatchingFailure(env,sigma,upats_origin,upats,e))lethas_instances=function|None->false|Someinstances->not(List.is_empty!instances)letfind_tpattern~raise_NoMatch~instances~upat_that_matched~upats_origin~upatssigma0iseocc_state:find_P=funenvch~k->do_onceupat_that_matched(fun()->letfailed_because_of_TC=reffalseintrylet()=matchinstanceswith|None->match_upats_FOupatsenvsigma0isec|Some_->()inleton_instance=matchinstanceswith|None->funx->raise(FoundUnifx)|Somer->funx->r:=!r@[x]infailed_because_of_TC:=match_upats_HO~on_instanceupatsenvsigma0isec;raiseNoMatchwithFoundUnifsigma_u->env,0,[sigma_u]|(NoMatch|NoProgress)whenhas_instancesinstances->env,0,uniquize(!(Option.getinstances))|NoMatchwhen(notraise_NoMatch)->if!failed_because_of_TCthenssrfailenviseupats_originupatsSsrTCFailelsessrfailenviseupats_originupatsSsrMatchFail|NoProgresswhen(notraise_NoMatch)->ssrfailenviseupats_originupatsSsrProgressFail|NoProgress->raiseNoMatch);let_,sigma,_,({up_f=pf;up_a=pa}asu)=matchinstanceswith|Some_->assert_done_multiresupat_that_matched|None->List.hd(pi3(assert_doneupat_that_matched))in(* pp(lazy(str"sigma@tmatch=" ++ pr_evar_map None sigma)); *)if!(occ_state.skip_occ)then((*ignore(k env u.up_t 0);*)c)elseletmatch_EQ=match_EQenvsigma(ise,u)inletpn=Array.lengthpainletrecsubst_loop(env,hasacc)c'=if!(occ_state.skip_occ)thenc'elseletf,a=splay_appsigmac'inifArray.lengtha>=pn&&match_EQf&&unif_EQ_argsenvsigmapaathenletopenEConstrinleta1,a2=Array.chop(Array.lengthpa)ainletfa1=mkApp(f,a1)inletf'=ifsubst_occocc_statethenkenvu.up_tfa1helsefa1inmkApp(f',Array.map_left(subst_loopacc)a2)elseletopenEConstrin(* TASSI: clear letin values to avoid unfolding *)letinc_hrd(env,h')=letctx_item=matchrdwith|Context.Rel.Declaration.LocalAssum_asx->x|Context.Rel.Declaration.LocalDef(x,_,y)->Context.Rel.Declaration.LocalAssum(x,y)inEConstr.push_relctx_itemenv,h'+1inletselfaccc=subst_loopacccinletf'=map_constr_with_binders_left_to_rightenvsigmainc_hselfaccfinmkApp(f',Array.map_left(subst_loopacc)a)insubst_loop(env,h)cletconclude_tpattern~raise_NoMatch~upat_that_matched~upats_origin~upats{max_occ;nocc}:conclude=fun()->letenv,(c,sigma,uc,({up_f=pf;up_a=pa}asu))=match!upat_that_matchedwith|Some(env,_,x)->env,List.hdx|Nonewhenraise_NoMatch->raiseNoMatch|None->CErrors.anomaly(str"companion function never called.")inletp'=EConstr.mkApp(pf,pa)inifmax_occ<=!noccthenp',u.up_dir,(c,sigma,uc,u.up_t)elsessrfailenvsigmaupats_originupats(SsrOccMissing(!nocc,max_occ,p'))(* upats_origin makes a better error message only *)letmk_tpattern_matcher?(all_instances=false)?(raise_NoMatch=false)?upats_originsigma0occ{tpat_sigma=ise;tpat_pats=upats}=letocc_state=create_occ_stateoccinletupat_that_matched=refNoneinletinstances=ifall_instancesthenSome(ref[])elseNoneinfind_tpattern~raise_NoMatch~instances~upat_that_matched~upats_origin~upatssigma0iseocc_state,conclude_tpattern~raise_NoMatch~upat_that_matched~upats_origin~upatsocc_statetype('ident,'term)ssrpattern=|Tof'term|In_Tof'term|X_In_Tof'ident*'term|In_X_In_Tof'ident*'term|E_In_X_In_Tof'term*'ident*'term|E_As_X_In_Tof'term*'ident*'termletpr_patternpr_identpr_term=function|Tt->pr_termt|In_Tt->str"in "++pr_termt|X_In_T(x,t)->pr_identx++str" in "++pr_termt|In_X_In_T(x,t)->str"in "++pr_identx++str" in "++pr_termt|E_In_X_In_T(e,x,t)->pr_terme++str" in "++pr_identx++str" in "++pr_termt|E_As_X_In_T(e,x,t)->pr_terme++str" as "++pr_identx++str" in "++pr_termtletpr_holepr_constre=pr_constr(EConstr.mkEvare)letpr_pattern_auxpr_constr=function|Tt->pr_constrt|In_Tt->str"in "++pr_constrt|X_In_T(x,t)->pr_holepr_constrx++str" in "++pr_constrt|In_X_In_T(x,t)->str"in "++pr_holepr_constrx++str" in "++pr_constrt|E_In_X_In_T(e,x,t)->pr_constre++str" in "++pr_holepr_constrx++str" in "++pr_constrt|E_As_X_In_T(e,x,t)->pr_constre++str" as "++pr_holepr_constrx++str" in "++pr_constrttypepattern={pat_sigma:Evd.evar_map;pat_pat:(EConstr.existential,EConstr.t)ssrpattern;}letpp_patternenv{pat_sigma=sigma;pat_pat=p}=pr_pattern_aux(funt->pr_econstr_patenvsigmat)ptypecpattern={kind:ssrtermkind;pattern:Genintern.glob_constr_and_expr;interpretation:Geninterp.interp_signoption}letpr_term{kind;pattern;_}=letenv=Global.env()inletsigma=Evd.from_envenvinpr_guarded(guard_termkind)(pr_glob_constr_and_exprenvsigma)patternletprl_term{kind;pattern;_}=letenv=Global.env()inletsigma=Evd.from_envenvinpr_guarded(guard_termkind)(prl_glob_constr_and_exprenvsigma)patternletpr_cpattern=pr_termletpr_pattern_w_ids=pr_patternpr_idprl_termletmk_termkcist={kind=k;pattern=(mkRHole,Somec);interpretation=ist}letmk_lterm=mk_termNoFlagletglob_ssrtermgs=function|{kind;pattern=(_,Somec);interpretation=None}->letx=Tacintern.intern_constrgscin{kind;pattern=(fstx,Somec);interpretation=None}|ct->ct(* ssrterm conbinators *)letcombineCGt1t2fg=letmk_isti1i2=matchi1,i2with|None,Somei->Somei|Somei,None->Somei|None,None->None|Somei,Somejwheni==j->Somei|_->CErrors.anomaly(Pp.str"combineCG: different ist")inmatcht1,t2with|{kind=x;pattern=(t1,None);interpretation=i1},{pattern=(t2,None);interpretation=i2}->{kind=x;pattern=(gt1t2,None);interpretation=mk_isti1i2}|{kind=x;pattern=(_,Somet1);interpretation=i1},{pattern=(_,Somet2);interpretation=i2}->{kind=x;pattern=(mkRHole,Some(ft1t2));interpretation=mk_isti1i2}|_,{pattern=(_,None);_}->CErrors.anomaly(str"have: mixed C-G constr.")|_->CErrors.anomaly(str"have: mixed G-C constr.")letloc_ofCG=function|{pattern=(s,None);_}->Glob_ops.loc_of_glob_constrs|{pattern=(_,Somes);_}->Constrexpr_ops.constr_locs(* This piece of code asserts the following notations are reserved *)(* Reserved Notation "( a 'in' b )" (at level 0). *)(* Reserved Notation "( a 'as' b )" (at level 0). *)(* Reserved Notation "( a 'in' b 'in' c )" (at level 0). *)(* Reserved Notation "( a 'as' b 'in' c )" (at level 0). *)letglob_cpatterngsp=pp(lazy(str"globbing pattern: "++pr_termp));letglobx=(glob_ssrtermgs(mk_ltermxNone)).patterninletencodeksl=letname=Name(Id.of_string("_ssrpat_"^s))in{kind=k;pattern=(mkRCastmkRHole(mkRLambdanamemkRHole(mkRAppmkRHolel)),None);interpretation=None}inletbind_int1t2=letmkCHole=mkCHole~loc:Noneinletn=Name(destCVart1)infst(glob(mkCCastmkCHole(mkCLambdanmkCHolet2)))inletcheck_vart2=ifnot(isCVart2)thenloc_error(constr_loct2)"Only identifiers are allowed here"inmatchpwith|{pattern=(_,None);_}asx->x|{kind=k;pattern=(v,Somet);_}asorig->ifk=Cpatternthenglob_ssrtermgs{kind=InParens;pattern=(v,Somet);interpretation=None}elsematcht.CAst.vwith|CNotation(_,(InConstrEntry,"( _ in _ )"),([t1;t2],[],[],[]))->(trymatchglobt1,globt2with|(r1,None),(r2,None)->encodek"In"[r1;r2]|(r1,Some_),(r2,Some_)whenisCVart1->encodek"In"[r1;r2;bind_int1t2]|(r1,Some_),(r2,Some_)->encodek"In"[r1;r2]|_->CErrors.anomaly(str"where are we?.")withewhenCErrors.noncriticale&&isCVart1->encodek"In"[bind_int1t2])|CNotation(_,(InConstrEntry,"( _ in _ in _ )"),([t1;t2;t3],[],[],[]))->check_vart2;encodek"In"[fst(globt1);bind_int2t3]|CNotation(_,(InConstrEntry,"( _ as _ )"),([t1;t2],[],[],[]))->encodek"As"[fst(globt1);fst(globt2)]|CNotation(_,(InConstrEntry,"( _ as _ in _ )"),([t1;t2;t3],[],[],[]))->check_vart2;encodek"As"[fst(globt1);bind_int2t3]|_->glob_ssrtermgsorig;;letglob_rpatternsp=matchpwith|Tt->T(glob_cpatternst)|In_Tt->In_T(glob_ssrtermst)|X_In_T(x,t)->X_In_T(x,glob_ssrtermst)|In_X_In_T(x,t)->In_X_In_T(x,glob_ssrtermst)|E_In_X_In_T(e,x,t)->E_In_X_In_T(glob_ssrtermse,x,glob_ssrtermst)|E_As_X_In_T(e,x,t)->E_As_X_In_T(glob_ssrtermse,x,glob_ssrtermst)letsubst_ssrterms{kind;pattern;interpretation}={kind;pattern=Tacsubst.subst_glob_constr_and_exprspattern;interpretation}letsubst_rpatterns=function|Tt->T(subst_ssrtermst)|In_Tt->In_T(subst_ssrtermst)|X_In_T(x,t)->X_In_T(x,subst_ssrtermst)|In_X_In_T(x,t)->In_X_In_T(x,subst_ssrtermst)|E_In_X_In_T(e,x,t)->E_In_X_In_T(subst_ssrtermse,x,subst_ssrtermst)|E_As_X_In_T(e,x,t)->E_As_X_In_T(subst_ssrtermse,x,subst_ssrtermst)letinterp_ssrtermist{kind;pattern;_}={kind;pattern;interpretation=Someist}letinterp_rpatterns=function|Tt->T(interp_ssrtermst)|In_Tt->In_T(interp_ssrtermst)|X_In_T(x,t)->X_In_T(interp_ssrtermsx,interp_ssrtermst)|In_X_In_T(x,t)->In_X_In_T(interp_ssrtermsx,interp_ssrtermst)|E_In_X_In_T(e,x,t)->E_In_X_In_T(interp_ssrtermse,interp_ssrtermsx,interp_ssrtermst)|E_As_X_In_T(e,x,t)->E_As_X_In_T(interp_ssrtermse,interp_ssrtermsx,interp_ssrtermst)letinterp_rpattern0ist__t=interp_rpatternisttlettag_of_cpatternp=p.kindletloc_of_cpattern=loc_ofCGtypeocc=(bool*intlist)optiontyperpattern=(cpattern,cpattern)ssrpatternletpr_rpattern=pr_patternpr_cpatternpr_cpatternletwit_rpatternty=add_genarg"rpatternty"(funenvsigma->pr_patternpr_cpatternpr_cpattern)letid_of_cpattern{pattern=(c1,c2);_}=letopenCAstinmatchDAst.getc1,c2with|_,Some{v=CRef(qid,_)}whenqualid_is_identqid->Some(qualid_basenameqid)|_,Some{v=CAppExpl((qid,_),[])}whenqualid_is_identqid->Some(qualid_basenameqid)|GRef(GlobRef.VarRefx,_),None->Somex|_->Noneletid_of_Ctermt=matchid_of_cpatterntwith|Somex->x|None->loc_error(loc_of_cpatternt)"Only identifiers are allowed here"letinterp_open_constristenvsigmagc=Tacinterp.interp_open_constristenvsigmagcletpf_intern_termenvsigma{pattern=c;interpretation=ist;_}=glob_constristenvsigmacletinterp_ssrtermistenvsigmat=interp_ssrtermisttletinterp_termenvsigma=function|{pattern=c;interpretation=Someist;_}->interp_open_constristenvsigmac|_->errorstrm(str"interpreting a term with no ist")letthinidsigmagoal=letids=Id.Set.singletonidinletevi=Evd.find_undefinedsigmagoalinletenv=Evd.evar_filtered_env(Global.env())eviinletcl=Evd.evar_concleviinletans=trySome(Evarutil.clear_hyps_in_evienvsigma(Environ.named_context_valenv)clids)withEvarutil.ClearDependencyError_->Noneinmatchanswith|None->sigma|Some(sigma,hyps,concl)->let(sigma,evk)=Evarutil.new_pure_evar~src:(Loc.tagEvar_kinds.GoalEvar)~typeclass_candidate:falsehypssigmaconclinletsigma=Evd.remove_future_goalsigmaevkinletid=Evd.evar_identgoalsigmainletproof=EConstr.mkEvar(evk,Evd.evar_identity_subst@@Evd.find_undefinedsigmaevk)inletsigma=Evd.definegoalproofsigmainmatchidwith|None->sigma|Someid->Evd.renameevkidsigma(*
let pr_ist { lfun= lfun } =
prlist_with_sep spc
(fun (id, Geninterp.Val.Dyn(ty,_)) ->
pr_id id ++ str":" ++ Geninterp.Val.pr ty) (Id.Map.bindings lfun)
*)letinterp_pattern?wit_ssrpatternargenvsigma0redredty=pp(lazy(str"interpreting: "++pr_rpatternred));letxInTxy=X_In_T(x,y)andinXInTxy=In_X_In_T(x,y)inletinTx=In_TxandeInXInText=E_In_X_In_T(e,x,t)inleteAsXInText=E_As_X_In_T(e,x,t)inletmkG?(k=NoFlag)xist={kind=k;pattern=(x,None);interpretation=ist}inletist_ofx=x.interpretationinletdecode({interpretation=ist;_}ast)?reccallfg=trymatchDAst.get(pf_intern_termenvsigma0t)with|GCast(t,SomeDEFAULTcast,c)whenisGHolet&&isGLambdac->let(x,c)=destGLambdacinfx{kind=NoFlag;pattern=(c,None);interpretation=ist}|GVaridwhenOption.has_someist&&letist=Option.getistinId.Map.memidist.lfun&¬(Option.is_emptyreccall)&¬(Option.is_emptywit_ssrpatternarg)->letv=Id.Map.findid(Option.getist).lfuninOption.getreccall(Value.cast(topwit(Option.getwit_ssrpatternarg))v)|it->gtwithewhenCErrors.noncriticale->gtinletdecodeGisttfg=decode(mkGtist)fginletbad_encid_=CErrors.anomaly(str"bad encoding for pattern "++strid++str".")inletcleanup_XinE(h_k,_)xrpsigma=letto_clean,update=(* handle rename if x is already used *)letctx=Environ.named_contextenvinletlen=Context.Named.lengthctxinletname=refNoneintryignore(Context.Named.lookupxctx);(name,funk->if!name=NonethenletEvarInfoevi=Evd.findsigmakinletnctx=Evd.evar_contexteviinletnlen=Context.Named.lengthnctxinifnlen>lenthenbeginname:=Some(Context.Named.Declaration.get_id(List.nthnctx(nlen-len-1)))end)withNot_found->ref(Somex),fun_->()inletnew_evars=letrecauxacct=matchEConstr.kindsigmatwith|Evar(k,_)->ifk=h_k||List.memkacc||Evd.memsigma0kthenaccelse(updatek;k::acc)|_->EConstr.foldsigmaauxacctinaux[]rpinletsigma=List.fold_left(funsigmae->ifEvd.is_definedsigmaethensigmaelse(* clear may be recursive *)ifOption.is_empty!to_cleanthensigmaelseletname=Option.get!to_cleaninpp(lazy(pr_idname));thinnamesigmae)sigmanew_evarsinsigmainletred=letrecdecode_red=function|T{kind=k;pattern=(t,None);interpretation=ist}->beginmatchDAst.gettwith|GCast(c,SomeDEFAULTcast,t)whenisGHolec&&let(id,t)=destGLambdatinletid=Id.to_stringidinletlen=String.lengthidin(len>8&&String.subid08="_ssrpat_")->let(id,t)=destGLambdatinletid=Id.to_stringidinletlen=String.lengthidin(matchString.subid8(len-8),DAst.gettwith|"In",GApp(_,[t])->decodeGisttxInT(funx->Tx)|"In",GApp(_,[e;t])->decodeGistt(eInXInT(mkGeist))(bad_encid)|"In",GApp(_,[e;t;e_in_t])->decodeGistt(eInXInT(mkGeist))(fun_->decodeGiste_in_txInT(fun_->assertfalse))|"As",GApp(_,[e;t])->decodeGistt(eAsXInT(mkGeist))(bad_encid)|_->bad_encid())|_->decode~reccall:decode_red(mkG~ktist)xInT(funx->Tx)end|Tt->decode~reccall:decode_redtxInT(funx->Tx)|In_Tt->decodetinXInTinT|X_In_T(e,t)->decodet(eInXInTe)(funx->xInT(id_of_Cterme)x)|In_X_In_T(e,t)->inXInT(id_of_Cterme)t|E_In_X_In_T(e,x,rp)->eInXInTe(id_of_Ctermx)rp|E_As_X_In_T(e,x,rp)->eAsXInTe(id_of_Ctermx)rpindecode_redredinpp(lazy(str"decoded as: "++pr_pattern_w_idsred));letred=matchredtywith|None->red|Some(ty,ist)->letty={kind=NoFlag;pattern=ty;interpretation=Someist}inmatchredwith|Tt->T(combineCGtty(mkCCast?loc:(loc_ofCGt))mkRCast)|X_In_T(x,t)->letgty=pf_intern_termenvsigma0tyinE_As_X_In_T(mkG(mkRCastmkRHolegty)(ist_ofty),x,t)|E_In_X_In_T(e,x,t)->letty=mkG(pf_intern_termenvsigma0ty)(ist_ofty)inE_In_X_In_T(combineCGety(mkCCast?loc:(loc_ofCGt))mkRCast,x,t)|E_As_X_In_T(e,x,t)->letty=mkG(pf_intern_termenvsigma0ty)(ist_ofty)inE_As_X_In_T(combineCGety(mkCCast?loc:(loc_ofCGt))mkRCast,x,t)|red->redinpp(lazy(str"typed as: "++pr_pattern_w_idsred));letmkXLetIn?locx{kind;pattern=(g,c);interpretation}=matchcwith|Someb->{kind;pattern=(g,Some(mkCLetIn?locx(mkCHole~loc)b));interpretation}|None->{kind;pattern=DAst.make?loc@@GLetIn(x,None,DAst.make?loc@@GHole(GBinderTypex),None,g),None;interpretation}inmatchredwith|Tt->letsigma,t=interp_termenvsigma0tin{pat_sigma=sigma;pat_pat=Tt}|In_Tt->letsigma,t=interp_termenvsigma0tin{pat_sigma=sigma;pat_pat=In_Tt}|X_In_T(x,rp)|In_X_In_T(x,rp)->letmkxp=matchredwithX_In_T_->X_In_T(x,p)|_->In_X_In_T(x,p)inletrp=mkXLetIn(Namex)rpinletsigma,rp=interp_termenvsigma0rpinlet_,h,_,rp=EConstr.destLetInsigmarpinleth=EConstr.destEvarsigmahinletsigma=cleanup_XinEhxrpsigmainletrp=EConstr.Vars.subst1(EConstr.mkEvarh)(Evarutil.nf_evarsigmarp)in{pat_sigma=sigma;pat_pat=mkhrp}|E_In_X_In_T(e,x,rp)|E_As_X_In_T(e,x,rp)->letmkexp=matchredwithE_In_X_In_T_->E_In_X_In_T(e,x,p)|_->E_As_X_In_T(e,x,p)inletrp=mkXLetIn(Namex)rpinletsigma,rp=interp_termenvsigma0rpinlet_,h,_,rp=EConstr.destLetInsigmarpinleth=EConstr.destEvarsigmahinletsigma=cleanup_XinEhxrpsigmainletrp=EConstr.Vars.subst1(EConstr.mkEvarh)(Evarutil.nf_evarsigmarp)inletsigma,e=interp_termenvsigmaein{pat_sigma=sigma;pat_pat=mkehrp}letinterp_cpatternenvsigmaredredty=interp_patternenvsigma(Tred)redty;;letinterp_rpattern~wit_ssrpatternargenvsigmared=interp_pattern~wit_ssrpatternargenvsigmaredNone;;letid_of_patternsigmap=matchp.pat_patwith|Tt->(matchEConstr.kindsigmatwithVarid->Someid|_->None)|_->None(* The full occurrence set *)letnoindex=Some(false,[])(* calls do_subst on every sub-term identified by (pattern,occ) *)leteval_pattern?raise_NoMatchenv0sigma0concl0patternocc(do_subst:subst)=letrigidev=Evd.memsigma0evinletfssigmax=Reductionops.nf_evarsigmaxinletpop_evarsigmaep=letEvarInfoe_def=Evd.findsigmaeinlete_body=matchEvd.evar_bodye_defwithEvar_definedc->c|_->errorstrm(str"Matching the pattern "++pr_econstr_envenv0sigma0p++str" did not instantiate ?"++int(Evar.repre)++spc()++str"Does the variable bound by the \"in\" construct occur "++str"in the pattern?")inletty=Retyping.get_type_of(Evd.evar_filtered_envenv0e_def)sigma(EConstr.mkEvar(e,Evd.evar_identity_subste_def))inletsigma=Evd.undefinesigmaety[@@ocaml.warning"-3"]insigma,e_bodyinletmk_upat_for?hack~rigid(sigma,t)=mk_tpattern?hack~rigidenv0tL2R(fssigmat)(empty_tpatternssigma)inmatchpatternwith|None->do_substenv0concl0concl01,UState.empty|Some{pat_sigma=sigma;pat_pat=(Trp|In_Trp)}->letrp=fssigmarpinletise=create_evar_defssigmainletocc=matchpatternwithSome{pat_pat=T_}->occ|_->noindexinletrp=mk_upat_for~rigid(ise,rp)inletfind_T,end_T=mk_tpattern_matcher?raise_NoMatchsigma0occrpinletconcl=find_Tenv0concl01~k:do_substinlet_,_,(_,_,us,_)=end_T()inconcl,us|Some{pat_sigma=sigma;pat_pat=(X_In_T(hole,p)|In_X_In_T(hole,p))}->letp=fssigmapinletocc=matchpatternwithSome{pat_pat=X_In_T_}->occ|_->noindexinletex=fstholeinlethole=EConstr.mkEvarholeinletrp=mk_upat_for~hack:true~rigid(sigma,p)inletfind_T,end_T=mk_tpattern_matchersigma0noindexrpin(* we start from sigma, so hole is considered a rigid head *)letholep=mk_upat_for~rigid:(funev->Evd.memsigmaev)(sigma,hole)inletfind_X,end_X=mk_tpattern_matcher?raise_NoMatchsigmaoccholepinletconcl=find_Tenv0concl01~k:(funenvc_h->letp_sigma=unify_HOenv(create_evar_defssigma)cpinletsigma,e_body=pop_evarp_sigmaexpinfsp_sigma(find_Xenv(fssigmap)h~k:(funenv_->do_substenve_body)))inlet_=end_X()inlet_,_,(_,_,us,_)=end_T()inconcl,us|Some{pat_sigma=sigma;pat_pat=E_In_X_In_T(e,hole,p)}->letp,e=fssigmap,fssigmaeinletex=fstholeinlethole=EConstr.mkEvarholeinletrp=mk_upat_for~hack:true~rigid(sigma,p)inletfind_T,end_T=mk_tpattern_matchersigma0noindexrpinletholep=mk_upat_for~rigid:(funev->Evd.memsigmaev)(sigma,hole)inletfind_X,end_X=mk_tpattern_matchersigmanoindexholepinletre=mk_upat_for~rigid(sigma,e)inletfind_E,end_E=mk_tpattern_matcher?raise_NoMatchsigma0occreinletconcl=find_Tenv0concl01~k:(funenvc_h->letp_sigma=unify_HOenv(create_evar_defssigma)cpinletsigma,e_body=pop_evarp_sigmaexpinfsp_sigma(find_Xenv(fssigmap)h~k:(funenvc_h->find_Eenve_bodyh~k:do_subst)))inlet_,_,(_,_,us,_)=end_E()inlet_=end_X()inlet_=end_T()inconcl,us|Some{pat_sigma=sigma;pat_pat=E_As_X_In_T(e,hole,p)}->letp,e=fssigmap,fssigmaeinletex=fstholeinlethole=EConstr.mkEvarholeinletrp=lete_sigma=unify_HOenv0sigmaholeeine_sigma,fse_sigmapinletrp=mk_upat_for~hack:true~rigidrpinletfind_TE,end_TE=mk_tpattern_matchersigma0noindexrpinletholep=mk_upat_for~rigid:(funev->Evd.memsigmaev)(sigma,hole)inletfind_X,end_X=mk_tpattern_matchersigmaoccholepinletconcl=find_TEenv0concl01~k:(funenvc_h->letp_sigma=unify_HOenv(create_evar_defssigma)cpinletsigma,e_body=pop_evarp_sigmaexpinfsp_sigma(find_Xenv(fssigmap)h~k:(funenvc_h->lete_sigma=unify_HOenvsigmae_bodyeinlete_body=fse_sigmaeindo_substenve_bodye_bodyh)))inlet_=end_X()inlet_,_,(_,_,us,_)=end_TE()inconcl,usletredex_of_pattern{pat_sigma=sigma;pat_pat=p}=matchpwith|In_T_|In_X_In_T_->None|X_In_T(e,_)->Some(sigma,EConstr.mkEvare)|Te|E_As_X_In_T(e,_,_)|E_In_X_In_T(e,_,_)->Some(sigma,e)letredex_of_pattern_nfenvp=letsigma,e=matchredex_of_patternpwith|None->CErrors.anomaly(str"pattern without redex.")|Some(sigma,e)->sigma,einEvarutil.nf_evarsigmae,Evd.evar_universe_contextsigmaletfill_occ_pattern?raise_NoMatchenvsigmaclpatocch=letdo_make_rel,occ=ifocc=Some(true,[])thenfalse,Some(false,[1])elsetrue,occinletr=refNoneinletfind_Renvc_h'=let()=do_oncer(fun()->c)inifdo_make_relthenEConstr.mkRel(h'+h-1)elsecinletcl,us=eval_pattern?raise_NoMatchenvsigmacl(Somepat)occfind_Rinlete=match!rwithNone->fst(redex_of_pattern_nfenvpat)|Somex->xin(e,us),clletfill_rel_occ_patternenvsigmaclpatocc=let(e,us),cl=tryfill_occ_pattern~raise_NoMatch:trueenvsigmaclpatocc1withNoMatch->redex_of_pattern_nfenvpat,clinletsigma=Evd.merge_universe_contextsigmausinsigma,e,cl(* clenup interface for external use *)letmk_tpattern?p_origin?ok~rigidenvsigma_tdirc=mk_tpattern?p_origin?ok~rigidenvsigma_tdircleteval_pattern?raise_NoMatchenv0sigma0concl0patternoccdo_subst=fst(eval_pattern?raise_NoMatchenv0sigma0concl0patternoccdo_subst)letpf_fill_occenvconcloccsigma0p(sigma,t)h=letrigidev=Evd.memsigma0evinletu=mk_tpattern~rigidenvtL2Rp(empty_tpatterns(create_evar_defssigma))inletfind_U,end_U=mk_tpattern_matcher~raise_NoMatch:truesigma0occuinletconcl=find_Uenvconclh~k:(fun___n->EConstr.mkReln)inletrdx,_,(c,sigma,uc,p)=end_U()inc,sigma,uc,p,concl,rdxletfill_occ_termenvsigma0clocc(sigma,t)=tryletchanged,sigma',uc,t',cl,_=pf_fill_occenvcloccsigma0t(sigma,t)1inifchangedthenCErrors.user_errPp.(str"matching impacts evars")elsecl,t'withNoMatch->tryletchanged,sigma',uc,t'=unif_endenvsigma0(create_evar_defssigma)t(fun_->true)inifchangedthenraiseNoMatchelsecl,t'withewhenCErrors.noncriticale->errorstrm(str"partial term "++pr_econstr_patenvsigmat++str" does not match any subterm of the goal")letcpattern_of_idid={kind=NoFlag;pattern=DAst.make@@GRef(GlobRef.VarRefid,None),None;interpretation=SomeGeninterp.({lfun=Id.Map.empty;poly=false;extra=Tacinterp.TacStore.empty})}letis_wildcard({pattern=(l,r);_}:cpattern):bool=matchDAst.getl,rwith|_,Some{CAst.v=CHole_}|GHole_,None->true|_->false(* "ssrpattern" *)(** All the pattern types reuse the same dynamic toplevel tag *)letwit_ssrpatternarg=wit_rpatterntyletinterp_rpattern=interp_rpattern~wit_ssrpatternargletssrpatterntac_istarg=letopenProofview.NotationsinProofview.Goal.enterbeginfungl->letsigma0=Proofview.Goal.sigmaglinletconcl0=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletpat=interp_rpatternenvsigma0arginlet(t,uc),concl_x=fill_occ_patternenvsigma0concl0patnoindex1inletsigma=Evd.set_universe_contextsigma0ucinletsigma,tty=Typing.type_ofenvsigmatinletconcl=EConstr.mkLetIn(make_annot(Name(Id.of_string"selected"))EConstr.ERelevance.relevant,t,tty,concl_x)inProofview.Unsafe.tclEVARSsigma<*>convert_concl~cast:false~check:trueconclDEFAULTcastend(* Register "ssrpattern" tactic *)let()=letmltac_ist=letarg=letv=Id.Map.find(Names.Id.of_string"pattern")ist.lfuninValue.cast(topwitwit_ssrpatternarg)vinssrpatterntacistarginletname={mltac_plugin="coq-core.plugins.ssrmatching";mltac_tactic="ssrpattern";}inlet()=Tacenv.register_ml_tacticname[|mltac|]inlettac=CAst.make(TacFun([Name(Id.of_string"pattern")],CAst.make(TacML({mltac_name=name;mltac_index=0},[]))))inletobj()=Tacenv.register_ltactruefalse(Id.of_string"ssrpattern")tacinMltop.declare_cache_objobj"coq-core.plugins.ssrmatching"letssrinstancesofarg=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletconcl=Reductionops.nf_evarsigmaconclinlet{pat_sigma=sigma0;pat_pat=cpat}=interp_cpatternenvsigmaargNoneinletpat=matchcpatwithTx->x|_->errorstrm(str"Not supported")inletrigidev=Evd.memsigmaevinlettpat=mk_tpattern~rigidenvpatL2Rpat(empty_tpatternssigma0)inletfind,conclude=mk_tpattern_matcher~all_instances:true~raise_NoMatch:truesigmaNonetpatinletprintenvpc_=ppnl(hov1(str"instance:"++spc()++pr_econstr_envenv(Proofview.Goal.sigmagl)p++spc()++str"matches:"++spc()++pr_econstr_envenv(Proofview.Goal.sigmagl)c));cinppnl(str"BEGIN INSTANCES");trywhiletruedoignore(findenvconcl1~k:print)done;raiseNoMatchwithNoMatch->ppnl(str"END INSTANCES");Tacticals.tclIDTACendmoduleInternal=structletwit_rpatternty=wit_rpatterntyletglob_rpattern=glob_rpatternletsubst_rpattern=subst_rpatternletinterp_rpattern=interp_rpattern0letpr_rpattern=pr_rpatternletmk_rpatternx=xletmk_lterm=mk_ltermletmk_term=mk_termletglob_cpattern=glob_cpatternletsubst_ssrterm=subst_ssrtermletinterp_ssrterm=interp_ssrtermletpr_ssrterm=pr_termend(* vim: set filetype=ocaml foldmethod=marker: *)