123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421(************************************************************************)(* * 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) *)(************************************************************************)openNamesopenModPathopenCErrorsopenUtilopenMinimlopenTableopenMlutil(*S Functions upon ML modules. *)(** Note: a syntax like [(F M) with ...] is actually legal, see for instance
bug #4720. Hence the code below tries to handle [MTsig], maybe not in
a perfect way, but that should be enough for the use of [se_iter] below. *)letrecmsid_of_mt=function|MTidentmp->mp|MTsig(mp,_)->mp|MTwith(mt,_)->msid_of_mtmt|MTfunsig_->assertfalse(* A functor cannot be inside a MTwith *)(*s Apply some functions upon all [ml_decl] and [ml_spec] found in a
[ml_structure]. *)letse_iterdo_decldo_specdo_mp=letrecmt_iter=function|MTidentmp->do_mpmp|MTfunsig(_,mt,mt')->mt_itermt;mt_itermt'|MTwith(mt,ML_With_type(idl,l,t))->letmp_mt=msid_of_mtmtinletl',idl'=List.sep_lastidlinletmp_w=List.fold_left(funmpl->MPdot(mp,Label.of_idl))mp_mtidl'inletr=GlobRef.ConstRef(Constant.make2mp_w(Label.of_idl'))inmt_itermt;do_spec(Stype(r,l,Somet))|MTwith(mt,ML_With_module(idl,mp))->letmp_mt=msid_of_mtmtinletmp_w=List.fold_left(funmpl->MPdot(mp,Label.of_idl))mp_mtidlinmt_itermt;do_mpmp_w;do_mpmp|MTsig(_,sign)->List.iterspec_itersignandspec_iter=function|(_,Specs)->do_specs|(_,Smodulemt)->mt_itermt|(_,Smodtypemt)->mt_itermtinletrecse_iter=function|(_,SEdecld)->do_decld|(_,SEmodulem)->me_iterm.ml_mod_expr;mt_iterm.ml_mod_type|(_,SEmodtypem)->mt_itermandme_iter=function|MEidentmp->do_mpmp|MEfunctor(_,mt,me)->me_iterme;mt_itermt|MEapply(me,me')->me_iterme;me_iterme'|MEstruct(msid,sel)->List.iterse_iterselinse_iterletstruct_iterdo_decldo_specdo_mps=List.iter(function(_,sel)->List.iter(se_iterdo_decldo_specdo_mp)sel)s(*s Apply some fonctions upon all references in [ml_type], [ml_ast],
[ml_decl], [ml_spec] and [ml_structure]. *)typedo_ref=GlobRef.t->unitletrecord_iter_referencesdo_term=function|Recordl->List.iter(Option.iterdo_term)l|_->()lettype_iter_referencesdo_typet=letreciter=function|Tglob(r,l)->do_typer;List.iteriterl|Tarr(a,b)->itera;iterb|_->()initertletpatt_iter_referencesdo_consp=letreciter=function|Pcons(r,l)->do_consr;List.iteriterl|Pusualr->do_consr|Ptuplel->List.iteriterl|Prel_|Pwild->()initerpletast_iter_referencesdo_termdo_consdo_typea=letrecitera=ast_iteritera;matchawith|MLglobr->do_termr|MLcons(_,r,_)->do_consr|MLcase(ty,_,v)->type_iter_referencesdo_typety;Array.iter(fun(_,p,_)->patt_iter_referencesdo_consp)v|MLrel_|MLlam_|MLapp_|MLletin_|MLtuple_|MLfix_|MLexn_|MLdummy_|MLaxiom|MLmagic_|MLuint_|MLfloat_|MLparray_->()initeraletind_iter_referencesdo_termdo_consdo_typeknind=lettype_iter=type_iter_referencesdo_typeinletcons_itercpl=do_cons(GlobRef.ConstructRefcp);List.itertype_iterlinletpacket_iteripp=do_type(GlobRef.IndRefip);iflang()==Ocamlthen(matchind.ind_equivwith|Miniml.Equivkne->do_type(GlobRef.IndRef(MutInd.make1kne,sndip));|_->());Array.iteri(funj->cons_iter(ip,j+1))p.ip_typesiniflang()==Ocamlthenrecord_iter_referencesdo_termind.ind_kind;Array.iteri(funi->packet_iter(kn,i))ind.ind_packetsletdecl_iter_referencesdo_termdo_consdo_type=lettype_iter=type_iter_referencesdo_typeandast_iter=ast_iter_referencesdo_termdo_consdo_typeinfunction|Dind(kn,ind)->ind_iter_referencesdo_termdo_consdo_typeknind|Dtype(r,_,t)->do_typer;type_itert|Dterm(r,a,t)->do_termr;ast_itera;type_itert|Dfix(rv,c,t)->Array.iterdo_termrv;Array.iterast_iterc;Array.itertype_itertletspec_iter_referencesdo_termdo_consdo_type=function|Sind(kn,ind)->ind_iter_referencesdo_termdo_consdo_typeknind|Stype(r,_,ot)->do_typer;Option.iter(type_iter_referencesdo_type)ot|Sval(r,t)->do_termr;type_iter_referencesdo_typet(*s Searching occurrences of a particular term (no lifting done). *)exceptionFoundletrecast_searchfa=iffathenraiseFoundelseast_iter(ast_searchf)aletdecl_ast_searchf=function|Dterm(_,a,_)->ast_searchfa|Dfix(_,c,_)->Array.iter(ast_searchf)c|_->()letstruct_ast_searchfs=trystruct_iter(decl_ast_searchf)(fun_->())(fun_->())s;falsewithFound->trueletrectype_searchf=function|Tarr(a,b)->type_searchfa;type_searchfb|Tglob(r,l)->List.iter(type_searchf)l|u->iffuthenraiseFoundletdecl_type_searchf=function|Dind(_,{ind_packets=p})->Array.iter(fun{ip_types=v}->Array.iter(List.iter(type_searchf))v)p|Dterm(_,_,u)->type_searchfu|Dfix(_,_,v)->Array.iter(type_searchf)v|Dtype(_,_,u)->type_searchfuletspec_type_searchf=function|Sind(_,{ind_packets=p})->Array.iter(fun{ip_types=v}->Array.iter(List.iter(type_searchf))v)p|Stype(_,_,ot)->Option.iter(type_searchf)ot|Sval(_,u)->type_searchfuletstruct_type_searchfs=trystruct_iter(decl_type_searchf)(spec_type_searchf)(fun_->())s;falsewithFound->true(*s Generating the signature. *)letrecmsig_of_ms=function|[]->[]|(l,SEdecl(Dind(kn,i)))::ms->(l,Spec(Sind(kn,i)))::(msig_of_msms)|(l,SEdecl(Dterm(r,_,t)))::ms->(l,Spec(Sval(r,t)))::(msig_of_msms)|(l,SEdecl(Dtype(r,v,t)))::ms->(l,Spec(Stype(r,v,Somet)))::(msig_of_msms)|(l,SEdecl(Dfix(rv,_,tv)))::ms->letmsig=ref(msig_of_msms)infori=Array.lengthrv-1downto0domsig:=(l,Spec(Sval(rv.(i),tv.(i))))::!msigdone;!msig|(l,SEmodulem)::ms->(l,Smodulem.ml_mod_type)::(msig_of_msms)|(l,SEmodtypem)::ms->(l,Smodtypem)::(msig_of_msms)letsignature_of_structures=List.map(fun(mp,ms)->mp,msig_of_msms)sletrecmtyp_of_mexpr=function|MEfunctor(id,ty,e)->MTfunsig(id,ty,mtyp_of_mexpre)|MEstruct(mp,str)->MTsig(mp,msig_of_msstr)|_->assertfalse(*s Searching one [ml_decl] in a [ml_structure] by its [global_reference] *)letis_modular=function|SEdecl_->false|SEmodule_|SEmodtype_->trueletrecsearch_structurelm=function|[]->raiseNot_found|(lab,d)::_whenLabel.equallabl&&(is_modulard:bool)==m->d|_::fields->search_structurelmfieldsletget_decl_in_structurerstruc=tryletbase_mp,ll=labels_of_refrinifnot(at_toplevelbase_mp)thenerror_not_visibler;letsel=List.assoc_fModPath.equalbase_mpstrucinletrecgollsel=matchllwith|[]->assertfalse|l::ll->matchsearch_structurel(not(List.is_emptyll))selwith|SEdecld->d|SEmodtypem->assertfalse|SEmodulem->letrecaux=function|MEstruct(_,sel)->gollsel|MEfunctor(_,_,sel)->auxsel|MEident_|MEapply_->error_not_visiblerinauxm.ml_mod_expringollselwithNot_found->anomaly(Pp.str"reference not found in extracted structure.")(*s Optimization of a [ml_structure]. *)(* Some transformations of ML terms. [optimize_struct] simplify
all beta redexes (when the argument does not occur, it is just
thrown away; when it occurs exactly once it is substituted; otherwise
a let-in redex is created for clarity) and iota redexes, plus some other
optimizations. *)letdfix_to_mlfixrvavi=letrecmake_substns=ifn<0thenselsemake_subst(n-1)(Refmap'.addrv.(n)(n+1)s)inlets=make_subst(Array.lengthrv-1)Refmap'.emptyinletrecsubstnt=matchtwith|MLglob((GlobRef.ConstRefkn)asrefe)->(tryMLrel(n+(Refmap'.findrefes))withNot_found->t)|_->ast_map_liftsubstntinletids=Array.map(funr->Label.to_id(label_of_rr))rvinletc=Array.map(subst0)avinMLfix(i,ids,c)(* [optim_se] applies the [normalize] function everywhere and does the
inlining of code. The inlined functions are kept for the moment in
order to preserve the global interface, later [depcheck_se] will get
rid of them if possible *)letrecoptim_setopto_appears=function|[]->[]|(l,SEdecl(Dterm(r,a,t)))::lse->leta=normalize(ast_glob_subst!sa)inleti=inlinerainifithens:=Refmap'.addra!s;letd=matchdump_unused_vars(optimize_fixa)with|MLfix(0,_,[|c|])->Dfix([|r|],[|ast_subst(MLglobr)c|],[|t|])|a->Dterm(r,a,t)in(l,SEdecld)::(optim_setopto_appearslse)|(l,SEdecl(Dfix(rv,av,tv)))::lse->letav=Array.map(funa->normalize(ast_glob_subst!sa))avin(* This fake body ensures that no fixpoint will be auto-inlined. *)letfake_body=MLfix(0,[||],[||])infori=0toArray.lengthrv-1doifinlinerv.(i)fake_bodythens:=Refmap'.addrv.(i)(dfix_to_mlfixrvavi)!sdone;letav'=Array.mapdump_unused_varsavin(l,SEdecl(Dfix(rv,av',tv)))::(optim_setopto_appearslse)|(l,SEmodulem)::lse->letm={mwithml_mod_expr=optim_meto_appearsm.ml_mod_expr}in(l,SEmodulem)::(optim_setopto_appearslse)|se::lse->se::(optim_setopto_appearslse)andoptim_meto_appears=function|MEstruct(msid,lse)->MEstruct(msid,optim_sefalseto_appearslse)|MEidentmpasme->me|MEapply(me,me')->MEapply(optim_meto_appearsme,optim_meto_appearsme')|MEfunctor(mbid,mt,me)->MEfunctor(mbid,mt,optim_meto_appearsme)(* After these optimisations, some dependencies may not be needed anymore.
For non-library extraction, we recompute a minimal set of dependencies
for first-level definitions (no module pruning yet). *)letbase_r=letopenGlobRefinfunction|ConstRefcasr->r|IndRef(kn,_)->IndRef(kn,0)|ConstructRef((kn,_),_)->IndRef(kn,0)|_->assertfalseletreset_needed,add_needed,add_needed_mp,found_needed,is_needed=letneeded=refRefset'.emptyandneeded_mps=refMPset.emptyin((fun()->needed:=Refset'.empty;needed_mps:=MPset.empty),(funr->needed:=Refset'.add(base_rr)!needed),(funmp->needed_mps:=MPset.addmp!needed_mps),(funr->needed:=Refset'.remove(base_rr)!needed),(funr->letr=base_rrinRefset'.memr!needed||MPset.mem(modpath_of_rr)!needed_mps))letdeclared_refs=function|Dind(kn,_)->[GlobRef.IndRef(kn,0)]|Dtype(r,_,_)->[r]|Dterm(r,_,_)->[r]|Dfix(rv,_,_)->Array.to_listrv(* Computes the dependencies of a declaration, except in case
of custom extraction. *)letcompute_deps_decl=function|Dind(kn,ind)->(* Todo Later : avoid dependencies when Extract Inductive *)ind_iter_referencesadd_neededadd_neededadd_neededknind|Dtype(r,ids,t)->ifnot(is_customr)thentype_iter_referencesadd_neededt|Dterm(r,u,t)->type_iter_referencesadd_neededt;ifnot(is_customr)thenast_iter_referencesadd_neededadd_neededadd_neededu|Dfix_asd->decl_iter_referencesadd_neededadd_neededadd_neededdletcompute_deps_spec=function|Sind(kn,ind)->(* Todo Later : avoid dependencies when Extract Inductive *)ind_iter_referencesadd_neededadd_neededadd_neededknind|Stype(r,ids,t)->ifnot(is_customr)thenOption.iter(type_iter_referencesadd_needed)t|Sval(r,t)->type_iter_referencesadd_neededtletrecdepcheck_se=function|[]->[]|((l,SEdecld)ast)::se->letse'=depcheck_seseinletrefs=declared_refsdinletrefs'=List.filteris_neededrefsinifList.is_emptyrefs'then(List.iterremove_info_axiomrefs;List.iterremove_opaquerefs;se')elsebeginList.iterfound_neededrefs';(* Hack to avoid extracting unused part of a Dfix *)matchdwith|Dfix(rv,trms,tys)when(List.for_allis_customrefs')->lettrms'=Array.make(Array.lengthrv)(MLexn"UNUSED")in((l,SEdecl(Dfix(rv,trms',tys)))::se')|_->(compute_deps_decld;t::se')end|t::se->letse'=depcheck_seseinse_itercompute_deps_declcompute_deps_specadd_needed_mpt;t::se'letrecdepcheck_struct=function|[]->[]|(mp,lse)::struc->letstruc'=depcheck_structstrucinletlse'=depcheck_selseinifList.is_emptylse'thenstruc'else(mp,lse')::struc'exceptionRemainingImplicitofkill_reasonletcheck_for_remaining_implicitsstruc=letcheck=function|MLdummy(Kimplicit_ask)->raise(RemainingImplicitk)|_->falseintryignore(struct_ast_searchcheckstruc)withRemainingImplicitk->err_or_warn_remaining_implicitkletoptimize_structto_appearstruc=letsubst=ref(Refmap'.empty:ml_astRefmap'.t)inletopt_struc=List.map(fun(mp,lse)->(mp,optim_setrue(fstto_appear)substlse))strucinletmini_struc=iflibrary()thenList.filter(fun(_,lse)->not(List.is_emptylse))opt_strucelsebeginreset_needed();List.iteradd_needed(fstto_appear);List.iteradd_needed_mp(sndto_appear);depcheck_structopt_strucendinlet()=check_for_remaining_implicitsmini_strucinmini_struc