12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259(************************************************************************)(* * 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) *)(************************************************************************)(*i*)openUtilopenNamesopenTermopenConstropenContextopenDeclarationsopenDeclareopsopenEnvironopenReductionopsopenInductiveopenInductiveopsopenNamegenopenMinimlopenTableopenMlutilopenContext.Rel.Declaration(*i*)exceptionIofinductive_kind(* A set of all fixpoint functions currently being extracted *)letcurrent_fixpoints=ref([]:Constant.tlist)(* NB: In OCaml, [type_of] and [get_of] might raise
[SingletonInductiveBecomeProp]. This exception will be caught
in late wrappers around the exported functions of this file,
in order to display the location of the issue. *)lettype_ofenvsgc=letpolyprop=(lang()==Haskell)inRetyping.get_type_of~polypropenvsg(Termops.strip_outer_castsgc)letsort_ofenvsgc=letpolyprop=(lang()==Haskell)inRetyping.get_sort_family_of~polypropenvsg(Termops.strip_outer_castsgc)(*S Generation of flags and signatures. *)(* The type [flag] gives us information about any Coq term:
\begin{itemize}
\item [TypeScheme] denotes a type scheme, that is
something that will become a type after enough applications.
More formally, a type scheme has type $(x_1:X_1)\ldots(x_n:X_n)s$ with
[s = Set], [Prop] or [Type]
\item [Default] denotes the other cases. It may be inexact after
instantiation. For example [(X:Type)X] is [Default] and may give [Set]
after instantiation, which is rather [TypeScheme]
\item [Logic] denotes a term of sort [Prop], or a type scheme on sort [Prop]
\item [Info] is the opposite. The same example [(X:Type)X] shows
that an [Info] term might in fact be [Logic] later on.
\end{itemize} *)typeinfo=Logic|Infotypescheme=TypeScheme|Defaulttypeflag=info*scheme(*s [flag_of_type] transforms a type [t] into a [flag].
Really important function. *)letinfo_of_family=function|InSProp|InProp->Logic|InSet|InType|InQSort->Infoletinfo_of_sorts=info_of_family(Sorts.familys)letrecflag_of_typeenvsgt:flag=lett=whd_allenvsgtinmatchEConstr.kindsgtwith|Prod(x,t,c)->flag_of_type(EConstr.push_rel(LocalAssum(x,t))env)sgc|Sorts->(info_of_sort(EConstr.ESorts.kindsgs),TypeScheme)|_->(info_of_family(sort_ofenvsgt),Default)(*s Two particular cases of [flag_of_type]. *)letis_defaultenvsgt=matchflag_of_typeenvsgtwith|(Info,Default)->true|_->falseexceptionNotDefaultofkill_reasonletcheck_defaultenvsgt=matchflag_of_typeenvsgtwith|_,TypeScheme->raise(NotDefaultKtype)|Logic,_->raise(NotDefaultKprop)|_->()letis_info_schemeenvsgt=matchflag_of_typeenvsgtwith|(Info,TypeScheme)->true|_->falseletpush_rel_assum(n,t)env=EConstr.push_rel(LocalAssum(n,t))envletpush_rels_assumassums=EConstr.push_rel_context(List.map(fun(x,t)->LocalAssum(x,t))assums)letget_bodylconstr=EConstr.of_constrlconstrletget_opaqueaccessenvc=EConstr.of_constr(fst(Global.force_proofaccessc))letapplistccargs=EConstr.mkApp(c,Array.of_listargs)(* Same as [Environ.push_rec_types], but for [EConstr.t] *)letpush_rec_types(lna,typarray,_)env=letctxt=Array.map2_i(funinat->LocalAssum(na,EConstr.Vars.liftit))lnatyparrayinArray.fold_left(funeassum->EConstr.push_relassume)envctxt(* Same as [Termops.nb_lam], but for [EConstr.t] *)letnb_lamsgc=List.length(fst(EConstr.decompose_lambdasgc))(* Same as [Term.decompose_lambda_n] but for [EConstr.t] *)letdecompose_lambda_nsgn=letreclamdec_reclnc=ifn<=0thenl,celsematchEConstr.kindsgcwith|Lambda(x,t,c)->lamdec_rec((x,t)::l)(n-1)c|Cast(c,_,_)->lamdec_reclnc|_->raiseNot_foundinlamdec_rec[]n(*s [type_sign] gernerates a signature aimed at treating a type application. *)letrectype_signenvsgc=matchEConstr.kindsg(whd_allenvsgc)with|Prod(n,t,d)->(ifis_info_schemeenvsgtthenKeepelseKillKprop)::(type_sign(push_rel_assum(n,t)env)sgd)|_->[]letrectype_scheme_nb_argsenvsgc=matchEConstr.kindsg(whd_allenvsgc)with|Prod(n,t,d)->letn=type_scheme_nb_args(push_rel_assum(n,t)env)sgdinifis_info_schemeenvsgtthenn+1elsen|_->0lettype_scheme_nb_args'envc=type_scheme_nb_argsenv(Evd.from_envenv)(EConstr.of_constrc)let_=Hook.settype_scheme_nb_args_hooktype_scheme_nb_args'(*s [type_sign_vl] does the same, plus a type var list. *)(* When generating type variables, we avoid any ' in their names
(otherwise this may cause a lexer conflict in ocaml with 'a').
We also get rid of unicode characters. Anyway, since type variables
are local, the created name is just a matter of taste...
See also Bug #3227 *)letmake_typvarnvl=letid=id_of_nameninletid'=lets=Id.to_stringidinifnot(String.containss'\'')&&Unicode.is_basic_asciisthenidelseid_of_nameAnonymousinletvl=Id.Set.of_listvlinnext_ident_awayid'vlletrectype_sign_vlenvsgc=matchEConstr.kindsg(whd_allenvsgc)with|Prod(n,t,d)->lets,vl=type_sign_vl(push_rel_assum(n,t)env)sgdinifnot(is_info_schemeenvsgt)thenKillKprop::s,vlelseKeep::s,(make_typvarn.binder_namevl)::vl|_->[],[]letrecnb_default_paramsenvsgc=matchEConstr.kindsg(whd_allenvsgc)with|Prod(n,t,d)->letn=nb_default_params(push_rel_assum(n,t)env)sgdinifis_defaultenvsgtthenn+1elsen|_->0(* Enriching a signature with implicit information *)letsign_with_implicitsrsnb_params=letimplicits=implicits_of_globalrinletrecadd_impli=function|[]->[]|Keep::swhenInt.Set.memiimplicits->Kill(Kimplicit(r,i))::add_impl(i+1)s|sign::s->sign::add_impl(i+1)sinadd_impl(1+nb_params)s(*S Management of type variable contexts. *)(* A De Bruijn variable context (db) is a context for translating Coq [Rel]
into ML type [Tvar]. *)(*s From a type signature toward a type variable context (db). *)letdb_from_signs=letrecmakeiacc=function|[]->acc|Keep::l->make(i+1)(i::acc)l|Kill_::l->makei(0::acc)linmake1[]s(*s Create a type variable context from indications taken from
an inductive type (see just below). *)letrecdb_from_inddbmapi=ifInt.equali0then[]else(tryInt.Map.findidbmapwithNot_found->0)::(db_from_inddbmap(i-1))(*s [parse_ind_args] builds a map: [i->j] iff the i-th Coq argument
of a constructor corresponds to the j-th type var of the ML inductive. *)(* \begin{itemize}
\item [si] : signature of the inductive
\item [i] : counter of Coq args for [(I args)]
\item [j] : counter of ML type vars
\item [relmax] : total args number of the constructor
\end{itemize} *)letparse_ind_argssiargsrelmax=letrecparseij=function|[]->Int.Map.empty|Kill_::s->parse(i+1)js|Keep::s->(matchConstr.kindargs.(i-1)with|Relk->Int.Map.add(relmax+1-k)j(parse(i+1)(j+1)s)|_->parse(i+1)(j+1)s)inparse11siletcheck_sort_polysigmagru=letu=EConstr.EInstance.kindsigmauinletqs,_=UVars.Instance.to_arrayuinifArray.exists(function|Sorts.Quality.QConstant(QSProp|QProp)->true|QConstantQType|QVar_->false)qsthenCErrors.user_errPp.(str"Cannot extract nontrivial sort polymorphism"++spc()++str"(instantiation of "++Nametab.pr_global_envId.Set.emptygr++spc()++str"using Prop or SProp).")letrelevance_of_projection_reprmibp=let_mind,i=Names.Projection.Repr.inductivepinmatchmib.mind_recordwith|NotRecord|FakeRecord->CErrors.anomaly~label:"relevance_of_projection"Pp.(str"not a projection")|PrimRecordinfos->let_,_,rs,_=infos.(i)inrs.(Names.Projection.Repr.argp)(** Because of automatic unboxing the easy way [mk_def c] on the
constant body of primitive projections doesn't work. We pretend
that they are implemented by matches until someone figures out how
to clean it up (test with #4710 when working on this). *)letfake_match_projectionenvp=letind=Projection.Repr.inductivepinletproj_arg=Projection.Repr.argpinletmib,mip=Inductive.lookup_mind_specifenvindinletu=UVars.make_abstract_instance(Declareops.inductive_polymorphic_contextmib)inletindu=mkIndU(ind,u)inletctx,paramslet=letsubst=List.initmib.mind_ntypes(funi->mkIndU((fstind,mib.mind_ntypes-i-1),u))inlet(ctx,cty)=mip.mind_nf_lc.(0)inletcty=Term.it_mkProd_or_LetInctyctxinletrctx,_=decompose_prod_decls(Vars.substlsubstcty)inList.chopmip.mind_consnrealdecls.(0)rctxinletci_pp_info={style=LetStyle}inletci={ci_ind=ind;ci_npar=mib.mind_nparams;ci_cstr_ndecls=mip.mind_consnrealdecls;ci_cstr_nargs=mip.mind_consnrealargs;ci_pp_info;}inletrelevance=relevance_of_projection_reprmibpinletx=matchmib.mind_recordwith|NotRecord|FakeRecord->assertfalse|PrimRecordinfo->letx,_,_,_=info.(sndind)inmake_annot(Namex)mip.mind_relevanceinletindty=mkApp(indu,Context.Rel.instancemkRel0paramslet)inletrecfoldargjsubst=function|[]->assertfalse|LocalAssum(na,ty)::rem->letty=Vars.substlsubst(liftn1jty)inifarg!=proj_argthenletlab=matchna.binder_namewithNameid->Label.of_idid|Anonymous->assertfalseinletkn=Projection.Repr.makeind~proj_npars:mib.mind_nparams~proj_arg:arglabinfold(arg+1)(j+1)(mkProj(Projection.makeknfalse,na.binder_relevance,mkRel1)::subst)remelseletp=([|x|],liftn12ty)inletbranch=letnas=Array.of_list(List.rev_mapContext.Rel.Declaration.get_annotctx)in(nas,mkRel(List.lengthctx-(j-1)))inletparams=Context.Rel.instancemkRel1paramsletinletbody=mkCase(ci,u,params,(p,relevance),NoInvert,mkRel1,[|branch|])init_mkLambda_or_LetIn(mkLambda(x,indty,body))mib.mind_params_ctxt|LocalDef(_,c,t)::rem->letc=liftn1jcinletc1=Vars.substlsubstcinfoldarg(j+1)(c1::subst)reminfold01[](List.revctx)(*S Extraction of a type. *)(* [extract_type env db c args] is used to produce an ML type from the
coq term [(c args)], which is supposed to be a Coq type. *)(* [db] is a context for translating Coq [Rel] into ML type [Tvar]. *)(* [j] stands for the next ML type var. [j=0] means we do not
generate ML type var anymore (in subterms for example). *)letrecextract_typeenvsgdbjcargs=matchEConstr.kindsg(whd_betaiotazetaenvsgc)with|App(d,args')->(* We just accumulate the arguments. *)extract_typeenvsgdbjd(Array.to_listargs'@args)|Lambda(_,_,d)->(matchargswith|[]->assertfalse(* A lambda cannot be a type. *)|a::args->extract_typeenvsgdbj(EConstr.Vars.subst1ad)args)|Prod(n,t,d)->assert(List.is_emptyargs);letenv'=push_rel_assum(n,t)envin(matchflag_of_typeenvsgtwith|(Info,Default)->(* Standard case: two [extract_type] ... *)letmld=extract_typeenv'sg(0::db)jd[]in(matchexpandenvmldwith|Tdummyd->Tdummyd|_->Tarr(extract_typeenvsgdb0t[],mld))|(Info,TypeScheme)whenj>0->(* A new type var. *)letmld=extract_typeenv'sg(j::db)(j+1)d[]in(matchexpandenvmldwith|Tdummyd->Tdummyd|_->Tarr(TdummyKtype,mld))|_,lvl->letmld=extract_typeenv'sg(0::db)jd[]in(matchexpandenvmldwith|Tdummyd->Tdummyd|_->letreason=iflvl==TypeSchemethenKtypeelseKpropinTarr(Tdummyreason,mld)))|Sort_->TdummyKtype(* The two logical cases. *)|_wheninfo_of_family(sort_ofenvsg(applistccargs))==Logic->TdummyKprop|Reln->(matchEConstr.lookup_relnenvwith|LocalDef(_,t,_)->extract_typeenvsgdbj(EConstr.Vars.liftnt)args|_->(* Asks [db] a translation for [n]. *)ifn>List.lengthdbthenTunknownelseletn'=List.nthdb(n-1)inifInt.equaln'0thenTunknownelseTvarn')|Const(kn,u)->letr=GlobRef.ConstRefkninlet()=check_sort_polysgruinlettyp=type_ofenvsg(EConstr.mkConstU(kn,u))in(matchflag_of_typeenvsgtypwith|(Logic,_)->assertfalse(* Cf. logical cases above *)|(Info,TypeScheme)->letmlt=extract_type_appenvsgdb(r,type_signenvsgtyp)argsinmlt|(Info,Default)->(* Not an ML type, for example [(c:forall X, X->X) Type nat] *)(match(lookup_constantknenv).const_bodywith|Undef_|OpaqueDef_|Primitive_|Symbol_->Tunknown(* Brutal approx ... *)|Deflbody->(* We try to reduce. *)letnewc=applistc(get_bodylbody)argsinextract_typeenvsgdbjnewc[]))|Ind((kn,i)asind,u)->let()=check_sort_polysg(IndRefind)uinlets=(extract_indenvkn).ind_packets.(i).ip_signinextract_type_appenvsgdb(GlobRef.IndRef(kn,i),s)args|Proj(p,r,t)->(* Let's try to reduce, if it hasn't already been done. *)ifProjection.unfoldedpthenTunknownelseextract_typeenvsgdbj(EConstr.mkProj(Projection.unfoldp,r,t))args|Case_|Fix_|CoFix_->Tunknown|Evar_|Meta_->Taxiom(* only possible during Show Extraction *)|Varv->(* For Show Extraction *)letopenContext.Named.Declarationin(matchEConstr.lookup_namedvenvwith|LocalDef(_,body,_)->extract_typeenvsgdbj(EConstr.applist(body,args))[]|LocalAssum(_,ty)->letr=GlobRef.VarRefvin(matchflag_of_typeenvsgtywith|(Logic,_)->assertfalse(* Cf. logical cases above *)|(Info,TypeScheme)->extract_type_appenvsgdb(r,type_signenvsgty)args|(Info,Default)->Tunknown))|Cast_|LetIn_|Construct_|Int_|Float_|String_|Array_->assertfalse(*s Auxiliary function dealing with type application.
Precondition: [r] is a type scheme represented by the signature [s],
and is completely applied: [List.length args = List.length s]. *)andextract_type_appenvsgdb(r,s)args=letml_args=List.fold_right(fun(b,c)a->ifb==Keepthenletp=List.length(fst(whd_decompose_prodenvsg(type_ofenvsgc)))inletdb=iterate(funl->0::l)pdbin(extract_type_schemeenvsgdbcp)::aelsea)(List.combinesargs)[]inTglob(r,ml_args)(*S Extraction of a type scheme. *)(* [extract_type_scheme env db c p] works on a Coq term [c] which is
an informative type scheme. It means that [c] is not a Coq type, but will
be when applied to sufficiently many arguments ([p] in fact).
This function decomposes p lambdas, with eta-expansion if needed. *)(* [db] is a context for translating Coq [Rel] into ML type [Tvar]. *)andextract_type_schemeenvsgdbcp=ifInt.equalp0thenextract_typeenvsgdb0c[]elseletc=whd_betaiotazetaenvsgcinmatchEConstr.kindsgcwith|Lambda(n,t,d)->extract_type_scheme(push_rel_assum(n,t)env)sgdbd(p-1)|_->letrels=fst(whd_decompose_prodenvsg(type_ofenvsgc))inletenv=push_rels_assumrelsenvinleteta_args=List.rev_mapEConstr.mkRel(List.interval1p)inextract_typeenvsgdb0(EConstr.Vars.liftpc)eta_args(*S Extraction of an inductive type. *)(* First, a version with cache *)andextract_indenvkn=(* kn is supposed to be in long form *)letmib=Environ.lookup_mindknenvinmatchlookup_indknmibwith|Someml_ind->ml_ind|None->tryextract_really_indenvknmibwithSingletonInductiveBecomesPropid->(* TODO : which inductive is concerned in the block ? *)error_singleton_become_propid(Some(GlobRef.IndRef(kn,0)))(* Then the real function *)andextract_really_indenvknmib=(* First, if this inductive is aliased via a Module,
we process the original inductive if possible.
When at toplevel of the monolithic case, we cannot do much
(cf Vector and bug #2570) *)letequiv=iflang()!=Ocaml||(not(modular())&&at_toplevel(MutInd.modpathkn))||KerName.equal(MutInd.canonicalkn)(MutInd.userkn)thenNoEquivelsebeginignore(extract_indenv(MutInd.make1(MutInd.canonicalkn)));Equiv(MutInd.canonicalkn)endin(* Everything concerning parameters. *)(* We do that first, since they are common to all the [mib]. *)letmip0=mib.mind_packets.(0)inletndecls=List.lengthmib.mind_params_ctxtinletnpar=mib.mind_nparamsinletepar=push_rel_contextmib.mind_params_ctxtenvinletsg=Evd.from_envenvin(* First pass: we store inductive signatures together with *)(* their type var list. *)letpackets=Array.mapi(funimip->let(_,u),_=UnivGen.fresh_inductive_instanceenv(kn,i)inletar=Inductive.type_of_inductive((mib,mip),u)inletar=EConstr.of_constrarinletinfo=(fst(flag_of_typeenvsgar)=Info)inlets,v=ifinfothentype_sign_vlenvsgarelse[],[]inlett=Array.make(Array.lengthmip.mind_nf_lc)[]in{ip_typename=mip.mind_typename;ip_consnames=mip.mind_consnames;ip_logical=notinfo;ip_sign=s;ip_vars=v;ip_types=t},u)mib.mind_packetsinadd_indknmib{ind_kind=Standard;ind_nparams=npar;ind_packets=Array.mapfstpackets;ind_equiv=equiv};(* Second pass: we extract constructors *)fori=0tomib.mind_ntypes-1doletp,u=packets.(i)inifnotp.ip_logicalthenlettypes=Inductive.arities_of_constructors((kn,i),u)(mib,mib.mind_packets.(i))inforj=0toArray.lengthtypes-1dolett=snd(decompose_prod_n_declsndeclstypes.(j))inletprods,head=Reduction.whd_decompose_prodepartinletnprods=List.lengthprodsinletargs=matchConstr.kindheadwith|App(f,args)->args(* [Constr.kind f = Ind ip] *)|_->[||]inletdbmap=parse_ind_argsp.ip_signargs(nprods+ndecls)inletdb=db_from_inddbmapndeclsinp.ip_types.(j)<-extract_type_conseparsgdbdbmap(EConstr.of_constrt)(ndecls+1)donedone;(* Third pass: we determine special cases. *)letind_info=tryletip=(kn,0)inletr=GlobRef.IndRefipinifis_customrthenraise(IStandard);ifmib.mind_finite==CoFinitethenraise(ICoinductive);ifnot(Int.equalmib.mind_ntypes1)thenraise(IStandard);letp,u=packets.(0)inifp.ip_logicalthenraise(IStandard);ifnot(Int.equal(Array.lengthp.ip_types)1)thenraise(IStandard);lettyp=p.ip_types.(0)inletl=ifconservative_types()then[]elseList.filter(funt->not(isTdummy(expandenvt)))typinifList.is_emptylthenraise(IStandard);ifmib.mind_record==Declarations.NotRecordthenifnot(keep_singleton())&&Int.equal(List.lengthl)1&¬(type_mem_knkn(List.hdl))thenraise(ISingleton)elseraise(IStandard);(* Now we're sure it's a record. *)(* First, we find its field names. *)letrecnames_prodt=matchConstr.kindtwith|Prod(n,_,t)->n::(names_prodt)|LetIn(_,_,_,t)->names_prodt|Cast(t,_,_)->names_prodt|_->[]inletfield_names=List.skipnmib.mind_nparams(names_prodmip0.mind_user_lc.(0))inassert(Int.equal(List.lengthfield_names)(List.lengthtyp));letmp=MutInd.modpathkninletimplicits=implicits_of_global(GlobRef.ConstructRef(ip,1))inletty=Inductive.type_of_inductive((mib,mip0),u)inletnparams=nb_default_paramsenvsg(EConstr.of_constrty)inletrecselect_fieldsiltyps=matchl,typswith|[],[]->[]|_::l,typ::typswhenisTdummy(expandenvtyp)||Int.Set.memiimplicits->select_fields(i+1)ltyps|{binder_name=Anonymous}::l,typ::typs->None::(select_fields(i+1)ltyps)|{binder_name=Nameid}::l,typ::typs->letknp=Constant.make2mp(Label.of_idid)in(* Is it safe to use [id] for projections [foo.id] ? *)ifList.for_all((==)Keep)(type2signatureenvtyp)then(* for OCaml inlining: *)add_projectionnparamsknpip;Some(GlobRef.ConstRefknp)::(select_fields(i+1)ltyps)|_->assertfalseinletfield_glob=select_fields(1+npar)field_namestypinifnot(keep_singleton())&&Int.equal(List.lengthl)1&¬(type_mem_knkn(List.hdl))thenSingleton(* in passing, we registered the (identity) projection *)elseRecordfield_globwith(Iinfo)->infoinleti={ind_kind=ind_info;ind_nparams=npar;ind_packets=Array.mapfstpackets;ind_equiv=equiv}inadd_indknmibi;add_inductive_kindkni.ind_kind;i(*s [extract_type_cons] extracts the type of an inductive
constructor toward the corresponding list of ML types.
- [db] is a context for translating Coq [Rel] into ML type [Tvar]
- [dbmap] is a translation map (produced by a call to [parse_in_args])
- [i] is the rank of the current product (initially [params_nb+1])
*)andextract_type_consenvsgdbdbmapci=matchEConstr.kindsg(whd_allenvsgc)with|Prod(n,t,d)->letenv'=push_rel_assum(n,t)envinletdb'=(tryInt.Map.findidbmapwithNot_found->0)::dbinletl=extract_type_consenv'sgdb'dbmapd(i+1)in(extract_typeenvsgdb0t[])::l|_->[](*s Recording the ML type abbreviation of a Coq type scheme constant. *)andmlt_envenvr=letopenGlobRefinmatchrwith|IndRef_|ConstructRef_|VarRef_->None|ConstRefkn->letcb=Environ.lookup_constantknenvinmatchcb.const_bodywith|Undef_|OpaqueDef_|Primitive_|Symbol_->None|Defl_body->matchlookup_typedefkncbwith|Some_aso->o|None->letsg=Evd.from_envenvinlettyp=EConstr.of_constrcb.const_type(* FIXME not sure if we should instantiate univs here *)inmatchflag_of_typeenvsgtypwith|Info,TypeScheme->letbody=get_bodyl_bodyinlets=type_signenvsgtypinletdb=db_from_signsinlett=extract_type_schemeenvsgdbbody(List.lengths)inadd_typedefkncbt;Somet|_->Noneandexpandenv=type_expand(mlt_envenv)andtype2signatureenv=type_to_signature(mlt_envenv)lettype2signenv=type_to_sign(mlt_envenv)lettype_expungeenv=type_expunge(mlt_envenv)lettype_expunge_from_signenv=type_expunge_from_sign(mlt_envenv)(*s Extraction of the type of a constant. *)letrecord_constant_typeenvsgknopt_typ=letcb=lookup_constantknenvinmatchlookup_cst_typekncbwith|Someschema->schema|None->lettyp=matchopt_typwith|None->EConstr.of_constrcb.const_type|Sometyp->typinletmlt=extract_typeenvsg[]1typ[]inletschema=(type_maxvarmlt,mlt)inlet()=add_cst_typekncbschemainschema(*S Extraction of a term. *)(* Precondition: [(c args)] is not a type scheme, and is informative. *)(* [mle] is a ML environment [Mlenv.t]. *)(* [mlt] is the ML type we want our extraction of [(c args)] to have. *)letrecextract_termenvsgmlemltcargs=matchEConstr.kindsgcwith|App(f,a)->extract_termenvsgmlemltf(Array.to_lista@args)|Lambda(n,t,d)->letid=map_annotid_of_nameninletidna=map_annotName.mk_nameidin(matchargswith|a::l->(* We make as many [LetIn] as possible. *)letl'=List.map(EConstr.Vars.lift1)linletd'=EConstr.mkLetIn(idna,a,t,applistcdl')inextract_termenvsgmlemltd'[]|[]->letenv'=push_rel_assum(idna,t)envinletid,a=trycheck_defaultenvsgt;Idid.binder_name,new_meta()withNotDefaultd->Dummy,Tdummydinletb=new_meta()in(* If [mlt] cannot be unified with an arrow type, then magic! *)letmagic=needs_magic(mlt,Tarr(a,b))inletd'=extract_termenv'sg(Mlenv.push_typemlea)bd[]input_magic_ifmagic(MLlam(id,d')))|LetIn(n,c1,t1,c2)->letid=map_annotid_of_nameninletenv'=EConstr.push_rel(LocalDef(map_annotName.mk_nameid,c1,t1))envin(* We directly push the args inside the [LetIn].
TODO: the opt_let_app flag is supposed to prevent that *)letargs'=List.map(EConstr.Vars.lift1)argsin(trycheck_defaultenvsgt1;leta=new_meta()inletc1'=extract_termenvsgmleac1[]in(* The type of [c1'] is generalized and stored in [mle]. *)letmle'=ifgeneralizablec1'thenMlenv.push_genmleaelseMlenv.push_typemleainMLletin(Idid.binder_name,c1',extract_termenv'sgmle'mltc2args')withNotDefaultd->letmle'=Mlenv.push_std_typemle(Tdummyd)inast_pop(extract_termenv'sgmle'mltc2args'))|Const(kn,u)->let()=check_sort_polysg(ConstRefkn)uinextract_cst_appenvsgmlemltknargs|Construct(cp,u)->let()=check_sort_polysg(ConstructRefcp)uinextract_cons_appenvsgmlemltcpargs|Proj(p,_,c)->letp=Projection.reprpinletterm=fake_match_projectionenvpinletind=Inductiveops.find_rectypeenvsg(Retyping.get_type_ofenvsgc)inletindf,_=Inductiveops.dest_ind_typeindinlet_,indargs=Inductiveops.dest_ind_familyindfinextract_termenvsgmlemlt(beta_applistsg(EConstr.of_constrterm,indargs@[c]))args|Reln->(* As soon as the expected [mlt] for the head is known, *)(* we unify it with an fresh copy of the stored type of [Rel n]. *)letextract_relmlt=put_magic(mlt,Mlenv.getmlen)(MLreln)inextract_appenvsgmlemltextract_relargs|Case(ci,u,pms,r,iv,c0,br)->(* If invert_case then this is a match that will get erased later, but right now we don't care. *)let(ip,r,iv,c0,br)=EConstr.expand_caseenvsg(ci,u,pms,r,iv,c0,br)inletip=ci.ci_indinextract_appenvsgmlemlt(extract_caseenvsgmle(ip,c0,br))args|Fix((_,i),recd)->extract_appenvsgmlemlt(extract_fixenvsgmleirecd)args|CoFix(i,recd)->extract_appenvsgmlemlt(extract_fixenvsgmleirecd)args|Cast(c,_,_)->extract_termenvsgmlemltcargs|Evar_|Meta_->MLaxiom"evar"|Varv->(* Only during Show Extraction *)letopenContext.Named.Declarationinletty=matchEConstr.lookup_namedvenvwith|LocalAssum(_,ty)->ty|LocalDef(_,_,ty)->tyinletvty=extract_typeenvsg[]0ty[]inletextract_varmlt=put_magic(mlt,vty)(MLglob(GlobRef.VarRefv))inextract_appenvsgmlemltextract_varargs|Inti->assert(args=[]);MLuinti|Floatf->assert(args=[]);MLfloatf|Strings->assert(args=[]);MLstrings|Array(_u,t,def,_ty)->assert(args=[]);leta=new_meta()inletml_arr=Array.map(func->extract_termenvsgmleac[])tinletdef=extract_termenvsgmleadef[]inMLparray(ml_arr,def)|Ind_|Prod_|Sort_->assertfalse(*s [extract_maybe_term] is [extract_term] for usual terms, else [MLdummy] *)andextract_maybe_termenvsgmlemltc=trycheck_defaultenvsg(type_ofenvsgc);extract_termenvsgmlemltc[]withNotDefaultd->put_magic(mlt,Tdummyd)(MLdummyd)(*s Generic way to deal with an application. *)(* We first type all arguments starting with unknown meta types.
This gives us the expected type of the head. Then we use the
[mk_head] to produce the ML head from this type. *)andextract_appenvsgmlemltmk_headargs=letmetas=List.mapnew_metaargsinlettype_head=type_recomp(metas,mlt)inletmlargs=List.map2(extract_maybe_termenvsgmle)metasargsinmlapp(mk_headtype_head)mlargs(*s Auxiliary function used to extract arguments of constant or constructor. *)andmake_mlargsenvsgesargstyps=letrecf=function|[],[],_->[]|a::la,t::lt,[]->extract_maybe_termenvsgeta::(f(la,lt,[]))|a::la,t::lt,Keep::s->extract_maybe_termenvsgeta::(f(la,lt,s))|_::la,_::lt,_::s->f(la,lt,s)|_->assertfalseinf(args,typs,s)(*s Extraction of a constant applied to arguments. *)andextract_cst_appenvsgmlemltknargs=(* First, the [ml_schema] of the constant, in expanded version. *)letnb,t=record_constant_typeenvsgknNoneinletschema=nb,expandenvtin(* Can we instantiate types variables for this constant ? *)(* In Ocaml, inside the definition of this constant, the answer is no. *)letinstantiated=iflang()==Ocaml&&List.exists(func->QConstant.equalenvknc)!current_fixpointsthenvar2var'(sndschema)elseinstantiationschemain(* Then the expected type of this constant. *)leta=new_meta()in(* We compare stored and expected types in two steps. *)(* First, can [kn] be applied to all args ? *)letmetas=List.mapnew_metaargsinletmagic1=needs_magic(type_recomp(metas,a),instantiated)in(* Second, is the resulting type compatible with the expected type [mlt] ? *)letmagic2=needs_magic(a,mlt)in(* The internal head receives a magic if [magic1] *)lethead=put_magic_ifmagic1(MLglob(GlobRef.ConstRefkn))in(* Now, the extraction of the arguments. *)lets_full=type2signatureenv(sndschema)inlets_full=sign_with_implicits(GlobRef.ConstRefkn)s_full0inlets=sign_no_final_keepss_fullinletls=List.lengthsinletla=List.lengthargsin(* The ml arguments, already expunged from known logical ones *)letmla=make_mlargsenvsgmlesargsmetasin(* For strict languages, purely logical signatures lead to a dummy lam
(except when [Kill Ktype] everywhere). So a [MLdummy] is left
accordingly. *)letoptdummy=matchsign_kinds_fullwith|UnsafeLogicalSigwhenlang()!=Haskell->[MLdummyKprop]|_->[]in(* Different situations depending of the number of arguments: *)ifla>=lsthen(* Enough args, cleanup already done in [mla], we only add the
additional dummy if needed. *)put_magic_if(magic2&¬magic1)(mlapphead(optdummy@mla))else(* Partially applied function with some logical arg missing.
We complete via eta and expunge logical args. *)letls'=ls-lainlets'=List.skipnlasinletmla=(List.map(ast_liftls')mla)@(eta_args_signls's')inlete=anonym_or_dummy_lams(mlappheadmla)s'input_magic_ifmagic2(remove_n_lams(List.lengthoptdummy)e)(*s Extraction of an inductive constructor applied to arguments. *)(* \begin{itemize}
\item In ML, constructor arguments are uncurryfied.
\item We managed to suppress logical parts inside inductive definitions,
but they must appears outside (for partial applications for instance)
\item We also suppressed all Coq parameters to the inductives, since
they are fixed, and thus are not used for the computation.
\end{itemize} *)andextract_cons_appenvsgmlemlt(((kn,i)asip,j)ascp)args=(* First, we build the type of the constructor, stored in small pieces. *)letmi=extract_indenvkninletparams_nb=mi.ind_nparamsinletoi=mi.ind_packets.(i)inletnb_tvars=List.lengthoi.ip_varsandtypes=List.map(expandenv)oi.ip_types.(j-1)inletlist_tvar=List.map(funi->Tvari)(List.interval1nb_tvars)inlettype_cons=type_recomp(types,Tglob(GlobRef.IndRefip,list_tvar))inlettype_cons=instantiation(nb_tvars,type_cons)in(* Then, the usual variables [s], [ls], [la], ... *)lets=List.map(type2signenv)typesinlets=sign_with_implicits(GlobRef.ConstructRefcp)sparams_nbinletls=List.lengthsinletla=List.lengthargsinassert(la<=ls+params_nb);letla'=max0(la-params_nb)inletargs'=List.lastnla'argsin(* Now, we build the expected type of the constructor *)letmetas=List.mapnew_metaargs'in(* If stored and expected types differ, then magic! *)leta=new_meta()inletmagic1=needs_magic(type_cons,type_recomp(metas,a))inletmagic2=needs_magic(a,mlt)inletheadmla=ifmi.ind_kind==Singletonthenput_magic_ifmagic1(List.hdmla)(* assert (List.length mla = 1) *)elselettypeargs=matchsnd(type_decomptype_cons)with|Tglob(_,l)->List.maptype_simpll|_->assertfalseinlettyp=Tglob(GlobRef.IndRefip,typeargs)input_magic_ifmagic1(MLcons(typ,GlobRef.ConstructRefcp,mla))in(* Different situations depending of the number of arguments: *)ifla<params_nbthenlethead'=head(eta_args_signlss)input_magic_ifmagic2(dummy_lams(anonym_or_dummy_lamshead's)(params_nb-la))elseletmla=make_mlargsenvsgmlesargs'metasinifInt.equalla(ls+params_nb)thenput_magic_if(magic2&¬magic1)(headmla)else(* [ params_nb <= la <= ls + params_nb ] *)letls'=params_nb+ls-lainlets'=List.lastnls'sinletmla=(List.map(ast_liftls')mla)@(eta_args_signls's')input_magic_ifmagic2(anonym_or_dummy_lams(headmla)s')(*S Extraction of a case. *)andextract_caseenvsgmle((kn,i)asip,c,br)mlt=(* [br]: bodies of each branch (in functional form) *)(* [ni]: number of arguments without parameters in each branch *)letni=constructors_nrealargsenvipinletbr_size=Array.lengthbrinassert(Int.equal(Array.lengthni)br_size);ifInt.equalbr_size0thenbeginadd_recursorsenvkn;(* May have passed unseen if logical ... *)MLexn"absurd case"endelse(* [c] has an inductive type, and is not a type scheme type. *)lett=type_ofenvsgcin(* The only non-informative case: [c] is of sort [Prop]/[SProp] *)ifinfo_of_family(sort_ofenvsgt)==Logicthenbeginadd_recursorsenvkn;(* May have passed unseen if logical ... *)(* Logical singleton case: *)(* [match c with C i j k -> t] becomes [t'] *)assert(Int.equalbr_size1);lets=iterate(funl->KillKprop::l)ni.(0)[]inletmlt=iterate(funt->Tarr(TdummyKprop,t))ni.(0)mltinlete=extract_maybe_termenvsgmlemltbr.(0)insnd(case_expungese)endelseletmi=extract_indenvkninletoi=mi.ind_packets.(i)inletmetas=Array.init(List.lengthoi.ip_vars)new_metain(* The extraction of the head. *)lettype_head=Tglob(GlobRef.IndRefip,Array.to_listmetas)inleta=extract_termenvsgmletype_headc[]in(* The extraction of each branch. *)letextract_branchi=letr=GlobRef.ConstructRef(ip,i+1)in(* The types of the arguments of the corresponding constructor. *)letft=type_subst_vectmetas(expandenvt)inletl=List.mapfoi.ip_types.(i)in(* the corresponding signature *)lets=List.map(type2signenv)oi.ip_types.(i)inlets=sign_with_implicitsrsmi.ind_nparamsin(* Extraction of the branch (in functional form). *)lete=extract_maybe_termenvsgmle(type_recomp(l,mlt))br.(i)in(* We suppress dummy arguments according to signature. *)letids,e=case_expungesein(List.revids,Pusualr,e)inifmi.ind_kind==Singletonthenbegin(* Informative singleton case: *)(* [match c with C i -> t] becomes [let i = c' in t'] *)assert(Int.equalbr_size1);let(ids,_,e')=extract_branch0inassert(Int.equal(List.lengthids)1);MLletin(tmp_id(List.hdids),a,e')endelse(* Standard case: we apply [extract_branch]. *)lettyps=List.maptype_simpl(Array.to_listmetas)inlettyp=Tglob(GlobRef.IndRefip,typs)inMLcase(typ,a,Array.initbr_sizeextract_branch)(*s Extraction of a (co)-fixpoint. *)andextract_fixenvsgmlei(fi,ti,ciasrecd)mlt=letenv=push_rec_typesrecdenvinletmetas=Array.mapnew_metafiinmetas.(i)<-mlt;letmle=Array.fold_leftMlenv.push_typemlemetasinletei=Array.map2(extract_maybe_termenvsgmle)metasciinMLfix(i,Array.map(funx->id_of_namex.binder_name)fi,ei)(*S ML declarations. *)(* [decomp_lams_eta env c t] finds the number [n] of products in the type [t],
and decompose the term [c] in [n] lambdas, with eta-expansion if needed. *)letdecomp_lams_eta_nnmenvsgct=letrels=fst(whd_decompose_prod_nenvsgnt)inletrels',c=EConstr.decompose_lambdasgcinletd=n-min(* we'd better keep rels' as long as possible. *)letrels=(List.firstndrels)@rels'inleteta_args=List.rev_mapEConstr.mkRel(List.interval1d)inrels,applistc(EConstr.Vars.liftdc)eta_args(* Let's try to identify some situation where extracted code
will allow generalisation of type variables *)letrecgentypvar_oksgc=matchEConstr.kindsgcwith|Lambda_|Const_->true|App(c,v)->(* if all arguments are variables, these variables will
disappear after extraction (see [empty_s] below) *)Array.for_all(EConstr.isRelsg)v&&gentypvar_oksgc|Cast(c,_,_)->gentypvar_oksgc|_->false(*s From a constant to a ML declaration. *)letextract_std_constantenvsgknbodytyp=reset_meta_count();(* The short type [t] (i.e. possibly with abbreviations). *)lett=snd(record_constant_typeenvsgkn(Sometyp))in(* The real type [t']: without head products, expanded, *)(* and with [Tvar] translated to [Tvar'] (not instantiable). *)letl,t'=type_decomp(expandenv(var2var't))inlets=List.map(type2signenv)lin(* Check for user-declared implicit information *)lets=sign_with_implicits(GlobRef.ConstRefkn)s0in(* Decomposing the top level lambdas of [body].
If there isn't enough, it's ok, as long as remaining args
aren't to be pruned (and initial lambdas aren't to be all
removed if the target language is strict). In other situations,
eta-expansions create artificially enough lams (but that may
break user's clever let-ins and partial applications). *)letrels,c=letn=List.lengthsandm=nb_lamsgbodyinifn<=mthendecompose_lambda_nsgnbodyelselets,s'=List.chopmsinifList.for_all((==)Keep)s'&&(lang()==Haskell||sign_kinds!=UnsafeLogicalSig)thendecompose_lambda_nsgmbodyelsedecomp_lams_eta_nnmenvsgbodytypin(* Should we do one eta-expansion to avoid non-generalizable '_a ? *)letrels,c=letn=List.lengthrelsinlets,s'=List.chopnsinletk=sign_kindsinletempty_s=(k==EmptySig||k==SafeLogicalSig)iniflang()==Ocaml&&empty_s&¬(gentypvar_oksgc)&¬(List.is_emptys')&¬(Int.equal(type_maxvart)0)thendecomp_lams_eta_n(n+1)nenvsgbodytypelserels,cinletn=List.lengthrelsinlets=List.firstnnsinletl,l'=List.chopnlinlett'=type_recomp(l',t')in(* The initial ML environment. *)letmle=List.fold_leftMlenv.push_std_typeMlenv.emptylin(* The lambdas names. *)letids=List.map(fun(n,_)->Id(id_of_namen.binder_name))relsin(* The according Coq environment. *)letenv=push_rels_assumrelsenvin(* The real extraction: *)lete=extract_termenvsgmlet'c[]in(* Expunging term and type from dummy lambdas. *)lettrm=term_expunges(ids,e)intrm,type_expunge_from_signenvst(* Extracts the type of an axiom, honors the Extraction Implicit declaration. *)letextract_axiomenvsgkntyp=reset_meta_count();(* The short type [t] (i.e. possibly with abbreviations). *)lett=snd(record_constant_typeenvsgkn(Sometyp))in(* The real type [t']: without head products, expanded, *)(* and with [Tvar] translated to [Tvar'] (not instantiable). *)letl,_=type_decomp(expandenv(var2var't))inlets=List.map(type2signenv)lin(* Check for user-declared implicit information *)lets=sign_with_implicits(GlobRef.ConstRefkn)s0intype_expunge_from_signenvstletextract_fixpointenvsgvkn(fi,ti,ci)=letn=Array.lengthvkninlettypes=Array.maken(TdummyKprop)andterms=Array.maken(MLdummyKprop)inletkns=Array.to_listvknincurrent_fixpoints:=kns;(* for replacing recursive calls [Rel ..] by the corresponding [Const]: *)letsg,sub=CList.fold_left_map(funsgcon->Evd.fresh_globalenvsg(ConstRefcon))sg(List.revkns)infori=0ton-1doifinfo_of_family(sort_ofenvsgti.(i))!=Logicthentrylete,t=extract_std_constantenvsgvkn.(i)(EConstr.Vars.substlsubci.(i))ti.(i)interms.(i)<-e;types.(i)<-t;withSingletonInductiveBecomesPropid->error_singleton_become_propid(Some(GlobRef.ConstRefvkn.(i)))done;current_fixpoints:=[];Dfix(Array.map(funkn->GlobRef.ConstRefkn)vkn,terms,types)letextract_constantaccessenvkncb=letsg=Evd.from_envenvinletr=GlobRef.ConstRefkninlettyp=EConstr.of_constrcb.const_typeinletwarn_info()=ifnot(is_customr)thenadd_info_axiomrinletwarn_log()=ifnot(constant_has_bodycb)thenadd_log_axiomrinletmk_typ_ax()=letn=type_scheme_nb_argsenvsgtypinletids=iterate(funl->anonymous_name::l)n[]inDtype(r,ids,Taxiom)inletmk_typc=lets,vl=type_sign_vlenvsgtypinletdb=db_from_signsinlett=extract_type_schemeenvsgdbc(List.lengths)inDtype(r,vl,t)inletmk_ax()=lett=extract_axiomenvsgkntypinDterm(r,MLaxiom(Constant.to_stringkn),t)inletmk_defc=lete,t=extract_std_constantenvsgknctypinDterm(r,e,t)intrymatchflag_of_typeenvsgtypwith|(Logic,TypeScheme)->warn_log();lets,vl=type_sign_vlenvsgtypinDtype(r,vl,TdummyKtype)|(Logic,Default)->warn_log();Dterm(r,MLdummyKprop,TdummyKprop)|(Info,TypeScheme)->(matchcb.const_bodywith|Symbol_->add_symbolr;mk_typ_ax()|Primitive_|Undef_->warn_info();mk_typ_ax()|Defc->(matchStructures.PrimitiveProjections.find_optknwith|None->mk_typ(get_bodyc)|Somep->letbody=fake_match_projectionenvpinmk_typ(EConstr.of_constrbody))|OpaqueDefc->add_opaquer;ifaccess_opaque()thenmk_typ(get_opaqueaccessenvc)elsemk_typ_ax())|(Info,Default)->(matchcb.const_bodywith|Symbol_->add_symbolr;mk_ax()|Primitive_|Undef_->warn_info();mk_ax()|Defc->(matchStructures.PrimitiveProjections.find_optknwith|None->mk_def(get_bodyc)|Somep->letbody=fake_match_projectionenvpinmk_def(EConstr.of_constrbody))|OpaqueDefc->add_opaquer;ifaccess_opaque()thenmk_def(get_opaqueaccessenvc)elsemk_ax())withSingletonInductiveBecomesPropid->error_singleton_become_propid(Some(GlobRef.ConstRefkn))letextract_constant_specenvkncb=letsg=Evd.from_envenvinletr=GlobRef.ConstRefkninlettyp=EConstr.of_constrcb.const_typeintrymatchflag_of_typeenvsgtypwith|(Logic,TypeScheme)->lets,vl=type_sign_vlenvsgtypinStype(r,vl,Some(TdummyKtype))|(Logic,Default)->Sval(r,TdummyKprop)|(Info,TypeScheme)->lets,vl=type_sign_vlenvsgtypin(matchcb.const_bodywith|Undef_|OpaqueDef_|Primitive_|Symbol_->Stype(r,vl,None)|Defbody->letdb=db_from_signsinletbody=get_bodybodyinlett=extract_type_schemeenvsgdbbody(List.lengths)inStype(r,vl,Somet))|(Info,Default)->lett=snd(record_constant_typeenvsgkn(Sometyp))inSval(r,type_expungeenvt)withSingletonInductiveBecomesPropid->error_singleton_become_propid(Some(GlobRef.ConstRefkn))letextract_with_typeenvsgc=trylettyp=type_ofenvsgcinmatchflag_of_typeenvsgtypwith|(Info,TypeScheme)->lets,vl=type_sign_vlenvsgtypinletdb=db_from_signsinlett=extract_type_schemeenvsgdbc(List.lengths)inSome(vl,t)|_->NonewithSingletonInductiveBecomesPropid->error_singleton_become_propidNoneletextract_constrenvsgc=reset_meta_count();trylettyp=type_ofenvsgcinmatchflag_of_typeenvsgtypwith|(_,TypeScheme)->MLdummyKtype,TdummyKtype|(Logic,_)->MLdummyKprop,TdummyKprop|(Info,Default)->letmlt=extract_typeenvsg[]1typ[]inextract_termenvsgMlenv.emptymltc[],mltwithSingletonInductiveBecomesPropid->error_singleton_become_propidNoneletextract_inductiveenvkn=letind=extract_indenvkninadd_recursorsenvkn;letfijl=letimplicits=implicits_of_global(GlobRef.ConstructRef((kn,i),j+1))inletrecfilteri=function|[]->[]|t::l->letl'=filter(succi)linifisTdummy(expandenvt)||Int.Set.memiimplicitsthenl'elset::l'infilter(1+ind.ind_nparams)linletpackets=Array.mapi(funip->{pwithip_types=Array.mapi(fi)p.ip_types})ind.ind_packetsin{indwithind_packets=packets}(*s Is a [ml_decl] logical ? *)letlogical_decl=function|Dterm(_,MLdummy_,Tdummy_)->true|Dtype(_,_,Tdummy_)->true|Dfix(_,av,tv)->(Array.for_allisMLdummyav)&&(Array.for_allisTdummytv)|Dind(_,i)->Array.for_all(funip->ip.ip_logical)i.ind_packets|_->false(*s Is a [ml_spec] logical ? *)letlogical_spec=function|Stype(_,_,Some(Tdummy_))->true|Sval(_,Tdummy_)->true|Sind(_,i)->Array.for_all(funip->ip.ip_logical)i.ind_packets|_->false