123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002(************************************************************************)(* * The Rocq Prover / The Rocq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openUtilopenNamesopenConstropenVarsopenEsubst(**** Call by value reduction ****)(* The type of terms with closure. The meaning of the constructors and
* the invariants of this datatype are the following:
* VAL(k,c) represents the constr c with a delayed shift of k. c must be
* in normal form and neutral (i.e. not a lambda, a construct or a
* (co)fix, because they may produce redexes by applying them,
* or putting them in a case)
* STACK(k,v,stk) represents an irreductible value [v] in the stack [stk].
* [k] is a delayed shift to be applied to both the value and
* the stack.
* LAMBDA(n,a,b,S) is the term [S]([x:a]b) where [a] is a list of bindings and
* [n] is the length of [a]. the environment [S] is propagated
* only when the abstraction is applied, and then we use the rule
* ([S]([x:a]b) c) --> [S.c]b
* This corresponds to the usual strategy of weak reduction
* PROD(na,t,u,S) is the term [S](forall na:t, u).
* LETIN(na,b,t,S) is the term [S](let na:= b : t in.c).
* FIX(op,bd,S,args) is the fixpoint (Fix or Cofix) of bodies bd under
* the bindings S, and then applied to args. Here again,
* weak reduction.
* CONSTRUCT(c,args) is the constructor [c] applied to [args].
* PRIMITIVE(cop,args) represent a particial application of
* a primitive, or a fully applied primitive
* which does not reduce.
* cop is the constr representing op.
*
*)typecbv_value=|VALofint*constr|STACKofint*cbv_value*cbv_stack|LAMBDAofint*(Name.tConstr.binder_annot*types)list*constr*cbv_valuesubs|PRODofName.tConstr.binder_annot*types*types*cbv_valuesubs|LETINofName.tConstr.binder_annot*cbv_value*types*constr*cbv_valuesubs|FIXoffixpoint*cbv_valuesubs*cbv_valuearray|COFIXofcofixpoint*cbv_valuesubs*cbv_valuearray|CONSTRUCTofconstructorUVars.puniverses*cbv_valuearray|PRIMITIVEofCPrimitives.t*pconstant*cbv_valuearray|ARRAYofUVars.Instance.t*cbv_valueParray.t*cbv_value|SYMBOLof{cst:Constant.tUVars.puniverses;unfoldfix:bool;rules:Declarations.rewrite_rulelist;stk:cbv_stack}(* type of terms with a hole. This hole can appear only under App or Case.
* TOP means the term is considered without context
* APP(v,stk) means the term is applied to v, and then the context stk
* (v.0 is the first argument).
* this corresponds to the application stack of the KAM.
* The members of l are values: we evaluate arguments before
calling the function.
* CASE(t,br,pat,S,stk) means the term is in a case (which is himself in stk
* t is the type of the case and br are the branches, all of them under
* the subs S, pat is information on the patterns of the Case
* (Weak reduction: we propagate the sub only when the selected branch
* is determined)
* PROJ(p,pb,stk) means the term is in a primitive projection p, itself in stk.
* pb is the associated projection body
*
* Important remark: the APPs should be collapsed:
* (APP (l,(APP ...))) forbidden
*)andcbv_stack=|TOP|APPofcbv_valuelist*cbv_stack|CASEofUVars.Instance.t*constrarray*case_return*case_brancharray*Constr.case_invert*case_info*cbv_valuesubs*cbv_stack|PROJofProjection.t*Sorts.relevance*cbv_stack(* les vars pourraient etre des constr,
cela permet de retarder les lift: utile ?? *)(* relocation of a value; used when a value stored in a context is expanded
* in a larger context. e.g. [%k (S.t)](k+1) --> [^k]t (t is shifted of k)
*)letrecshift_valuen=function|VAL(k,t)->VAL(k+n,t)|STACK(k,v,stk)->STACK(k+n,v,stk)|PROD(na,t,u,s)->PROD(na,t,u,subs_shft(n,s))|LETIN(na,b,t,c,s)->LETIN(na,shift_valuenb,t,c,subs_shft(n,s))|LAMBDA(nlams,ctxt,b,s)->LAMBDA(nlams,ctxt,b,subs_shft(n,s))|FIX(fix,s,args)->FIX(fix,subs_shft(n,s),Array.map(shift_valuen)args)|COFIX(cofix,s,args)->COFIX(cofix,subs_shft(n,s),Array.map(shift_valuen)args)|CONSTRUCT(c,args)->CONSTRUCT(c,Array.map(shift_valuen)args)|PRIMITIVE(op,c,args)->PRIMITIVE(op,c,Array.map(shift_valuen)args)|ARRAY(u,t,ty)->ARRAY(u,Parray.map(shift_valuen)t,shift_valuenty)|SYMBOLs->SYMBOL{swithstk=shift_stackns.stk}andshift_stackn=function(* Slow *)|TOP->TOP|APP(args,stk)->APP(List.map(shift_valuen)args,shift_stacknstk)|CASE(u,pms,c,b,iv,i,s,stk)->CASE(u,pms,c,b,iv,i,subs_shft(n,s),shift_stacknstk)|PROJ(p,r,stk)->PROJ(p,r,shift_stacknstk)letshift_valuenv=ifInt.equaln0thenvelseshift_valuenv(* Contracts a fixpoint: given a fixpoint and a bindings,
* returns the corresponding fixpoint body, and the bindings in which
* it should be evaluated: its first variables are the fixpoint bodies
* (S, (fix Fi {F0 := T0 .. Fn-1 := Tn-1}))
* -> (S. [S]F0 . [S]F1 ... . [S]Fn-1, Ti)
*)letrecmk_fix_subsmake_bodynenvi=ifInt.equalinthenenvelsemk_fix_subsmake_bodyn(subs_cons(make_bodyi)env)(i+1)letcontract_fixpenv((reci,i),(_,_,bdsasbodies))=letmake_bodyj=FIX(((reci,j),bodies),env,[||])inletn=Array.lengthbdsinmk_fix_subsmake_bodynenv0,bds.(i)letcontract_cofixpenv(i,(_,_,bdsasbodies))=letmake_bodyj=COFIX((j,bodies),env,[||])inletn=Array.lengthbdsinmk_fix_subsmake_bodynenv0,bds.(i)letmake_constr_refnkt=matchkwith|RelKeyp->mkRel(n+p)|VarKeyid->t|ConstKeycst->t(* Adds an application list. Collapse APPs! *)letstack_vect_appapplstack=ifInt.equal(Array.lengthappl)0thenstackelsematchstackwith|APP(args,stk)->APP(Array.fold_right(funvaccu->v::accu)applargs,stk)|_->APP(Array.to_listappl,stack)letstack_appapplstack=ifList.is_emptyapplthenstackelsematchstackwith|APP(args,stk)->APP(appl@args,stk)|_->APP(appl,stack)letrecstack_concatstk1stk2=matchstk1withTOP->stk2|APP(v,stk1')->APP(v,stack_concatstk1'stk2)|CASE(u,pms,c,b,iv,i,s,stk1')->CASE(u,pms,c,b,iv,i,s,stack_concatstk1'stk2)|PROJ(p,r,stk1')->PROJ(p,r,stack_concatstk1'stk2)(* merge stacks when there is no shifts in between *)letmkSTACK=functionv,TOP->v|STACK(0,v0,stk0),stk->STACK(0,v0,stack_concatstk0stk)|v,stk->STACK(0,v,stk)moduleKeyTable=Hashtbl.Make(structtypet=Constant.tUVars.puniversestableKeyletequal=Names.eq_table_key(eq_paireq_constant_keyUVars.Instance.equal)lethash=Names.hash_table_key(fun(c,_)->Constant.UserOrd.hashc)end)typecbv_infos={env:Environ.env;tab:(cbv_value,Empty.t,bool*Declarations.rewrite_rulelist)Declarations.constant_defKeyTable.t;reds:RedFlags.reds;sigma:Evd.evar_map;strong:bool;}(* Change: zeta reduction cannot be avoided in CBV *)openRedFlagsletred_set_refflags=function|RelKey_->red_setflagsfDELTA|VarKeyid->red_setflags(fVARid)|ConstKey(sp,_)->red_setflags(fCONSTsp)(* Transfer application lists from a value to the stack
* useful because fixpoints may be totally applied in several times.
* On the other hand, irreductible atoms absorb the full stack.
*)letstrip_applheadstack=matchheadwith|FIX(fix,env,app)->(FIX(fix,env,[||]),stack_vect_appappstack)|COFIX(cofix,env,app)->(COFIX(cofix,env,[||]),stack_vect_appappstack)|CONSTRUCT(c,app)->(CONSTRUCT(c,[||]),stack_vect_appappstack)|PRIMITIVE(op,c,app)->(PRIMITIVE(op,c,[||]),stack_vect_appappstack)|LETIN_|VAL_|STACK_|PROD_|LAMBDA_|ARRAY_|SYMBOL_->(head,stack)letdestackheadstack=matchheadwith|FIX(fix,env,app)->(FIX(fix,env,[||]),stack_vect_appappstack)|COFIX(cofix,env,app)->(COFIX(cofix,env,[||]),stack_vect_appappstack)|CONSTRUCT(c,app)->(CONSTRUCT(c,[||]),stack_vect_appappstack)|PRIMITIVE(op,c,app)->(PRIMITIVE(op,c,[||]),stack_vect_appappstack)|STACK(k,v,stk)->(shift_valuekv,stack_concat(shift_stackkstk)stack)|SYMBOL({stk}ass)->(SYMBOL{swithstk=TOP},stack_concatstkstack)|LETIN_|VAL_|PROD_|LAMBDA_|ARRAY_->(head,stack)letrecfixp_reducible_symb_stk=function|TOP->true|APP(_,stk)->fixp_reducible_symb_stkstk|CASE_|PROJ_->false(* Tests if fixpoint reduction is possible. *)letfixp_reducibleflgs((reci,i),_)stk=ifred_setflgsfFIXthenmatchstkwith|APP(appl,_)->letreccheckn=function|[]->false|v::appl->ifInt.equaln0thenmatchvwith|CONSTRUCT_->true|SYMBOL{unfoldfix=true;stk;_}->fixp_reducible_symb_stkstk|_->falseelsecheck(n-1)applincheckreci.(i)appl|_->falseelsefalseletcofixp_reducibleflgs_stk=ifred_setflgsfCOFIXthenmatchstkwith|(CASE_|PROJ_|APP(_,CASE_)|APP(_,PROJ_))->true|_->falseelsefalseletdebug_cbv=CDebug.create~name:"Cbv"()(* Reduction of primitives *)openPrimredmoduleVNativeEntries=structtypeelem=cbv_valuetypeargs=cbv_valuearraytypeevd=unittypeuinstance=UVars.Instance.tletget=Array.getletget_int()e=matchewith|VAL(_,ci)->(matchkindciwith|Inti->i|_->raisePrimred.NativeDestKO)|_->raisePrimred.NativeDestKOletget_float()e=matchewith|VAL(_,cf)->(matchkindcfwith|Floatf->f|_->raisePrimred.NativeDestKO)|_->raisePrimred.NativeDestKOletget_string()e=matchewith|VAL(_,cf)->(matchkindcfwith|Strings->s|_->raisePrimred.NativeDestKO)|_->raisePrimred.NativeDestKOletget_parray()e=matchewith|ARRAY(_u,t,_ty)->t|_->raisePrimred.NativeDestKOletmkIntenvi=VAL(0,mkInti)letmkFloatenvf=VAL(0,mkFloatf)letmkStringenvs=VAL(0,mkStrings)letmkBoolenvb=let(ct,cf)=get_bool_constructorsenvinCONSTRUCT(UVars.in_punivs(ifbthenctelsecf),[||])letint_tyenv=VAL(0,UnsafeMonomorphic.mkConst@@get_int_typeenv)letfloat_tyenv=VAL(0,UnsafeMonomorphic.mkConst@@get_float_typeenv)letmkCarryenvbe=let(c0,c1)=get_carry_constructorsenvinCONSTRUCT(UVars.in_punivs(ifbthenc1elsec0),[|int_tyenv;e|])letmkIntPairenve1e2=letint_ty=int_tyenvinletc=get_pair_constructorenvinCONSTRUCT(UVars.in_punivsc,[|int_ty;int_ty;e1;e2|])letmkFloatIntPairenvfi=letfloat_ty=float_tyenvinletint_ty=int_tyenvinletc=get_pair_constructorenvinCONSTRUCT(UVars.in_punivsc,[|float_ty;int_ty;f;i|])letmkLtenv=let(_eq,lt,_gt)=get_cmp_constructorsenvinCONSTRUCT(UVars.in_punivslt,[||])letmkEqenv=let(eq,_lt,_gt)=get_cmp_constructorsenvinCONSTRUCT(UVars.in_punivseq,[||])letmkGtenv=let(_eq,_lt,gt)=get_cmp_constructorsenvinCONSTRUCT(UVars.in_punivsgt,[||])letmkFLtenv=let(_eq,lt,_gt,_nc)=get_f_cmp_constructorsenvinCONSTRUCT(UVars.in_punivslt,[||])letmkFEqenv=let(eq,_lt,_gt,_nc)=get_f_cmp_constructorsenvinCONSTRUCT(UVars.in_punivseq,[||])letmkFGtenv=let(_eq,_lt,gt,_nc)=get_f_cmp_constructorsenvinCONSTRUCT(UVars.in_punivsgt,[||])letmkFNotComparableenv=let(_eq,_lt,_gt,nc)=get_f_cmp_constructorsenvinCONSTRUCT(UVars.in_punivsnc,[||])letmkPNormalenv=let(pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivspNormal,[||])letmkNNormalenv=let(_pNormal,nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivsnNormal,[||])letmkPSubnenv=let(_pNormal,_nNormal,pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivspSubn,[||])letmkNSubnenv=let(_pNormal,_nNormal,_pSubn,nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivsnSubn,[||])letmkPZeroenv=let(_pNormal,_nNormal,_pSubn,_nSubn,pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivspZero,[||])letmkNZeroenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivsnZero,[||])letmkPInfenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivspInf,[||])letmkNInfenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,nInf,_nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivsnInf,[||])letmkNaNenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,nan)=get_f_class_constructorsenvinCONSTRUCT(UVars.in_punivsnan,[||])letmkArrayenvutty=ARRAY(u,t,ty)endmoduleVredNative=RedNative(VNativeEntries)letdebug_pr_key=function|ConstKey(sp,_)->Names.Constant.printsp|VarKeyid->Names.Id.printid|RelKeyn->Pp.(str"REL_"++intn)letrecreify_stackt=function|TOP->t|APP(args,st)->reify_stack(mkApp(t,Array.map_of_listreify_valueargs))st|CASE(u,pms,ty,br,iv,ci,env,st)->reify_stack(apply_envenv@@mkCase(ci,u,pms,ty,iv,t,br))st|PROJ(p,r,st)->reify_stack(mkProj(p,r,t))standreify_value=function(* reduction under binders *)|VAL(n,t)->liftnt|STACK(0,v,stk)->reify_stack(reify_valuev)stk|STACK(n,v,stk)->liftn(reify_stack(reify_valuev)stk)|PROD(na,t,u,env)->apply_envenv(mkProd(na,t,u))|LETIN(na,b,t,c,env)->apply_envenv(mkLetIn(na,reify_valueb,t,c))|LAMBDA(k,ctxt,b,env)->apply_envenv@@List.fold_left(func(n,t)->mkLambda(n,t,c))bctxt|FIX((lij,fix),env,args)->letfix=mkFix(lij,fix)inmkApp(apply_envenvfix,Array.mapreify_valueargs)|COFIX((j,cofix),env,args)->letcofix=mkCoFix(j,cofix)inmkApp(apply_envenvcofix,Array.mapreify_valueargs)|CONSTRUCT(c,args)->mkApp(mkConstructUc,Array.mapreify_valueargs)|PRIMITIVE(op,c,args)->mkApp(mkConstUc,Array.mapreify_valueargs)|ARRAY(u,t,ty)->lett,def=Parray.to_arraytinmkArray(u,Array.mapreify_valuet,reify_valuedef,reify_valuety)|SYMBOL{cst;stk;_}->reify_stack(mkConstUcst)stkandapply_envenvt=matchkindtwith|Reli->beginmatchexpand_relienvwith|Inl(k,v)->reify_value(shift_valuekv)|Inr(k,_)->mkRelkend|_->map_with_binderssubs_liftapply_envenvtletapply_env_contextectx=letopenContext.Rel.Declarationinletrecsubst_contextctx=matchctxwith|[]->e,[]|LocalAssum(na,ty)::ctx->lete,ctx=subst_contextctxinletty=apply_envetyinsubs_lifte,LocalAssum(na,ty)::ctx|LocalDef(na,ty,bdy)::ctx->lete,ctx=subst_contextctxinletty=apply_envetyinletbdy=apply_envebdyinsubs_lifte,LocalDef(na,ty,bdy)::ctxinsnd@@subst_contextctxletrecstrip_app=function|APP(args,st)->APP(args,strip_appst)|s->TOP(* TODO: share the common parts with EConstr *)letexpand_branchenvupms(ind,i)br=letopenDeclarationsinletnas,_br=br.(i-1)inlet(mib,mip)=Inductive.lookup_mind_specifenvindinletparamdecl=Vars.subst_instance_contextumib.mind_params_ctxtinletparamsubst=Vars.subst_of_rel_context_instanceparamdeclpmsinlet(ctx,_)=mip.mind_nf_lc.(i-1)inlet(ctx,_)=List.chopmip.mind_consnrealdecls.(i-1)ctxinInductive.instantiate_contextuparamsubstnasctxletcbv_subst_of_rel_context_instance_listmkclossignargsenv=letrecauxsubstsignl=letopenContext.Rel.Declarationinmatchsign,lwith|LocalAssum_::sign',a::args'->aux(subs_consasubst)sign'args'|LocalDef(_,c,_)::sign',args'->aux(subs_cons(mkclossubstc)subst)sign'args'|[],[]->subst|_->CErrors.anomaly(Pp.str"Instance and signature do not match.")inauxenv(List.revsign)args(* The main recursive functions
*
* Go under applications and cases/projections (pushed in the stack),
* expand head constants or substitued de Bruijn, and try to a make a
* constructor, a lambda or a fixp appear in the head. If not, it is a value
* and is completely computed here. The head redexes are NOT reduced:
* the function returns the pair of a cbv_value and its stack. *
* Invariant: if the result of norm_head is CONSTRUCT or (CO)FIX, its last
* argument is []. Because we must put all the applied terms in the
* stack. *)exceptionPatternFailureletrecnorm_headinfoenvtstack=(* no reduction under binders *)matchkindtwith(* stack grows (remove casts) *)|App(head,args)->(* Applied terms are normalized immediately;
they could be computed when getting out of the stack *)letfoldcaccu=cbv_stack_terminfoTOPenvc::accuinletrem,stack=matchstackwith|APP(nargs,stack)->nargs,stack|_->[],stackinletstack=APP(Array.fold_rightfoldargsrem,stack)innorm_headinfoenvheadstack|Case(ci,u,pms,p,iv,c,v)->norm_headinfoenvc(CASE(u,pms,p,v,iv,ci,env,stack))|Cast(ct,_,_)->norm_headinfoenvctstack|Proj(p,r,c)->letp'=ifred_setinfo.reds(fPROJ(Projection.reprp))thenProjection.unfoldpelsepinnorm_headinfoenvc(PROJ(p',r,stack))(* constants, axioms
* the first pattern is CRUCIAL, n=0 happens very often:
* when reducing closed terms, n is always 0 *)|Reli->(matchexpand_relienvwith|Inl(0,v)->strip_applvstack|Inl(n,v)->strip_appl(shift_valuenv)stack|Inr(n,None)->(VAL(0,mkReln),stack)|Inr(n,Somep)->norm_head_ref(n-p)infoenvstack(RelKeyp)t)|Varid->norm_head_ref0infoenvstack(VarKeyid)t|Constsp->Reductionops.reduction_effect_hookinfo.envinfo.sigma(fstsp)(lazy(reify_stackt(strip_appstack)));norm_head_ref0infoenvstack(ConstKeysp)t|LetIn(na,b,u,c)->(* zeta means letin are contracted; delta without zeta means we *)(* allow bindings but leave let's in place *)ifred_setinfo.redsfZETAthen(* New rule: for Cbv, Delta does not apply to locally bound variables
or red_set info.reds fDELTA
*)letenv'=subs_cons(cbv_stack_terminfoTOPenvb)envinnorm_headinfoenv'cstackelse(* Note: we may also consider a commutative cut! *)LETIN(na,cbv_stack_terminfoTOPenvb,u,c,env),stack|Evar((e,_)asev)->(matchEvd.existential_opt_value0info.sigmaevwithSomec->norm_headinfoenvcstack|None->letev=EConstr.of_existentialevinletmapc=EConstr.of_constr@@apply_envenv(EConstr.Unsafe.to_constrc)inletev'=EConstr.map_existentialinfo.sigmamapevin(VAL(0,EConstr.Unsafe.to_constr@@EConstr.mkEvarev'),stack))(* non-neutral cases *)|Lambda_->letctxt,b=Term.decompose_lambdatin(LAMBDA(List.lengthctxt,List.revctxt,b,env),stack)|Fixfix->(FIX(fix,env,[||]),stack)|CoFixcofix->(COFIX(cofix,env,[||]),stack)|Constructc->(CONSTRUCT(c,[||]),stack)|Array(u,t,def,ty)->letty=cbv_stack_terminfoTOPenvtyinletlen=Array.lengthtinlett=Parray.init(Uint63.of_intlen)(funi->cbv_stack_terminfoTOPenvt.(i))(cbv_stack_terminfoTOPenvdef)in(ARRAY(u,t,ty),stack)(* neutral cases *)|(Sort_|Meta_|Ind_|Int_|Float_|String_)->(VAL(0,t),stack)|Prod(na,t,u)->(PROD(na,t,u,env),stack)andnorm_head_refkinfoenvstacknormtt=ifred_set_refinfo.redsnormtthenmatchcbv_value_cacheinfonormtwith|Declarations.Defbody->debug_cbv(fun()->Pp.(str"Unfolding "++debug_pr_keynormt));strip_appl(shift_valuekbody)stack|Declarations.Primitiveop->letc=matchnormtwith|ConstKeyc->c|RelKey_|VarKey_->assertfalsein(PRIMITIVE(op,c,[||]),stack)|Declarations.Symbol(unfoldfix,rules)->assert(k=0);letcst=matchnormtwith|ConstKeyc->c|RelKey_|VarKey_->assertfalsein(SYMBOL{cst;unfoldfix;rules;stk=TOP},stack)|Declarations.OpaqueDef_|Declarations.Undef_->debug_cbv(fun()->Pp.(str"Not unfolding "++debug_pr_keynormt));(VAL(0,make_constr_refknormtt),stack)elsebegindebug_cbv(fun()->Pp.(str"Not unfolding "++debug_pr_keynormt));(VAL(0,make_constr_refknormtt),stack)end(* cbv_stack_term performs weak reduction on constr t under the subs
* env, with context stack, i.e. ([env]t stack). First computes weak
* head normal form of t and checks if a redex appears with the stack.
* If so, recursive call to reach the real head normal form. If not,
* we build a value.
*)andcbv_stack_terminfostackenvt=cbv_stack_valueinfoenv(norm_headinfoenvtstack)andcbv_stack_valueinfoenv=function(* a lambda meets an application -> BETA *)|(LAMBDA(nlams,ctxt,b,env),APP(args,stk))whenred_setinfo.redsfBETA->letrecapplyenvlamsargs=ifInt.equallams0thenletstk=ifList.is_emptyargsthenstkelseAPP(args,stk)incbv_stack_terminfostkenvbelsematchargswith|[]->letctxt'=List.skipn(nlams-lams)ctxtinLAMBDA(lams,ctxt',b,env)|v::args->letenv=subs_consvenvinapplyenv(lams-1)argsinapplyenvnlamsargs(* a Fix applied enough -> IOTA *)|(FIX(fix,env,[||]),stk)whenfixp_reducibleinfo.redsfixstk->let(envf,redfix)=contract_fixpenvfixincbv_stack_terminfostkenvfredfix(* constructor guard satisfied or Cofix in a Case -> IOTA *)|(COFIX(cofix,env,[||]),stk)whencofixp_reducibleinfo.redscofixstk->let(envf,redfix)=contract_cofixpenvcofixincbv_stack_terminfostkenvfredfix(* constructor in a Case -> IOTA *)|(CONSTRUCT(((sp,n),_),[||]),APP(args,CASE(u,pms,_p,br,iv,ci,env,stk)))whenred_setinfo.redsfMATCH->letcargs=List.skipnci.ci_nparargsinletenv=if(Int.equalci.ci_cstr_ndecls.(n-1)ci.ci_cstr_nargs.(n-1))then(* no lets *)List.fold_left(funaccuv->subs_consvaccu)envcargselseletmkclosenvc=cbv_stack_terminfoTOPenvcinletctx=expand_branchinfo.envupms(sp,n)brincbv_subst_of_rel_context_instance_listmkclosctxcargsenvincbv_stack_terminfostkenv(sndbr.(n-1))(* constructor of arity 0 in a Case -> IOTA *)|(CONSTRUCT(((sp,n),_),[||]),CASE(u,pms,_,br,_,ci,env,stk))whenred_setinfo.redsfMATCH->letenv=if(Int.equalci.ci_cstr_ndecls.(n-1)ci.ci_cstr_nargs.(n-1))then(* no lets *)envelseletmkclosenvc=cbv_stack_terminfoTOPenvcinletctx=expand_branchinfo.envupms(sp,n)brincbv_subst_of_rel_context_instance_listmkclosctx[]envincbv_stack_terminfostkenv(sndbr.(n-1))(* constructor in a Projection -> IOTA *)|(CONSTRUCT(((sp,n),u),[||]),APP(args,PROJ(p,_,stk)))whenred_setinfo.redsfMATCH&&Projection.unfoldedp->letarg=List.nthargs(Projection.nparsp+Projection.argp)incbv_stack_valueinfoenv(strip_applargstk)(* may be reduced later by application *)|(FIX(fix,env,[||]),APP(appl,TOP))->FIX(fix,env,Array.of_listappl)|(COFIX(cofix,env,[||]),APP(appl,TOP))->COFIX(cofix,env,Array.of_listappl)|(CONSTRUCT(c,[||]),APP(appl,TOP))->CONSTRUCT(c,Array.of_listappl)(* primitive apply to arguments *)|(PRIMITIVE(op,(_,uasc),[||]),APP(appl,stk))->letnargs=CPrimitives.arityopinbeginmatchList.chopnargsapplwith|(args,appl)->letstk=ifList.is_emptyapplthenstkelsestack_appapplstkinbeginmatchVredNative.red_priminfo.env()opu(Array.of_listargs)with|Some(CONSTRUCT(c,args))->(* args must be moved to the stack to allow future reductions *)cbv_stack_valueinfoenv(CONSTRUCT(c,[||]),stack_vect_appargsstk)|Somev->cbv_stack_valueinfoenv(v,stk)|None->mkSTACK(PRIMITIVE(op,c,Array.of_listargs),stk)end|exceptionFailure_->(* partial application *)(assert(stk=TOP);PRIMITIVE(op,c,Array.of_listappl))end|SYMBOL({cst;rules;stk}ass),stk'->letstk=stack_concatstkstk'inbegintryletrhs,stack=cbv_apply_rulesinfoenv(sndcst)rulesstkincbv_stack_valueinfoenv(destackrhsstack)withPatternFailure->SYMBOL{swithstk}end(* definitely a value *)|(head,stk)->mkSTACK(head,stk)andcbv_value_cacheinforef=tryKeyTable.findinfo.tabrefwithNot_found->letv=tryletbody=matchrefwith|RelKeyn->letopenContext.Rel.DeclarationinbeginmatchEnviron.lookup_relninfo.envwith|LocalDef(_,c,_)->liftnc|LocalAssum_->raiseNot_foundend|VarKeyid->letopenContext.Named.DeclarationinbeginmatchEnviron.lookup_namedidinfo.envwith|LocalDef(_,c,_)->c|LocalAssum_->raiseNot_foundend|ConstKeycst->Environ.constant_value_ininfo.envcstinletv=cbv_stack_terminfoTOP(subs_id0)bodyinDeclarations.Defvwith|Environ.NotEvaluableConst(Environ.IsPrimitive(_u,op))->Declarations.Primitiveop|Environ.NotEvaluableConst(Environ.HasRules(u,b,r))->Declarations.Symbol(b,r)|Not_found|Environ.NotEvaluableConst_->Declarations.UndefNoneinKeyTable.addinfo.tabrefv;vandit_mkLambda_or_LetIninfoctxt=letopenContext.Rel.DeclarationinmatchList.revctxwith|[]->t|LocalAssum(n,ty)::ctx->letassums,ctx=List.map_until(functionLocalAssum(n,ty)->Some(n,ty)|LocalDef_->None)ctxinletassums=(n,ty)::assumsinLAMBDA(List.lengthassums,assums,Term.it_mkLambda_or_LetIn(reify_valuet)(List.revctx),subs_id0)|LocalDef_::_->cbv_stack_terminfoTOP(subs_id0)(Term.it_mkLambda_or_LetIn(reify_valuet)ctx)andcbv_match_arg_patterninfoenvctxpsubstpt=letopenDeclarationsinlett'=it_mkLambda_or_LetIninfoctxtinmatchpwith|EHolei->Partial_subst.add_termit'psubst|EHoleIgnored->psubst|ERigid(ph,es)->lett,stk=destacktTOPinletpsubst=cbv_match_rigid_arg_patterninfoenvctxpsubstphtinletpsubst,stk=cbv_apply_ruleinfoenvctxpsubstesstkinmatchstkwith|TOP->psubst|APP_|CASE_|PROJ_->raisePatternFailureandcbv_match_arg_pattern_liftinfoenvctxnpsubstpt=letenv=subs_liftnnenvincbv_match_arg_patterninfoenvctxpsubstp(cbv_stack_terminfoTOPenvt)andmatch_sortpsssubst=matchSorts.pattern_matchpsssubstwith|Somesubst->subst|None->raisePatternFailureandmatch_instancepuupsubst=matchUVars.Instance.pattern_matchpuupsubstwith|Somesubst->subst|None->raisePatternFailureandcbv_match_rigid_arg_patterninfoenvctxpsubstpt=letopenDeclarationsinmatch[@ocaml.warning"-4"]p,twith|PHInd(ind,pu),VAL(0,t')->beginmatchkindt'withInd(ind',u)whenInd.CanOrd.equalindind'->match_instancepuupsubst|_->raisePatternFailureend|PHConstr(constr,pu),CONSTRUCT((constr',u),[||])->ifConstruct.CanOrd.equalconstrconstr'thenmatch_instancepuupsubstelseraisePatternFailure|PHReli,VAL(k,t')->beginmatchkindt'withRelnwhenInt.equali(k+n)->psubst|_->raisePatternFailureend|PHSortps,VAL(0,t')->beginmatchkindt'withSorts->match_sortpsspsubst|_->raisePatternFailureend|PHSymbol(c,pu),SYMBOL{cst=c',u;_}->ifConstant.CanOrd.equalcc'thenmatch_instancepuupsubstelseraisePatternFailure|PHInti,VAL(0,t')->beginmatchkindt'withInti'whenUint63.equalii'->psubst|_->raisePatternFailureend|PHFloatf,VAL(0,t')->beginmatchkindt'withFloatf'whenFloat64.equalff'->psubst|_->raisePatternFailureend|PHStrings,VAL(0,t')->beginmatchkindt'withStrings'whenPstring.equalss'->psubst|_->raisePatternFailureend|PHLambda(ptys,pbod),LAMBDA(nlam,ntys,body,env)->letnp=Array.lengthptysinifnp>nlamthenraisePatternFailure;letntys,body=ifnp=nlamthenntys,bodyelse(* np < nlam *)letntys,tys'=List.chopnpntysinntys,Term.compose_lam(List.revtys')bodyinletctx'=List.rev_map(fun(n,ty)->Context.Rel.Declaration.LocalAssum(n,ty))ntysinletctx'=apply_env_contextenvctx'inlettys=Array.of_listntysinletcontexts_upto=Array.initnp(funi->List.lastnictx'@ctx)inletpsubst=Array.fold_left3_i(funipsubstctxpty(_,ty)->cbv_match_arg_pattern_liftinfoenvctxipsubstptyty)psubstcontexts_uptoptystysinletpsubst=cbv_match_arg_pattern_liftinfoenv(ctx'@ctx)nppsubstpbodbodyinpsubst|PHProd(ptys,pbod),PROD(na,ty,body,env)->letntys,_=Term.decompose_prodbodyinletnp=Array.lengthptysinletnprod=1+List.lengthntysinifnp>nprodthenraisePatternFailure;letntys,body=Term.decompose_prod_n(np-1)bodyinletctx'=List.map(fun(n,ty)->Context.Rel.Declaration.LocalAssum(n,ty))(ntys@[na,ty])inletctx'=apply_env_contextenvctx'inlettys=Array.of_list((na,ty)::List.revntys)inletna=Array.lengthtysinletcontexts_upto=Array.initna(funi->List.lastnictx'@ctx)inletpsubst=Array.fold_left3_i(funipsubstctxpty(_,ty)->cbv_match_arg_pattern_liftinfoenvctxipsubstptyty)psubstcontexts_uptoptystysinletpsubst=cbv_match_arg_pattern_liftinfoenv(ctx'@ctx)napsubstpbodbodyinpsubst|(PHInd_|PHConstr_|PHRel_|PHInt_|PHFloat_|PHString_|PHSort_|PHSymbol_|PHLambda_|PHProd_),_->raisePatternFailureandcbv_apply_ruleinfoenvctxpsubstesstk=match[@ocaml.warning"-4"]es,stkwith|[],_->psubst,stk|Declarations.PEApppargs::e,APP(args,s)->letargs=Array.of_listargsinletnp=Array.lengthpargsinletna=Array.lengthargsinifnp==nathenletpsubst=Array.fold_left2(cbv_match_arg_patterninfoenvctx)psubstpargsargsincbv_apply_ruleinfoenvctxpsubsteselseifnp<nathen(* more real arguments *)letusedargs,remargs=Array.chopnpargsinletpsubst=Array.fold_left2(cbv_match_arg_patterninfoenvctx)psubstpargsusedargsincbv_apply_ruleinfoenvctxpsubste(APP(Array.to_listremargs,s))else(* more pattern arguments *)letusedpargs,rempargs=Array.chopnapargsinletpsubst=Array.fold_left2(cbv_match_arg_patterninfoenvctx)psubstusedpargsargsincbv_apply_ruleinfoenvctxpsubst(PEApprempargs::e)s|Declarations.PECase(pind,pu,pret,pbrs)::e,CASE(u,pms,(p,_),brs,iv,ci,env,s)->ifnot@@Ind.CanOrd.equalpindci.ci_indthenraisePatternFailure;letspecif=Inductive.lookup_mind_specifinfo.envci.ci_indinletntys_ret=Inductive.expand_arityspecif(ci.ci_ind,u)pms(fstp)inletntys_ret=apply_env_contextenvntys_retinletntys_brs=Inductive.expand_branch_contextsspecifupmsbrsinletpsubst=match_instancepuupsubstinletbrs=Array.map2(functx'br->List.lengthctx',ctx'@ctx,(sndbr))ntys_brsbrsinletpsubst=cbv_match_arg_pattern_liftinfoenv(ntys_ret@ctx)(List.lengthntys_ret)psubstpret(sndp)inletpsubst=Array.fold_left2(funpsubstpat(n,ctx,br)->cbv_match_arg_pattern_liftinfoenv(apply_env_contextenvctx)npsubstpatbr)psubstpbrsbrsincbv_apply_ruleinfoenvctxpsubstes|Declarations.PEProjproj::e,PROJ(proj',r,s)->ifnot@@Projection.(Repr.CanOrd.equalproj(reprproj'))thenraisePatternFailure;cbv_apply_ruleinfoenvctxpsubstes|_,_->raisePatternFailureandcbv_apply_rulesinfoenvurstk=matchrwith|[]->raisePatternFailure|{lhs_pat=(pu,elims);nvars;rhs}::rs->tryletpsubst=Partial_subst.makenvarsinletpsubst=match_instancepuupsubstinletpsubst,stk=cbv_apply_ruleinfoenv[]psubstelimsstkinletsubst,qsubst,usubst=Partial_subst.to_arrayspsubstinletsubst=Array.fold_rightsubs_conssubstenvinletusubst=UVars.Instance.of_array(qsubst,usubst)inletrhsu=Vars.subst_instance_construsubstrhsinletrhs'=cbv_stack_terminfoTOPsubstrhsuinrhs',stkwithPatternFailure->cbv_apply_rulesinfoenvursstk(* When we are sure t will never produce a redex with its stack, we
* normalize (even under binders) the applied terms and we build the
* final term
*)letrecapply_stackinfot=function|TOP->t|APP(args,st)->(* Note: should "theoretically" use a right-to-left version of map_of_list *)apply_stackinfo(mkApp(t,Array.map_of_list(cbv_norm_valueinfo)args))st|CASE(u,pms,ty,br,iv,ci,env,st)->(* FIXME: Prevent this expansion by caching whether an inductive contains let-bindings *)let(_,(ty,r),_,_,br)=Inductive.expand_caseinfo.env(ci,u,pms,ty,iv,mkProp,br)inletty=let(_,mip)=Inductive.lookup_mind_specifinfo.envci.ci_indinTerm.decompose_lambda_n_decls(mip.Declarations.mind_nrealdecls+1)tyinletmk_brcn=Term.decompose_lambda_n_declsncinletbr=Array.map2mk_brbrci.ci_cstr_ndeclsinletaux=ifinfo.strongthencbv_norm_terminfoelseapply_envinletmap_ctx(nas,c)=letopenContext.Rel.Declarationinletfolddecle=matchdeclwith|LocalAssum_->subs_lifte|LocalDef(_,b,_)->letb=cbv_stack_terminfoTOPebin(* The let-binding persists, so we have to shift *)subs_shft(1,subs_consbe)inletenv=List.fold_rightfoldnasenvinletnas=Array.of_list(List.rev_mapget_annotnas)in(nas,auxenvc)inapply_stackinfo(mkCase(ci,u,Array.map(auxenv)pms,(map_ctxty,r),iv,t,Array.mapmap_ctxbr))st|PROJ(p,r,st)->apply_stackinfo(mkProj(p,r,t))st(* performs the reduction on a constr, and returns a constr *)andcbv_norm_terminfoenvt=(* reduction under binders *)cbv_norm_valueinfo(cbv_stack_terminfoTOPenvt)(* reduction of a cbv_value to a constr *)andcbv_norm_valueinfo=function|VAL(n,t)->liftnt|STACK(0,v,stk)->apply_stackinfo(cbv_norm_valueinfov)stk|STACK(n,v,stk)->liftn(apply_stackinfo(cbv_norm_valueinfov)stk)|PROD(na,t,u,env)->mkProd(na,cbv_norm_terminfoenvt,cbv_norm_terminfo(subs_liftenv)u)|LETIN(na,b,t,c,env)->letaux=ifinfo.strongthencbv_norm_terminfoelseapply_envinmkLetIn(na,cbv_norm_valueinfob,auxenvt,aux(subs_liftenv)c)|LAMBDA(n,ctxt,b,env)->letnctxt=List.map_i(funi(x,ty)->(x,cbv_norm_terminfo(subs_liftnienv)ty))0ctxtinletaux=ifinfo.strongthencbv_norm_terminfoelseapply_envinTerm.compose_lam(List.revnctxt)(aux(subs_liftnnenv)b)|FIX((lij,(names,lty,bds)),env,args)->letaux=ifinfo.strongthencbv_norm_terminfoelseapply_envinmkApp(mkFix(lij,(names,Array.map(auxenv)lty,Array.map(aux(subs_liftn(Array.lengthlty)env))bds)),Array.map(cbv_norm_valueinfo)args)|COFIX((j,(names,lty,bds)),env,args)->mkApp(mkCoFix(j,(names,Array.map(cbv_norm_terminfoenv)lty,Array.map(cbv_norm_terminfo(subs_liftn(Array.lengthlty)env))bds)),Array.map(cbv_norm_valueinfo)args)|CONSTRUCT(c,args)->mkApp(mkConstructUc,Array.map(cbv_norm_valueinfo)args)|PRIMITIVE(op,c,args)->mkApp(mkConstUc,Array.map(cbv_norm_valueinfo)args)|ARRAY(u,t,ty)->letty=cbv_norm_valueinfotyinlett,def=Parray.to_arraytinletdef=cbv_norm_valueinfodefinmkArray(u,Array.map(cbv_norm_valueinfo)t,def,ty)|SYMBOL{cst;stk;_}->apply_stackinfo(mkConstUcst)stk(* with profiling *)letcbv_norminfosconstr=letconstr=EConstr.Unsafe.to_constrconstrinEConstr.of_constr(cbv_norm_terminfos(subs_id0)constr)(* constant bodies are normalized at the first expansion *)letcreate_cbv_infosreds~strongenvsigma={tab=KeyTable.create91;reds;env;sigma;strong}