1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821(************************************************************************)(* * 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) *)(************************************************************************)(** This module is about the low-level declaration of logical objects *)openPpopenUtilopenNamesopenSafe_typingmoduleNamedDecl=Context.Named.Declaration(* Hooks naturally belong here as they apply to both definitions and lemmas *)moduleHook=structmoduleS=structtypet={uctx:UState.t(** [ustate]: universe constraints obtained when the term was closed *);obls:(Names.Id.t*Constr.t)list(** [(n1,t1),...(nm,tm)]: association list between obligation
name and the corresponding defined term (might be a constant,
but also an arbitrary term in the Expand case of obligations) *);scope:Locality.definition_scope(** [locality]: Locality of the original declaration *);dref:Names.GlobRef.t(** [ref]: identifier of the original declaration *)}endtype'ag=(S.t->'a->'a)CEphemeron.keytypet=unitgletmake_ghook=CEphemeron.createhookletmake(hook:S.t->unit):t=CEphemeron.create(funx()->hookx)lethcallhookxs=CEphemeron.defaulthook(fun_x->x)xsletcall_g?hookxs=Option.cata(funhook->hcallhookxs)shookletcall?hookx=Option.iter(funhook->hcallhookx())hookendmoduleCInfo=structtype'constrt={name:Id.t(** Name of theorem *);typ:'constr(** Type of theorem *);args:Name.tlist(** Names to pre-introduce *);impargs:Impargs.manual_implicits(** Explicitily declared implicit arguments *)}letmake~name~typ?(args=[])?(impargs=[])()={name;typ;args;impargs}letto_constrsigmathm={thmwithtyp=EConstr.to_constrsigmathm.typ}letget_typ{typ;_}=typletget_name{name;_}=nameend(** Information for a declaration, interactive or not, includes
parameters shared by mutual constants *)moduleInfo=structtypet={poly:bool;inline:bool;kind:Decls.logical_kind;udecl:UState.universe_decl;scope:Locality.definition_scope;clearbody:bool(* always false for non Discharge scope *);hook:Hook.toption;typing_flags:Declarations.typing_flagsoption;user_warns:Globnames.extended_global_referenceUserWarn.with_qfoption;ntns:Metasyntax.notation_interpretation_decllist;loc:Loc.toption}(** Note that [opaque] doesn't appear here as it is not known at the
start of the proof in the interactive case. *)letmake?loc?(poly=false)?(inline=false)?(kind=Decls.(IsDefinitionDefinition))?(udecl=UState.default_univ_decl)?(scope=Locality.default_scope)?(clearbody=false)?hook?typing_flags?user_warns?(ntns=[])()=letloc=matchlocwith|None->Loc.get_current_command_loc()|Some_->locin{poly;inline;kind;udecl;scope;hook;typing_flags;clearbody;user_warns;ntns;loc}end(** Declaration of constants and parameters *)(* Deferred proofs: monomorphic, opaque, and udecl is for body+type *)type'effdeferred_opaque_proof_body={body:((Constr.t*Univ.ContextSet.t)*'eff)Future.computation;feedback_id:Stateid.toption(* State id on which the completion of type checking is reported *)}(* Opacity of default proofs, possibly with private universes *)typedefault_body_opacity=|Transparent(* udecl is for body+type; all universes are in proof_entry_universes *)|OpaqueofUniv.ContextSet.t(* if poly, the private uctx, udecl excludes the private uctx *)(* if mono, the body uctx *)(* Default (non-deferred) proofs/definitions, possibly with effects *)type'effdefault_proof_body={body:Constr.t*'eff;opaque:default_body_opacity}(* A proof body is either immediate or deferred *)type'effproof_body=|DeferredOpaqueof'effdeferred_opaque_proof_body|Defaultof'effdefault_proof_body(* A proof entry, parameterized with its kind of proof body *)type'bodypproof_entry={proof_entry_body:'body;proof_entry_secctx:Id.Set.toption;(* List of section variables *)proof_entry_type:Constr.typesoption;(* the initial type if deferred *)proof_entry_universes:UState.named_universes_entry;(* refers to:
- the initial uctx if opaque deferred;
- the uctx of type only if opaque private;
- the full uctx otherwise *)proof_entry_inline_code:bool;}(* The most general form of proof entry *)typeproof_entry=Evd.side_effectsproof_bodypproof_entrytypeparameter_entry={parameter_entry_secctx:Id.Set.toption;parameter_entry_type:Constr.types;parameter_entry_universes:UState.named_universes_entry;parameter_entry_inline_code:Entries.inline;}typeprimitive_entry={prim_entry_type:(Constr.types*UState.named_universes_entry)option;prim_entry_content:CPrimitives.op_or_type;}typesymbol_entry={symb_entry_type:Constr.types;symb_entry_unfold_fix:bool;symb_entry_universes:UState.named_universes_entry;}letdefault_univ_entry=UState.Monomorphic_entryUniv.ContextSet.emptyletdefault_named_univ_entry=default_univ_entry,UnivNames.empty_bindersletextract_monomorphic=function|UState.Monomorphic_entryctx->Entries.Monomorphic_entry,ctx|UState.Polymorphic_entryuctx->Entries.Polymorphic_entryuctx,Univ.ContextSet.emptyletinstance_of_univs=function|UState.Monomorphic_entry_,_->UVars.Instance.empty|UState.Polymorphic_entryuctx,_->UVars.UContext.instanceuctxletadd_mono_uctxuctx=function|UState.Monomorphic_entryctx,ubinders->UState.Monomorphic_entry(Univ.ContextSet.union(UState.context_setuctx)ctx),ubinders|UState.Polymorphic_entry_,_asx->assert(Univ.ContextSet.is_empty(UState.context_setuctx));xletmake_ubindersuctx(univs,ubindersasu)=matchunivswith|UState.Monomorphic_entry_->(UState.Monomorphic_entryuctx,ubinders)|UState.Polymorphic_entry_->ulet{Goptions.get=private_poly_univs}=Goptions.declare_bool_option_and_ref~key:["Private";"Polymorphic";"Universes"]~value:true()letuniverses_of_body_type~used_univsbodytyp=letused_univs_typ=Option.cata(Vars.universes_of_constr~init:used_univs)used_univstypinletused_univs=Vars.universes_of_constrbody~init:used_univs_typinused_univs_typ,used_univsletmake_univs_deferred_private_mono~initial_euctx?feedback_id~uctx~udeclbodytyp=let_,used_univs=universes_of_body_type~used_univs:Univ.Level.Set.emptybodytypinletuctx=UState.constrain_variables(fst(UState.context_setinitial_euctx))uctxin(* For vi2vo compilation proofs are computed now but we need to
complement the univ constraints of the typ with the ones of
the body. So we keep the two sets distinct. *)letuctx_body=UState.restrictuctxused_univsinUState.check_mono_univ_decluctx_bodyudeclletmake_univs_immediate_private_mono~initial_euctx~uctx~udecl~eff~used_univsbodytyp=letutyp=UState.univ_entry~poly:falseinitial_euctxinlet_,used_univs=universes_of_body_type~used_univsbodytypinletubody=letuctx=UState.constrain_variables(fst(UState.context_setinitial_euctx))uctxin(* For vi2vo compilation proofs are computed now but we need to
complement the univ constraints of the typ with the ones of
the body. So we keep the two sets distinct. *)letuctx_body=UState.restrictuctxused_univsinUState.check_mono_univ_decluctx_bodyudeclininitial_euctx,utyp,used_univs,Default{body=(body,eff);opaque=Opaqueubody}letmake_univs_immediate_private_poly~uctx~udecl~eff~used_univsbodytyp=letused_univs_typ,used_univs=universes_of_body_type~used_univsbodytypinletuctx'=UState.restrictuctxused_univs_typinletutyp=UState.check_univ_decl~poly:trueuctx'udeclinletubody=letuctx=UState.restrictuctxused_univsinUniv.ContextSet.diff(UState.context_setuctx)(UState.context_setuctx')inuctx',utyp,used_univs,Default{body=(body,eff);opaque=Opaqueubody}letmake_univs_immediate_default~poly~opaque~uctx~udecl~eff~used_univsbodytyp=let_,used_univs=universes_of_body_type~used_univsbodytypin(* Since the proof is computed now, we can simply have 1 set of
constraints in which we merge the ones for the body and the ones
for the typ. We recheck the declaration after restricting with
the actually used universes.
TODO: check if restrict is really necessary now. *)letuctx=UState.restrictuctxused_univsinletutyp=UState.check_univ_decl~polyuctxudeclinletutyp=matchfstutypwith|Polymorphic_entry_->utyp|Monomorphic_entryuctx->(* the constraints from the body may depend on universes from
the side effects, so merge it all together.
Example failure if we don't is "l1" in test-suite/success/rewrite.v.
Not sure if it makes more sense to merge them in the ustate
before restrict/check_univ_decl or here. Since we only do it
when monomorphic it shouldn't really matter. *)Monomorphic_entry(Univ.ContextSet.unionuctx(Safe_typing.universes_of_privateeff.Evd.seff_private)),sndutypinuctx,utyp,used_univs,Default{body=(body,eff);opaque=ifopaquethenOpaqueUniv.ContextSet.emptyelseTransparent}letmake_univs_immediate~poly?keep_body_ucst_separate~opaque~uctx~udecl~eff~used_univsbodytyp=(* allow_deferred case *)matchkeep_body_ucst_separatewith|Someinitial_euctxwhennotpoly->make_univs_immediate_private_mono~initial_euctx~uctx~udecl~eff~used_univsbodytyp|_->(* private_poly_univs case *)ifpoly&&opaque&&private_poly_univs()thenmake_univs_immediate_private_poly~uctx~udecl~eff~used_univsbodytypelsemake_univs_immediate_default~poly~opaque~uctx~udecl~eff~used_univsbodytyp(** [univsbody] are universe-constraints attached to the body-only,
used in vio-delayed opaque constants and private poly universes *)letdefinition_entry_core?using?(inline=false)?types?(univs=default_named_univ_entry)body={proof_entry_body=body;proof_entry_secctx=using;proof_entry_type=types;proof_entry_universes=univs;proof_entry_inline_code=inline}letpure_definition_entry?(opaque=Transparent)?using?inline?types?univsbody=definition_entry_core?using?inline?types?univsbodyletdefinition_entry?(opaque=false)?using?inline?types?univsbody=letopaque=ifopaquethenOpaqueUniv.ContextSet.emptyelseTransparentindefinition_entry_core?using?inline?types?univs(Default{body=(body,Evd.empty_side_effects);opaque})letdelayed_definition_entry?feedback_id?using~univs?typesbody=definition_entry_core?using?types~univs(DeferredOpaque{body;feedback_id})letparameter_entry?inline?(univs=default_named_univ_entry)typ={parameter_entry_secctx=None;parameter_entry_type=typ;parameter_entry_universes=univs;parameter_entry_inline_code=inline;}letprimitive_entry?typesc={prim_entry_type=types;prim_entry_content=c;}letsymbol_entry?(univs=default_named_univ_entry)~unfold_fixsymb_entry_type={symb_entry_universes=univs;symb_entry_unfold_fix=unfold_fix;symb_entry_type;}typeconstant_entry=|DefinitionEntryofproof_entry|ParameterEntryofparameter_entry|PrimitiveEntryofprimitive_entry|SymbolEntryofsymbol_entrymoduleProofEntry=structletmap_entry_body~f=function|Default{body=body;opaque}->Default{body=fbody;opaque}|DeferredOpaque{body;feedback_id}->letbody=Future.chainbody(fun((b,c),eff)->letb,eff=f(b,eff)in((b,c),eff))inDeferredOpaque{body;feedback_id}letmap_entry~fentry={entrywithproof_entry_body=map_entry_body~f:(on_fstf)entry.proof_entry_body;proof_entry_type=Option.mapfentry.proof_entry_type}letget_opacityentry=matchentry.proof_entry_bodywith|Default{body;opaque=Transparent}->false|Default{body;opaque=Opaque_}->true|DeferredOpaque_->trueletforce_entry_bodyentry=matchentry.proof_entry_bodywith|Default{body;opaque}->body,opaque|DeferredOpaque{body;feedback_id=Some_}->CErrors.anomaly(str"Forcing a proof with feedback")|DeferredOpaque{body;feedback_id=None}->let(body,uctx),eff=Future.forcebodyin(body,eff),Opaqueuctxletforce_extract_bodyentry=matchentry.proof_entry_bodywith|Default{body=(body,eff);opaque=Transparent}->((body,Univ.ContextSet.empty),eff),false,None|Default{body=(body,eff);opaque=Opaqueuctx}->((body,uctx),eff),true,None|DeferredOpaque{body;feedback_id}->Future.forcebody,true,feedback_idletget_entry_bodyentry=let(body,eff),opaque=force_entry_bodyentryinletuctx=matchopaquewith|Opaqueuctx->uctx|Transparent->Univ.ContextSet.emptyin(body,uctx),effletrecshrinkctxsignctaccu=letopenConstrinletopenVarsinmatchctx,signwith|[],[]->(c,t,accu)|p::ctx,decl::sign->ifnoccurn1c&&noccurn1tthenletc=subst1mkPropcinlett=subst1mkProptinshrinkctxsignctaccuelseletc=Term.mkLambda_or_LetInpcinlett=Term.mkProd_or_LetInptinletaccu=ifContext.Rel.Declaration.is_local_assumpthenEConstr.mkVar(NamedDecl.get_iddecl)::accuelseaccuinshrinkctxsignctaccu|_->assertfalse(* If [sign] is [x1:T1..xn:Tn], [c] is [fun x1:T1..xn:Tn => c']
and [t] is [forall x1:T1..xn:Tn, t'], returns a new [c'] and [t'],
where all non-dependent [xi] are removed, as well as a
restriction [args] of [x1..xn] such that [c' args] = [c x1..xn] *)letshrink_entrysignbodytyp=lettyp=matchtypwith|None->assertfalse|Somet->tinlet(ctx,body,typ)=Term.decompose_lambda_prod_n_decls(List.lengthsign)bodytypinlet(body,typ,args)=shrinkctxsignbodytyp[]inbody,Sometyp,argsendletlocal_csts=Summary.ref~name:"local-csts"Cset_env.emptyletis_local_constantc=Cset_env.memc!local_cststypeconstant_obj={cst_kind:Decls.logical_kind;cst_locl:Locality.import_status;cst_warn:Globnames.extended_global_referenceUserWarn.with_qfoption;cst_loc:Loc.toption;}letload_constanti((sp,kn),obj)=ifNametab.exists_ccispthenraise(DeclareUniv.AlreadyDeclared(None,Libnames.basenamesp));letcon=Global.constant_of_delta_knkninletgr=GlobRef.ConstRefconinNametab.push?user_warns:obj.cst_warn(Nametab.Untili)spgr;Dumpglob.add_constant_kindconobj.cst_kind;obj.cst_loc|>Option.iter(funloc->Nametab.set_cci_src_loc(TrueGlobalgr)loc);beginmatchobj.cst_loclwith|Locality.ImportNeedQualified->local_csts:=Cset_env.addcon!local_csts|Locality.ImportDefaultBehavior->()end(* Opening means making the name without its module qualification available *)letopen_constanti((sp,kn),obj)=(* Never open a local definition *)matchobj.cst_loclwith|Locality.ImportNeedQualified->()|Locality.ImportDefaultBehavior->letcon=Global.constant_of_delta_knkninNametab.push(Nametab.Exactlyi)sp(GlobRef.ConstRefcon)letexists_nameid=Decls.variable_existsid||Global.exists_objlabel(Label.of_idid)letcheck_existsid=ifexists_nameidthenraise(DeclareUniv.AlreadyDeclared(None,id))letcache_constant((sp,kn),obj)=letkn=Global.constant_of_delta_knkninletgr=GlobRef.ConstRefkninNametab.push?user_warns:obj.cst_warn(Nametab.Until1)spgr;Dumpglob.add_constant_kindknobj.cst_kind;obj.cst_loc|>Option.iter(funloc->Nametab.set_cci_src_loc(TrueGlobalgr)loc)letdischarge_constantobj=Someobjletclassify_constantcst=Libobject.Substitutelet(objConstant:(Id.t*constant_obj)Libobject.Dyn.tag)=letopenLibobjectindeclare_named_object_full{(default_object"CONSTANT")withcache_function=cache_constant;load_function=load_constant;open_function=simple_openopen_constant;classify_function=classify_constant;subst_function=ident_subst_function;discharge_function=discharge_constant}letinConstantv=Libobject.Dyn.Easy.injvobjConstant(* Register the libobjects attached to the constants *)letregister_constantloccstkind?user_warnslocal=(* Register the declaration *)letid=Label.to_id(Constant.labelcst)inletloc=matchlocwith|Some_->loc|None->Loc.get_current_command_loc()inleto=inConstant(id,{cst_kind=kind;cst_locl=local;cst_warn=user_warns;cst_loc=loc;})inlet()=Lib.add_leafoin(* Register associated data *)Impargs.declare_constant_implicitscst;Notation.declare_ref_arguments_scope(GlobRef.ConstRefcst)letregister_side_effect(c,body,role)=(* Register the body in the opaque table *)let()=matchbodywith|None->()|Someopaque->Opaques.declare_private_opaqueopaqueinlet()=register_constant(Loc.get_current_command_loc())cDecls.(IsProofTheorem)Locality.ImportDefaultBehaviorinmatchrolewith|None->()|Some(Evd.Schema(ind,kind))->DeclareScheme.declare_schemeSuperGlobalkind(ind,c)letget_rolesexporteff=letmap(c,body)=letrole=trySome(Cmap.findceff.Evd.seff_roles)withNot_found->Nonein(c,body,role)inList.mapmapexportletexport_side_effectseff=letexport=Global.export_private_constantseff.Evd.seff_privateinletexport=get_rolesexporteffinList.iterregister_side_effectexportletrecord_auxenvs_tys_bo=letopenEnvironinletin_ty=keep_hypsenvs_tyinletv=String.concat" "(CList.map_filter(fundecl->letid=NamedDecl.get_iddeclinifList.exists(NamedDecl.get_id%>Id.equalid)in_tythenNoneelseSome(Id.to_stringid))(keep_hypsenvs_bo))inAux_file.record_in_aux"context_used"vletcast_pure_proof_entry(e:Constr.constrpproof_entry)=letuniv_entry,ctx=extract_monomorphic(fst(e.proof_entry_universes))in{Entries.definition_entry_body=e.proof_entry_body;definition_entry_secctx=e.proof_entry_secctx;definition_entry_type=e.proof_entry_type;definition_entry_universes=univ_entry;definition_entry_inline_code=e.proof_entry_inline_code;},ctxtype('a,'b)effect_entry=|ImmediateEffectEntry:(private_constantsEntries.proof_output,unit)effect_entry|DeferredEffectEntry:(private_constantsEntries.proof_outputFuture.computation,unit)effect_entry|PureEntry:(Constr.constr,Constr.constr)effect_entryletsection_context_of_opaque_proof_entry(typeab)(entry:(a,b)effect_entry)(body:a)typ=letopenEnvironinletenv=Global.env()inlethyp_typ,hyp_def=ifList.is_empty(Environ.named_contextenv)thenId.Set.empty,Id.Set.emptyelseletids_typ=global_vars_setenvtypinlet(pf:Constr.constr),env=matchentrywith|PureEntry->body,env|ImmediateEffectEntry->let(pf,_),eff=bodyinletenv=Safe_typing.push_private_constantsenveffinpf,env|DeferredEffectEntry->let(pf,_),eff=Future.forcebodyinletenv=Safe_typing.push_private_constantsenveffinpf,envinletvars=global_vars_setenvpfinids_typ,varsinlet()=ifAux_file.recording()thenrecord_auxenvhyp_typhyp_definEnviron.really_neededenv(Id.Set.unionhyp_typhyp_def)letcast_opaque_proof_entry(typeab)(entry:(a,b)effect_entry)(e:approof_entry):bEntries.opaque_entry*_=lettyp=matche.proof_entry_typewith|None->assertfalse|Sometyp->typinletsecctx=matche.proof_entry_secctxwith|None->section_context_of_opaque_proof_entryentrye.proof_entry_bodytyp|Somehyps->hypsinletbody:b=matchentrywith|PureEntry->e.proof_entry_body|ImmediateEffectEntry->()|DeferredEffectEntry->()inletuniv_entry,ctx=extract_monomorphic(fst(e.proof_entry_universes))in{Entries.opaque_entry_body=body;opaque_entry_secctx=secctx;opaque_entry_type=typ;opaque_entry_universes=univ_entry;},ctxletfeedback_axiom()=Feedback.(feedbackAddedAxiom)letis_unsafe_typing_flagsflags=letflags=Option.default(Global.typing_flags())flagsinletopenDeclarationsinnot(flags.check_universes&&flags.check_guarded&&flags.check_positive)letdeclare_constant~loc?(local=Locality.ImportDefaultBehavior)~name~kind~typing_flags?user_warnscd=letbefore_univs=Global.universes()inletmake_constant=function(* Logically define the constant and its subproofs, no libobject tampering *)|DefinitionEntryde->(* We deal with side effects *)(matchde.proof_entry_bodywith|Default{body=(body,eff);opaque=Transparent}->(* This globally defines the side-effects in the environment
and registers their libobjects. *)let()=export_side_effectseffinletde={dewithproof_entry_body=body}inlete,ctx=cast_pure_proof_entrydeinletubinders=make_ubindersctxde.proof_entry_universesin(* We register the global universes after exporting side-effects, since
the latter depend on the former. *)let()=Global.push_context_setctxinEntries.DefinitionEntrye,false,ubinders,None,ctx|Default{body=(body,eff);opaque=Opaquebody_uctx}->letbody=((body,body_uctx),eff.Evd.seff_private)inletde={dewithproof_entry_body=body}inletcd,ctx=cast_opaque_proof_entryImmediateEffectEntrydeinletubinders=make_ubindersctxde.proof_entry_universesinlet()=Global.push_context_setctxinEntries.OpaqueEntrycd,false,ubinders,Some(Future.from_valbody,None),ctx|DeferredOpaque{body;feedback_id}->letmap(body,eff)=body,eff.Evd.seff_privateinletbody=Future.chainbodymapinletde={dewithproof_entry_body=body}inletcd,ctx=cast_opaque_proof_entryDeferredEffectEntrydeinletubinders=make_ubindersctxde.proof_entry_universesinlet()=Global.push_context_setctxinEntries.OpaqueEntrycd,false,ubinders,Some(body,feedback_id),ctx)|ParameterEntrye->letuniv_entry,ctx=extract_monomorphic(fste.parameter_entry_universes)inletubinders=make_ubindersctxe.parameter_entry_universesinlet()=Global.push_context_setctxinlete={Entries.parameter_entry_secctx=e.parameter_entry_secctx;Entries.parameter_entry_type=e.parameter_entry_type;Entries.parameter_entry_universes=univ_entry;Entries.parameter_entry_inline_code=e.parameter_entry_inline_code;}inEntries.ParameterEntrye,not(Lib.is_modtype_strict()),ubinders,None,ctx|PrimitiveEntrye->lettyp,univ_entry,ctx=matche.prim_entry_typewith|None->None,(UState.Monomorphic_entryUniv.ContextSet.empty,UnivNames.empty_binders),Univ.ContextSet.empty|Some(typ,entry_univs)->letuniv_entry,ctx=extract_monomorphic(fstentry_univs)inSome(typ,univ_entry),entry_univs,ctxinlet()=Global.push_context_setctxinlete={Entries.prim_entry_type=typ;Entries.prim_entry_content=e.prim_entry_content;}inletubinders=make_ubindersctxuniv_entryinEntries.PrimitiveEntrye,false,ubinders,None,ctx|SymbolEntry{symb_entry_type=typ;symb_entry_unfold_fix=un_fix;symb_entry_universes=entry_univs}->letuniv_entry,ctx=extract_monomorphic(fstentry_univs)inlet()=Global.push_context_setctxinlete={Entries.symb_entry_type=typ;Entries.symb_entry_unfold_fix=un_fix;Entries.symb_entry_universes=univ_entry;}inletubinders=make_ubindersctxentry_univsinEntries.SymbolEntrye,false,ubinders,None,ctxinletdeclare_opaquekn=function|None->()|Some(body,feedback_id)->letopenDeclarationsinmatch(Global.lookup_constantkn).const_bodywith|OpaqueDefo->let(_,_,_,i)=Opaqueproof.reproinOpaques.declare_defined_opaque?feedback_idibody|Def_|Undef_|Primitive_|Symbol_->assertfalseinlet()=check_existsnameinletdecl,unsafe,ubinders,delayed,ctx=make_constantcdinletkn=Global.add_constant?typing_flagsnamedeclinlet()=letis_new_constraint(u,_,vasc)=matchUGraph.check_declared_universesbefore_univsUniv.Level.Set.(addu(addvempty))with|Ok()->not(UGraph.check_constraintbefore_univsc)|Error_->trueinletctx=on_snd(Univ.Constraints.filteris_new_constraint)ctxinDeclareUniv.add_constraint_source(ConstRefkn)ctxinlet()=DeclareUniv.declare_univ_binders(GlobRef.ConstRefkn)ubindersinlet()=declare_opaquekndelayedinlet()=register_constantlocknkindlocal?user_warnsinifunsafe||is_unsafe_typing_flagstyping_flagsthenfeedback_axiom();knletdeclare_private_constant?role?(local=Locality.ImportDefaultBehavior)~name~kind~opaquede=letde,ctx=ifnotopaquethenletde,ctx=cast_pure_proof_entrydeinDefinitionEffde,ctxelseletde,ctx=cast_opaque_proof_entryPureEntrydeinOpaqueEffde,ctxinletkn,eff=Global.add_private_constantnamectxdeinlet()=ifUniv.Level.Set.is_empty(fstctx)then()elseDeclareUniv.declare_univ_binders(ConstRefkn)(Monomorphic_entryctx,UnivNames.empty_binders)inlet()=register_constant(Loc.get_current_command_loc())knkindlocalinletseff_roles=matchrolewithNone->Cmap.empty|Somer->Cmap.singletonknrinleteff={Evd.seff_private=eff;Evd.seff_roles;}inkn,effletinline_private_constants~uctxenv(body,eff)=letbody,ctx=Safe_typing.inline_private_constantsenv(body,eff.Evd.seff_private)inletuctx=UState.merge~sideff:trueEvd.univ_rigiductxctxinbody,uctx(** Declaration of section variables and local definitions *)typevariable_declaration=|SectionLocalDefof{clearbody:bool;entry:proof_entry;}|SectionLocalAssumof{typ:Constr.types;impl:Glob_term.binding_kind;univs:UState.named_universes_entry;}(* This object is only for things which iterate over objects to find
variables (only Prettyp.print_context AFAICT) *)letobjVariable:Id.tLibobject.Dyn.tag=letopenLibobjectindeclare_object_full{(default_object"VARIABLE")withclassify_function=(fun_->Dispose)}letinVariablev=Libobject.Dyn.Easy.injvobjVariableletdeclare_variable~name~kind~typing_flagsd=(* Variables are distinguished by only short names *)ifDecls.variable_existsnamethenraise(DeclareUniv.AlreadyDeclared(None,name));letimpl,opaque=matchdwith(* Fails if not well-typed *)|SectionLocalAssum{typ;impl;univs}->let()=matchfstunivswith|UState.Monomorphic_entryuctx->(* XXX [snd univs] is ignored, should we use it? *)DeclareUniv.name_mono_section_univs(fstuctx);Global.push_context_setuctx|UState.Polymorphic_entryuctx->Global.push_section_contextuctxinlet()=Global.push_named_assum(name,typ)inimpl,true|SectionLocalDef{clearbody;entry=de}->(* The body should already have been forced upstream because it is a
section-local definition, but it's not enforced by typing *)let((body,body_uctx),eff),opaque,feedback_id=ProofEntry.force_extract_bodydeinlet()=export_side_effectseffin(* We must declare the universe constraints before type-checking the
term. *)letunivs=matchfstde.proof_entry_universeswith|UState.Monomorphic_entryuctx->DeclareUniv.name_mono_section_univs(fstuctx);Global.push_context_set(Univ.ContextSet.unionuctxbody_uctx);UState.Monomorphic_entryUniv.ContextSet.empty,UnivNames.empty_binders|UState.Polymorphic_entryuctx->Global.push_section_contextuctx;letmk_anon_namesu=letqs,us=UVars.Instance.to_arrayuinArray.make(Array.lengthqs)Anonymous,Array.make(Array.lengthus)AnonymousinGlobal.push_section_context(UVars.UContext.of_context_setmk_anon_namesSorts.QVar.Set.emptybody_uctx);UState.Polymorphic_entryUVars.UContext.empty,UnivNames.empty_bindersinletse=ifopaquethenletcname=Id.of_string(Id.to_stringname^"_subproof")inletcname=Namegen.next_global_ident_awaycnameId.Set.emptyinletde={proof_entry_body=DeferredOpaque{body=Future.from_val((body,Univ.ContextSet.empty),Evd.empty_side_effects);feedback_id};proof_entry_secctx=None;(* de.proof_entry_secctx is NOT respected *)proof_entry_type=de.proof_entry_type;proof_entry_universes=univs;proof_entry_inline_code=de.proof_entry_inline_code;}inletkn=declare_constant~name:cname~loc:None~local:ImportNeedQualified~kind:(IsProofLemma)~typing_flags(DefinitionEntryde)in{Entries.secdef_body=Constr.mkConstU(kn,UVars.Instance.empty);secdef_type=None;}else{Entries.secdef_body=body;secdef_type=de.proof_entry_type;}inlet()=Global.push_named_def(name,se)in(* opaque implies clearbody, so we don't see useless "foo := foo_subproof" in the context *)Glob_term.Explicit,opaque||clearbodyinNametab.push(Nametab.Until1)(Libnames.make_pathDirPath.emptyname)(GlobRef.VarRefname);Decls.(add_variable_dataname{opaque;kind});Lib.add_leaf(inVariablename);Impargs.declare_var_implicits~implname;Notation.declare_ref_arguments_scope(GlobRef.VarRefname)(* Declaration messages *)letpr_ranki=pr_nth(i+1)letfixpoint_messageindexesl=Flags.if_verboseFeedback.msg_info(matchlwith|[]->CErrors.anomaly(Pp.str"no recursive definition.")|[id]->Id.printid++str" is recursively defined"++(matchindexeswith|Some[|i|]->str" (guarded on "++pr_ranki++str" argument)"|_->mt())|l->hov0(prlist_with_seppr_commaId.printl++spc()++str"are recursively defined"++matchindexeswith|Somea->spc()++str"(guarded respectively on "++prvect_with_seppr_commapr_ranka++str" arguments)"|None->mt()))letcofixpoint_messagel=Flags.if_verboseFeedback.msg_info(matchlwith|[]->CErrors.anomaly(Pp.str"No corecursive definition.")|[id]->Id.printid++str" is corecursively defined"|l->hov0(prlist_with_seppr_commaId.printl++spc()++str"are corecursively defined"))letrecursive_messageindexesl=matchindexeswith|None->cofixpoint_messagel|Someindexes->fixpoint_message(Someindexes)lletdefinition_messageid=Flags.if_verboseFeedback.msg_info(Id.printid++str" is defined")letassumption_messageid=(* Changing "assumed" to "declared", "assuming" referring more to
the type of the object than to the name of the object (see
discussion on coqdev: "Chapter 4 of the Reference Manual", 8/10/2015) *)Flags.if_verboseFeedback.msg_info(Id.printid++str" is declared")moduleInternal=structmoduleConstant=structtypet=constant_objlettag=objConstantletkindobj=obj.cst_kindendletobjVariable=objVariableletexport_side_effects=export_side_effectsend(* The word [proof] is to be understood as [justification] *)(* A possible alternatve would be [evidence]?? *)typeclosed_proof_output=((Constr.t*Evd.side_effects)*Constr.toption)list*UState.ttypeproof_object=|DefaultProofof{proof:closed_proof_output;opaque:bool;using:Names.Id.Set.toption;keep_body_ucst_separate:UState.toption}|DeferredOpaqueProofof{deferred_proof:closed_proof_outputFuture.computation;using:Names.Id.Set.toption;initial_proof_data:Proof.data;feedback_id:Stateid.t;initial_euctx:UState.t}letfuture_map2_pair_list_distributeplf=List.map_i(funic->f(Future.chainp(fun(a,b)->(List.nthai,b)))c)0lletprocess_proof~info:Info.({udecl;poly})?(is_telescope=false)=function|DefaultProof{proof=(entries,uctx);opaque;using;keep_body_ucst_separate}->(* Force transparency for Derive-like dependent statements *)letopaques=letn=List.lengthentriesinList.initn(funi->ifi<n-1&&is_telescopethen(* waiting for addition of cinfo-based opacity in #19029 *)falseelseopaque)in(* Multiple entries mean either a recursive block of definitions
(as in Co/Fixpoint) or a sequence of dependent definitions (as
in "Derive"). In the second case, the dependency in the
previous entries requires to accumulate the universes from the
previous definitions *)snd(List.fold_left2_map(funused_univs((body,eff),typ)opaque->letuctx,univs,used_univs,body=make_univs_immediate~poly?keep_body_ucst_separate~opaque~uctx~udecl~eff~used_univsbodytypin(used_univs,(definition_entry_core?using~univs?types:typbody,uctx)))Univ.Level.Set.emptyentriesopaques)|DeferredOpaqueProof{deferred_proof=bodies;using;initial_proof_data;feedback_id;initial_euctx}->let{Proof.poly;entry;sigma}=initial_proof_datain(* Deferred multiple entries currently assume either a mutual
Co/Fixpoint or no dependency (thus no "Derive"); to support
"Derive"-like statements, we would need a combinator on futures
that fold used universes *)future_map2_pair_list_distributebodies(Proofview.initial_goalsentry)(funbody_typ_uctx(_,_,initial_typ)->(* Testing if evar-closed? *)letinitial_typ=Evarutil.nf_evars_universessigma(EConstr.Unsafe.to_constrinitial_typ)in(* The flags keep_body_ucst_separate, opaque, etc. should be consistent with evar-closedness? *)letunivs=UState.univ_entry~poly:falseinitial_euctxinletbody=Future.chainbody_typ_uctx(fun(((body,eff),_typ),uctx)->letuctx=make_univs_deferred_private_mono~initial_euctx~uctx~udeclbody(Someinitial_typ)in((body,uctx),eff))in(delayed_definition_entry?using~univs~types:initial_typ~feedback_idbody,initial_euctx))letustate_of_proof=function|DefaultProof{proof=(_entries,uctx)}->uctx|DeferredOpaqueProof{initial_euctx}->initial_euctxletdeclare_definition_scheme~internal~univs~role~name?locc=letkind=Decls.(IsDefinitionScheme)inletentry=pure_definition_entry~univscinletkn,eff=declare_private_constant~role~kind~name~opaque:falseentryinDumpglob.dump_definition(CAst.make?loc(Constant.labelkn|>Label.to_id))false"scheme";let()=ifinternalthen()elsedefinition_messagenameinkn,eff(* Locality stuff *)letdeclare_entry~loc~name?(scope=Locality.default_scope)?(clearbody=false)~kind~typing_flags~user_warns?hook?(obls=[])~impargs~uctxentry=letshould_suggest=ProofEntry.get_opacityentry&¬(List.is_empty(Global.named_context()))&&Option.is_emptyentry.proof_entry_secctxinletdref=matchscopewith|Locality.Discharge->let()=declare_variable~typing_flags~name~kind(SectionLocalDef{clearbody;entry})inifshould_suggestthenProof_using.suggest_variable(Global.env())name;Names.GlobRef.VarRefname|Locality.Globallocal->assert(notclearbody);letkn=declare_constant~loc~name~local~kind~typing_flags?user_warns(DefinitionEntryentry)inletgr=Names.GlobRef.ConstRefkninifshould_suggestthenProof_using.suggest_constant(Global.env())kn;grinlet()=Impargs.maybe_declare_manual_implicitsfalsedrefimpargsinlet()=definition_messagenameinHook.call?hook{Hook.S.uctx;obls;scope;dref};drefletwarn_let_as_axiom=CWarnings.create~name:"let-as-axiom"~category:CWarnings.CoreCategories.vernacularPp.(funid->strbrk"Let definition"++spc()++Names.Id.printid++spc()++strbrk"declared as an axiom.")(* Declare an assumption when not in a section: Parameter/Axiom but also
Variable/Hypothesis seen as Local Parameter/Axiom *)letdeclare_parameter~name~scope~hook~impargs~uctxpe=letlocal=matchscopewith|Locality.Discharge->warn_let_as_axiomname;Locality.ImportNeedQualified|Locality.Globallocal->localinletkind=Decls.(IsAssumptionConjectural)inletdecl=ParameterEntrypeinletcst=declare_constant~loc:None~name~local~kind~typing_flags:Nonedeclinletdref=Names.GlobRef.ConstRefcstinlet()=Impargs.maybe_declare_manual_implicitsfalsedrefimpargsinlet()=assumption_messagenameinlet()=Hook.(call?hook{S.uctx;obls=[];scope;dref})incst(* Using processing *)letinterp_proof_using_genfenvevdcinfousing=letcextractv(fixnames,terms)=letname,new_terms=fvinname::fixnames,new_terms@termsinletfixnames,terms=CList.fold_rightcextractcinfo([],[])inProof_using.definition_usingenvevd~fixnames~terms~usingletinterp_proof_using_cinfoenvevdcinfousing=letf{CInfo.name;typ;_}=name,[EConstr.of_constrtyp]ininterp_proof_using_genfenvevdcinfousingletgather_mutual_using_datacinfo=List.fold_left2(funaccCInfo.{name}(body,typ)->letl=Option.List.flattenEConstr.[Option.mapof_constrtyp;Some(of_constrbody)]in(name,l)::acc)[]cinfoletinterp_mutual_usingenvcinfobodies_typesusing=letevd=Evd.from_envenvinOption.map(funusing->letcinfos=gather_mutual_using_datacinfobodies_typesinletfx=xininterp_proof_using_genfenvevdcinfosusing)usingletdeclare_possibly_mutual_definitions~info~cinfo~obls?(is_telescope=false)obj=letentries=process_proof~info~is_telescopeobjinlet{Info.hook;scope;clearbody;kind;typing_flags;user_warns;ntns;_}=infoinlet_,refs=List.fold_left2_map(funsubstCInfo.{name;impargs}(entry,uctx)->(* replacing matters for Derive-like statement but it does not hurt otherwise *)letentry=ProofEntry.map_entryentry~f:(Vars.replace_varssubst)inletgref=declare_entry~loc:info.loc~name~scope~clearbody~kind?hook~impargs~typing_flags~user_warns~obls~uctxentryinletinst=instance_of_univsentry.proof_entry_universesinletconst=Constr.mkRef(gref,inst)in((name,const)::subst,gref))[]cinfoentriesinlet()=(* For the recursive case, we override the temporary notations used while proving, now using the global names *)letlocal=info.scope=Locality.Dischargeinifntns<>[]thenCWarnings.with_warn("-"^Notation.warning_overridden_name)(List.iter(Metasyntax.add_notation_interpretation~local(Global.env())))ntnsinrefsletdeclare_possibly_mutual_parameters~info~cinfo?(mono_uctx_extra=UState.empty)~sec_varstyps=(* Note, if an initial uctx, minimize and restrict have not been done *)(* if the uctx of an abandonned proof, minimize is redundant (see close_proof) *)let{Info.scope;poly;hook;udecl}=infoinpi3(List.fold_left2(fun(i,subst,csts){CInfo.name;impargs}(typ,uctx)->letuctx'=UState.restrictuctx(Vars.universes_of_constrtyp)inletunivs=UState.check_univ_decl~polyuctx'udeclinletunivs=ifi=0thenadd_mono_uctxmono_uctx_extraunivselseunivsinlettyp=Vars.replace_varssubsttypinletpe={parameter_entry_secctx=sec_vars;parameter_entry_type=Evarutil.nf_evars_universes(Evd.from_ctxuctx)typ;parameter_entry_universes=univs;parameter_entry_inline_code=None;}inletcst=declare_parameter~name~scope~hook~impargs~uctxpeinletinst=instance_of_univsunivsin(i+1,(name,Constr.mkConstU(cst,inst))::subst,(cst,univs)::csts))(0,[],[])cinfotyps)letmake_recursive_bodiesenv~typing_flags~possible_guard~rec_declaration=letenv=Environ.update_typing_flags?typing_flagsenvinletindexes=Pretyping.search_guardenvpossible_guardrec_declarationinletmkbodyi=matchindexeswith|Someindexes->Constr.mkFix((indexes,i),rec_declaration)|None->Constr.mkCoFix(i,rec_declaration)inList.map_i(funityp->(mkbodyi,typ))0(Array.to_list(pi2rec_declaration)),indexesletprepare_recursive_declarationcinfofixtypesfixrsfixdefs=letfixnames=List.map(funCInfo.{name}->name)cinfoinletnames=List.map2(funnamer->Context.make_annot(Namename)r)fixnamesfixrsinletdefs=List.map(Vars.subst_vars(List.revfixnames))fixdefsin(Array.of_listnames,Array.of_listfixtypes,Array.of_listdefs)letprepare_recursive_edeclarationsigmacinfofixtypesfixrsfixdefs=letfixnames=List.map(funCInfo.{name}->name)cinfoinletnames=List.map2(funnamer->Context.make_annot(Namename)(EConstr.ERelevance.maker))fixnamesfixrsinletdefs=List.map(EConstr.Vars.subst_varssigma(List.revfixnames))fixdefsin(Array.of_listnames,Array.of_listfixtypes,Array.of_listdefs)letdeclare_mutual_definitions~info~cinfo~opaque~uctx~bodies~possible_guard?using()=(* Note: uctx is supposed to be already minimized *)let{Info.typing_flags;_}=infoinletenv=Global.env()inletpossible_guard,fixrelevances=possible_guardinletfixtypes=List.map(funCInfo.{typ}->typ)cinfoinletrec_declaration=prepare_recursive_declarationcinfofixtypesfixrelevancesbodiesinletbodies_types,indexes=make_recursive_bodiesenv~typing_flags~rec_declaration~possible_guardinletentries=List.map(fun(body,typ)->((body,Evd.empty_side_effects),Sometyp))bodies_typesinletentries_for_using=List.map(fun(body,typ)->(body,Sometyp))bodies_typesinletusing=interp_mutual_usingenvcinfoentries_for_usingusinginletobj=DefaultProof{proof=(entries,uctx);opaque;using;keep_body_ucst_separate=None}inletrefs=declare_possibly_mutual_definitions~info~cinfo~obls:[]objinletfixnames=List.map(fun{CInfo.name}->name)cinfoinrecursive_messageindexesfixnames;refs(* Preparing proof entries *)leterror_unresolved_evarsenvsigmatevars=letpr_unresolved_evare=hov2(str"- "++Printer.pr_existential_keyenvsigmae++str": "++Himsg.explain_pretype_errorenvsigma(Pretype_errors.UnsolvableImplicit(e,None)))inCErrors.user_err(hov0beginstr"The following term contains unresolved implicit arguments:"++fnl()++str" "++Printer.pr_econstr_envenvsigmat++fnl()++str"More precisely: "++fnl()++v0(prlist_with_sepcutpr_unresolved_evar(Evar.Set.elementsevars))end)letcheck_evars_are_solvedenvsigmat=letevars=Evarutil.undefined_evars_of_termsigmatinifnot(Evar.Set.is_emptyevars)thenerror_unresolved_evarsenvsigmatevarsletdeclare_definition~info~cinfo~opaque~obls~body?usingsigma=let{CInfo.name;typ;_}=cinfoinletenv=Global.env()inOption.iter(check_evars_are_solvedenvsigma)typ;check_evars_are_solvedenvsigmabody;letsigma=Evd.minimize_universessigmainletbody=EConstr.to_constrsigmabodyinlettyp=Option.map(EConstr.to_constrsigma)typinletuctx=Evd.ustatesigmainletusing=interp_mutual_usingenv[cinfo][body,typ]usinginletobj=DefaultProof{proof=([((body,Evd.empty_side_effects),typ)],uctx);opaque;using;keep_body_ucst_separate=None}inletgref=List.hd(declare_possibly_mutual_definitions~info~cinfo:[cinfo]~oblsobj)ingref,uctxletprepare_obligations~name?types~bodyenvsigma=letenv=Global.env()inlettypes=matchtypeswith|Somet->t|None->Retyping.get_type_ofenvsigmabodyinletsigma,(body,types)=Evarutil.finalize~abort_on_undefined_evars:falsesigma(funnf->nfbody,nftypes)inRetrieveObl.check_evarsenvsigma;letbody,types=EConstr.(of_constrbody,of_constrtypes)inletobls,(_,evmap),body,cty=RetrieveObl.retrieve_obligationsenvnamesigma0bodytypesinletuctx=Evd.ustatesigmainbody,cty,uctx,evmap,oblsletprepare_parameter~poly~udecl~typessigma=letenv=Global.env()inPretyping.check_evars_are_solved~program_mode:falseenvsigma;letsigma,typ=Evarutil.finalize~abort_on_undefined_evars:truesigma(funnf->nftypes)inletunivs=Evd.check_univ_decl~polysigmaudeclinletpe={parameter_entry_secctx=None;parameter_entry_type=typ;parameter_entry_universes=univs;parameter_entry_inline_code=None;}insigma,petypeprogress=Remainofint|Dependent|DefinedofGlobRef.tmoduleObls_=structopenConstrtype'aobligation_body=DefinedOblof'a|TermOblofconstrmoduleObligation=structtypet={obl_name:Id.t;obl_type:types;obl_location:Evar_kinds.tLoc.located;obl_body:pconstantobligation_bodyoption;obl_status:bool*Evar_kinds.obligation_definition_status;obl_deps:Int.Set.t;obl_tac:unitProofview.tacticoption}letset_type~typobl={oblwithobl_type=typ}endtypeobligations={obls:Obligation.tarray;remaining:int}typefixpoint_kind=IsFixpointoflidentoptionlist|IsCoFixpointmoduleProgramDecl=structtype'at={prg_cinfo:constrCInfo.t;prg_info:Info.t;prg_using:Vernacexpr.section_subset_exproption;prg_opaque:bool;prg_hook:'aoption;prg_body:constr;prg_uctx:UState.t;prg_obligations:obligations;prg_deps:Id.tlist;prg_possible_guard:(Pretyping.possible_guard*Sorts.relevancelist)option(* None = not recursive *);prg_reduce:constr->constr}openObligationletmake~info~cinfo~opaque~reduce~deps~uctx~body~possible_guard?obl_hook?usingobls=letobls',body=matchbodywith|None->assert(Int.equal(Array.lengthobls)0);letn=Nameops.add_suffixcinfo.CInfo.name"_obligation"in([|{obl_name=n;obl_body=None;obl_location=Loc.tagEvar_kinds.InternalHole;obl_type=cinfo.CInfo.typ;obl_status=(false,Evar_kinds.Expand);obl_deps=Int.Set.empty;obl_tac=None}|],mkVarn)|Someb->(Array.mapi(funi(n,t,l,o,d,tac)->{obl_name=n;obl_body=None;obl_location=l;obl_type=t;obl_status=o;obl_deps=d;obl_tac=tac})obls,b)inletprg_uctx=UState.make_flexible_nonalgebraicuctxin{prg_cinfo={cinfowithCInfo.typ=reducecinfo.CInfo.typ};prg_info=info;prg_using=using;prg_hook=obl_hook;prg_opaque=opaque;prg_body=body;prg_uctx;prg_obligations={obls=obls';remaining=Array.lengthobls'};prg_deps=deps;prg_possible_guard=possible_guard;prg_reduce=reduce}letshowprg=let{CInfo.name;typ;_}=prg.prg_cinfoinletenv=Global.env()inletsigma=Evd.from_envenvinId.printname++spc()++str":"++spc()++Printer.pr_constr_envenvsigmatyp++spc()++str":="++fnl()++Printer.pr_constr_envenvsigmaprg.prg_bodymoduleInternal=structletget_nameprg=prg.prg_cinfo.CInfo.nameletget_uctxprg=prg.prg_uctxletset_uctx~uctxprg={prgwithprg_uctx=uctx}letget_polyprg=prg.prg_info.Info.polyletget_obligationsprg=prg.prg_obligationsletget_usingprg=prg.prg_usingendendopenObligationopenProgramDecl(* Saving an obligation *)(* XXX: Is this the right place for this? *)letit_mkLambda_or_LetIn_or_cleantctx=letopenContext.Rel.Declarationinletfoldtdecl=ifis_local_assumdeclthenTerm.mkLambda_or_LetIndecltelseifVars.noccurn1tthenVars.subst1mkProptelseTerm.mkLambda_or_LetIndecltinContext.Rel.fold_insidefoldctx~init:t(* XXX: Is this the right place for this? *)letdecompose_lam_prodcty=letopenContext.Rel.Declarationinletrecauxctxcty=match(Constr.kindc,Constr.kindty)with|LetIn(x,b,t,c),LetIn(x',b',t',ty)whenConstr.equalbb'&&Constr.equaltt'->letctx'=Context.Rel.add(LocalDef(x,b',t'))ctxinauxctx'cty|_,LetIn(x',b',t',ty)->letctx'=Context.Rel.add(LocalDef(x',b',t'))ctxinauxctx'(lift1c)ty|LetIn(x,b,t,c),_->letctx'=Context.Rel.add(LocalDef(x,b,t))ctxinauxctx'c(lift1ty)|Lambda(x,b,t),Prod(x',b',t')(* By invariant, must be convertible *)->letctx'=Context.Rel.add(LocalAssum(x,b'))ctxinauxctx'tt'|Cast(c,_,_),_->auxctxcty|_,_->(ctx,c,ty)inauxContext.Rel.emptycty(* XXX: What's the relation of this with Abstract.shrink ? *)letshrink_bodycty=letctx,b,ty=matchtywith|None->letctx,b=Term.decompose_lambda_declscin(ctx,b,None)|Somety->letctx,b,ty=decompose_lam_prodctyin(ctx,b,Somety)inletb',ty',n,args=List.fold_left(fun(b,ty,i,args)decl->ifVars.noccurn1b&&Option.cata(Vars.noccurn1)truetythen(Vars.subst1mkPropb,Option.map(Vars.subst1mkProp)ty,succi,args)elseletopenContext.Rel.Declarationinletargs=ifis_local_assumdeclthenmkReli::argselseargsin(Term.mkLambda_or_LetIndeclb,Option.map(Term.mkProd_or_LetIndecl)ty,succi,args))(b,ty,1,[])ctxin(ctx,b',ty',Array.of_listargs)(***********************************************************************)(* Saving an obligation *)(***********************************************************************)letuniverses_of_declbodytyp=letunivs_typ=matchtypwithNone->Univ.Level.Set.empty|Somety->Vars.universes_of_constrtyinletunivs_body=Vars.universes_of_constrbodyinUniv.Level.Set.unionunivs_bodyunivs_typletcurrent_obligation_uctxprguctxvars=letuctx=UState.restrictuctxvarsinifprg.prg_info.Info.polythenuctxelse(* We let the first obligation declare the monomorphic universe
context of the main constant (goes together with
update_global_obligation_uctx) *)UState.unionprg.prg_uctxuctxletupdate_global_obligation_uctxprguctx=letuctx=ifprg.prg_info.Info.polythen(* Accumulate the polymorphic constraints *)UState.unionprg.prg_uctxuctxelse(* The monomorphic universe context of the main constant has
been declared by the first obligation; it is now in the
global env and we now remove it for the further
declarations *)UState.Internal.reboot(Global.env())uctxinProgramDecl.Internal.set_uctx~uctxprgletdeclare_obligationprgobl~uctx~types~body=letbody=prg.prg_reducebodyinlettypes=Option.mapprg.prg_reducetypesinmatchobl.obl_statuswith|_,Evar_kinds.Expand->letprg_uctx=UState.unionprg.prg_uctxuctxinletprg=ProgramDecl.Internal.set_uctx~uctx:prg_uctxprgin(prg,{oblwithobl_body=Some(TermOblbody)},[])|force,Evar_kinds.Defineopaque->letopaque=(notforce)&&opaqueinletpoly=prg.prg_info.Info.polyinletctx,body,ty,args=ifnotpolythenshrink_bodybodytypeselse([],body,types,[||])inletuctx'=current_obligation_uctxprguctx(universes_of_declbodytypes)inletunivs=UState.univ_entry~polyuctx'inletinst=instance_of_univsunivsinletce=definition_entry?types:ty~opaque~univsbodyin(* ppedrot: seems legit to have obligations as local *)letconstant=declare_constant~loc:None~name:obl.obl_name~typing_flags:prg.prg_info.Info.typing_flags~local:Locality.ImportNeedQualified~kind:Decls.(IsProofProperty)(DefinitionEntryce)indefinition_messageobl.obl_name;letprg=update_global_obligation_uctxprguctxinletbody=ifpolythenDefinedObl(constant,inst)elseletconst=mkConstU(constant,inst)inTermObl(it_mkLambda_or_LetIn_or_clean(mkApp(const,args))ctx)in(prg,{oblwithobl_body=Somebody},[GlobRef.ConstRefconstant])(* Updating the obligation meta-info on close *)letnot_transp_msg=Pp.(str"Obligation should be transparent but was declared opaque."++spc()++str"Use 'Defined' instead.")leterr_not_transp()=CErrors.user_errnot_transp_msgmoduleProgMap=Id.MapmoduleState=structtypet=prg_hookProgramDecl.tCEphemeron.keyProgMap.tandprg_hook=PrgHookoftHook.gletcall_prg_hook{prg_hook=hook}xpm=lethook=Option.map(fun(PrgHookh)->h)hookinHook.call_g?hookxpmletempty=ProgMap.emptyletpendingpm=ProgMap.filter(fun_v->(CEphemeron.getv).prg_obligations.remaining>0)pmletnum_pendingpm=pendingpm|>ProgMap.cardinalletfirst_pendingpm=pendingpm|>ProgMap.choose_opt|>Option.map(fun(_,v)->CEphemeron.getv)letget_unique_open_progpmname:(_,Id.tlist)result=matchnamewith|Somen->Option.cata(funp->Ok(CEphemeron.getp))(Error[])(ProgMap.find_optnpm)|None->(letn=num_pendingpminmatchnwith|0->Error[]|1->Option.cata(funp->Okp)(Error[])(first_pendingpm)|_->letprogs=Id.Set.elements(ProgMap.domainpm)inErrorprogs)letaddtkeyprg=ProgMap.addkey(CEphemeron.createprg)tletfoldt~f~init=letfkvacc=fk(CEphemeron.getv)accinProgMap.foldftinitletallpm=ProgMap.bindingspm|>List.map(fun(_,v)->CEphemeron.getv)letfindmt=ProgMap.find_opttm|>Option.mapCEphemeron.getmoduleView=structmoduleObl=structtypet={name:Id.t;loc:Loc.toption;status:bool*Evar_kinds.obligation_definition_status;solved:bool}letmake(o:Obligation.t)=let{obl_name;obl_location;obl_status;obl_body;_}=oin{name=obl_name;loc=fstobl_location;status=obl_status;solved=Option.has_someobl_body}endtypet={opaque:bool;remaining:int;obligations:Obl.tarray}letmake{prg_opaque;prg_obligations;_}={opaque=prg_opaque;remaining=prg_obligations.remaining;obligations=Array.mapObl.makeprg_obligations.obls}letmakeeph=CEphemeron.geteph|>makeendletviews=Id.Map.mapView.makesend(* In all cases, the use of the map is read-only so we don't expose the ref *)letmap_non_empty_keysis_emptym=ProgMap.fold(funkprgl->ifis_emptyprgthenlelsek::l)m[]letcheck_solved_obligationsis_empty~pm~what_for:unit=ifnot(ProgMap.is_emptypm)thenletkeys=map_non_empty_keysis_emptypminlethave_string=ifInt.equal(List.lengthkeys)1then" has "else" have "inCErrors.user_errPp.(str"Unsolved obligations when closing "++what_for++str":"++spc()++prlist_with_sepspc(funx->Id.printx)keys++strhave_string++str"unsolved obligations.")letmap_replacekvm=ProgMap.addk(CEphemeron.createv)(ProgMap.removekm)letprogmap_removepmprg=ProgMap.removeprg.prg_cinfo.CInfo.namepmletprogmap_replaceprg'pm=map_replaceprg'.prg_cinfo.CInfo.nameprg'pmletobligations_solvedprg=Int.equalprg.prg_obligations.remaining0letobligations_messagerem=Format.asprintf"%s %s remaining"(ifrem>0thenstring_of_intremelse"No more")(CString.pluralrem"obligation")|>Pp.str|>Flags.if_verboseFeedback.msg_infoletget_obligation_bodyexpandobl=matchobl.obl_bodywith|None->None|Somec->(ifexpand&&sndobl.obl_status==Evar_kinds.Expandthenmatchcwith|DefinedOblpc->Some(Environ.constant_value_in(Global.env())pc)|TermOblc->SomecelsematchcwithDefinedOblpc->Some(mkConstUpc)|TermOblc->Somec)letobl_substitutionexpandoblsdeps=Int.Set.fold(funxacc->letxobl=obls.(x)inmatchget_obligation_bodyexpandxoblwith|None->acc|Someoblb->(xobl.obl_name,(xobl.obl_type,oblb))::acc)deps[]letrecintset_to=function|-1->Int.Set.empty|n->Int.Set.addn(intset_to(predn))letobligation_substitutionexpandprg=letobls=prg.prg_obligations.oblsinletints=intset_to(pred(Array.lengthobls))inobl_substitutionexpandoblsintsletsubst_progsubstprg=letsubst'=List.map(fun(n,(_,b))->(n,b))substin(Vars.replace_varssubst'prg.prg_body,Vars.replace_varssubst'(* Termops.refresh_universes *)prg.prg_cinfo.CInfo.typ)letdeclare_definition~pmprg=letvarsubst=obligation_substitutiontrueprginletsigma=Evd.from_ctxprg.prg_uctxinletbody,types=subst_progvarsubstprginletbody,types=EConstr.(of_constrbody,of_constrtypes)inletcinfo={prg.prg_cinfowithCInfo.typ=Sometypes}inletname,info,opaque,using=prg.prg_cinfo.CInfo.name,prg.prg_info,prg.prg_opaque,prg.prg_usinginletobls=List.map(fun(id,(_,c))->(id,c))varsubstin(* XXX: This is doing normalization twice *)letkn,uctx=declare_definition~cinfo~info~obls~body~opaque?usingsigmain(* XXX: We call the obligation hook here, by consistency with the
previous imperative behaviour, however I'm not sure this is right *)letpm=State.call_prg_hookprg{Hook.S.uctx;obls;scope=prg.prg_info.Info.scope;dref=kn}pminletpm=progmap_removepmprginpm,knletdeclare_mutual_definitions~pml=letfirst=List.hdlinletdefoblx=letoblsubst=obligation_substitutiontruexinletsubs,typ=subst_progoblsubstxinletsigma=Evd.from_ctxx.prg_uctxinletterm=EConstr.of_constrsubsinlettyp=EConstr.of_constrtypinletterm=EConstr.to_constrsigmaterminlettyp=EConstr.to_constrsigmatypinletdef=(x.prg_reduceterm,x.prg_reducetyp,x.prg_cinfo.CInfo.impargs)inletoblsubst=List.map(fun(id,(_,c))->(id,c))oblsubstin(def,oblsubst)inletdefs,obls=List.split(List.mapdefobll)inletobls=List.flattenoblsinletfixitems=List.map2(fun(d,typ,impargs)name->CInfo.make~name~typ~impargs())defsfirst.prg_depsinletfixdefs,fixtypes,_=List.split3defsinletpossible_guard=Option.getfirst.prg_possible_guardin(* Declare the recursive definitions *)letkns=declare_mutual_definitions~info:first.prg_info~uctx:first.prg_uctx~bodies:fixdefs~possible_guard~opaque:first.prg_opaque~cinfo:fixitems?using:first.prg_using()in(* Only for the first constant *)letdref=List.hdknsinletscope=first.prg_info.Info.scopeinlets_hook={Hook.S.uctx=first.prg_uctx;obls;scope;dref}inHook.call?hook:first.prg_info.Info.hooks_hook;(* XXX: We call the obligation hook here, by consistency with the
previous imperative behaviour, however I'm not sure this is right *)letpm=State.call_prg_hookfirsts_hookpminletpm=List.fold_leftprogmap_removepmlinpm,drefletupdate_obls~pmprgoblsrem=letprg_obligations={obls;remaining=rem}inletprg'={prgwithprg_obligations}inletpm=progmap_replaceprg'pminobligations_messagerem;ifrem>0thenpm,Remainremelsematchprg'.prg_depswith|[]->letpm,kn=declare_definition~pmprg'inpm,Definedkn|l->letprogs=List.map(funx->CEphemeron.get(ProgMap.findxpm))prg'.prg_depsinifList.for_all(funx->obligations_solvedx)progsthenletpm,kn=declare_mutual_definitions~pmprogsinpm,Definedknelsepm,Dependentletdependenciesoblsn=letres=refInt.Set.emptyinArray.iteri(funiobl->if(not(Int.equalin))&&Int.Set.memnobl.obl_depsthenres:=Int.Set.addi!res)obls;!resletupdate_program_decl_on_defined~pmprgoblsnumoblrem~auto=letobls=Array.copyoblsinlet()=obls.(num)<-oblinletpm,_progress=update_obls~pmprgobls(predrem)inletpm=ifpredrem>0thenletdeps=dependenciesoblsnuminifnot(Int.Set.is_emptydeps)thenletpm,_progress=auto~pm(Someprg.prg_cinfo.CInfo.name)depsNoneinpmelsepmelsepminpmtypeobligation_resolver=pm:State.t->Id.toption->Int.Set.t->unitProofview.tacticoption->State.t*progresstypeobl_check_final=AllFinal|SpecificFinalofId.ttypeobligation_qed_info={name:Id.t;num:int;auto:obligation_resolver;check_final:obl_check_finaloption;}letnot_final_obligationn=letmsg=matchnwith|AllFinal->str"This obligation is not final."|SpecificFinaln->str"This obligation is not final for program "++Id.printn++str"."inCErrors.user_errmsgletdo_check_final~pm=function|None->()|Somecheck_final->letfinal=matchcheck_finalwith|AllFinal->beginmatchState.first_pendingpmwith|Some_->false|None->trueend|SpecificFinaln->beginmatchState.get_unique_open_progpm(Somen)with|Error_->true|Ok_->falseendinifnotfinalthennot_final_obligationcheck_finalletobligation_terminator~pm~entry~uctx~oinfo:{name;num;auto;check_final}=letenv=Global.env()inletty=entry.proof_entry_typeinletbody,uctx=inline_private_constants~uctxenv(ProofEntry.get_entry_bodyentry)inletsigma=Evd.from_ctxuctxinInductiveops.control_only_guard(Global.env())sigma(EConstr.of_constrbody);(* Declare the obligation ourselves and drop the hook *)letprg=Option.get(State.findpmname)inlet{obls;remaining=rem}=prg.prg_obligationsinletobl=obls.(num)inletstatus=match(obl.obl_status,ProofEntry.get_opacityentry)with|(_,Evar_kinds.Expand),true->err_not_transp()|(true,_),true->err_not_transp()|(false,_),true->Evar_kinds.Definetrue|(_,Evar_kinds.Definetrue),false->Evar_kinds.Definefalse|(_,status),false->statusinletobl={oblwithobl_status=(false,status)}inletprg,obl,cst=declare_obligationprgobl~body~types:ty~uctxinletpm=update_program_decl_on_defined~pmprgoblsnumoblrem~autoinlet()=do_check_final~pmcheck_finalinpm,cst(* Similar to the terminator but for the admitted path; this assumes
the admitted constant was already declared.
FIXME: There is duplication of this code with obligation_terminator
and Obligations.admit_obligations *)letobligation_admitted_terminator~pmtyp{name;num;auto;check_final}declare_funsec_varsuctx=letprg=Option.get(State.findpmname)inlet{obls;remaining=rem}=prg.prg_obligationsinletobl=obls.(num)inlet()=matchobl.obl_statuswith|true,Evar_kinds.Expand|true,Evar_kinds.Definetrue->err_not_transp()|_->()inletmono_uctx_extra=ifprg.prg_info.Info.polythenUState.emptyelseprg.prg_uctxinletcst,univs=declare_fun~uctx~mono_uctx_extratypinletinst=instance_of_univsunivsinletobl={oblwithobl_body=Some(DefinedObl(cst,inst))}inletprg=update_global_obligation_uctxprguctxinletpm=update_program_decl_on_defined~pmprgoblsnumoblrem~autoinlet()=do_check_final~pmcheck_finalinpmend(************************************************************************)(* Handling of interactive proofs *)(************************************************************************)moduleProof_ending=structtypet=|Regular|End_obligationofObls_.obligation_qed_info|End_equationsof{hook:pm:Obls_.State.t->Constant.tlist->Evd.evar_map->Obls_.State.t;i:Id.t;types:(Environ.env*Evar.t*Evd.undefinedEvd.evar_info*EConstr.named_context*Evd.econstr)list;sigma:Evd.evar_map}endmoduleProof_info=structtypet={cinfo:unitCInfo.tlist(** cinfo contains each individual constant info in a mutual decl *);info:Info.t;proof_ending:Proof_ending.tCEphemeron.key(* This could be improved and the CEphemeron removed *);possible_guard:(Pretyping.possible_guard*Sorts.relevancelist)option(* None = not recursive *)(** thms and compute guard are specific only to
start_definition + regular terminator, so we
could make this per-proof kind *)}letmake~cinfo~info?possible_guard?(proof_ending=Proof_ending.Regular)()={cinfo;info;possible_guard;proof_ending=CEphemeron.createproof_ending}endmoduleProof_object=structtypet={proof_object:proof_object;pinfo:Proof_info.t}end(* Alias *)moduleProof_=ProofmoduleProof=structtypenonrecclosed_proof_output=closed_proof_outputtypeproof_object=Proof_object.ttypet={endline_tactic:Genarg.glob_generic_argumentoption;using:Id.Set.toption;proof:Proof.t;initial_euctx:UState.t(** The initial universe context (for the statement) *);pinfo:Proof_info.t}(*** Proof Global manipulation ***)letgetps=ps.proofletget_nameps=(Proof.dataps.proof).Proof.nameletfold~fp=fp.proofletmap~fp={pwithproof=fp.proof}letmap_fold~fp=letproof,res=fp.proofin{pwithproof},resletmap_fold_endline~fps=letet=matchps.endline_tacticwith|None->Proofview.tclUNIT()|Sometac->letopenGeninterpinlet{Proof.poly}=Proof.dataps.proofinletist={lfun=Id.Map.empty;poly;extra=TacStore.empty}inlettac=Geninterp.generic_interpisttacinFtactic.runtac(fun_->Proofview.tclUNIT())inlet(newpr,ret)=fetps.proofinletps={pswithproof=newpr}inps,retletcompactpf=map~f:Proof.compactpf(* Sets the tactic to be used when a tactic line is closed with [...] *)letset_endline_tactictacps={pswithendline_tactic=Sometac}letinitialize_named_context_for_proof()=letsign=Global.named_context()inList.fold_right(fundsignv->letid=NamedDecl.get_iddinletd=ifDecls.variable_opacityidthenNamedDecl.drop_bodydelsedinEnviron.push_named_context_valdsignv)signEnviron.empty_named_context_valletstart_proof_core~name~pinfo?usingsigmagoals=(* In ?sign, we remove the bodies of variables in the named context
marked "opaque", this is a hack tho, see #10446, and
build_constant_by_tactic uses a different method that would break
program_inference_hook *)let{Proof_info.info={Info.poly;typing_flags;_};_}=pinfoinletgoals=List.map(fun(sign,typ)->letsign=matchsignwithNone->initialize_named_context_for_proof()|Somesign->signin(Global.env_of_contextsign,typ))goalsinletproof=Proof.start~name~poly?typing_flagssigmagoalsinletinitial_euctx=Evd.ustateProof.((dataproof).sigma)in{proof;endline_tactic=None;using;initial_euctx;pinfo}(** [start_proof ~info ~cinfo sigma] starts a proof of [cinfo].
The proof is started in the evar map [sigma] (which
can typically contain universe constraints) *)letstart_core~info~cinfo?proof_ending?usingsigma=let{CInfo.name;typ;_}=cinfoincheck_existsname;letcinfo=[{cinfowithCInfo.typ=()}]inletpinfo=Proof_info.make~cinfo~info?proof_ending()instart_proof_core~name~pinfo?usingsigma[None,typ]letstart=start_core?proof_ending:Noneletstart_dependent~info~cinfo~name~proof_endinggoals=let{Info.poly;typing_flags;_}=infoinletproof=Proof.dependent_start~name~poly?typing_flagsgoalsinletinitial_euctx=Evd.ustateProof.((dataproof).sigma)inletpinfo=Proof_info.make~info~cinfo~proof_ending()in{proof;endline_tactic=None;using=None;initial_euctx;pinfo}letstart_derive~name~info~cinfogoals=letproof_ending=Proof_ending.Regularinstart_dependent~info~cinfo~name~proof_endinggoalsletstart_equations~name~info~hook~typessigmagoals=letproof_ending=Proof_ending.End_equations{hook;i=name;types;sigma}instart_dependent~name~cinfo:[]~info~proof_endinggoalsletstart_definition~info~cinfo?usingsigma=let{CInfo.name;typ;args}=cinfoinletinit_tac=Tactics.auto_intros_tacargsinletpinfo=Proof_info.make~cinfo:[{cinfowithtyp=()}]~info()inletenv=Global.env()inletusing=Option.map(interp_proof_using_cinfoenvsigma[cinfo])usinginletlemma=start_proof_core~name~pinfo?usingsigma[None,EConstr.of_constrtyp]inmaplemma~f:(funp->pi1@@Proof.run_tacticGlobal.(env())init_tacp)letstart_mutual_definitions~info~cinfo~bodies~possible_guard?usingsigma=letintro_tac{CInfo.args;_}=Tactics.auto_intros_tacargsinletfixrs=sndpossible_guardinletinit_tac=(* This is the case for hybrid proof mode / definition
fixpoint, where terms for some constants are given with := *)lettacl=List.map(Option.cata(EConstr.of_constr%>Tactics.exact_no_check)Tacticals.tclIDTAC)bodiesinList.map2(funtacthm->Tacticals.tclTHENtac(intro_tacthm))taclcinfoinmatchcinfowith|[]->CErrors.anomaly(Pp.str"No proof to start.")|{CInfo.name;_}::_asthms->letpinfo=Proof_info.make~cinfo:(List.map(funcinfo->{cinfowithCInfo.typ=()})cinfo)~info~possible_guard()in(* start_lemma has the responsibility to add (name, impargs, typ)
to thms, once Info.t is more refined this won't be necessary *)letenv=Global.env()inletsign=List.fold_left2(funsignCInfo.{name;typ}r->lettyp=EConstr.of_constrtypinletr=EConstr.ERelevance.makerinletdecl=Context.Named.Declaration.LocalAssum(Context.make_annotnamer,typ)inEConstr.push_named_context_valdeclsign)(initialize_named_context_for_proof())cinfofixrsinletusing=Option.map(interp_proof_using_cinfoenvsigmacinfo)usinginletgoals=List.map(functionCInfo.{typ}->(Somesign,EConstr.of_constrtyp))thmsinletlemma=start_proof_core~name~pinfo?usingsigmagoalsinletlemma=maplemma~f:(funp->pi1@@Proof.run_tacticGlobal.(env())(Proofview.tclFOCUS1(List.lengththms)(Proofview.tclDISPATCHinit_tac))p)inlet()=(* Temporary declaration of notations for the time of the proofs *)letntn_env=(* We simulate the goal context in which the fixpoint bodies have to be proved (exact relevance does not matter) *)letmake_declCInfo.{name;typ}=Context.Named.Declaration.LocalAssum(Context.annotRname,typ)inEnviron.push_named_context(List.mapmake_declcinfo)(Global.env())inList.iter(Metasyntax.add_notation_interpretation~local:(info.scope=Locality.Discharge)ntn_env)info.ntnsinlemmaletget_used_variablespf=pf.usingletdefinition_scopeps=ps.pinfo.info.scopeletset_used_variablesps~using=letopenContext.Named.Declarationinletenv=Global.env()inletctx=Environ.keep_hypsenvusinginletctx_set=List.fold_rightId.Set.add(List.mapNamedDecl.get_idctx)Id.Set.emptyinletvars_of=Environ.global_vars_setinletauxenventry(ctx,all_safeasorig)=matchentrywith|LocalAssum({Context.binder_name=x},_)->ifId.Set.memxall_safethenorigelse(ctx,all_safe)|LocalDef({Context.binder_name=x},bo,ty)asdecl->ifId.Set.memxall_safethenorigelseletvars=Id.Set.union(vars_ofenvbo)(vars_ofenvty)inifId.Set.subsetvarsall_safethen(decl::ctx,Id.Set.addxall_safe)else(ctx,all_safe)inletctx,_=Environ.fold_named_contextauxenv~init:(ctx,ctx_set)inifnot(Option.is_emptyps.using)thenCErrors.user_errPp.(str"Used section variables can be declared only once");ctx,{pswithusing=Some(Context.Named.to_varsctx)}(* Interprets the expression in the current proof context, from vernacentries *)letget_recnamespf=ifOption.has_somepf.pinfo.Proof_info.possible_guardthenList.map(func->c.CInfo.name)pf.pinfo.Proof_info.cinfoelse[]letinterpret_proof_usingpstateusing=letenv=Global.env()inletpf=getpstateinletsigma,_=Proof.get_proof_contextpfinletfixnames=get_recnamespstateinletinitial_goalspf=Proofview.initial_goalsProof.((datapf).entry)inletterms=List.mappi3(initial_goals(getpstate))inProof_using.definition_usingenvsigma~fixnames~using~termsletset_proof_usingpstateusing=letusing=interpret_proof_usingpstateusinginset_used_variablespstate~usingletget_open_goalsps=letProof.{goals;stack;sigma}=Proof.dataps.proofinList.lengthgoals+List.fold_left(+)0(List.map(fun(l1,l2)->List.lengthl1+List.lengthl2)stack)+List.length(Evd.shelfsigma)letwarn_remaining_shelved_goals=CWarnings.create~name:"remaining-shelved-goals"~category:CWarnings.CoreCategories.tactics(fun()->Pp.str"The proof has remaining shelved goals.")letwarn_given_up=CWarnings.create~name:"remaining-given-up"~category:CWarnings.CoreCategories.tactics(fun()->Pp.str"The proof has given up (admitted) goals.")letwarn_remaining_unresolved_evars=CWarnings.create~name:"remaining-unresolved-evars"~category:CWarnings.CoreCategories.tactics(fun()->Pp.str"The proof has unresolved variables.")typeopen_proof_kind=|OpenGoals|NonGroundResultofbool(* true = at least some of the evars in the proof term are given up *)exceptionOpenProofofNames.Id.t*open_proof_kindlet()=CErrors.register_handlerbeginfunction|OpenProof(pid,reason)->letopenPpinletppreason=matchreasonwith|OpenGoals->str"(there are remaining open goals)"|NonGroundResulthas_given_up->str"(the proof term is not complete"++(ifhas_given_upthenstr" because of given up (admitted) goals"elsemt())++str")"inlethow_to_admit=matchreasonwith|OpenGoals|NonGroundResultfalse->mt()|NonGroundResulttrue->fnl()++str"If this is really what you want to do, use Admitted in place of Qed."inSome(str" (in proof "++Names.Id.printpid++str"): "++str"Attempt to save an incomplete proof"++spc()++ppreason++str"."++how_to_admit)|_->Noneendletraise_non_ground_proofevdpidc=lethas_given_up=letexceptionFoundinletrecauxc=let()=matchEConstr.kindevdcwith|Evar(e,_)->ifEvar.Set.meme(Evd.given_upevd)thenraiseFound|_->()inEConstr.iterevdauxcintryauxc;falsewithFound->trueinraise(OpenProof(pid,NonGroundResulthas_given_up))letcheck_incomplete_proofevd=ifEvd.has_shelvedevdthenwarn_remaining_shelved_goals()elseifEvd.has_given_upevdthenwarn_given_up()elseifEvd.has_undefinedevdthenwarn_remaining_unresolved_evars()(* XXX: This is still separate from close_proof below due to drop_pt in the STM *)letprepare_proof?(warn_incomplete=true){proof;pinfo}=letProof.{name=pid;entry;poly;sigma=evd}=Proof.dataproofinletinitial_goals=Proofview.initial_goalsentryinlet()=ifnot@@Proof.is_doneproofthenraise(OpenProof(pid,OpenGoals))inlet_:Proof.t=(* checks that we closed all brackets ("}") *)Proof.unfocus_allproofinleteff=Evd.eval_side_effectsevdinletevd=Evd.minimize_universesevdinletto_constrc=matchEConstr.to_constr_optevdcwith|Somep->p|None->raise_non_ground_proofevdpidcin(* ppedrot: FIXME, this is surely wrong. There is no reason to duplicate
side-effects... This may explain why one need to uniquize side-effects
thereafter... *)(* EJGA: actually side-effects de-duplication and this codepath is
unrelated. Duplicated side-effects arise from incorrect scheme
generation code, the main bulk of it was mostly fixed by #9836
but duplication can still happen because of rewriting schemes I
think; however the code below is mostly untested, the only
code-paths that generate several proof entries are derive and
equations and so far there is no code in the CI that will
actually call those and do a side-effect, TTBOMK *)(* EJGA: likely the right solution is to attach side effects to the first constant only? *)letproofs=List.map(fun(_,body,typ)->(to_constrbody,to_constrtyp))initial_goalsinletproofs=matchpinfo.possible_guardwith|None->proofs|Some(possible_guard,fixrelevances)->letenv=Safe_typing.push_private_constants(Global.env())eff.Evd.seff_privateinletfixbodies,fixtypes=List.splitproofsinletrec_declaration=prepare_recursive_declarationpinfo.cinfofixtypesfixrelevancesfixbodiesinlettyping_flags=pinfo.info.typing_flagsinfst(make_recursive_bodiesenv~typing_flags~possible_guard~rec_declaration)inletproofs=List.map(fun(body,typ)->((body,eff),Sometyp))proofsinlet()=ifwarn_incompletethencheck_incomplete_proofevdinproofs,Evd.ustateevdexceptionNotGuardedofEnviron.env*Evd.evar_map*(Environ.env*int*EConstr.tType_errors.pcofix_guard_error)option*(Environ.env*int*intlist*EConstr.tType_errors.pfix_guard_error)list*EConstr.rec_declarationlet()=CErrors.register_handler(function|NotGuarded(env,sigma,cofix_err,fix_errs,rec_declaration)->Some(Himsg.explain_not_guardedenvsigmacofix_errfix_errsrec_declaration)|_->None)letcontrol_only_guard{proof;pinfo}=let{Proof.entry;Proof.sigma;}=Proof.dataproofinletinitial_goals=Proofview.initial_goalsentryinletproofs=List.map(fun(_,body,typ)->Evarutil.(nf_evarsigmabody,nf_evarsigmatyp))initial_goalsinleteff=Evd.eval_side_effectssigmainletenv=Safe_typing.push_private_constants(Global.env())eff.Evd.seff_privateinletopenProof_infoinmatchpinfo.possible_guardwith|None->List.iter(fun(body,_)->Inductiveops.control_only_guardenvsigmabody)proofs|Some(possible_guard,fixrelevances)->letfixbodies,fixtypes=List.splitproofsinletrec_declaration=prepare_recursive_edeclarationsigmapinfo.cinfofixtypesfixrelevancesfixbodiesintryletcofix_error=ifpossible_guard.possibly_cofixthentryInductiveops.control_only_guardenvsigma(EConstr.mkCoFix(0,rec_declaration));raiseExitwithPretype_errors.PretypeError(env,sigma,TypingError(IllFormedRecBody(CoFixGuardErrorwhy,lna,i,fixenv,vdefj)))->Some(env,i,why)elseNoneinletcombinations=List.combinationspossible_guard.possible_fix_indicesinletfix_errors=List.map(funlv->tryInductiveops.control_only_guardenvsigma(EConstr.mkFix((Array.of_listlv,0),rec_declaration));raiseExitwithPretype_errors.PretypeError(env,sigma,TypingError(IllFormedRecBody(FixGuardErrorwhy,lna,i,fixenv,vdefj)))->(env,i,lv,why))combinationsinraise(NotGuarded(env,sigma,cofix_error,fix_errors,rec_declaration))withExit->()letreturn_proofp=(prepare_proofp:closed_proof_output)letclose_proof?warn_incomplete~opaque~keep_body_ucst_separate(proof:t):Proof_object.t=NewProfile.profile"close_proof"(fun()->letopaque=matchopaquewith|Vernacexpr.Opaque->true|Vernacexpr.Transparent->falseinletkeep_body_ucst_separate=ifkeep_body_ucst_separatethenSomeproof.initial_euctxelseNonein{Proof_object.proof_object=DefaultProof{proof=prepare_proof?warn_incompleteproof;opaque;using=proof.using;keep_body_ucst_separate};pinfo=proof.pinfo})()letclose_proof_delayed~feedback_idproof(fpl:closed_proof_outputFuture.computation):Proof_object.t=NewProfile.profile"close_proof_delayed"(fun()->{Proof_object.proof_object=DeferredOpaqueProof{deferred_proof=fpl;using=proof.using;initial_proof_data=Proof.dataproof.proof;feedback_id;initial_euctx=proof.initial_euctx};pinfo=proof.pinfo})()letclose_future_proof=close_proof_delayedletupdate_sigma_univsugraphp=map~f:(Proof.update_sigma_univsugraph)pletnext=letn=ref0infun()->incrn;!nletbytac=map_fold~f:(Proof.solve(Goal_select.SelectNth1)Nonetac)letbuild_constant_by_tactic~name?warn_incomplete~sigma~sign~poly(typ:EConstr.t)tac=letcinfo=[CInfo.make~name~typ:()()]inletinfo=Info.make~poly()inletpinfo=Proof_info.make~cinfo~info()inletpf=start_proof_core~name~pinfosigma[Somesign,typ]inletpf,status=bytacpfinletproof=close_proof?warn_incomplete~keep_body_ucst_separate:false~opaque:Vernacexpr.Transparentpfinletentries=process_proof~infoproof.proof_objectinlet{Proof.sigma}=Proof.datapf.proofinletsigma=Evd.set_universe_contextsigma(ustate_of_proofproof.proof_object)inmatchentrieswith|[{proof_entry_body=Default{body;opaque=Transparent}}asentry,_]->{entrywithproof_entry_body=body},status,sigma|_->CErrors.anomalyPp.(str"[build_constant_by_tactic] close_proof returned more than one proof term, or a non transparent one.")letbuild_by_tacticenv~uctx~poly~typtac=letname=Id.of_string("temporary_proof"^string_of_int(next()))inletsign=Environ.(val_of_named_context(named_contextenv))inletsigma=Evd.from_ctxuctxinletce,status,sigma=build_constant_by_tactic~name~sigma~sign~polytyptacinletuctx=Evd.ustatesigmain(* ignore side effect universes:
we don't reset the global env in this code path so the side effects are still present
cf #13271 and discussion in #18874
(but due to #13324 we still want to inline them) *)letbody,effs=ce.proof_entry_bodyinletbody,_uctx=inline_private_constants~uctxenv((body,Univ.ContextSet.empty),effs)inbody,ce.proof_entry_type,ce.proof_entry_universes,status,uctxletdeclare_abstract~name~poly~sign~secsign~opaque~solve_tacsigmaconcl=letkind=ifopaquethenDecls.(IsProofLemma)elseDecls.(IsDefinitionDefinition)inlet(const,safe,sigma')=trybuild_constant_by_tactic~warn_incomplete:false~name~poly~sigma~sign:secsignconclsolve_tacwithLogic_monad.TacticFailureeassrc->(* if the tactic [tac] fails, it reports a [TacticFailure e],
which is an error irrelevant to the proof system (in fact it
means that [e] comes from [tac] failing to yield enough
success). Hence it reraises [e]. *)let(_,info)=Exninfo.capturesrcinExninfo.iraise(e,info)inletsigma=Evd.drop_new_defined~original:sigmasigma'inletbody,effs=const.proof_entry_bodyin(* EJGA: Hack related to the above call to
`build_constant_by_tactic` with `~opaque:Transparent`. Even if
the abstracted term is destined to be opaque, if we trigger the
`if poly && opaque && private_poly_univs ()` in `close_proof`
kernel will boom. This deserves more investigation. *)letbody,typ,args=ProofEntry.shrink_entrysignbodyconst.proof_entry_typeinletcst()=(* do not compute the implicit arguments, it may be costly *)let()=Impargs.make_implicit_argsfalsein(* No side-effects in the entry, they already exist in the ambient environment *)letconst={constwithproof_entry_body=body;proof_entry_type=typ}in(* ppedrot: seems legit to have abstracted subproofs as local*)declare_private_constant~local:Locality.ImportNeedQualified~name~kind~opaqueconstinletcst,eff=Impargs.with_implicit_protectioncst()inletinst=instance_of_univsconst.proof_entry_universesinletlem=EConstr.of_constr(Constr.mkConstU(cst,inst))inleteffs=Evd.concat_side_effectseffeffsineffs,sigma,lem,args,safeletget_goal_contextpfi=letp=getpfinProof.get_goal_context_genpiletget_current_goal_contextpf=letp=getpfintryProof.get_goal_context_genp1with|Proof.NoSuchGoal_->(* spiwack: returning empty evar_map, since if there is no goal,
under focus, there is no accessible evar either. EJGA: this
seems strange, as we have pf *)letenv=Global.env()inEvd.from_envenv,envletget_current_contextpf=letp=getpfinProof.get_proof_contextp(************************************************************************)(* Admitting a lemma-like constant *)(************************************************************************)(* Admitted *)let{Goptions.get=get_keep_admitted_vars}=Goptions.declare_bool_option_and_ref~key:["Keep";"Admitted";"Variables"]~value:true()letcompute_proof_using_for_admittedpinfoprooftypsiproof=ifnot(get_keep_admitted_vars())||not(Lib.sections_are_opened())thenNoneelsematchget_used_variablesproofwith|Some_asx->x|None->letpproofs=Proof.partial_proofiproofinletenv=Global.env()inletsigma=(Proof.dataiproof).Proof.sigmainletids_def=Id.Set.List.union(List.map(Termops.global_vars_setenvsigma)pproofs)inletids_typ=Id.Set.List.union(List.map(Termops.global_vars_setenvsigma)typs)in(* [pproof] is evar-normalized by [partial_proof]. We don't
count variables appearing only in the type of evars. *)letvars=Id.Set.unionids_defids_typinletvars=matchpinfo.Proof_info.possible_guardwith|Some_->letrecvars=Id.Set.of_list(List.map(funCInfo.{name}->name)pinfo.cinfo)inId.Set.diffvarsrecvars|None->varsinSome(Environ.really_neededenvvars)letcheck_type_evars_solvedenvsigmatyp=letevars=Evar.Set.elements(Evarutil.undefined_evars_of_termsigmatyp)inmatchevarswith|[]->()|evk::_->CErrors.user_err(str"Cannot admit: the statement has unresolved existential variables.")letfinish_admitted~pm~pinfo~sec_varstyps=(* If the constant was an obligation we need to update the program map *)let{Proof_info.info;cinfo}=pinfoinmatchCEphemeron.defaultpinfo.Proof_info.proof_endingProof_ending.Regularwith|Proof_ending.End_obligationoinfo->letdeclare_fun~uctx~mono_uctx_extratyp=List.hd(declare_possibly_mutual_parameters~info~cinfo~sec_vars~mono_uctx_extra[typ,uctx])inlettyp,uctx=matchtypswith[typ,uctx]->typ,uctx|_->assertfalseinObls_.obligation_admitted_terminator~pmtypoinfodeclare_funsec_varsuctx|_->let(_:'alist)=declare_possibly_mutual_parameters~info~cinfo~sec_varstypsinpmletsave_admitted~pm~proof=letiproof=getproofinletProof.{entry}=Proof.dataiproofinlettyps=List.mappi3(Proofview.initial_goalsentry)inletsigma=Evd.from_ctxproof.initial_euctxinList.iter(check_type_evars_solved(Global.env())sigma)typs;letsec_vars=compute_proof_using_for_admittedproof.pinfoprooftypsiproofinletsigma=Evd.minimize_universessigmainletuctx=Evd.ustatesigmainlettyps=List.map(funtyp->(EConstr.to_constrsigmatyp,uctx))typsinfinish_admitted~pm~pinfo:proof.pinfo~sec_varstyps(************************************************************************)(* Saving a lemma-like constant *)(************************************************************************)letfinish_proved_equations~pm~kind~hookientriestypessigma0=letobls=ref1inletsigma,recobls=CList.fold_left2_map(funsigma(_evar_env,ev,_evi,local_context,_type)entry->letid=matchEvd.evar_identevsigma0with|Someid->id|None->letn=!oblsinincrobls;Nameops.add_suffixi("_obligation_"^string_of_intn)inlet(body,eff),opaque=matchentry.proof_entry_bodywithDefault{body;opaque}->body,opaque|_->assertfalseinletbody,typ,args=ProofEntry.shrink_entrylocal_contextbodyentry.proof_entry_typeinletentry={entrywithproof_entry_body=Default{body=(body,eff);opaque};proof_entry_type=typ}inletcst=declare_constant~loc:None~name:id~kind~typing_flags:None(DefinitionEntryentry)inletsigma,app=Evd.fresh_global(Global.env())sigma(GlobRef.ConstRefcst)inletsigma=Evd.defineev(EConstr.applist(app,args))sigmainsigma,cst)sigma0typesentriesinletpm=hook~pmrecoblssigmainpm,List.map(funcst->GlobRef.ConstRefcst)recoblsletcheck_single_entryentrieslabel=matchentrieswith|[entry,uctx]->entry,uctx|_->CErrors.anomaly~labelPp.(str"close_proof returned more than one proof term")letfinish_proof~pmproof_objproof_info=letopenProof_endinginlet{Proof_info.info;cinfo;possible_guard}=proof_infoinmatchCEphemeron.defaultproof_info.Proof_info.proof_endingRegularwith|Regular->(* Unless this is a block of mutual fixpoint, we assume the
statements, if more than one, to form a telescope, as in Derive *)letis_telescope=Option.is_emptyproof_info.possible_guardinpm,declare_possibly_mutual_definitions~info~cinfo~obls:[]~is_telescopeproof_obj|End_obligationoinfo->letentries=process_proof~infoproof_objinletentry,uctx=check_single_entryentries"Obligation.save"inObls_.obligation_terminator~pm~entry~uctx~oinfo|End_equations{hook;i;types;sigma}->letkind=info.Info.kindinletentries=process_proof~infoproof_objinletentries=List.mapfstentriesinfinish_proved_equations~pm~kind~hookientriestypessigmaleterr_save_forbidden_in_place_of_qed()=CErrors.user_err(Pp.str"Cannot use Save with more than one constant or in this proof mode")letprocess_idopt_for_save~idoptinfo=matchidoptwith|None->info|Some{CAst.v=save_name}->(* Save foo was used; we override the info in the first theorem *)letcinfo=matchinfo.Proof_info.cinfo,CEphemeron.defaultinfo.Proof_info.proof_endingProof_ending.Regularwith|[{CInfo.name;_}asdecl],Proof_ending.Regular->[{declwithCInfo.name=save_name}]|_->err_save_forbidden_in_place_of_qed()in{infowithProof_info.cinfo}letsave~pm~proof~opaque~idopt=(* Env and sigma are just used for error printing in save_remaining_recthms *)letproof_obj=close_proof~opaque~keep_body_ucst_separate:falseproofinletproof_info=process_idopt_for_save~idoptproof.pinfoinfinish_proof~pmproof_obj.proof_objectproof_infoletsave_regular~(proof:t)~opaque~idopt=letopenProof_endinginmatchCEphemeron.defaultproof.pinfo.Proof_info.proof_endingRegularwith|Regular->let(_,grs):Obls_.State.t*_=save~pm:Obls_.State.empty~proof~opaque~idoptingrs|_->CErrors.anomalyPp.(str"save_regular: unexpected proof ending")(***********************************************************************)(* Special case to close a lemma without forcing a proof *)(***********************************************************************)letsave_lemma_admitted_delayed~pm~proof=let{Proof_object.proof_object;pinfo}=proofinletentries=process_proof~info:pinfo.infoproof_objectinlettyps=List.map(function{proof_entry_type},uctx->Option.getproof_entry_type,uctx)entriesin(* Note: an alternative would be to compute sec_vars of the partial
proof as a Future computation, as in compute_proof_using_for_admitted *)letsec_vars=ifget_keep_admitted_vars()then(fst(List.hdentries)).proof_entry_secctxelseNonein(* If the proof is partial, do we want to take the (restriction on
visible uvars of) uctx so far or (as done below) the initial ones
that refers to only the types *)finish_admitted~pm~pinfo:proof.pinfo~sec_varstypsletsave_lemma_proved_delayed~pm~proof~idopt=(* vio2vo used to call this with invalid [pinfo], now it should work fine. *)letpinfo=process_idopt_for_save~idoptproof.Proof_object.pinfoinletpm,_=finish_proof~pmproof.proof_objectpinfoinpmend(* Proof module *)let_=Ind_tables.declare_definition_scheme:=declare_definition_schemelet_=Abstract.declare_abstract:=Proof.declare_abstractletbuild_by_tactic=Proof.build_by_tactic(* This module could be merged with Obl, and placed before [Proof],
however there is a single dependency on [Proof.start] for the interactive case *)moduleObls=struct(* For the records fields, opens should go away one these types are private *)openObls_openObls_.ObligationopenObls_.ProgramDeclletreducec=letenv=Global.env()inletsigma=Evd.from_envenvinEConstr.Unsafe.to_constr(Reductionops.clos_norm_flagsRedFlags.betaiotaenvsigma(EConstr.of_constrc))letexplain_no_obligations=functionSomeident->str"No obligations for program "++Id.printident|None->str"No obligations remaining"moduleError=structletno_obligationsn=CErrors.user_err(explain_no_obligationsn)letambiguous_programidids=CErrors.user_errPp.(str"More than one program with unsolved obligations: "++prlistId.printids++str"; use the \"of\" clause to specify, as in \"Obligation 1 of "++Id.printid++str"\"")letunknown_obligationnum=CErrors.user_err(Pp.str(Printf.sprintf"Unknown obligation number %i"(succnum)))letalready_solvednum=CErrors.user_errPp.(str"Obligation "++intnum++str" already solved.")letdependsnumrem=CErrors.user_err(str"Obligation "++intnum++str" depends on obligation(s) "++pr_sequence(funx->int(succx))rem)endletdefault_tactic=ref(Proofview.tclUNIT())letsubst_depsexpandoblsdepst=letosubst=Obls_.obl_substitutionexpandoblsdepsin(Vars.replace_vars(List.map(fun(n,(_,b))->n,b)osubst)t)letsubst_deps_obloblsobl=lett'=subst_depstrueoblsobl.obl_depsobl.obl_typeinObligation.set_type~typ:t'oblletis_definedoblsx=not(Option.is_emptyobls.(x).obl_body)letdeps_remainingoblsdeps=Int.Set.fold(funxacc->ifis_definedoblsxthenaccelsex::acc)deps[]letgoal_kind=Decls.(IsDefinitionDefinition)letgoal_proof_kind=Decls.(IsProofLemma)letkind_of_obligationo=matchowith|Evar_kinds.Definefalse|Evar_kinds.Expand->goal_kind|_->goal_proof_kind(* Solve an obligation using tactics, return the corresponding proof term *)letwarn_solve_errored=CWarnings.create~name:"solve_obligation_error"~category:CWarnings.CoreCategories.tactics(funerr->Pp.seq[str"Solve Obligations tactic returned error: ";err;fnl();str"This will become an error in the future"])letsolve_by_tacprgoblsitac=letobl=obls.(i)inletobl=subst_deps_obloblsoblinlettac=Option.(default!default_tactic(appendtacobl.obl_tac))inletuctx=Internal.get_uctxprginletuctx=UState.update_sigma_univsuctx(Global.universes())inletpoly=Internal.get_polyprgin(* the status of [build_by_tactic] is dropped. *)tryletenv=Global.env()inletbody,types,_univs,_,uctx=build_by_tacticenv~uctx~poly~typ:(EConstr.of_constrobl.obl_type)tacinInductiveops.control_only_guardenv(Evd.from_ctxuctx)(EConstr.of_constrbody);Some(body,types,uctx)with|Tacticals.FailError(_,s)asexn->let_=Exninfo.captureexninletloc=fstobl.obl_locationinCErrors.user_err?loc(Lazy.forces)(* If the proof is open we absorb the error and leave the obligation open *)|Proof.OpenProof_->None|ewhenCErrors.noncriticale->leterr=CErrors.printeinletloc=fstobl.obl_locationinwarn_solve_errored?locerr;Noneletsolve_and_declare_by_tacprgoblsitac=matchsolve_by_tacprgoblsitacwith|None->None|Some(t,ty,uctx)->letobl=obls.(i)inletprg,obl',_cst=declare_obligationprgobl~body:t~types:ty~uctxinobls.(i)<-obl';Someprgletsolve_obligation_by_tacprgoblsitac=letobl=obls.(i)inmatchobl.obl_bodywith|Some_->None|None->ifList.is_empty(deps_remainingoblsobl.obl_deps)thensolve_and_declare_by_tacprgoblsitacelseNoneletget_unique_prog~pmprg=matchState.get_unique_open_progpmprgwith|Okprg->prg|Error[]->Error.no_obligationsNone|Error((id::_)asids)->Error.ambiguous_programididsletsolve_prg_obligations~pmprg?oblsettac=let{obls;remaining}=Internal.get_obligationsprginletrem=refremaininginletobls'=Array.copyoblsinletset=refInt.Set.emptyinletp=matchoblsetwith|None->(fun_->true)|Somes->set:=s;(funi->Int.Set.memi!set)inletprg=Array.fold_left_i(funiprgx->ifpithen(matchsolve_obligation_by_tacprgobls'itacwith|None->prg|Someprg->letdeps=dependenciesoblsiinset:=Int.Set.union!setdeps;decrrem;prg)elseprg)prgobls'inupdate_obls~pmprgobls'!remletauto_solve_obligations~pmn?oblsettac:State.t*progress=Flags.if_verboseFeedback.msg_info(str"Solving obligations automatically...");letprg=get_unique_prog~pmninsolve_prg_obligations~pmprg?oblsettacletsolve_obligation?check_finalprgnumtac=letuser_num=succnuminlet{obls;remaining=rem}=Internal.get_obligationsprginletobl=obls.(num)inletremaining=deps_remainingoblsobl.obl_depsinlet()=ifnot(Option.is_emptyobl.obl_body)thenError.already_solveduser_num;ifnot(List.is_emptyremaining)thenError.dependsuser_numremaininginletobl=subst_deps_obloblsoblinletkind=kind_of_obligation(sndobl.obl_status)inletevd=Evd.from_ctx(Internal.get_uctxprg)inletevd=Evd.update_sigma_univs(Global.universes())evdinletauto~pmnoblsettac=auto_solve_obligations~pmn~oblsettacinletproof_ending=letname=Internal.get_nameprginProof_ending.End_obligation{name;num;auto;check_final}inletcinfo=CInfo.make~name:obl.obl_name~typ:(EConstr.of_constrobl.obl_type)()inletusing=letusing=Internal.get_usingprginletenv=Global.env()inletf{CInfo.name;typ;_}=name,[typ]inOption.map(interp_proof_using_genfenvevd[cinfo])usinginletpoly=Internal.get_polyprginletinfo=Info.make~kind~poly()inletlemma=Proof.start_core~cinfo~info~proof_ending?usingevdinletlemma=fst@@Proof.by!default_tacticlemmainletlemma=Option.cata(funtac->Proof.set_endline_tactictaclemma)lemmatacinlemmaletsolve_obligations~pmntac=letprg=get_unique_prog~pmninsolve_prg_obligations~pmprgtac(** Implements [Solve All Obligations with tac] *)letsolve_all_obligations~pmtac=State.foldpm~init:pm~f:(funkvpm->solve_prg_obligations~pmvtac|>fst)(** Implements [Solve Obligations of name with tac] *)lettry_solve_obligations~pmnametac=solve_obligations~pmnametac|>fst(** Implements [Obligation n of name with tac] *)letobligation(user_num,name)~pmtac=letnum=preduser_numinletprg=get_unique_prog~pmnameinlet{obls;remaining}=Internal.get_obligationsprginifnum>=0&&num<Array.lengthoblsthenletobl=obls.(num)inmatchobl.obl_bodywith|None->solve_obligationprgnumtac|Somer->Error.already_solveduser_numelseError.unknown_obligationnum(** Implements [Obligations of name] *)letshow_single_obligationinameoblsx=letx=subst_deps_obloblsxinletenv=Global.env()inletsigma=Evd.from_envenvinletmsg=str"Obligation"++spc()++int(succi)++spc()++str"of"++spc()++Id.printname++str":"++spc()++hov1(Printer.pr_constr_envenvsigmax.obl_type++str"."++fnl())inFeedback.msg_infomsgletshow_obligations_of_prg?(msg=true)prg=letname=Internal.get_nameprginlet{obls;remaining}=Internal.get_obligationsprginletshowed=ref5inifmsgthenFeedback.msg_info(intremaining++str" obligation(s) remaining: ");Array.iteri(funix->matchx.obl_bodywith|None->if!showed>0thenbegindecrshowed;show_single_obligationinameoblsxend|Some_->())oblsletshow_obligations~pm?(msg=true)name=letprogs=matchnamewith|None->State.allpm|Somename->(matchState.findpmnamewith|Someprg->[prg]|None->Error.no_obligations(Somename))inList.iter(funx->show_obligations_of_prg~msgx)progs(** Implementation of the [Preterm of name] command *)letshow_term~pmname=letprg=get_unique_prog~pmnameinProgramDecl.showprgletmsg_generating_oblnameobls=letlen=Array.lengthoblsinletinfo=Id.printname++str" has type-checked"inFeedback.msg_info(iflen=0theninfo++str"."elseinfo++str", generating "++intlen++str(String.plurallen" obligation"))letadd_definition~pm~info~cinfo~opaque~uctx?body?tactic?(reduce=reduce)?using?obl_hookobls=letobl_hook=Option.map(funh->State.PrgHookh)obl_hookinletprg=ProgramDecl.make~info~cinfo~body~opaque~uctx~reduce~deps:[]~possible_guard:None?obl_hook?usingoblsinletname=CInfo.get_namecinfoinlet{obls;_}=Internal.get_obligationsprginifInt.equal(Array.lengthobls)0then(Flags.if_verbose(msg_generating_oblname)obls;letpm,cst=Obls_.declare_definition~pmprginpm,Definedcst)elselet()=Flags.if_verbose(msg_generating_oblname)oblsinletpm=State.addpmnameprginletpm,res=auto_solve_obligations~pm(Somename)tacticinmatchreswith|Remainrem->Flags.if_verbose(show_obligations~pm~msg:false)(Somename);pm,res|_->pm,resletadd_mutual_definitions~pm~info~cinfo~opaque~uctx~bodies~possible_guard?tactic?(reduce=reduce)?using?obl_hookobls=letobl_hook=Option.map(funh->State.PrgHookh)obl_hookinletdeps=List.mapCInfo.get_namecinfoinletpm=List.fold_left3(funpmcinfobodyobls->letprg=ProgramDecl.make~info~cinfo~opaque~body:(Somebody)~uctx~deps~possible_guard:(Somepossible_guard)~reduce?obl_hook?usingoblsinState.addpm(CInfo.get_namecinfo)prg)pmcinfobodiesoblsinletpm,_defined=List.fold_left(fun(pm,finished)x->iffinishedthen(pm,finished)elseletpm,res=auto_solve_obligations~pm(Somex)tacticinmatchreswith|Defined_->(* If one definition is turned into a constant,
the whole block is defined. *)(pm,true)|_->(pm,false))(pm,false)depsinpm(** [admit_obligations ~pm name] implements [Admit Obligations of name] *)letrecadmit_prog~pmprg=let{obls}=Internal.get_obligationsprginletis_open_x=Option.is_emptyx.obl_body&&List.is_empty(deps_remainingoblsx.obl_deps)inleti=matchArray.findiis_openoblswith|Somei->i|None->CErrors.anomaly(Pp.str"Could not find a solvable obligation.")inletproof=solve_obligationprgiNoneinletpm=Proof.save_admitted~pm~proofinmatchProgMap.find_opt(Internal.get_nameprg)pmwith|Someprg->admit_prog~pm(CEphemeron.getprg)|None->pmletrecadmit_all_obligations~pm=letprg=State.first_pendingpminmatchprgwith|None->pm|Someprg->letpm=admit_prog~pmprginadmit_all_obligations~pmletadmit_obligations~pmname=matchnamewith|None->admit_all_obligations~pm|Some_->letprg=get_unique_prog~pmnameinletpm=admit_prog~pmprginpm(** Implements [Next Obligation of name with tac] and [Final Obligation of name with tac] *)letnext_obligation~pm?(final=false)nametac=letprg=matchnamewith|None->beginmatchState.first_pendingpmwith|Someprg->prg|None->Error.no_obligationsNoneend|Some_->get_unique_prog~pmnameinlet{obls;remaining}=Internal.get_obligationsprginletis_open_x=Option.is_emptyx.obl_body&&List.is_empty(deps_remainingoblsx.obl_deps)inleti=matchArray.findiis_openoblswith|Somei->i|None->matchnamewith|None->CErrors.anomaly(Pp.str"Could not find a solvable obligation.")|Somename->CErrors.user_err(str"No more obligations for "++Id.printname++str".")inletcheck_final=ifnotfinalthenNoneelsematchnamewith|None->SomeAllFinal|Somename->Some(SpecificFinalname)insolve_obligation?check_finalprgitacletcheck_program_libraries()=Rocqlib.check_required_libraryRocqlib.datatypes_module_name;Rocqlib.check_required_library["Corelib";"Init";"Specif"]letprogram_inference_hookenvsigmaev=lettac=!default_tacticinletevi=Evd.find_undefinedsigmaevinletevi=Evarutil.nf_evar_infosigmaeviinletenv=Evd.evar_filtered_envenveviintryletconcl=Evd.evar_concleviinifnot(Evarutil.is_ground_envsigmaenv&&Evarutil.is_ground_termsigmaconcl)thenNoneelseletc,sigma=Proof_.refine_by_tactic~name:(Id.of_string"program_subproof")~poly:falseenvsigmaconcl(Tacticals.tclSOLVE[tac])inSome(sigma,c)with|(Proof.OpenProof_ase|Logic_monad.TacticFailuree)whenCErrors.noncriticale->CErrors.user_errPp.(str"The statement obligations could not be resolved \
automatically, write a statement definition first.")(* aliases *)letprepare_obligations=prepare_obligationsletcheck_solved_obligations=letis_emptyprg=letobls=(Internal.get_obligations(CEphemeron.getprg)).oblsinletis_openx=Option.is_emptyx.obl_body&&List.is_empty(deps_remainingoblsx.obl_deps)inArray.existsis_openoblsinObls_.check_solved_obligationsis_emptytypefixpoint_kind=Obls_.fixpoint_kind=|IsFixpointoflidentoptionlist|IsCoFixpointtypenonrecprogress=progress=|Remainofint|Dependent|DefinedofGlobRef.tendmoduleOblState=Obls_.Stateletdeclare_constant?loc?local~name~kind?typing_flags=declare_constant~loc?local~name~kind~typing_flagsletdeclare_entry?loc~name?scope~kind?user_warns?hook~impargs~uctxentry=declare_entry~loc~name?scope~kind~typing_flags:None?clearbody:None~user_warns?hook~impargs~uctxentryletdeclare_definition_full~info~cinfo~opaque~body?usingsigma=letc,uctx=declare_definition~obls:[]~info~cinfo~opaque~body?usingsigmainc,ifinfo.polythenUniv.ContextSet.emptyelseUState.context_setuctxletdeclare_definition~info~cinfo~opaque~body?usingsigma=declare_definition~obls:[]~info~cinfo~opaque~body?usingsigma|>fst