123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamesopenConstropenVarsopenCClosureopenEsubst(**** 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.
* CBN(t,S) is the term [S]t. It is used to delay evaluation. For
* instance products are evaluated only when actually needed
* (CBN strategy).
* LAM(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
* FIXP(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.
* CONSTR(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|CBNofconstr*cbv_valuesubs|LAMofint*(Name.tContext.binder_annot*constr)list*constr*cbv_valuesubs|FIXPoffixpoint*cbv_valuesubs*cbv_valuearray|COFIXPofcofixpoint*cbv_valuesubs*cbv_valuearray|CONSTRofconstructorUniv.puniverses*cbv_valuearray|PRIMITIVEofCPrimitives.t*pconstant*cbv_valuearray|ARRAYofUniv.Instance.t*cbv_valueParray.t*cbv_value(* 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|CASEofUniv.Instance.t*constrarray*case_return*case_brancharray*Constr.case_invert*case_info*cbv_valuesubs*cbv_stack|PROJofProjection.t*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)|CBN(t,s)->CBN(t,subs_shft(n,s))|LAM(nlams,ctxt,b,s)->LAM(nlams,ctxt,b,subs_shft(n,s))|FIXP(fix,s,args)->FIXP(fix,subs_shft(n,s),Array.map(shift_valuen)args)|COFIXP(cofix,s,args)->COFIXP(cofix,subs_shft(n,s),Array.map(shift_valuen)args)|CONSTR(c,args)->CONSTR(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)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=FIXP(((reci,j),bodies),env,[||])inletn=Array.lengthbdsinmk_fix_subsmake_bodynenv0,bds.(i)letcontract_cofixpenv(i,(_,_,bdsasbodies))=letmake_bodyj=COFIXP((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,stk1')->PROJ(p,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)typecbv_infos={env:Environ.env;tab:(cbv_value,Empty.t)Declarations.constant_defKeyTable.t;reds:RedFlags.reds;sigma:Evd.evar_map}(* 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|FIXP(fix,env,app)->(FIXP(fix,env,[||]),stack_vect_appappstack)|COFIXP(cofix,env,app)->(COFIXP(cofix,env,[||]),stack_vect_appappstack)|CONSTR(c,app)->(CONSTR(c,[||]),stack_vect_appappstack)|PRIMITIVE(op,c,app)->(PRIMITIVE(op,c,[||]),stack_vect_appappstack)|VAL_|STACK_|CBN_|LAM_|ARRAY_->(head,stack)(* Tests if fixpoint reduction is possible. *)letfixp_reducibleflgs((reci,i),_)stk=ifred_setflgsfFIXthenmatchstkwith|APP(appl,_)->letreccheckn=function|[]->false|v::appl->ifInt.equaln0thenmatchvwith|CONSTR_->true|_->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=Univ.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_parray()e=matchewith|ARRAY(_u,t,_ty)->t|_->raisePrimred.NativeDestKOletmkIntenvi=VAL(0,mkInti)letmkFloatenvf=VAL(0,mkFloatf)letmkBoolenvb=let(ct,cf)=get_bool_constructorsenvinCONSTR(Univ.in_punivs(ifbthenctelsecf),[||])letint_tyenv=VAL(0,mkConst@@get_int_typeenv)letfloat_tyenv=VAL(0,mkConst@@get_float_typeenv)letmkCarryenvbe=let(c0,c1)=get_carry_constructorsenvinCONSTR(Univ.in_punivs(ifbthenc1elsec0),[|int_tyenv;e|])letmkIntPairenve1e2=letint_ty=int_tyenvinletc=get_pair_constructorenvinCONSTR(Univ.in_punivsc,[|int_ty;int_ty;e1;e2|])letmkFloatIntPairenvfi=letfloat_ty=float_tyenvinletint_ty=int_tyenvinletc=get_pair_constructorenvinCONSTR(Univ.in_punivsc,[|float_ty;int_ty;f;i|])letmkLtenv=let(_eq,lt,_gt)=get_cmp_constructorsenvinCONSTR(Univ.in_punivslt,[||])letmkEqenv=let(eq,_lt,_gt)=get_cmp_constructorsenvinCONSTR(Univ.in_punivseq,[||])letmkGtenv=let(_eq,_lt,gt)=get_cmp_constructorsenvinCONSTR(Univ.in_punivsgt,[||])letmkFLtenv=let(_eq,lt,_gt,_nc)=get_f_cmp_constructorsenvinCONSTR(Univ.in_punivslt,[||])letmkFEqenv=let(eq,_lt,_gt,_nc)=get_f_cmp_constructorsenvinCONSTR(Univ.in_punivseq,[||])letmkFGtenv=let(_eq,_lt,gt,_nc)=get_f_cmp_constructorsenvinCONSTR(Univ.in_punivsgt,[||])letmkFNotComparableenv=let(_eq,_lt,_gt,nc)=get_f_cmp_constructorsenvinCONSTR(Univ.in_punivsnc,[||])letmkPNormalenv=let(pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivspNormal,[||])letmkNNormalenv=let(_pNormal,nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivsnNormal,[||])letmkPSubnenv=let(_pNormal,_nNormal,pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivspSubn,[||])letmkNSubnenv=let(_pNormal,_nNormal,_pSubn,nSubn,_pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivsnSubn,[||])letmkPZeroenv=let(_pNormal,_nNormal,_pSubn,_nSubn,pZero,_nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivspZero,[||])letmkNZeroenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,nZero,_pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivsnZero,[||])letmkPInfenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,pInf,_nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivspInf,[||])letmkNInfenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,nInf,_nan)=get_f_class_constructorsenvinCONSTR(Univ.in_punivsnInf,[||])letmkNaNenv=let(_pNormal,_nNormal,_pSubn,_nSubn,_pZero,_nZero,_pInf,_nInf,nan)=get_f_class_constructorsenvinCONSTR(Univ.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(mkCase(ci,u,pms,ty,iv,t,br))st|PROJ(p,st)->reify_stack(mkProj(p,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)|CBN(t,env)->apply_envenvt|LAM(k,ctxt,b,env)->apply_envenv@@List.fold_left(func(n,t)->mkLambda(n,t,c))bctxt|FIXP((lij,fix),env,args)->letfix=mkFix(lij,fix)inmkApp(apply_envenvfix,Array.mapreify_valueargs)|COFIXP((j,cofix),env,args)->letcofix=mkCoFix(j,cofix)inmkApp(apply_envenvcofix,Array.mapreify_valueargs)|CONSTR(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)andapply_envenvt=matchkindtwith|Reli->beginmatchexpand_relienvwith|Inl(k,v)->reify_value(shift_valuekv)|Inr(k,_)->mkRelkend|_->map_with_binderssubs_liftapply_envenvtletrecstrip_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 CONSTR or (CO)FIXP, it last
* argument is []. Because we must put all the applied terms in the
* stack. *)letrecnorm_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,c)->letp'=ifred_setinfo.reds(fCONST(Projection.constantp))&&red_setinfo.redsfBETAthenProjection.unfoldpelsepinnorm_headinfoenvc(PROJ(p',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(_,b,_,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(CBN(t,env),stack)(* Should we consider a commutative cut ? *)|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_lamtin(LAM(List.lengthctxt,List.revctxt,b,env),stack)|Fixfix->(FIXP(fix,env,[||]),stack)|CoFixcofix->(COFIXP(cofix,env,[||]),stack)|Constructc->(CONSTR(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_)->(VAL(0,t),stack)|Prod_->(CBN(t,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.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 *)|(LAM(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)ctxtinLAM(lams,ctxt',b,env)|v::args->letenv=subs_consvenvinapplyenv(lams-1)argsinapplyenvnlamsargs(* a Fix applied enough -> IOTA *)|(FIXP(fix,env,[||]),stk)whenfixp_reducibleinfo.redsfixstk->let(envf,redfix)=contract_fixpenvfixincbv_stack_terminfostkenvfredfix(* constructor guard satisfied or Cofix in a Case -> IOTA *)|(COFIXP(cofix,env,[||]),stk)whencofixp_reducibleinfo.redscofixstk->let(envf,redfix)=contract_cofixpenvcofixincbv_stack_terminfostkenvfredfix(* constructor in a Case -> IOTA *)|(CONSTR(((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 *)|(CONSTR(((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 *)|(CONSTR(((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 *)|(FIXP(fix,env,[||]),APP(appl,TOP))->FIXP(fix,env,Array.of_listappl)|(COFIXP(cofix,env,[||]),APP(appl,TOP))->COFIXP(cofix,env,Array.of_listappl)|(CONSTR(c,[||]),APP(appl,TOP))->CONSTR(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(CONSTR(c,args))->(* args must be moved to the stack to allow future reductions *)cbv_stack_valueinfoenv(CONSTR(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(* 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|Not_found|Environ.NotEvaluableConst_->Declarations.UndefNoneinKeyTable.addinfo.tabrefv;v(* 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)->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,_,_,br)=Inductive.expand_caseinfo.env(ci,u,pms,ty,iv,mkProp,br)inletty=let(_,mip)=Inductive.lookup_mind_specifinfo.envci.ci_indinTerm.decompose_lam_n_decls(mip.Declarations.mind_nrealdecls+1)tyinletmk_brcn=Term.decompose_lam_n_declsncinletbr=Array.map2mk_brbrci.ci_cstr_ndeclsinletmap_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,cbv_norm_terminfoenvc)inapply_stackinfo(mkCase(ci,u,Array.map(cbv_norm_terminfoenv)pms,map_ctxty,iv,t,Array.mapmap_ctxbr))st|PROJ(p,st)->apply_stackinfo(mkProj(p,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(* reduction under binders *)|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)|CBN(t,env)->Constr.map_with_binderssubs_lift(cbv_norm_terminfo)envt|LAM(n,ctxt,b,env)->letnctxt=List.map_i(funi(x,ty)->(x,cbv_norm_terminfo(subs_liftnienv)ty))0ctxtinTerm.compose_lam(List.revnctxt)(cbv_norm_terminfo(subs_liftnnenv)b)|FIXP((lij,(names,lty,bds)),env,args)->mkApp(mkFix(lij,(names,Array.map(cbv_norm_terminfoenv)lty,Array.map(cbv_norm_terminfo(subs_liftn(Array.lengthlty)env))bds)),Array.map(cbv_norm_valueinfo)args)|COFIXP((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)|CONSTR(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)(* 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_infosredsenvsigma={tab=KeyTable.create91;reds;env;sigma}