123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407(************************************************************************)(* * 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) *)(************************************************************************)(* The following definitions are used by the function
[assumptions] which gives as an output the set of all
axioms and sections variables on which a given term depends
in a context (expectingly the Global context) *)(* Initial author: Arnaud Spiwack
Module-traversing code: Pierre Letouzey *)openUtilopenNamesopenDeclarationsmoduleNamedDecl=Context.Named.Declaration(** For a constant c in a module sealed by an interface (M:T and
not M<:T), [Global.lookup_constant] may return a [constant_body]
without body. We fix this by looking in the implementation
of the module *)letmodcache=ref(MPmap.empty:structure_bodyMPmap.t)letrecsearch_mod_labellab=function|[]->raiseNot_found|(l,SFBmodulemb)::_whenLabel.equalllab->mb|_::fields->search_mod_labellabfieldsletrecsearch_cst_labellab=function|[]->raiseNot_found|(l,SFBconstcb)::_whenLabel.equalllab->cb|_::fields->search_cst_labellabfieldsletrecsearch_mind_labellab=function|[]->raiseNot_found|(l,SFBmindmind)::_whenLabel.equalllab->mind|_::fields->search_mind_labellabfields(* TODO: using [empty_delta_resolver] below is probably slightly incorrect. But:
a) I don't see currently what should be used instead
b) this shouldn't be critical for Print Assumption. At worse some
constants will have a canonical name which is non-canonical,
leading to failures in [Global.lookup_constant], but our own
[lookup_constant] should work.
*)letrecfields_of_functorfsubsmp0args=function|NoFunctora->fsubsmp0argsa|MoreFunctor(mbid,_,e)->letopenMod_substinmatchargswith|[]->assertfalse(* we should only encounter applied functors *)|mpa::args->letsubs=join(map_mbidmbidmpaempty_delta_resolver(*TODO*))subsinfields_of_functorfsubsmp0argseletreclookup_module_in_implmp=matchmpwith|MPfile_->Global.lookup_modulemp|MPbound_->Global.lookup_modulemp|MPdot(mp',lab')->ifModPath.equalmp'(Global.current_modpath())thenGlobal.lookup_modulempelseletfields=memoize_fields_of_mpmp'insearch_mod_labellab'fieldsandmemoize_fields_of_mpmp=tryMPmap.findmp!modcachewithNot_found->letl=fields_of_mpmpinmodcache:=MPmap.addmpl!modcache;landfields_of_mpmp=letopenMod_substinletmb=lookup_module_in_implmpinletfields,inner_mp,subs=fields_of_mbempty_substmb[]inletsubs=ifModPath.equalinner_mpmpthensubselseadd_mpinner_mpmpmb.mod_deltasubsinModops.subst_structuresubsfieldsandfields_of_mbsubsmbargs=matchmb.mod_exprwith|Algebraicexpr->fields_of_expressionsubsmb.mod_mpargsmb.mod_typeexpr|Structsign->letsign=Modops.annotate_struct_bodysignmb.mod_typeinfields_of_signaturesubsmb.mod_mpargssign|Abstract|FullStruct->fields_of_signaturesubsmb.mod_mpargsmb.mod_type(** The Abstract case above corresponds to [Declare Module] *)andfields_of_signaturex=fields_of_functor(funsubsmp0argsstruc->assert(List.is_emptyargs);(struc,mp0,subs))xandfields_of_exprsubsmp0args=function|MEidentmp->letmb=lookup_module_in_impl(Mod_subst.subst_mpsubsmp)infields_of_mbsubsmbargs|MEapply(me1,mp2)->fields_of_exprsubsmp0(mp2::args)me1|MEwith_->assertfalse(* no 'with' in [mod_expr] *)andfields_of_expressionsubsmpargsmtyme=letme=Modops.annotate_module_expressionmemtyinfields_of_functorfields_of_exprsubsmpargsmeletlookup_constant_in_implcstfallback=tryletmp,lab=KerName.repr(Constant.canonicalcst)inletfields=memoize_fields_of_mpmpin(* A module found this way is necessarily closed, in particular
our constant cannot be in an opened section : *)search_cst_labellabfieldswithNot_found->(* Either:
- The module part of the constant isn't registered yet :
we're still in it, so the [constant_body] found earlier
(if any) was a true axiom.
- The label has not been found in the structure. This is an error *)matchfallbackwith|Somecb->cb|None->CErrors.anomalyPp.(str"Print Assumption: unknown constant "++Constant.printcst++str".")letlookup_constantcst=letenv=Global.env()inifnot(Environ.mem_constantcstenv)thenlookup_constant_in_implcstNoneelseletcb=Environ.lookup_constantcstenvinifDeclareops.constant_has_bodycbthencbelselookup_constant_in_implcst(Somecb)letlookup_mind_in_implmind=tryletmp,lab=KerName.repr(MutInd.canonicalmind)inletfields=memoize_fields_of_mpmpinsearch_mind_labellabfieldswithNot_found->CErrors.anomalyPp.(str"Print Assumption: unknown inductive "++MutInd.printmind++str".")letlookup_mindmind=letenv=Global.env()inifEnviron.mem_mindmindenvthenEnviron.lookup_mindmindenvelselookup_mind_in_implmind(** Graph traversal of an object, collecting on the way the dependencies of
traversed objects *)letlabel_of=letopenGlobRefinfunction|ConstRefkn->Constant.labelkn|IndRef(kn,_)|ConstructRef((kn,_),_)->MutInd.labelkn|VarRefid->Label.of_ididletfold_with_full_bindersgfnaccc=letopenContext.Rel.DeclarationinletopenConstrinmatchkindcwith|Rel_|Meta_|Var_|Sort_|Const_|Ind_|Construct_|Int_|Float_|String_->acc|Cast(c,_,t)->fn(fnaccc)t|Prod(na,t,c)->f(g(LocalAssum(na,t))n)(fnacct)c|Lambda(na,t,c)->f(g(LocalAssum(na,t))n)(fnacct)c|LetIn(na,b,t,c)->f(g(LocalDef(na,b,t))n)(fn(fnaccb)t)c|App(c,l)->Array.fold_left(fn)(fnaccc)l|Proj(_,_,c)->fnaccc|Evar_->assertfalse|Case(ci,u,pms,p,iv,c,bl)->letmib=lookup_mind(fstci.ci_ind)inlet(ci,(p,_),iv,c,bl)=Inductive.expand_case_specifmib(ci,u,pms,p,iv,c,bl)inArray.fold_left(fn)(fn(fold_invert(fn)(fnaccp)iv)c)bl|Fix(_,(lna,tl,bl))->letn'=CArray.fold_left2_i(funicnt->g(LocalAssum(n,liftit))c)nlnatlinletfd=Array.map2(funtb->(t,b))tlblinArray.fold_left(funacc(t,b)->fn'(fnacct)b)accfd|CoFix(_,(lna,tl,bl))->letn'=CArray.fold_left2_i(funicnt->g(LocalAssum(n,liftit))c)nlnatlinletfd=Array.map2(funtb->(t,b))tlblinArray.fold_left(funacc(t,b)->fn'(fnacct)b)accfd|Array(_u,t,def,ty)->fn(fn(Array.fold_left(fn)acct)def)tyletget_constant_bodyaccesskn=letcb=lookup_constantkninmatchcb.const_bodywith|Undef_|Primitive_|Symbol_->None|Defc->Somec|OpaqueDefo->matchGlobal.force_proofaccessowith|c,_->Somec|exceptionewhenCErrors.noncriticale->None(* missing delayed body, e.g. in vok mode *)letrectraverseaccesscurrentctxaccut=letopenGlobRefinletopenConstrinmatchConstr.kindtwith|Varid->letbody()=id|>Global.lookup_named|>NamedDecl.get_valueintraverse_objectaccessaccubody(VarRefid)|Const(kn,_)->letbody()=get_constant_bodyaccessknintraverse_objectaccessaccubody(ConstRefkn)|Ind((mind,_)asind,_)->traverse_inductiveaccessaccumind(IndRefind)|Construct(((mind,_),_)ascst,_)->traverse_inductiveaccessaccumind(ConstructRefcst)|Meta_|Evar_->assertfalse|Case(_,_,_,(([|_|],oty),_),_,c,[||])whenVars.noccurn1oty->(* non dependent match on an inductive with no constructors *)beginmatchConstr.kindcwith|Const(kn,_)whennot(Declareops.constant_has_body(lookup_constantkn))->let(curr,data,ax2ty)=accuinletobj=ConstRefkninletalready_in=GlobRef.Map_env.memobjdatainletdata=ifnotalready_inthenGlobRef.Map_env.addobjNonedataelsedatainletty=(current,ctx,Vars.subst1mkPropoty)inletax2ty=tryletl=GlobRef.Map_env.findobjax2tyinGlobRef.Map_env.addobj(ty::l)ax2tywithNot_found->GlobRef.Map_env.addobj[ty]ax2tyin(GlobRef.Set_env.addobjcurr,data,ax2ty)|_->fold_with_full_bindersContext.Rel.add(traverseaccesscurrent)ctxaccutend|_->fold_with_full_bindersContext.Rel.add(traverseaccesscurrent)ctxaccutandtraverse_objectaccess(curr,data,ax2ty)bodyobj=letdata,ax2ty=letalready_in=GlobRef.Map_env.memobjdatainifalready_inthendata,ax2tyelsematchbody()(* Beware: this can be very costly *)with|None->GlobRef.Map_env.addobjNonedata,ax2ty|Somebody->letcontents,data,ax2ty=traverseaccess(label_ofobj)Context.Rel.empty(GlobRef.Set_env.empty,data,ax2ty)bodyinGlobRef.Map_env.addobj(Somecontents)data,ax2tyin(GlobRef.Set_env.addobjcurr,data,ax2ty)(** Collects the references occurring in the declaration of mutual inductive
definitions. All the constructors and names of a mutual inductive
definition share exactly the same dependencies. Also, there is no explicit
dependency between mutually defined inductives and constructors. *)andtraverse_inductiveaccess(curr,data,ax2ty)mindobj=letfirstind_ref=(GlobRef.IndRef(mind,0))inletlabel=label_ofobjinletdata,ax2ty=(* Invariant : I_0 \in data iff I_i \in data iff c_ij \in data
where I_0, I_1, ... are in the same mutual definition and c_ij
are all their constructors. *)if(* recursive call: *)GlobRef.Set_env.memfirstind_refcurr||(* already in: *)GlobRef.Map_env.memfirstind_refdatathendata,ax2tyelse(* Take into account potential recursivity of ind in itself *)letcurr=GlobRef.Set_env.addfirstind_refGlobRef.Set_env.emptyinletaccu=(curr,data,ax2ty)inletmib=lookup_mindmindin(* Collects references of parameters *)letparam_ctx=mib.mind_params_ctxtinletnparam=List.lengthparam_ctxinletaccu=traverse_contextaccesslabelContext.Rel.emptyaccuparam_ctxin(* For each inductive, collects references in their arity and in the type
of constructors*)let(contents,data,ax2ty)=Array.fold_left(funaccuoib->letarity_wo_param=List.rev(List.skipnnparam(List.revoib.mind_arity_ctxt))inletaccu=traverse_contextaccesslabelparam_ctxaccuarity_wo_paraminArray.fold_left(funaccucst_typ->letparam_ctx,cst_typ_wo_param=Term.decompose_prod_n_declsnparamcst_typintraverseaccesslabelparam_ctxaccucst_typ_wo_param)accuoib.mind_user_lc)accumib.mind_packetsin(* Maps all these dependencies to inductives and constructors*)letdata=letcontents=GlobRef.Set_env.removefirstind_refcontentsinArray.fold_left_i(funndataoib->letind=(mind,n)inletdata=GlobRef.Map_env.add(GlobRef.IndRefind)(Somecontents)datainArray.fold_left_i(funkdata_->GlobRef.Map_env.add(GlobRef.ConstructRef(ind,k+1))(Somecontents)data)dataoib.mind_consnames)datamib.mind_packetsin(data,ax2ty)in(GlobRef.Set_env.addobjcurr,data,ax2ty)(** Collects references in a rel_context. *)andtraverse_contextaccesscurrentctxaccuctxt=snd(Context.Rel.fold_outside(fundecl(ctx,accu)->matchdeclwith|Context.Rel.Declaration.LocalDef(_,c,t)->letaccu=traverseaccesscurrentctx(traverseaccesscurrentctxaccut)cinletctx=Context.Rel.adddeclctxinctx,accu|Context.Rel.Declaration.LocalAssum(_,t)->letaccu=traverseaccesscurrentctxaccutinletctx=Context.Rel.adddeclctxinctx,accu)ctxt~init:(ctx,accu))lettraverseaccesscurrentt=let()=modcache:=MPmap.emptyintraverseaccesscurrentContext.Rel.empty(GlobRef.Set_env.empty,GlobRef.Map_env.empty,GlobRef.Map_env.empty)t(** Hopefully bullet-proof function to recover the type of a constant. It just
ignores all the universe stuff. There are many issues that can arise when
considering terms out of any valid environment, so use with caution. *)lettype_of_constantcb=cb.Declarations.const_typeletuses_uipmib=Array.exists(funmip->Option.is_emptymip.mind_squashed&&mip.mind_relevance==Sorts.Irrelevant&&Array.lengthmip.mind_nf_lc=1&&List.length(fstmip.mind_nf_lc.(0))=List.lengthmib.mind_params_ctxt)mib.mind_packetsletassumptions?(add_opaque=false)?(add_transparent=false)accessstgrt=letopenPrinterin(* Only keep the transitive dependencies *)let(_,graph,ax2ty)=traverseaccess(label_ofgr)tinletopenGlobRefinletfoldobjcontentsaccu=matchobjwith|VarRefid->letdecl=Global.lookup_namedidinifContext.Named.Declaration.is_local_assumdeclthenlett=Context.Named.Declaration.get_typedeclinContextObjectMap.add(Variableid)taccuelseaccu|ConstRefkn->letcb=lookup_constantkninletaccu=ifcb.const_typing_flags.check_guardedthenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(Guardedobj,l))Constr.mkPropaccuinletaccu=ifcb.const_typing_flags.check_universesthenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(TypeInTypeobj,l))Constr.mkPropaccuinifnot(Option.has_somecontents)thenlett=type_of_constantcbinletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(Constantkn,l))taccuelseifadd_opaque&&(Declareops.is_opaquecb||not(Structures.PrimitiveProjections.is_transparent_constantstkn))thenlett=type_of_constantcbinContextObjectMap.add(Opaquekn)taccuelseifadd_transparentthenlett=type_of_constantcbinContextObjectMap.add(Transparentkn)taccuelseaccu|IndRef(m,_)|ConstructRef((m,_),_)->letmind=lookup_mindminletaccu=ifmind.mind_typing_flags.check_positivethenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(Positivem,l))Constr.mkPropaccuinletaccu=ifmind.mind_typing_flags.check_guardedthenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(Guardedobj,l))Constr.mkPropaccuinletaccu=ifmind.mind_typing_flags.check_universesthenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(TypeInTypeobj,l))Constr.mkPropaccuinletaccu=ifnot(uses_uipmind)thenaccuelseletl=tryGlobRef.Map_env.findobjax2tywithNot_found->[]inContextObjectMap.add(Axiom(UIPm,l))Constr.mkPropaccuinaccuinGlobRef.Map_env.foldfoldgraphContextObjectMap.empty