123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * INRIA, CNRS and contributors - Copyright 1999-2019 *)(* <O___,, * (see CREDITS file for the list of authors) *)(* \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) *)(************************************************************************)openUtilopenNamesopenConstropenContextopenTermopsopenUnivopenEnvironopenEConstropenVarsopenContext.Rel.Declaration(** This module implements a call by name reduction used by the cbn tactic.
It has an ability to "refold" constants by storing constants and
their parameters in its stack.
*)(** Machinery to custom the behavior of the reduction *)moduleReductionBehaviour=Reductionops.ReductionBehaviourtypevolatile={volatile:bool}[@@unboxed](** Machinery about stack of unfolded constants *)moduleCst_stack=structopenEConstr(** constant * params * args
- constant applied to params = term in head applied to args
- there is at most one arguments with an empty list of args, it must be the first.
- in args, the int represents the indice of the first arg to consider *)typet=(constr*constrlist*(int*constrarray)list*volatile)listletempty=[]letall_volatile=CList.for_all(fun(_,_,_,{volatile})->volatile)letdrop_useless=function|_::((_,_,[],_)::_asq)->q|l->lletadd_paramhcst_l=letappend2cst=function|(c,params,[],vol)->(c,h::params,[],vol)|(c,params,((i,t)::q),vol)wheni=pred(Array.lengtht)->(c,params,q,vol)|(c,params,(i,t)::q,vol)->(c,params,(succi,t)::q,vol)indrop_useless(List.mapappend2cstcst_l)letadd_argscl=List.map(fun(a,b,args,vol)->(a,b,(0,cl)::args,vol))letadd_cst?(volatile=false)cst=function|(_,_,[],_)::qasl->l|l->(cst,[],[],{volatile})::lletbest_cst=function|(cst,params,[],_)::_->Some(cst,params)|_->Noneletreferencesigmat=matchbest_csttwith|Some(c,params)whenisConstsigmac->Some(fst(destConstsigmac),params)|_->None(** [best_replace d cst_l c] makes the best replacement for [d]
by [cst_l] in [c] *)letbest_replacesigmadcst_lc=letreconstruct_head=List.fold_left(funt(i,args)->mkApp(t,Array.subargsi(Array.lengthargs-i)))inList.fold_right(fun(cst,params,args,_)t->Termops.replace_termsigma(reconstruct_headdargs)(applist(cst,List.revparams))t)cst_lcletprenvsigmal=letopenPpinletp_cc=Termops.Internal.print_constr_envenvsigmacinprlist_with_seppr_semicolon(fun(c,params,args,{volatile})->hov1(str"("++p_cc++str")"++spc()++pr_sequencep_cparams++spc()++str"(args:"++pr_sequence(fun(i,el)->prvect_with_sepspcp_c(Array.subeli(Array.lengthel-i)))args++str")"++(ifvolatilethenstr" (volatile)"elsemt())))lend(** The type of (machine) stacks (= lambda-bar-calculus' contexts) *)moduleStack:sigopenEConstrtype'aapp_nodetypecst_member=|Cst_constofpconstant|Cst_projofProjection.t*ERelevance.ttype'acase_stk=case_info*EInstance.t*'aarray*('a,ERelevance.t)pcase_return*'apcase_invert*('a,ERelevance.t)pcase_brancharraytype'amember=|Appof'aapp_node|Caseof'acase_stk*Cst_stack.t|ProjofProjection.t*ERelevance.t*Cst_stack.t|Fixof('a,'a,ERelevance.t)pfixpoint*'at*Cst_stack.t|PrimitiveofCPrimitives.t*(Constant.t*EInstance.t)*'at*CPrimitives.args_red*Cst_stack.t|Cstof{const:cst_member;curr:int;remains:intlist;params:'at;volatile:bool;cst_l:Cst_stack.t;}and'at='amemberlistvalpr:('a->Pp.t)->'at->Pp.tvalempty:'atvalappend_app:'aarray->'at->'atvaldecomp:'at->('a*'at)optionvalequal:env->('a->'a->bool)->(('a,'a,ERelevance.t)pfixpoint->('a,'a,ERelevance.t)pfixpoint->bool)->('acase_stk->'acase_stk->bool)->'at->'at->boolvalstrip_app:'at->'at*'atvalstrip_n_app:int->'at->('at*'a*'at)optionvalwill_expose_iota:'at->boolvallist_of_app_stack:constrt->constrlistoptionvalargs_size:'at->intvaltail:int->'at->'atvalnth:'at->int->'avalbest_state:Evd.evar_map->constr*constrt->Cst_stack.t->constr*constrtvalzip:?refold:bool->Evd.evar_map->constr*constrt->constrvalcheck_native_args:CPrimitives.t->'at->boolvalget_next_primitive_args:CPrimitives.args_red->'at->CPrimitives.args_red*('at*'a*'at)optionend=structopenEConstrtype'aapp_node=int*'aarray*int(* first releavnt position, arguments, last relevant position *)(*
Invariant that this module must ensure :
(behare of direct access to app_node by the rest of Reductionops)
- in app_node (i,_,j) i <= j
- There is no array realocation (outside of debug printing)
*)letpr_app_nodepr(i,a,j)=letopenPpinsurround(prvect_with_seppr_commapr(Array.subai(j-i+1)))typecst_member=|Cst_constofpconstant|Cst_projofProjection.t*ERelevance.ttype'acase_stk=case_info*EInstance.t*'aarray*('a,ERelevance.t)pcase_return*'apcase_invert*('a,ERelevance.t)pcase_brancharraytype'amember=|Appof'aapp_node|Caseof'acase_stk*Cst_stack.t|ProjofProjection.t*ERelevance.t*Cst_stack.t|Fixof('a,'a,ERelevance.t)pfixpoint*'at*Cst_stack.t|PrimitiveofCPrimitives.t*(Constant.t*EInstance.t)*'at*CPrimitives.args_red*Cst_stack.t|Cstof{const:cst_member;curr:int;remains:intlist;params:'at;volatile:bool;cst_l:Cst_stack.t;}and'at='amemberlist(* Debugging printer *)letrecpr_memberpr_cmember=letopenPpinletpr_cx=hov1(pr_cx)inmatchmemberwith|Appapp->str"ZApp"++pr_app_nodepr_capp|Case((_,_,_,_,_,br),cst)->str"ZCase("++prvect_with_sep(pr_bar)(fun(_,b)->pr_cb)br++str")"|Proj(p,_,cst)->str"ZProj("++Projection.debug_printp++str")"|Fix(f,args,cst)->str"ZFix("++Constr.debug_print_fixpr_cf++pr_comma()++prpr_cargs++str")"|Primitive(p,c,args,kargs,cst_l)->str"ZPrimitive("++str(CPrimitives.to_stringp)++pr_comma()++prpr_cargs++str")"|Cst{const=mem;curr;remains;params;cst_l}->str"ZCst("++pr_cst_memberpr_cmem++pr_comma()++intcurr++pr_comma()++prlist_with_seppr_semicolonintremains++pr_comma()++prpr_cparams++str")"andprpr_cl=letopenPpinprlist_with_seppr_semicolon(funx->hov1(pr_memberpr_cx))landpr_cst_memberpr_cc=letopenPpinmatchcwith|Cst_const(c,u)->ifUVars.Instance.is_emptyuthenConstant.debug_printcelsestr"("++Constant.debug_printc++str", "++UVars.Instance.prSorts.QVar.raw_prUniv.Level.raw_pru++str")"|Cst_proj(p,r)->str".("++Projection.debug_printp++str")"letempty=[]letappend_appvs=letle=Array.lengthvinifInt.equalle0thenselseApp(0,v,predle)::sletdecomp_node(i,l,j)sk=ifi<jthen(l.(i),App(succi,l,j)::sk)else(l.(i),sk)letdecomp=function|Appnode::s->Some(decomp_nodenodes)|_->Noneletdecomp_node_last(i,l,j)sk=ifi<jthen(l.(j),App(i,l,predj)::sk)else(l.(j),sk)letequalenvff_fixf_casesk1sk2=letequal_cst_memberxy=matchx,ywith|Cst_const(c1,u1),Cst_const(c2,u2)->QConstant.equalenvc1c2&&UVars.Instance.equalu1u2|Cst_proj(p1,_),Cst_proj(p2,_)->QProjection.Repr.equalenv(Projection.reprp1)(Projection.reprp2)|_,_->falseinletrecequal_recsk1sk2=matchsk1,sk2with|[],[]->true|Appa1::s1,Appa2::s2->lett1,s1'=decomp_node_lasta1s1inlett2,s2'=decomp_node_lasta2s2in(ft1t2)&&(equal_recs1's2')|Case((ci1,pms1,p1,t1,iv1,a1),_)::s1,Case((ci2,pms2,p2,iv2,t2,a2),_)::s2->f_case(ci1,pms1,p1,t1,iv1,a1)(ci2,pms2,p2,iv2,t2,a2)&&equal_recs1s2|(Proj(p,_,_)::s1,Proj(p2,_,_)::s2)->QProjection.Repr.equalenv(Projection.reprp)(Projection.reprp2)&&equal_recs1s2|Fix(f1,s1,_)::s1',Fix(f2,s2,_)::s2'->f_fixf1f2&&equal_rec(List.revs1)(List.revs2)&&equal_recs1's2'|Cstc1::s1',Cstc2::s2'->equal_cst_memberc1.constc2.const&&equal_rec(List.revc1.params)(List.revc2.params)&&equal_recs1's2'|((App_|Case_|Proj_|Fix_|Cst_|Primitive_)::_|[]),_->falseinequal_rec(List.revsk1)(List.revsk2)letappend_app_listls=leta=Array.of_listlinappend_appasletrecargs_size=function|App(i,_,j)::s->j+1-i+args_sizes|(Case_|Fix_|Proj_|Cst_|Primitive_)::_|[]->0letstrip_apps=letrecauxout=function|(App_ase)::s->aux(e::out)s|s->List.revout,sinaux[]sletstrip_n_appns=letrecauxnout=function|App(i,a,j)ase::s->letnb=j-i+1inifn>=nbthenaux(n-nb)(e::out)selseletp=i+ninSome(CList.rev(ifInt.equaln0thenoutelseApp(i,a,p-1)::out),a.(p),ifj>pthenApp(succp,a,j)::selses)|s->Noneinauxn[]sletwill_expose_iotaargs=List.exists(function(Fix(_,_,l)|Case(_,l)|Proj(_,_,l)|Cst{cst_l=l})whenCst_stack.all_volatilel->true|_->false)argsletlist_of_app_stacks=letrecaux=function|App(i,a,j)::s->let(args',s')=auxsinleta'=Array.subai(j-i+1)in(Array.fold_right(funxy->x::y)a'args',s')|s->([],s)inlet(out,s')=auxsinletinit=matchs'with[]->true|_->falseinOption.initinitoutlettailn0s0=letrecauxns=ifInt.equaln0thenselsematchswith|App(i,a,j)::s->letnb=j-i+1inifn>=nbthenaux(n-nb)selseletp=i+ninifj>=pthenApp(p,a,j)::selses|_->raise(Invalid_argument"Reductionops.Stack.tail")inauxn0s0letnthsp=matchstrip_n_apppswith|Some(_,el,_)->el|None->raiseNot_found(** This function breaks the abstraction of Cst_stack ! *)letbest_statesigma(_,skass)l=letrecauxskdef=function|(_,_,_,{volatile=true})->def|(cst,params,[],_)->(cst,append_app_list(List.revparams)sk)|(cst,params,(i,t)::q,vol)->matchdecompskwith|Some(el,sk')whenEConstr.eq_constrsigmaelt.(i)->ifi=pred(Array.lengtht)thenauxsk'def(cst,params,q,vol)elseauxsk'def(cst,params,(succi,t)::q,vol)|_->definList.fold_left(auxsk)slletconstr_of_cst_memberfsk=matchfwith|Cst_const(c,u)->mkConstU(c,EInstance.makeu),sk|Cst_proj(p,r)->matchdecompskwith|Some(hd,sk)->mkProj(p,r,hd),sk|None->assertfalseletzip?(refold=false)sigmas=letreczip=function|f,[]->f|f,(App(i,a,j)::s)->leta'=ifInt.equali0&&Int.equalj(Array.lengtha-1)thenaelseArray.subai(j-i+1)inzip(mkApp(f,a'),s)|f,(Case((ci,u,pms,rt,iv,br),cst_l)::s)whenrefold->zip(best_statesigma(mkCase(ci,u,pms,rt,iv,f,br),s)cst_l)|f,(Case((ci,u,pms,rt,iv,br),_)::s)->zip(mkCase(ci,u,pms,rt,iv,f,br),s)|f,(Fix(fix,st,cst_l)::s)whenrefold->zip(best_statesigma(mkFixfix,st@(append_app[|f|]s))cst_l)|f,(Fix(fix,st,_)::s)->zip(mkFixfix,st@(append_app[|f|]s))|f,(Cst{const;params;cst_l}::s)whenrefold->zip(best_statesigma(constr_of_cst_memberconst(params@(append_app[|f|]s)))cst_l)|f,(Cst{const;params}::s)->zip(constr_of_cst_memberconst(params@(append_app[|f|]s)))|f,(Proj(p,r,cst_l)::s)whenrefold->zip(best_statesigma(mkProj(p,r,f),s)cst_l)|f,(Proj(p,r,_)::s)->zip(mkProj(p,r,f),s)|f,(Primitive(p,c,args,kargs,cst_l)::s)->zip(mkConstUc,args@append_app[|f|]s)inzips(* Check if there is enough arguments on [stk] w.r.t. arity of [op] *)letcheck_native_argsopstk=letnargs=CPrimitives.arityopinletrargs=args_sizestkinnargs<=rargsletget_next_primitive_argskargsstk=letrecnargs=function|[]->0|CPrimitives.Kwhnf::_->0|_::s->1+nargssinletn=nargskargsin(List.skipn(n+1)kargs,strip_n_appnstk)end(** The type of (machine) states (= lambda-bar-calculus' cuts) *)(*************************************)(*** Reduction Functions Operators ***)(*************************************)letsafe_meta_valuesigmaev=trySome(Evd.meta_valuesigmaev)withNot_found->None(*************************************)(*** Reduction using bindingss ***)(*************************************)(* Beta Reduction tools *)letapply_substenvsigmacst_ltstack=letrecauxenvcst_ltstack=match(Stack.decompstack,EConstr.kindsigmat)with|Some(h,stacktl),Lambda(_,_,c)->letcst_l'=Cst_stack.add_paramhcst_linaux(h::env)cst_l'cstacktl|_->(cst_l,(substlenvt,stack))inauxenvcst_ltstack(* Iota reduction tools *)(** @return c if there is a constant c whose body is bd
@return bd else.
It has only a meaning because internal representation of "Fixpoint f x
:= t" is Definition f := fix f x => t
Even more fragile that we could hope because do Module M. Fixpoint
f x := t. End M. Definition f := u. and say goodbye to any hope
of refolding M.f this way ...
*)letmagically_constant_of_fixbodyenvsigma(reference,params)bd=function|Name.Anonymous->bd|Name.Nameid->letopenUnivProbleminletcst=Constant.change_labelreference(Label.of_idid)inifnot(Environ.mem_constantcstenv)thenbdelselet(cst,u),ctx=UnivGen.fresh_constant_instanceenvcstinmatchconstant_opt_value_inenv(cst,u)with|None->bd|Somet->letcsts=EConstr.eq_constr_universesenvsigma(Reductionops.beta_applistsigma(EConstr.of_constrt,params))bdinbeginmatchcstswith|Somecsts->letaddqslr(qs,us)=Sorts.QVar.Map.addlrqs,usinletadduslr(qs,us)=qs,Univ.Level.Map.addlrusinletsubst=Set.fold(funcstacc->matchcstwith|QEq(a,b)|QLeq(a,b)->leta=matchawith|QVarq->q|_->assertfalseinaddqsabacc|ULub(u,v)|UWeak(u,v)->addusuvacc|UEq(u,v)|ULe(u,v)->(* XXX add something when qsort? *)letgetu=matchuwith|Sorts.SProp|Sorts.Prop->assertfalse|Sorts.Set->Level.set|Sorts.Typeu|Sorts.QSort(_,u)->Option.get(Universe.levelu)inaddus(getu)(getv)acc)cstsUVars.empty_sort_substinletinst=UVars.subst_sort_level_instancesubstuinapplist(mkConstU(cst,EInstance.makeinst),params)|None->bdendletcontract_cofixenvsigma?reference(bodynum,(names,types,bodiesastypedbodies))=letnbodies=Array.lengthbodiesinletmake_Fij=letind=nbodies-j-1inifInt.equalbodynumindthenmkCoFix(ind,typedbodies)elseletbd=mkCoFix(ind,typedbodies)inmatchreferencewith|None->bd|Somer->magically_constant_of_fixbodyenvsigmarbdnames.(ind).binder_nameinletclosure=List.initnbodiesmake_Fiinsubstlclosurebodies.(bodynum)(** Similar to the "fix" case below *)letreduce_and_refold_cofixrecfunenvsigmacst_lcofixsk=letraw_answer=contract_cofixenvsigma?reference:(Cst_stack.referencesigmacst_l)cofixinlet(x,(t,sk'))=apply_subst[]sigmaCst_stack.emptyraw_answerskinlett'=Cst_stack.best_replacesigma(mkCoFixcofix)cst_ltinrecfunx(t',sk')(* contracts fix==FIX[nl;i](A1...Ak;[F1...Fk]{B1....Bk}) to produce
Bi[Fj --> FIX[nl;j](A1...Ak;[F1...Fk]{B1...Bk})] *)letcontract_fixenvsigma?reference((recindices,bodynum),(names,types,bodiesastypedbodies))=letnbodies=Array.lengthrecindicesinletmake_Fij=letind=nbodies-j-1inifInt.equalbodynumindthenmkFix((recindices,ind),typedbodies)elseletbd=mkFix((recindices,ind),typedbodies)inmatchreferencewith|None->bd|Somer->magically_constant_of_fixbodyenvsigmarbdnames.(ind).binder_nameinletclosure=List.initnbodiesmake_Fiinsubstlclosurebodies.(bodynum)(** First we substitute the Rel bodynum by the fixpoint and then we try to
replace the fixpoint by the best constant from [cst_l]
Other rels are directly substituted by constants "magically found from the
context" in contract_fix *)letreduce_and_refold_fixrecfunenvsigmacst_lfixsk=letraw_answer=contract_fixenvsigma?reference:(Cst_stack.referencesigmacst_l)fixinlet(x,(t,sk'))=apply_subst[]sigmaCst_stack.emptyraw_answerskinlett'=Cst_stack.best_replacesigma(mkFixfix)cst_ltinrecfunx(t',sk')moduleCredNative=Reductionops.CredNative(** Generic reduction function with environment
Here is where unfolded constant are stored in order to be
eventually refolded.
It uses ReductionBehaviour, prefers
refold constant instead of value and tries to infer constants
fix and cofix came from.
It substitutes fix and cofix by the constant they come from in
contract_* in any case .
*)letdebug_RAKAM=Reductionops.debug_RAKAMletequal_stacksenvsigma(x,l)(y,l')=letf_equalxy=eq_constrsigmaxyinleteq_fixab=f_equal(mkFixa)(mkFixb)inleteq_case(ci1,u1,pms1,(p1,_),_,br1)(ci2,u2,pms2,(p2,_),_,br2)=Array.equalf_equalpms1pms2&&f_equal(sndp1)(sndp2)&&Array.equal(fun(_,c1)(_,c2)->f_equalc1c2)br1br2inStack.equalenvf_equaleq_fixeq_casell'&&f_equalxyletapply_branchenvsigma(ind,i)args(ci,u,pms,iv,r,lf)=letargs=Stack.tailci.ci_nparargsinletargs=Option.get(Stack.list_of_app_stackargs)inletbr=lf.(i-1)inletsubst=ifInt.equalci.ci_cstr_nargs.(i-1)ci.ci_cstr_ndecls.(i-1)then(* No let-bindings *)List.revargselseletctx=expand_branchenvsigmaupms(ind,i)brinsubst_of_rel_context_instance_listctxargsinVars.substlsubst(sndbr)exceptionPatternFailureletmatch_einstancesigmapuupsubst=matchUVars.Instance.pattern_matchpu(EInstance.kindsigmau)psubstwith|Somepsubst->psubst|None->raisePatternFailureletmatch_sortpsspsubst=matchSorts.pattern_matchpsspsubstwith|Somepsubst->psubst|None->raisePatternFailureletrecmatch_arg_patternwhrecenvsigmactxpsubstpt=letopenDeclarationsinlett'=EConstr.it_mkLambda_or_LetIntctxinmatchpwith|EHolei->Partial_subst.add_termit'psubst|EHoleIgnored->psubst|ERigid(ph,es)->let(t,stk),_=whrecCst_stack.empty(t,Stack.empty)inletpsubst=match_rigid_arg_patternwhrecenvsigmactxpsubstphtinletpsubst,stk=apply_rulewhrecenvsigmactxpsubstesstkinmatchstkwith|[]->psubst|_::_->raisePatternFailureandmatch_rigid_arg_patternwhrecenvsigmactxpsubstpt=match[@ocaml.warning"-4"]p,EConstr.kindsigmatwith|PHInd(ind,pu),Ind(ind',u)->ifInd.CanOrd.equalindind'thenmatch_einstancesigmapuupsubstelseraisePatternFailure|PHConstr(constr,pu),Construct(constr',u)->ifConstruct.CanOrd.equalconstrconstr'thenmatch_einstancesigmapuupsubstelseraisePatternFailure|PHReli,Relnwheni=n->psubst|PHSortps,Sorts->match_sortps(ESorts.kindsigmas)psubst|PHSymbol(c,pu),Const(c',u)->ifConstant.CanOrd.equalcc'thenmatch_einstancesigmapuupsubstelseraisePatternFailure|PHInti,Inti'->ifUint63.equalii'thenpsubstelseraisePatternFailure|PHFloatf,Floatf'->ifFloat64.equalff'thenpsubstelseraisePatternFailure|PHStrings,Strings'->ifPstring.equalss'thenpsubstelseraisePatternFailure|PHLambda(ptys,pbod),_->letntys,_=EConstr.decompose_lambdasigmatinletna=List.lengthntysandnp=Array.lengthptysinifnp>nathenraisePatternFailure;letntys,body=EConstr.decompose_lambda_nsigmanptinletctx'=List.map(fun(n,ty)->Context.Rel.Declaration.LocalAssum(n,ty))ntysinlettys=Array.of_list@@List.rev_mapsndntysinletna=Array.lengthtysinletcontexts_upto=Array.initna(funi->List.skipn(na-i)ctx'@ctx)inletpsubst=Array.fold_left3(funpsubstctx->match_arg_patternwhrecenvsigmactxpsubst)psubstcontexts_uptoptystysinletpsubst=match_arg_patternwhrecenvsigma(ctx'@ctx)psubstpbodbodyinpsubst|PHProd(ptys,pbod),_->letntys,_=EConstr.decompose_prodsigmatinletna=List.lengthntysandnp=Array.lengthptysinifnp>nathenraisePatternFailure;letntys,body=EConstr.decompose_prod_nsigmanptinletctx'=List.map(fun(n,ty)->Context.Rel.Declaration.LocalAssum(n,ty))ntysinlettys=Array.of_list@@List.rev_mapsndntysinletna=Array.lengthtysinletcontexts_upto=Array.initna(funi->List.skipn(na-i)ctx'@ctx)inletpsubst=Array.fold_left3(funpsubstctx->match_arg_patternwhrecenvsigmactxpsubst)psubstcontexts_uptoptystysinletpsubst=match_arg_patternwhrecenvsigma(ctx'@ctx)psubstpbodbodyinpsubst|(PHInd_|PHConstr_|PHRel_|PHInt_|PHFloat_|PHString_|PHSort_|PHSymbol_),_->raisePatternFailureandextract_n_stackargsns=ifn=0thenList.revargs,selsematchStack.decompswith|Some(arg,rest)->extract_n_stack(arg::args)(n-1)rest|None->raisePatternFailureandapply_rulewhrecenvsigmactxpsubstesstk=match[@ocaml.warning"-4"]es,stkwith|[],_->psubst,stk|Declarations.PEApppargs::e,s->letnp=Array.lengthpargsinletpargs=Array.to_listpargsinletargs,s=extract_n_stack[]npsinletpsubst=List.fold_left2(match_arg_patternwhrecenvsigmactx)psubstpargsargsinapply_rulewhrecenvsigmactxpsubstes|Declarations.PECase(pind,pu,pret,pbrs)::e,Stack.Case((ci,u,pms,p,iv,brs),cst_l)::s->ifnot@@Ind.CanOrd.equalpindci.ci_indthenraisePatternFailure;letdummy=mkPropinletpsubst=match_einstancesigmapuupsubstinlet(_,_,_,((ntys_ret,ret),_),_,_,brs)=EConstr.annotate_caseenvsigma(ci,u,pms,p,NoInvert,dummy,brs)inletpsubst=match_arg_patternwhrecenvsigma(ntys_ret@ctx)psubstpretretinletpsubst=Array.fold_left2(funpsubstpat(ctx',br)->match_arg_patternwhrecenvsigma(ctx'@ctx)psubstpatbr)psubstpbrsbrsinapply_rulewhrecenvsigmactxpsubstes|Declarations.PEProjproj::e,Stack.Proj(proj',r,cst_l')::s->ifnot@@Projection.CanOrd.equalprojproj'thenraisePatternFailure;apply_rulewhrecenvsigmactxpsubstes|_,_->raisePatternFailureletrecapply_ruleswhrecenvsigmaurstk=letopenDeclarationsinmatchrwith|[]->raisePatternFailure|{lhs_pat=(pu,elims);nvars;rhs}::rs->tryletpsubst=Partial_subst.makenvarsinletpsubst=match_einstancesigmapuupsubstinletpsubst,stk=apply_rulewhrecenvsigma[]psubstelimsstkinletsubst,qsubst,usubst=Partial_subst.to_arrayspsubstinletusubst=UVars.Instance.of_array(qsubst,usubst)inletrhsu=subst_instance_constr(EConstr.EInstance.makeusubst)(EConstr.of_constrrhs)inletrhs'=substl(Array.to_listsubst)rhsuin(rhs',stk)withPatternFailure->apply_ruleswhrecenvsigmaursstkletwhd_state_gen?cstsflagsenvsigma=letopenContext.Named.DeclarationinletopenReductionBehaviourinletrecwhreccst_l(x,stack)=let()=debug_RAKAM(fun()->letopenPpinletprc=Termops.Internal.print_constr_envenvsigmacin(h(str"<<"++prx++str"|"++cut()++Cst_stack.prenvsigmacst_l++str"|"++cut()++Stack.prprstack++str">>")))inletc0=EConstr.kindsigmaxinletfold()=let()=debug_RAKAM(fun()->Pp.(str"<><><><><>"))in((EConstr.of_kindc0,stack),cst_l)inmatchc0with|RelnwhenRedFlags.red_setflagsRedFlags.fDELTA->(matchlookup_relnenvwith|LocalDef(_,body,_)->whrecCst_stack.empty(liftnbody,stack)|_->fold())|VaridwhenRedFlags.red_setflags(RedFlags.fVARid)->(matchlookup_namedidenvwith|LocalDef(_,body,_)->whrec(Cst_stack.add_cst(mkVarid)cst_l)(body,stack)|_->fold())|Evarev->fold()|Metaev->(matchsafe_meta_valuesigmaevwith|Somebody->whreccst_l(body,stack)|None->fold())|Const(c,uasconst)->Reductionops.reduction_effect_hookenvsigmac(lazy(EConstr.to_constrsigma(Stack.zipsigma(x,fst(Stack.strip_appstack)))));ifRedFlags.red_setflags(RedFlags.fCONSTc)thenletu'=EInstance.kindsigmauinmatchconstant_value_inenv(c,u')with|body->beginletbody=EConstr.of_constrbodyin(* Looks for ReductionBehaviour *)matchReductionBehaviour.getcwith|None->whrec(Cst_stack.add_cst(mkConstUconst)cst_l)(body,stack)|Somebehavior->beginmatchbehaviorwith|NeverUnfold->fold()|(UnfoldWhen{nargs=Somen}|UnfoldWhenNoMatch{nargs=Somen})whenStack.args_sizestack<n->fold()|UnfoldWhenNoMatch{recargs;nargs}->(* maybe unfolds *)letapp_sk,sk=Stack.strip_appstackinletvolatile=Option.has_somenargsinlet(tm',sk'),cst_l'=matchrecargswith|[]->whrec(Cst_stack.add_cst~volatile(mkConstUconst)cst_l)(body,app_sk)|curr::remains->matchStack.strip_n_appcurrapp_skwith|None->(x,app_sk),cst_l|Some(bef,arg,app_sk')->letcst_l=Stack.Cst{const=Stack.Cst_const(fstconst,u');volatile;curr;remains;params=bef;cst_l;}inwhrecCst_stack.empty(arg,cst_l::app_sk')inletrecis_casex=matchEConstr.kindsigmaxwith|Lambda(_,_,x)|LetIn(_,_,_,x)|Cast(x,_,_)->is_casex|App(hd,_)->is_casehd|Case_->true|_->falseinifequal_stacksenvsigma(x,app_sk)(tm',sk')||Stack.will_expose_iotask'||is_casetm'thenfold()elsewhreccst_l'(tm',sk'@sk)|UnfoldWhen{recargs;nargs}->(* maybe unfolds *)beginmatchrecargswith|[]->(* if nargs has been specified *)(* CAUTION : the constant is NEVER refolded (even when it hides a (co)fix) *)whreccst_l(body,stack)|curr::remains->matchStack.strip_n_appcurrstackwith|None->fold()|Some(bef,arg,s')->letcst_l=Stack.Cst{const=Stack.Cst_const(fstconst,u');volatile=Option.has_somenargs;curr;remains;params=bef;cst_l;}inwhrecCst_stack.empty(arg,cst_l::s')endendend|exceptionNotEvaluableConst(IsPrimitive(u,p))whenStack.check_native_argspstack->letkargs=CPrimitives.kindpinlet(kargs,o)=Stack.get_next_primitive_argskargsstackin(* Should not fail thanks to [check_native_args] *)let(before,a,after)=Option.getoinwhrecCst_stack.empty(a,Stack.Primitive(p,const,before,kargs,cst_l)::after)|exceptionNotEvaluableConst(HasRules(u',b,r))->begintryletrhs_stack=apply_ruleswhrecenvsigmaurstackinwhrecCst_stack.emptyrhs_stackwithPatternFailure->ifnotbthenfold()elsematchStack.strip_appstackwith|args,(Stack.Fix(f,s',cst_l)::s'')whenRedFlags.red_setflagsRedFlags.fFIX->letx'=Stack.zipsigma(x,args)inletout_sk=s'@(Stack.append_app[|x'|]s'')inreduce_and_refold_fixwhrecenvsigmacst_lfout_sk|_->fold()end|exceptionNotEvaluableConst_->fold()elsefold()|Proj(p,r,c)whenRedFlags.red_projectionflagsp->(letnpars=Projection.nparspinmatchReductionBehaviour.get(Projection.constantp)with|None->letstack'=(c,Stack.Proj(p,r,cst_l)::stack)inletstack'',csts=whrecCst_stack.emptystack'inifequal_stacksenvsigmastack'stack''thenfold()elsestack'',csts|Somebehavior->beginmatchbehaviorwith|NeverUnfold->fold()|(UnfoldWhen{nargs=Somen}|UnfoldWhenNoMatch{nargs=Somen})whenStack.args_sizestack<n-(npars+1)->fold()|UnfoldWhen{recargs}|UnfoldWhenNoMatch{recargs}->(* maybe unfolds *)letrecargs=List.map_filter(funx->letidx=x-nparsinifidx<0thenNoneelseSomeidx)recargsinletvolatile=matchbehaviorwith|UnfoldWhen{nargs}->Option.has_somenargs|UnfoldWhenNoMatch_|NeverUnfold->falseinmatchrecargswith|[]->(* if nargs has been specified *)(* CAUTION : the constant is NEVER refold
(even when it hides a (co)fix) *)letstack'=(c,Stack.Proj(p,r,cst_l)::stack)inwhrecCst_stack.empty(* cst_l *)stack'|curr::remains->ifcurr==0then(* Try to reduce the record argument *)letcst_l=Stack.Cst{const=Stack.Cst_proj(p,r);volatile;curr;remains;params=Stack.empty;cst_l;}inwhrecCst_stack.empty(c,cst_l::stack)elsematchStack.strip_n_appcurrstackwith|None->fold()|Some(bef,arg,s')->letcst_l=Stack.Cst{const=Stack.Cst_proj(p,r);curr;remains;volatile;params=Stack.append_app[|c|]bef;cst_l;}inwhrecCst_stack.empty(arg,cst_l::s')end)|LetIn(_,b,_,c)whenRedFlags.red_setflagsRedFlags.fZETA->let(cst_l,p)=apply_subst[b]sigmacst_lcstackinwhreccst_lp|Cast(c,_,_)->whreccst_l(c,stack)|App(f,cl)->whrec(Cst_stack.add_argsclcst_l)(f,Stack.append_appclstack)|Lambda(na,t,c)->(matchStack.decompstackwith|Some_whenRedFlags.red_setflagsRedFlags.fBETA->let(cst_l,p)=apply_subst[]sigmacst_lxstackinwhreccst_lp|_->fold())|Case(ci,u,pms,p,iv,d,lf)->whrecCst_stack.empty(d,Stack.Case((ci,u,pms,p,iv,lf),cst_l)::stack)|Fix((ri,n),_asf)->(matchStack.strip_n_appri.(n)stackwith|None->fold()|Some(bef,arg,s')->whrecCst_stack.empty(arg,Stack.Fix(f,bef,cst_l)::s'))|Construct(cstr,u)->letuse_match=RedFlags.red_setflagsRedFlags.fMATCHinletuse_fix=RedFlags.red_setflagsRedFlags.fFIXinifuse_match||use_fixthenmatchStack.strip_appstackwith|args,(Stack.Case(case,_)::s')whenuse_match->letr=apply_branchenvsigmacstrargscaseinwhrecCst_stack.empty(r,s')|args,(Stack.Proj(p,_,_)::s')whenuse_match->whrecCst_stack.empty(Stack.nthargs(Projection.nparsp+Projection.argp),s')|args,(Stack.Fix(f,s',cst_l)::s'')whenuse_fix->letx'=Stack.zipsigma(x,args)inletout_sk=s'@(Stack.append_app[|x'|]s'')inreduce_and_refold_fixwhrecenvsigmacst_lfout_sk|args,(Stack.Cst{const;curr;remains;volatile;params=s';cst_l}::s'')->letx'=Stack.zipsigma(x,args)inbeginmatchremainswith|[]->(matchconstwith|Stack.Cst_constconst->(matchconstant_opt_value_inenvconstwith|None->fold()|Somebody->letconst=(fstconst,EInstance.make(sndconst))inletbody=EConstr.of_constrbodyinletcst_l=Cst_stack.add_cst~volatile(mkConstUconst)cst_linwhreccst_l(body,s'@(Stack.append_app[|x'|]s'')))|Stack.Cst_proj(p,r)->letstack=s'@(Stack.append_app[|x'|]s'')inmatchStack.strip_n_app0stackwith|None->assertfalse|Some(_,arg,s'')->whrecCst_stack.empty(arg,Stack.Proj(p,r,cst_l)::s''))|next::remains'->matchStack.strip_n_app(next-curr-1)s''with|None->fold()|Some(bef,arg,s''')->letcst_l=Stack.Cst{const;curr=next;volatile;remains=remains';params=s'@(Stack.append_app[|x'|]bef);cst_l;}inwhrecCst_stack.empty(arg,cst_l::s''')end|_,(Stack.App_)::_->assertfalse|_,_->fold()elsefold()|CoFixcofix->ifRedFlags.red_setflagsRedFlags.fCOFIXthenmatchStack.strip_appstackwith|args,((Stack.Case_|Stack.Proj_)::s')->reduce_and_refold_cofixwhrecenvsigmacst_lcofixstack|_->fold()elsefold()|Int_|Float_|String_|Array_->beginmatchStack.strip_appstackwith|(_,Stack.Primitive(p,(_,uaskn),rargs,kargs,cst_l')::s)->letmore_to_reduce=List.exists(funk->CPrimitives.Kwhnf=k)kargsinifmore_to_reducethenlet(kargs,o)=Stack.get_next_primitive_argskargssin(* Should not fail because Primitive is put on the stack only if fully applied *)let(before,a,after)=Option.getoinwhrecCst_stack.empty(a,Stack.Primitive(p,kn,rargs@Stack.append_app[|x|]before,kargs,cst_l')::after)elseletn=List.lengthkargsinlet(args,s)=Stack.strip_appsinlet(args,extra_args)=tryList.chopnargswithList.IndexOutOfRange->(args,[])(* FIXME probably useless *)inlets=extra_args@sinletargs=Array.of_list(Option.get(Stack.list_of_app_stack(rargs@Stack.append_app[|x|]args)))inbeginmatchCredNative.red_primenvsigmapuargswith|Somet->whreccst_l'(t,s)|None->((mkApp(mkConstUkn,args),s),cst_l)end|_->fold()end|Rel_|Var_|LetIn_|Proj_->fold()|Sort_|Ind_|Prod_->fold()infunxs->let(s,cst_lasres)=whrec(Option.defaultCst_stack.emptycsts)xsin(Stack.best_statesigmascst_l)letwhd_cbnflagsenvsigmat=letstate=whd_state_genflagsenvsigma(t,Stack.empty)inStack.zip~refold:truesigmastateletnorm_cbnflagsenvsigmat=letpush_rel_check_zetadenv=letopenRedFlagsinletd=matchdwith|LocalDef(na,c,t)whennot(red_setflagsfZETA)->LocalAssum(na,t)|d->dinpush_reldenvinletrecstrongrecenvt=map_constr_with_full_bindersenvsigmapush_rel_check_zetastrongrecenv(whd_cbnflagsenvsigmat)instrongrecenvt