123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440(************************************************************************)(* * 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) *)(************************************************************************)(* Created by Amokrane Saïbi, Dec 1998 *)(* Addition of products and sorts in canonical structures by Pierre
Corbineau, Feb 2008 *)(* This file registers properties of records: projections and
canonical structures *)openCErrorsopenUtilopenPpopenNamesopenConstropenMod_substopenReductionops(*s A structure S is a non recursive inductive type with a single
constructor (the name of which defaults to Build_S) *)(* Table of structures.
It maps to each structure name (of type [inductive]):
- the name of its constructor;
- the number of parameters;
- for each true argument, some data about the corresponding projection:
* its name (may be anonymous);
* whether it is a true projection (as opposed to a constant function, LetIn);
* whether it should be used as a canonical hint;
* the constant realizing this projection (if any).
*)moduleStructure=structtypeprojection={proj_name:Names.Name.t;proj_true:bool;proj_canonical:bool;proj_body:Names.Constant.toption;}typet={name:Names.inductive;projections:projectionlist;nparams:int;}letmakeenvnameprojections=letnparams=Inductiveops.inductive_nparamsenvnamein{name;projections;nparams}letstructure_table=Summary.ref(Indmap.empty:tIndmap.t)~name:"record-structs"letprojection_table=Summary.ref(Cmap.empty:tCmap.t)~name:"record-projs"letregister({name;projections;nparams}ass)=structure_table:=Indmap.addnames!structure_table;projection_table:=List.fold_right(fun{proj_body}m->Option.fold_right(funproj->Cmap.addprojs)proj_bodym)projections!projection_tableletsubstsubst({name;projections;nparams}ass)=letsubst_projectionsubst({proj_body}asp)=letproj_body=Option.Smart.map(subst_constantsubst)proj_bodyinifproj_body==p.proj_bodythenpelse{pwithproj_body}inletprojections=List.Smart.map(subst_projectionsubst)projectionsinletname=Mod_subst.subst_indsubstnameinifprojections==s.projections&&name==s.namethenselse{name;projections;nparams}letrebuildenvs=letmib=Environ.lookup_mind(fsts.name)envinletnparams=mib.Declarations.mind_nparamsin{swithnparams}letfindindsp=Indmap.findindsp!structure_tableletfind_projectionsindsp=(findindsp).projections|>List.map(fun{proj_body}->proj_body)letfind_from_projectioncst=Cmap.findcst!projection_tableletprojection_nparamscst=(Cmap.findcst!projection_table).nparamsletis_projectioncst=Cmap.memcst!projection_tableend(************************************************************************)(*s A canonical structure declares "canonical" conversion hints between *)(* the effective components of a structure and the projections of the *)(* structure *)(* Table of "object" definitions: for each object c,
c := [x1:B1]...[xk:Bk](Build_R a1...am t1...t_n)
If ti has the form (ci ui1...uir) where ci is a global reference (or
a sort, or a product or a reference to a parameter) and if the
corresponding projection Li of the structure R is defined, one
declares a "conversion" between ci and Li.
x1:B1..xk:Bk |- (Li a1..am (c x1..xk)) =_conv (ci ui1...uir)
that maps the pair (Li,ci) to the following data
o_ORIGIN = c (the constant name which this conversion rule is
synthesized from)
o_DEF = c
o_TABS = B1...Bk
o_INJ = Some n (when ci is a reference to the parameter xi)
o_TPARAMS = a1...am
o_NPARAMS = m
o_TCOMP = ui1...uir
*)typeobj_typ={o_ORIGIN:GlobRef.t;o_DEF:constr;o_CTX:Univ.AbstractContext.t;o_INJ:intoption;(* position of trivial argument if any *)o_TABS:constrlist;(* ordered *)o_TPARAMS:constrlist;(* ordered *)o_NPARAMS:int;o_TCOMPS:constrlist}(* ordered *)moduleValuePattern=structtypet=Const_csofGlobRef.t|Proj_csofNames.Projection.Repr.t|Prod_cs|Sort_csofSorts.family|Default_csletequalenvp1p2=matchp1,p2with|Const_csgr1,Const_csgr2->Environ.QGlobRef.equalenvgr1gr2|Proj_csp1,Proj_csp2->Environ.QProjection.Repr.equalenvp1p2|Prod_cs,Prod_cs->true|Sort_css1,Sort_css2->Sorts.family_equals1s2|Default_cs,Default_cs->true|_->falseletcomparep1p2=matchp1,p2with|Const_csgr1,Const_csgr2->GlobRef.CanOrd.comparegr1gr2|Proj_csp1,Proj_csp2->Projection.Repr.CanOrd.comparep1p2|Prod_cs,Prod_cs->0|Sort_css1,Sort_css2->Sorts.family_compares1s2|Default_cs,Default_cs->0|_->pervasives_comparep1p2letrecof_constrenvt=matchkindtwith|App(f,vargs)->letpatt,n,args=of_constrenvfinpatt,n,args@Array.to_listvargs|Reln->Default_cs,Somen,[]|Lambda(_,_,b)->letpatt,_,_=of_constrenvbinpatt,None,[]|Prod(_,_,_)->Prod_cs,None,[t]|Proj(p,c)->Proj_cs(Names.Projection.reprp),None,[c]|Sorts->Sort_cs(Sorts.familys),None,[]|_->Const_cs(fst@@destReft),None,[]letprint=functionConst_csc->Nametab.pr_global_envId.Set.emptyc|Proj_csp->Nametab.pr_global_envId.Set.empty(GlobRef.ConstRef(Names.Projection.Repr.constantp))|Prod_cs->str"forall _, _"|Default_cs->str"_"|Sort_css->Sorts.pr_sort_familysendmodulePatMap=Map.Make(ValuePattern)letobject_table=Summary.ref(GlobRef.Map.empty:(constr*obj_typ)PatMap.tGlobRef.Map.t)~name:"record-canonical-structs"letkeep_true_projectionsprojs=letfilter{Structure.proj_true;proj_canonical;proj_body}=ifproj_truethenSome(proj_body,proj_canonical)elseNoneinList.map_filterfilterprojsletwarn_projection_no_head_constant=CWarnings.create~name:"projection-no-head-constant"~category:CWarnings.CoreCategories.records(fun(sign,env,t,ref,proji_sp)->letenv=Environ.push_rel_contextsignenvinletcon_pp=Nametab.pr_global_envId.Set.emptyrefinletproji_sp_pp=Nametab.pr_global_envId.Set.empty(GlobRef.ConstRefproji_sp)inletterm_pp=Termops.Internal.print_constr_envenv(Evd.from_envenv)(EConstr.of_constrt)instrbrk"Projection value has no head constant: "++term_pp++strbrk" in canonical instance "++con_pp++str" of "++proji_sp_pp++strbrk", ignoring it.")(* Intended to always succeed *)letcompute_canonical_projectionsenv~warn(gref,ind)=leto_CTX=Environ.universes_of_globalenvgrefinleto_DEF,c=matchgrefwith|GlobRef.ConstRefcon->letu=Univ.make_abstract_instanceo_CTXinmkConstU(con,u),Environ.constant_value_inenv(con,u)|GlobRef.VarRefid->mkVarid,Option.get(Environ.named_bodyidenv)|GlobRef.ConstructRef_|GlobRef.IndRef_->assertfalseinletsign,t=Reduction.hnf_decompose_lambdaenvcinleto_TABS=List.rev_mapContext.Rel.Declaration.get_typesigninletargs=snd(decompose_app_listt)inlet{Structure.nparams=p;projections=lpj}=Structure.findindinleto_TPARAMS,projs=List.choppargsinleto_NPARAMS=List.lengtho_TPARAMSinletlpj=keep_true_projectionslpjinletnenv=Environ.push_rel_contextsignenvinList.fold_left2(funacc(spopt,canonical)t->lett=EConstr.Unsafe.to_constr(shrink_eta(Evd.from_envenv)(EConstr.of_constrt))inifcanonicalthenOption.cata(funproji_sp->matchValuePattern.of_constrnenvtwith|patt,o_INJ,o_TCOMPS->((GlobRef.ConstRefproji_sp,(patt,t)),{o_ORIGIN=gref;o_DEF;o_CTX;o_INJ;o_TABS;o_TPARAMS;o_NPARAMS;o_TCOMPS})::acc|exceptionDestKO->ifwarnthenwarn_projection_no_head_constant(sign,env,t,gref,proji_sp);acc)accspoptelseacc)[]lpjprojsletwarn_redundant_canonical_projection=CWarnings.create~name:"redundant-canonical-projection"~category:CWarnings.CoreCategories.records(fun(hd_val,prj,new_can_s,old_can_s)->strbrk"Ignoring canonical projection to "++hd_val++strbrk" by "++prj++strbrk" in "++new_can_s++strbrk": redundant with "++old_can_s)moduleInstance=structtypet=GlobRef.t*inductiveletrepr=fstletsubstsubst(gref,indasobj)=(* invariant: cst is an evaluable reference. Thus we can take *)(* the first component of subst_con. *)matchgrefwith|GlobRef.ConstRefcst->letcst'=subst_constantsubstcstinletind'=subst_indsubstindinifcst'==cst&&ind'==indthenobjelse(GlobRef.ConstRefcst',ind')|_->assertfalse(*s High-level declaration of a canonical structure *)leterror_not_structurerefdescription=user_err(str"Could not declare a canonical structure "++(Id.print(Nametab.basename_of_globalref)++str"."++spc()++description)++str".")letmakeenvsigmaref=letvc=matchrefwith|GlobRef.ConstRefsp->letu=Univ.make_abstract_instance(Environ.constant_contextenvsp)inbeginmatchEnviron.constant_opt_value_inenv(sp,u)with|Somevc->vc|None->error_not_structureref(str"Could not find its value in the global environment")end|GlobRef.VarRefid->beginmatchEnviron.named_bodyidenvwith|Someb->b|None->error_not_structureref(str"Could not find its value in the global environment")end|GlobRef.IndRef_|GlobRef.ConstructRef_->error_not_structureref(str"Expected an instance of a record or structure")inletbody=snd(hnf_decompose_lambdaenvsigma(EConstr.of_constrvc))inletbody=EConstr.Unsafe.to_constrbodyinletf,args=matchkindbodywith|App(f,args)->f,args|_->error_not_structureref(str"Expected a record or structure constructor applied to arguments")inletindsp=matchkindfwith|Construct((indsp,1),u)->indsp|_->error_not_structureref(str"Expected an instance of a record or structure")inlets=tryStructure.findindspwithNot_found->error_not_structureref(str"Could not find the record or structure "++Termops.pr_global_envenv(IndRefindsp))inletntrue_projs=List.count(fun{Structure.proj_true=x}->x)s.Structure.projectionsinifs.Structure.nparams+ntrue_projs>Array.lengthargsthenerror_not_structureref(str"Got too few arguments to the record or structure constructor");(ref,indsp)letregister~warnenvsigmao=compute_canonical_projectionsenv~warno|>List.iter(fun((proj,(cs_pat,t)),s)->letl=tryGlobRef.Map.findproj!object_tablewithNot_found->PatMap.emptyinmatchPatMap.findcs_patlwith|exceptionNot_found->object_table:=GlobRef.Map.addproj(PatMap.addcs_pat(t,s)l)!object_table|_,cs->ifwarnthenletold_can_s=Termops.Internal.print_constr_envenvsigma(EConstr.of_constrcs.o_DEF)inletnew_can_s=Termops.Internal.print_constr_envenvsigma(EConstr.of_constrs.o_DEF)inletprj=Nametab.pr_global_envId.Set.emptyprojinlethd_val=ValuePattern.printcs_patinwarn_redundant_canonical_projection(hd_val,prj,new_can_s,old_can_s))end(** The canonical solution of a problem (proj,val) is a global
[constant = fun abs : abstractions_ty => body] and
[ body = RecodConstructor params canon_values ] and the canonical value
corresponding to val is [val cvalue_arguments].
It is possible that val is one of the [abs] abstractions, eg [Default_cs],
and in that case [cvalue_abstraction = Some i] *)moduleCanonicalSolution=structtypet={constant:EConstr.t;abstractions_ty:EConstr.tlist;body:EConstr.t;nparams:int;params:EConstr.tlist;cvalue_abstraction:intoption;cvalue_arguments:EConstr.tlist;}letfindenvsigma(proj,pat)=lett',{o_DEF=c;o_CTX=ctx;o_INJ=n;o_TABS=bs;o_TPARAMS=params;o_NPARAMS=nparams;o_TCOMPS=us}=PatMap.findpat(GlobRef.Map.findproj!object_table)inletus=List.mapEConstr.of_construsinletparams=List.mapEConstr.of_constrparamsinletu,ctx'=UnivGen.fresh_instance_fromctxNoneinletc=EConstr.of_constrcinletc'=EConstr.Vars.subst_instance_construcinlett'=EConstr.of_constrt'inlett'=EConstr.Vars.subst_instance_construt'inletbs'=List.map(EConstr.of_constr%>EConstr.Vars.subst_instance_constru)bsinletparams=List.map(func->EConstr.Vars.subst_instance_construc)paramsinletus=List.map(func->EConstr.Vars.subst_instance_construc)usinletsigma=Evd.merge_context_setEvd.univ_flexiblesigmactx'insigma,{body=t';constant=c';abstractions_ty=bs';nparams;params;cvalue_arguments=us;cvalue_abstraction=n}letrecget_nthn=function|[]->raiseNot_found|arg::args->letlen=Array.lengtharginifn<lenthenarg.(n)elseget_nth(n-len)argsletrecdecompose_projectionsigmacargs=matchEConstr.kindsigmacwith|Metamv->decompose_projectionsigma(Evd.meta_valuesigmamv)args|Cast(c,_,_)->decompose_projectionsigmacargs|App(c,arg)->decompose_projectionsigmac(arg::args)|Const(c,u)->letn=Structure.projection_nparamscin(* Check if there is some canonical projection attached to this structure *)let_=GlobRef.Map.find(GlobRef.ConstRefc)!object_tableinget_nthnargs|Proj(p,c)->let_=GlobRef.Map.find(GlobRef.ConstRef(Names.Projection.constantp))!object_tableinc|_->raiseNot_foundletis_open_canonical_projectionenvsigmac=letopenEConstrintryletarg=decompose_projectionsigmac[]intryletarg=whd_allenvsigmaarginlethd=matchEConstr.kindsigmaargwithApp(hd,_)->hd|_->arginnot(isConstructsigmahd)withFailure_->falsewithNot_found->falseendmoduleCSTable=structtypeentry={projection:Names.GlobRef.t;value:ValuePattern.t;solution:Names.GlobRef.t;}letcanonical_entry_of_objectprojectionvalue(_,{o_ORIGIN=solution})={projection;value;solution}letentries()=GlobRef.Map.fold(funpolacc->PatMap.fold(funpatoacc->canonical_entry_of_objectppato::acc)olacc)!object_table[]letentries_for~projection:p=tryGlobRef.Map.findp!object_table|>PatMap.bindings|>List.map(fun(pat,o)->canonical_entry_of_objectppato)withNot_found->[]endmodulePrimitiveProjections=structletprim_table=Summary.ref(Cmap_env.empty:Names.Projection.Repr.tCmap_env.t)~name:"record-prim-projs"letregisterpc=prim_table:=Cmap_env.addcp!prim_tableletmemc=Cmap_env.memc!prim_tableletfind_optc=trySome(Cmap_env.findc!prim_table)withNot_found->Noneend