123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523(************************************************************************)(* * 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) *)(************************************************************************)openCErrorsopenUtilopenPpopenNamesopenConstropenLibnamesopenGlobnamesopenMod_subst(* usage qque peu general: utilise aussi dans record *)(* A class is a type constructor, its type is an arity whose number of
arguments is cl_param (0 for CL_SORT and CL_FUN) *)typecl_typ=|CL_SORT|CL_FUN|CL_SECVARofvariable|CL_CONSTofConstant.t|CL_INDofinductive|CL_PROJofProjection.Repr.tletcl_typ_ordt1t2=matcht1,t2with|CL_SECVARv1,CL_SECVARv2->Id.comparev1v2|CL_CONSTc1,CL_CONSTc2->Constant.CanOrd.comparec1c2|CL_PROJc1,CL_PROJc2->Projection.Repr.CanOrd.comparec1c2|CL_INDi1,CL_INDi2->Ind.CanOrd.comparei1i2|_->Stdlib.comparet1t2(** OK *)letcl_typ_eqt1t2=Int.equal(cl_typ_ordt1t2)0moduleClTyp=structtypet=cl_typletcompare=cl_typ_ordendmoduleClTypSet=Set.Make(ClTyp)moduleClTypMap=Map.Make(ClTyp)typecl_info_typ={(* The number of parameters of the coercion class. *)cl_param:int;(* The sets of coercion classes respectively reachable from and to the
coercion class. *)cl_reachable_from:ClTypSet.t;cl_reachable_to:ClTypSet.t;(* The representative class of the strongly connected component. *)cl_repr:cl_typ;}typecoe_typ=GlobRef.tmoduleCoeTypMap=GlobRef.Map_envtypecoe_info_typ={coe_value:GlobRef.t;coe_local:bool;coe_reversible:bool;coe_is_identity:bool;coe_is_projection:Projection.Repr.toption;coe_source:cl_typ;coe_target:cl_typ;coe_param:int;}typeinheritance_path=coe_info_typlistletinit_class_tab=letopenClTypMapinletcl_infoparamscl=letcl_singleton=ClTypSet.singletonclin{cl_param=params;cl_reachable_from=cl_singleton;cl_reachable_to=cl_singleton;cl_repr=cl}inaddCL_FUN(cl_info0CL_FUN)(addCL_SORT(cl_info0CL_SORT)empty)letclass_tab=Summary.ref~name:"class_tab"(init_class_tab:cl_info_typClTypMap.t)letcoercion_tab=Summary.ref~name:"coercion_tab"(CoeTypMap.empty:coe_info_typCoeTypMap.t)letreachable_fromcl=try(ClTypMap.findcl!class_tab).cl_reachable_fromwithNot_found->ClTypSet.emptymoduleClGraph:sigtypetvalempty:tvaladd:cl_typ->cl_typ->inheritance_path->t->tvalfind:cl_typ->cl_typ->t->inheritance_pathvalsrc:cl_typ->t->inheritance_pathClTypMap.tvaldst:cl_typ->t->inheritance_pathClTypMap.tvalbindings:t->((cl_typ*cl_typ)*inheritance_path)listend=structtypemap=inheritance_pathClTypMap.tClTypMap.ttypet=map*map(* Doubly-indexed map in both directions *)letempty=ClTypMap.empty,ClTypMap.emptyletadd0xypm=letn=tryClTypMap.findxmwithNot_found->ClTypMap.emptyinClTypMap.addx(ClTypMap.addypn)mletaddxyp(ml,mr)=(add0xypml,add0yxpmr)letfindxy(m,_)=ClTypMap.findy(ClTypMap.findxm)letsrcx(m,_)=tryClTypMap.findxmwithNot_found->ClTypMap.emptyletdstx(_,m)=tryClTypMap.findxmwithNot_found->ClTypMap.emptyletbindings(m,_)=letfoldsnaccu=letfoldtpaccu=((s,t),p)::accuinClTypMap.foldfoldnaccuinList.rev(ClTypMap.foldfoldm[])endletinheritance_graph=Summary.ref~name:"inheritance_graph"ClGraph.empty(* ajout de nouveaux "objets" *)letadd_new_classcls=class_tab:=ClTypMap.addcls!class_tabletadd_coercioncoes=coercion_tab:=CoeTypMap.addcoes!coercion_tabletadd_path(x,y)p=inheritance_graph:=ClGraph.addxyp!inheritance_graph(* class_info : cl_typ -> int * cl_info_typ *)letclass_infocl=ClTypMap.findcl!class_tabletclass_nparamscl=(class_infocl).cl_paramletclass_existscl=ClTypMap.memcl!class_tabletcoercion_infocoe=CoeTypMap.findcoe!coercion_tabletcoercion_typeenvsigma(coe,u)=Retyping.get_type_ofenvsigma(EConstr.mkRef(coe.coe_value,u))letcoercion_existscoe=CoeTypMap.memcoe!coercion_tab(* find_class_type : evar_map -> constr -> cl_typ * universe_list * constr list *)letfind_class_typeenvsigmat=letopenEConstrinlett',args=Reductionops.whd_betaiotazeta_stackenvsigmatinmatchEConstr.kindsigmat'with|Varid->CL_SECVARid,EInstance.empty,args|Const(sp,u)->CL_CONSTsp,u,args|Proj(p,_,c)whennot(Projection.unfoldedp)->letrevparams=letopenInductiveopsinlett=Retyping.get_type_ofenvsigmacinletIndType(fam,_)=find_rectypeenvsigmatinlet_,params=dest_ind_familyfaminList.revparamsinCL_PROJ(Projection.reprp),EInstance.empty,(List.rev_appendrevparams(c::args))|Ind(ind_sp,u)->CL_INDind_sp,u,args|Prod_->CL_FUN,EInstance.empty,[]|Sort_->CL_SORT,EInstance.empty,[]|_->raiseNot_foundletclass_of_global_reference=function|GlobRef.VarRefid->CL_SECVARid|GlobRef.ConstRefkn->CL_CONSTkn|GlobRef.IndRefind->CL_INDind|GlobRef.ConstructRef_->raiseNot_foundletfind_class_glob_typec=matchDAst.getcwith|Glob_term.GRef(ref,_)->class_of_global_referenceref|Glob_term.GProd_->CL_FUN|Glob_term.GSort_->CL_SORT|_->raiseNot_foundletsubst_cl_typenvsubstct=matchctwithCL_SORT|CL_FUN|CL_SECVAR_->ct|CL_PROJc->letc'=subst_proj_reprsubstcinifc'==cthenctelseCL_PROJc'|CL_CONSTc->letc',t=subst_consubstcinifc'==cthenctelse(matchtwith|None->CL_CONSTc'|Somet->pi1(find_class_typeenvEvd.empty(EConstr.of_constrt.UVars.univ_abstracted_value)))|CL_INDi->leti'=subst_indsubstiinifi'==ithenctelseCL_INDi'(*CSC: here we should change the datatype for coercions: it should be possible
to declare any term as a coercion *)letsubst_coe_typsubstt=subst_global_referencesubstt(* class_of : Term.constr -> int *)letclass_ofenvsigmat=let(t,n1,cl,u,args)=trylet(cl,u,args)=find_class_typeenvsigmatinlet{cl_param=n1}=class_infoclin(t,n1,cl,u,args)withNot_found->lett=Tacred.hnf_constrenvsigmatinlet(cl,u,args)=find_class_typeenvsigmatinlet{cl_param=n1}=class_infoclin(t,n1,cl,u,args)inifInt.equal(List.lengthargs)n1thent,clelseraiseNot_foundletclass_args_ofenvsigmac=pi3(find_class_typeenvsigmac)letstring_of_class=function|CL_FUN->"Funclass"|CL_SORT->"Sortclass"|CL_CONSTsp->string_of_qualid(Nametab.shortest_qualid_of_globalId.Set.empty(GlobRef.ConstRefsp))|CL_PROJsp->letsp=Projection.Repr.constantspinstring_of_qualid(Nametab.shortest_qualid_of_globalId.Set.empty(GlobRef.ConstRefsp))|CL_INDsp->string_of_qualid(Nametab.shortest_qualid_of_globalId.Set.empty(GlobRef.IndRefsp))|CL_SECVARsp->string_of_qualid(Nametab.shortest_qualid_of_globalId.Set.empty(GlobRef.VarRefsp))letpr_classx=str(string_of_classx)(* lookup paths *)letlookup_path_between_class(s,t)=ClGraph.findst!inheritance_graphletlookup_path_to_fun_from_classs=lookup_path_between_class(s,CL_FUN)letlookup_path_to_sort_from_classs=lookup_path_between_class(s,CL_SORT)(* advanced path lookup *)letapply_on_class_ofenvsigmatcont=trylet(cl,u,args)=find_class_typeenvsigmatinlet{cl_param=n1}=class_infoclinifnot(Int.equal(List.lengthargs)n1)thenraiseNot_found;contclwithNot_found->(* Is it worth to be more incremental on the delta steps? *)lett=Tacred.hnf_constrenvsigmatinlet(cl,u,args)=find_class_typeenvsigmatinlet{cl_param=n1}=class_infoclinifnot(Int.equal(List.lengthargs)n1)thenraiseNot_found;contclletlookup_path_betweenenvsigma~src:s~tgt:t=apply_on_class_ofenvsigmas(funi->apply_on_class_ofenvsigmat(funj->lookup_path_between_class(i,j)))letlookup_path_to_fun_fromenvsigmas=apply_on_class_ofenvsigmaslookup_path_to_fun_from_classletlookup_path_to_sort_fromenvsigmas=apply_on_class_ofenvsigmaslookup_path_to_sort_from_classletget_coercion_constructorenvcoe=letevd=Evd.from_envenvinletevd,c=Evd.fresh_globalenvevdcoe.coe_valueinletc=fst(Reductionops.whd_all_stackenvevdc)inmatchEConstr.kindevdcwith|Constr.Construct(c,_)->(* we don't return the modified evd as we drop the universes *)c,Inductiveops.constructor_nrealargsenvc-1|_->raiseNot_foundletlookup_pattern_path_betweenenv(s,t)=List.map(get_coercion_constructorenv)(ClGraph.find(CL_INDs)(CL_INDt)!inheritance_graph)letpath_is_reversiblep=List.for_all(func->c.coe_reversible)p(* rajouter une coercion dans le graphe *)letpath_printer:((cl_typ*cl_typ)*inheritance_path->Pp.t)ref=ref(fun_->str"<a class path>")letinstall_path_printerf=path_printer:=fletprint_pathx=!path_printerxletpath_comparator:(Environ.env->Evd.evar_map->cl_typ->inheritance_path->inheritance_path->bool)ref=ref(fun_____->false)letinstall_path_comparatorf=path_comparator:=fletcompare_pathenvsigmaclpq=!path_comparatorenvsigmaclpqletwarning_ambiguous_path="ambiguous-paths"letwarn_ambiguous_path=CWarnings.create~name:warning_ambiguous_path~category:CWarnings.CoreCategories.coercions(funl->prlist_with_sepfnl(fun(c,p,q)->str"New coercion path "++print_path(c,p)++ifList.is_emptyqthenstr" is not definitionally an identity function."elsestr" is ambiguous with existing "++print_path(c,q)++str".")l)(* add_coercion_in_graph : coe_index * cl_typ * cl_typ -> unit
coercion,source,target *)letdifferent_class_paramsenvci=if(class_infoci).cl_param>0thentrueelsematchciwith|CL_INDi->Environ.is_polymorphicenv(GlobRef.IndRefi)|CL_CONSTc->Environ.is_polymorphicenv(GlobRef.ConstRefc)|_->falseletadd_coercion_in_graphenvsigma?(update=false)ic=letsource=ic.coe_sourceinlettarget=ic.coe_targetinletsource_info=class_infosourceinlettarget_info=class_infotargetinletold_inheritance_graph=!inheritance_graphinletambig_paths:((cl_typ*cl_typ)*inheritance_path*inheritance_path)listref=ref[]inletwarn=matchCWarnings.get_warningwarning_ambiguous_pathwith|Therew->beginmatchCWarnings.warning_statuswwith|Disabled->false|Enabled|AsError->trueend|NotThere|OtherType->assertfalseinletcheck_coherence(i,jasij)pq=ifwarnthenleti_info=class_infoiinletj_info=class_infojinletbetween_ij=ClTypSet.interi_info.cl_reachable_fromj_info.cl_reachable_toinifcl_typ_eqi_info.cl_repri&&cl_typ_eqj_info.cl_reprj&&ClTypSet.is_empty(ClTypSet.diff(ClTypSet.interbetween_ijsource_info.cl_reachable_to)i_info.cl_reachable_to)&&ClTypSet.is_empty(ClTypSet.diff(ClTypSet.interbetween_ijtarget_info.cl_reachable_from)j_info.cl_reachable_from)&¬(compare_pathenvsigmaipq)thenambig_paths:=(ij,p,q)::!ambig_pathsinlettry_add_new_path(i,jasij)p=let()=ifcl_typ_eqijthencheck_coherenceijp[]inifnot(cl_typ_eqij)||different_class_paramsenvithenifupdatethenlet()=add_pathijpintrueelsematchlookup_path_between_classijwith|q->(ifnot(cl_typ_eqij)thencheck_coherenceijpq);false|exceptionNot_found->add_pathijp;trueelsefalseiniftry_add_new_path(source,target)[ic]thenbeginletrev=ClGraph.dstsourceold_inheritance_graphinletdir=ClGraph.srctargetold_inheritance_graphinletitersp=ifnot(cl_typ_eqssource)thenlet_=try_add_new_path(s,target)(p@[ic])inletitervq=ifnot(cl_typ_eqtargetv)thenignore(try_add_new_path(s,v)(p@[ic]@q))inClTypMap.iteriterdirinlet()=ClTypMap.iteriterrevinletitertp=ifnot(cl_typ_eqttarget)thenignore(try_add_new_path(source,t)(ic::p))inClTypMap.iteriterdirend;class_tab:=ClTypMap.mapi(funkk_info->letreachable_k_source=ClTypSet.memksource_info.cl_reachable_toinletreachable_target_k=ClTypSet.memktarget_info.cl_reachable_fromin{k_infowithcl_reachable_from=ifreachable_k_sourcethenClTypSet.unionk_info.cl_reachable_fromtarget_info.cl_reachable_fromelsek_info.cl_reachable_from;cl_reachable_to=ifreachable_target_kthenClTypSet.unionk_info.cl_reachable_tosource_info.cl_reachable_toelsek_info.cl_reachable_to;cl_repr=ifreachable_k_source&&reachable_target_kthentarget_info.cl_reprelsek_info.cl_repr})!class_tab;match!ambig_pathswith[]->()|_->warn_ambiguous_path!ambig_pathsletsubst_coercionsubstc=letenv=Global.env()inletcoe=subst_coe_typsubstc.coe_valueinletcls=subst_cl_typenvsubstc.coe_sourceinletclt=subst_cl_typenvsubstc.coe_targetinletclp=Option.Smart.map(subst_proj_reprsubst)c.coe_is_projectioninifc.coe_value==coe&&c.coe_source==cls&&c.coe_target==clt&&c.coe_is_projection==clpthencelse{cwithcoe_value=coe;coe_source=cls;coe_target=clt;coe_is_projection=clp;}(* Computation of the class arity *)letreference_arity_lengthenvsigmaref=lett,_=Typeops.type_of_global_in_contextenvrefinList.length(fst(Reductionops.splay_arityenvsigma(EConstr.of_constrt)))letprojection_arity_lengthenvsigmap=reference_arity_lengthenvsigma(GlobRef.ConstRef(Projection.Repr.constantp))letclass_paramsenvsigma=function|CL_FUN|CL_SORT->0|CL_CONSTsp->reference_arity_lengthenvsigma(GlobRef.ConstRefsp)|CL_PROJsp->projection_arity_lengthenvsigmasp|CL_SECVARsp->reference_arity_lengthenvsigma(GlobRef.VarRefsp)|CL_INDsp->reference_arity_lengthenvsigma(GlobRef.IndRefsp)(* add_class : cl_typ -> locality_flag option -> bool -> unit *)letadd_classenvsigmacl=ifnot(class_existscl)thenletcl_singleton=ClTypSet.singletonclinadd_new_classcl{cl_param=class_paramsenvsigmacl;cl_reachable_from=cl_singleton;cl_reachable_to=cl_singleton;cl_repr=cl}letdeclare_coercionenvsigma?updatec=let()=add_classenvsigmac.coe_sourceinlet()=add_classenvsigmac.coe_targetinlet()=add_coercionc.coe_valuecinadd_coercion_in_graphenvsigma?updatec(* For printing purpose *)letclasses()=List.rev(ClTypMap.fold(funx_acc->x::acc)!class_tab[])letcoercions()=List.rev(CoeTypMap.fold(fun_yacc->y::acc)!coercion_tab[])letinheritance_graph()=ClGraph.bindings!inheritance_graphletcoercion_of_referencer=letref=Nametab.globalrinifnot(coercion_existsref)thenuser_err(Nametab.pr_global_envId.Set.emptyref++str" is not a coercion.");refmoduleCoercionPrinting=structtypet=coe_typmoduleSet=GlobRef.Setletencode_env=coercion_of_referenceletsubst=subst_coe_typletcheck_locallocal=letopenGlobRefinfunction|ConstRef_|ConstructRef_|IndRef_->()|VarRefx->matchlocalwith|Libobject.Local->()|Export|SuperGlobal->letlocal=iflocal=Exportthen"export"else"global"inCErrors.user_errPp.(Id.printx++str" cannot be added with locality "++strlocal++str".")letdischarge=letopenGlobRefinfunction|ConstRef_|ConstructRef_|IndRef_asx->x|VarRef_asx->assert(not(Lib.is_in_sectionx));xletprinterx=Nametab.pr_global_envId.Set.emptyxletkey=["Printing";"Coercion"]lettitle="Explicitly printed coercions: "letmember_messagexb=str"Explicit printing of coercion "++printerx++str(ifbthen" is set"else" is unset")endmodulePrintingCoercion=Goptions.MakeRefTable(CoercionPrinting)lethide_coercioncoe=ifnot(PrintingCoercion.activecoe)thenletcoe_info=coercion_infocoeinSomecoe_info.coe_paramelseNone