1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426(************************************************************************)(* * 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_termopenUtilopenEvdopenTacexpropenTacinterpopenPretypingopenPpconstropenPrinteropenNamegenopenEvar_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()=Genintern.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,IntroAnonymous)letmkCLambda?locnametyt=CAst.make?loc@@CLambdaN([CLocalAssum([CAst.make?locname],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(InternalHole,IntroAnonymous)letmkRAppfargs=ifargs=[]thenfelseDAst.make@@GApp(f,args)letmkRCastrcrt=DAst.make@@GCast(rc,SomeDEFAULTcast,rt)letmkRLambdanst=DAst.make@@GLambda(n,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_)->()(* 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_|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|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_annotAnonymousSorts.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_->unif_HOenviseu.up_f(mkSubAppf(i-Array.lengthu.up_a)a)|_->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?.")with_whenisCVart1->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,DAst.make?loc@@GHole(BinderTypex,IntroAnonymous),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'with_->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,tty=Typing.type_ofenvsigma0tinletconcl=EConstr.mkLetIn(make_annot(Name(Id.of_string"selected"))Sorts.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: *)