12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(** 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.locality(** [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 *);using:Proof_using.toption(** Explicit declaration of section variables used by the constant *)}letmake~name~typ?(args=[])?(impargs=[])?using()={name;typ;args;impargs;using}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.locality;hook:Hook.toption;typing_flags:Declarations.typing_flagsoption}(** Note that [opaque] doesn't appear here as it is not known at the
start of the proof in the interactive case. *)letmake?(poly=false)?(inline=false)?(kind=Decls.(IsDefinitionDefinition))?(udecl=UState.default_univ_decl)?(scope=Locality.GlobalLocality.ImportDefaultBehavior)?hook?typing_flags()={poly;inline;kind;udecl;scope;hook;typing_flags}end(** Declaration of constants and parameters *)type'aproof_entry={proof_entry_body:'aEntries.const_entry_body;(* List of section variables *)proof_entry_secctx:Id.Set.toption;(* State id on which the completion of type checking is reported *)proof_entry_feedback:Stateid.toption;proof_entry_type:Constr.typesoption;proof_entry_universes:Entries.universes_entry;proof_entry_opaque:bool;proof_entry_inline_code:bool;}letdefault_univ_entry=Entries.Monomorphic_entryUniv.ContextSet.empty(** [univsbody] are universe-constraints attached to the body-only,
used in vio-delayed opaque constants and private poly universes *)letdefinition_entry_core?(opaque=false)?using?(inline=false)?feedback_id?types?(univs=default_univ_entry)?(eff=Evd.empty_side_effects)?(univsbody=Univ.ContextSet.empty)body={proof_entry_body=Future.from_val((body,univsbody),eff);proof_entry_secctx=using;proof_entry_type=types;proof_entry_universes=univs;proof_entry_opaque=opaque;proof_entry_feedback=feedback_id;proof_entry_inline_code=inline}letdefinition_entry=definition_entry_core?eff:None?univsbody:None?feedback_id:Nonetype'aconstant_entry=|DefinitionEntryof'aproof_entry|ParameterEntryofEntries.parameter_entry|PrimitiveEntryofEntries.primitive_entrytypeconstant_obj={cst_kind:Decls.logical_kind;cst_locl:Locality.import_status;}letload_constanti((sp,kn),obj)=ifNametab.exists_ccispthenraise(DeclareUniv.AlreadyDeclared(None,Libnames.basenamesp));letcon=Global.constant_of_delta_knkninNametab.push(Nametab.Untili)sp(GlobRef.ConstRefcon);Dumpglob.add_constant_kindconobj.cst_kind(* Opening means making the name without its module qualification available *)letopen_constantfi((sp,kn),obj)=(* Never open a local definition *)matchobj.cst_loclwith|Locality.ImportNeedQualified->()|Locality.ImportDefaultBehavior->letcon=Global.constant_of_delta_knkninifLibobject.in_filter_ref(GlobRef.ConstRefcon)fthenNametab.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)=(* Invariant: the constant must exist in the logical environment *)letkn'=ifGlobal.exists_objlabel(Label.of_id(Libnames.basenamesp))thenConstant.make1knelseCErrors.anomalyPp.(str"Missing constant "++Id.print(Libnames.basenamesp)++str".")inassert(Environ.QConstant.equal(Global.env())kn'(Constant.make1kn));Nametab.push(Nametab.Until1)sp(GlobRef.ConstRef(Constant.make1kn));Dumpglob.add_constant_kind(Constant.make1kn)obj.cst_kindletdischarge_constant((sp,kn),obj)=Someobjletclassify_constantcst=Libobject.Substitutecstlet(objConstant:constant_objLibobject.Dyn.tag)=letopenLibobjectindeclare_object_full{(default_object"CONSTANT")withcache_function=cache_constant;load_function=load_constant;open_function=open_constant;classify_function=classify_constant;subst_function=ident_subst_function;discharge_function=discharge_constant}letinConstantv=Libobject.Dyn.Easy.injvobjConstantletupdate_tablesc=Impargs.declare_constant_implicitsc;Notation.declare_ref_arguments_scopeEvd.empty(GlobRef.ConstRefc)letregister_constantknkindlocal=leto=inConstant{cst_kind=kind;cst_locl=local;}inletid=Label.to_id(Constant.labelkn)inlet_=Lib.add_leafidoinupdate_tablesknletregister_side_effect(c,role)=let()=register_constantcDecls.(IsProofTheorem)Locality.ImportDefaultBehaviorinmatchrolewith|None->()|Some(Evd.Schema(ind,kind))->DeclareScheme.declare_schemekind[|ind,c|]letget_rolesexporteff=letmapc=letrole=trySome(Cmap.findceff.Evd.seff_roles)withNot_found->Nonein(c,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"vletpure_definition_entry?(opaque=false)?(inline=false)?types?(univs=default_univ_entry)body={proof_entry_body=Future.from_val((body,Univ.ContextSet.empty),());proof_entry_secctx=None;proof_entry_type=types;proof_entry_universes=univs;proof_entry_opaque=opaque;proof_entry_feedback=None;proof_entry_inline_code=inline}letdelayed_definition_entry~opaque?feedback_id~using~univs?typesbody={proof_entry_body=body;proof_entry_secctx=using;proof_entry_type=types;proof_entry_universes=univs;proof_entry_opaque=opaque;proof_entry_feedback=feedback_id;proof_entry_inline_code=false}letcast_proof_entrye=let(body,ctx),()=Future.forcee.proof_entry_bodyinletunivs=ifUniv.ContextSet.is_emptyctxthene.proof_entry_universeselsematche.proof_entry_universeswith|Entries.Monomorphic_entryctx'->(* This can actually happen, try compiling EqdepFacts for instance *)Entries.Monomorphic_entry(Univ.ContextSet.unionctx'ctx)|Entries.Polymorphic_entry_->CErrors.anomalyPp.(str"Local universes in non-opaque polymorphic definition.");in{Entries.const_entry_body=body;const_entry_secctx=e.proof_entry_secctx;const_entry_feedback=e.proof_entry_feedback;const_entry_type=e.proof_entry_type;const_entry_universes=univs;const_entry_inline_code=e.proof_entry_inline_code;}type('a,'b)effect_entry=|EffectEntry:(private_constants,private_constantsEntries.const_entry_body)effect_entry|PureEntry:(unit,Constr.constr)effect_entryletcast_opaque_proof_entry(typeab)(entry:(a,b)effect_entry)(e:aproof_entry):bEntries.opaque_entry=lettyp=matche.proof_entry_typewith|None->assertfalse|Sometyp->typinletsecctx=matche.proof_entry_secctxwith|None->letopenEnvironinletenv=Global.env()inlethyp_typ,hyp_def=ifList.is_empty(Environ.named_contextenv)thenId.Set.empty,Id.Set.emptyelseletids_typ=global_vars_setenvtypinletpf,env=matchentrywith|PureEntry->let(pf,_),()=Future.forcee.proof_entry_bodyinpf,env|EffectEntry->let(pf,_),eff=Future.forcee.proof_entry_bodyinletenv=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)|Somehyps->hypsinlet(body,univs:b*_)=matchentrywith|PureEntry->let(body,uctx),()=Future.forcee.proof_entry_bodyinletunivs=matche.proof_entry_universeswith|Entries.Monomorphic_entryuctx'->Entries.Monomorphic_entry(Univ.ContextSet.unionuctxuctx')|Entries.Polymorphic_entry_->assert(Univ.ContextSet.is_emptyuctx);e.proof_entry_universesinbody,univs|EffectEntry->e.proof_entry_body,e.proof_entry_universesin{Entries.opaque_entry_body=body;opaque_entry_secctx=secctx;opaque_entry_feedback=e.proof_entry_feedback;opaque_entry_type=typ;opaque_entry_universes=univs;}letfeedback_axiom()=Feedback.(feedbackAddedAxiom)letis_unsafe_typing_flagsflags=letflags=Option.default(Global.typing_flags())flagsinletopenDeclarationsinnot(flags.check_universes&&flags.check_guarded&&flags.check_positive)letdefine_constant~name~typing_flagscd=(* Logically define the constant and its subproofs, no libobject tampering *)letdecl,unsafe=matchcdwith|DefinitionEntryde->(* We deal with side effects *)ifnotde.proof_entry_opaquethenletbody,eff=Future.forcede.proof_entry_bodyin(* This globally defines the side-effects in the environment
and registers their libobjects. *)let()=export_side_effectseffinletde={dewithproof_entry_body=Future.from_val(body,())}inletcd=Entries.DefinitionEntry(cast_proof_entryde)inConstantEntrycd,falseelseletmap(body,eff)=body,eff.Evd.seff_privateinletbody=Future.chainde.proof_entry_bodymapinletde={dewithproof_entry_body=body}inletde=cast_opaque_proof_entryEffectEntrydeinOpaqueEntryde,false|ParameterEntrye->ConstantEntry(Entries.ParameterEntrye),not(Lib.is_modtype_strict())|PrimitiveEntrye->ConstantEntry(Entries.PrimitiveEntrye),falseinletkn=Global.add_constant?typing_flagsnamedeclinifunsafe||is_unsafe_typing_flagstyping_flagsthenfeedback_axiom();knletdeclare_constant?(local=Locality.ImportDefaultBehavior)~name~kind~typing_flagscd=let()=check_existsnameinletkn=define_constant~typing_flags~namecdin(* Register the libobjects attached to the constants *)let()=register_constantknkindlocalinknletdeclare_private_constant?role?(local=Locality.ImportDefaultBehavior)~name~kindde=letkn,eff=letde=ifnotde.proof_entry_opaquethenDefinitionEff(cast_proof_entryde)elseletde=cast_opaque_proof_entryPureEntrydeinOpaqueEffdeinGlobal.add_private_constantnamedeinlet()=register_constantknkindlocalinletseff_roles=matchrolewith|None->Cmap.empty|Somer->Cmap.singletonknrinleteff={Evd.seff_private=eff;Evd.seff_roles;}inkn,effletinline_private_constants~uctxenvce=letbody,eff=Future.forcece.proof_entry_bodyinletcb,ctx=Safe_typing.inline_private_constantsenv(body,eff.Evd.seff_private)inletuctx=UState.merge~sideff:trueEvd.univ_rigiductxctxincb,uctx(** Declaration of section variables and local definitions *)typevariable_declaration=|SectionLocalDefofEvd.side_effectsproof_entry|SectionLocalAssumof{typ:Constr.types;impl:Glob_term.binding_kind;}(* This object is only for things which iterate over objects to find
variables (only Prettyp.print_context AFAICT) *)letobjVariable:unitLibobject.Dyn.tag=letopenLibobjectindeclare_object_full{(default_object"VARIABLE")withclassify_function=(fun()->Dispose)}letinVariablev=Libobject.Dyn.Easy.injvobjVariableletdeclare_variable_core~name~kindd=(* 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}->let()=Global.push_named_assum(name,typ)inimpl,true|SectionLocalDef(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_ui),eff)=Future.forcede.proof_entry_bodyinlet()=export_side_effectseffinletpoly,entry_ui=matchde.proof_entry_universeswith|Entries.Monomorphic_entryuctx->false,uctx|Entries.Polymorphic_entry(_,uctx)->true,Univ.ContextSet.of_contextuctxinletunivs=Univ.ContextSet.unionbody_uientry_uiin(* We must declare the universe constraints before type-checking the
term. *)let()=DeclareUctx.declare_universe_context~polyunivsinletse={Entries.secdef_body=body;secdef_secctx=de.proof_entry_secctx;secdef_feedback=de.proof_entry_feedback;secdef_type=de.proof_entry_type;}inlet()=Global.push_named_def(name,se)inGlob_term.Explicit,de.proof_entry_opaqueinNametab.push(Nametab.Until1)(Libnames.make_pathDirPath.emptyname)(GlobRef.VarRefname);Decls.(add_variable_dataname{opaque;kind});ignore(Lib.add_leafname(inVariable()):Libobject.object_name);Impargs.declare_var_implicits~implname;Notation.declare_ref_arguments_scopeEvd.empty(GlobRef.VarRefname)letdeclare_variable~name~kind~typ~impl=declare_variable_core~name~kind(SectionLocalAssum{typ;impl})(* 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_messageisfixil=(ifisfixthenfixpoint_messageielsecofixpoint_message)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=structletmap_entry_body~fentry={entrywithproof_entry_body=Future.chainentry.proof_entry_bodyf}letmap_entry_type~fentry={entrywithproof_entry_type=fentry.proof_entry_type}letset_opacity~opaqueentry={entrywithproof_entry_opaque=opaque}letrecdecomposelenctaccu=letopenConstrinletopenContext.Rel.Declarationiniflen=0then(c,t,accu)elsematchkindc,kindtwith|Lambda(na,u,c),Prod(_,_,t)->decompose(predlen)ct(LocalAssum(na,u)::accu)|LetIn(na,b,u,c),LetIn(_,_,_,t)->decompose(predlen)ct(LocalDef(na,b,u)::accu)|_->assertfalseletrecshrinkctxsignctaccu=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_assumpthenmkVar(NamedDecl.get_iddecl)::accuelseaccuinshrinkctxsignctaccu|_->assertfalseletshrink_entrysignconst=lettyp=matchconst.proof_entry_typewith|None->assertfalse|Somet->tin(* The body has been forced by the call to [build_constant_by_tactic] *)let()=assert(Future.is_overconst.proof_entry_body)inlet((body,uctx),eff)=Future.forceconst.proof_entry_bodyinlet(body,typ,ctx)=decompose(List.lengthsign)bodytyp[]inlet(body,typ,args)=shrinkctxsignbodytyp[]in{constwithproof_entry_body=Future.from_val((body,uctx),eff);proof_entry_type=Sometyp},argsmoduleConstant=structtypet=constant_objlettag=objConstantletkindobj=obj.cst_kindendletobjVariable=objVariableendletdeclare_definition_scheme~internal~univs~role~namec=letkind=Decls.(IsDefinitionScheme)inletentry=pure_definition_entry~univscinletkn,eff=declare_private_constant~role~kind~nameentryinlet()=ifinternalthen()elsedefinition_messagenameinkn,eff(* Locality stuff *)letdeclare_entry_core~name~scope~kind~typing_flags?hook~obls~impargs~uctxentry=letshould_suggest=entry.proof_entry_opaque&¬(List.is_empty(Global.named_context()))&&Option.is_emptyentry.proof_entry_secctxinletubind=UState.universe_bindersuctxinletdref=matchscopewith|Locality.Discharge->let()=declare_variable_core~name~kind(SectionLocalDefentry)inifshould_suggestthenProof_using.suggest_variable(Global.env())name;Names.GlobRef.VarRefname|Locality.Globallocal->letkn=declare_constant~name~local~kind~typing_flags(DefinitionEntryentry)inletgr=Names.GlobRef.ConstRefkninifshould_suggestthenProof_using.suggest_constant(Global.env())kn;let()=DeclareUniv.declare_univ_bindersgrubindingrinlet()=Impargs.maybe_declare_manual_implicitsfalsedrefimpargsinlet()=definition_messagenameinHook.call?hook{Hook.S.uctx;obls;scope;dref};drefletdeclare_entry=declare_entry_core~obls:[]letmutual_make_bodies~typing_flags~fixitems~rec_declaration~possible_indexes=matchpossible_indexeswith|Somepossible_indexes->letenv=Global.env()inletenv=Environ.update_typing_flags?typing_flagsenvinletindexes=Pretyping.search_guardenvpossible_indexesrec_declarationinletvars=Vars.universes_of_constr(Constr.mkFix((indexes,0),rec_declaration))inletfixdecls=CList.map_i(funi_->Constr.mkFix((indexes,i),rec_declaration))0fixitemsinvars,fixdecls,Someindexes|None->letfixdecls=CList.map_i(funi_->Constr.mkCoFix(i,rec_declaration))0fixitemsinletvars=Vars.universes_of_constr(List.hdfixdecls)invars,fixdecls,Noneletdeclare_mutually_recursive_core~info~cinfo~opaque~ntns~uctx~rec_declaration~possible_indexes?(restrict_ucontext=true)()=let{Info.poly;udecl;scope;kind;typing_flags;_}=infoinletvars,fixdecls,indexes=mutual_make_bodies~typing_flags~fixitems:cinfo~rec_declaration~possible_indexesinletuctx,univs=(* XXX: Obligations don't do this, this seems like a bug? *)ifrestrict_ucontextthenletuctx=UState.restrictuctxvarsinletunivs=UState.check_univ_decl~polyuctxudeclinuctx,univselseletunivs=UState.univ_entry~polyuctxinuctx,univsinletcsts=CList.map2(funCInfo.{name;typ;impargs;using}body->letentry=definition_entry~opaque~types:typ~univs?usingbodyindeclare_entry~name~scope~kind~impargs~uctx~typing_flagsentry)cinfofixdeclsinletisfix=Option.has_somepossible_indexesinletfixnames=List.map(fun{CInfo.name}->name)cinfoinrecursive_messageisfixindexesfixnames;List.iter(Metasyntax.add_notation_interpretation(Global.env()))ntns;cstsletdeclare_mutually_recursive=declare_mutually_recursive_core~restrict_ucontext:true()letwarn_let_as_axiom=CWarnings.create~name:"let-as-axiom"~category:"vernacular"Pp.(funid->strbrk"Let definition"++spc()++Names.Id.printid++spc()++strbrk"declared as an axiom.")letdeclare_assumption~name~scope~hook~impargs~uctxpe=letlocal=matchscopewith|Locality.Discharge->warn_let_as_axiomname;Locality.ImportNeedQualified|Locality.Globallocal->localinletkind=Decls.(IsAssumptionConjectural)inletdecl=ParameterEntrypeinletkn=declare_constant~name~local~kind~typing_flags:Nonedeclinletdref=Names.GlobRef.ConstRefkninlet()=Impargs.maybe_declare_manual_implicitsfalsedrefimpargsinlet()=assumption_messagenameinlet()=DeclareUniv.declare_univ_bindersdref(UState.universe_bindersuctx)inlet()=Hook.(call?hook{S.uctx;obls=[];scope;dref})indref(* Preparing proof entries *)leterror_unresolved_evarsenvsigmatevars=letpr_unresolved_evare=hov2(str"- "++Printer.pr_existential_keysigmae++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=lett=EConstr.of_constrtinletevars=Evarutil.undefined_evars_of_termsigmatinifnot(Evar.Set.is_emptyevars)thenerror_unresolved_evarsenvsigmatevarsletprepare_definition~info~opaque?using~body~typsigma=let{Info.poly;udecl;inline;_}=infoinletenv=Global.env()inletsigma,(body,types)=Evarutil.finalize~abort_on_undefined_evars:falsesigma(funnf->nfbody,Option.mapnftyp)inOption.iter(check_evars_are_solvedenvsigma)types;check_evars_are_solvedenvsigmabody;letunivs=Evd.check_univ_decl~polysigmaudeclinletentry=definition_entry~opaque?using~inline?types~univsbodyinletuctx=Evd.evar_universe_contextsigmainentry,uctxletdeclare_definition_core~info~cinfo~opaque~obls~bodysigma=let{CInfo.name;impargs;typ;using;_}=cinfoinletentry,uctx=prepare_definition~info~opaque?using~body~typsigmainlet{Info.scope;kind;hook;typing_flags;_}=infoindeclare_entry_core~name~scope~kind~impargs~typing_flags~obls?hook~uctxentry,uctxletdeclare_definition~info~cinfo~opaque~bodysigma=declare_definition_core~obls:[]~info~cinfo~opaque~bodysigma|>fstletprepare_obligation~name~types~bodysigma=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,_,body,cty=RetrieveObl.retrieve_obligationsenvnamesigma0bodytypesinletuctx=Evd.evar_universe_contextsigmainbody,cty,uctx,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~polysigmaudeclinsigma,(None(*proof using*),(typ,univs),None(*inline*))typeprogress=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_opaque:bool;prg_hook:'aHook.goption;prg_body:constr;prg_uctx:UState.t;prg_obligations:obligations;prg_deps:Id.tlist;prg_fixkind:fixpoint_kindoption;prg_notations:Vernacexpr.decl_notationlist;prg_reduce:constr->constr}openObligationletmake~info~cinfo~opaque~ntns~reduce~deps~uctx~body~fixpoint_kind?obl_hookobls=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_hook=obl_hook;prg_opaque=opaque;prg_body=body;prg_uctx;prg_obligations={obls=obls';remaining=Array.lengthobls'};prg_deps=deps;prg_fixkind=fixpoint_kind;prg_notations=ntns;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_cinfo.CInfo.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_lam_assumcin(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 *)(***********************************************************************)letunfold_entrycst=Hints.HintsUnfoldEntry[Tacred.EvalConstRefcst]letadd_hintlocalprgcst=letlocality=iflocalthenGoptions.OptLocalelseGoptions.OptExportinHints.add_hints~locality[Id.to_stringprg.prg_cinfo.CInfo.name](unfold_entrycst)letdeclare_obligationprgobl~uctx~types~body=letpoly=prg.prg_info.Info.polyinletunivs=UState.univ_entry~polyuctxinletbody=prg.prg_reducebodyinlettypes=Option.mapprg.prg_reducetypesinmatchobl.obl_statuswith|_,Evar_kinds.Expand->(false,{oblwithobl_body=Some(TermOblbody)},[])|force,Evar_kinds.Defineopaque->letopaque=(notforce)&&opaqueinletpoly=prg.prg_info.Info.polyinletctx,body,ty,args=ifnotpolythenshrink_bodybodytypeselse([],body,types,[||])inletce=definition_entry?types:ty~opaque~univsbodyin(* ppedrot: seems legit to have obligations as local *)letconstant=declare_constant~name:obl.obl_name~typing_flags:prg.prg_info.Info.typing_flags~local:Locality.ImportNeedQualified~kind:Decls.(IsProofProperty)(DefinitionEntryce)inifnotopaquethenadd_hint(Locality.make_section_localityNone)prgconstant;definition_messageobl.obl_name;letbody=matchunivswith|Entries.Polymorphic_entry(_,uctx)->Some(DefinedObl(constant,Univ.UContext.instanceuctx))|Entries.Monomorphic_entry_->Some(TermObl(it_mkLambda_or_LetIn_or_clean(mkApp(mkConstconstant,args))ctx))in(true,{oblwithobl_body=body},[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_err~hdr:"Program"not_transp_msgmoduleProgMap=Id.MapmoduleState=structtypet=tProgramDecl.tCEphemeron.keyProgMap.tletempty=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.getend(* In all cases, the use of the map is read-only so we don't expose the ref *)letmap_keysm=ProgMap.fold(funk_l->k::l)m[]letcheck_solved_obligations~pm~what_for:unit=ifnot(ProgMap.is_emptypm)thenletkeys=map_keyspminlethave_string=ifInt.equal(List.lengthkeys)1then" has "else" have "inCErrors.user_err~hdr:"Program"Pp.(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,Some(of_constrtypes))inletcinfo={prg.prg_cinfowithCInfo.typ=types}inletname,info,opaque=prg.prg_cinfo.CInfo.name,prg.prg_info,prg.prg_opaqueinletobls=List.map(fun(id,(_,c))->(id,c))varsubstin(* XXX: This is doing normalization twice *)letkn,uctx=declare_definition_core~cinfo~info~obls~body~opaquesigmain(* XXX: We call the obligation hook here, by consistency with the
previous imperative behaviour, however I'm not sure this is right *)letpm=Hook.call_g?hook:prg.prg_hook{Hook.S.uctx;obls;scope=prg.prg_info.Info.scope;dref=kn}pminletpm=progmap_removepmprginpm,knletreclam_indexntacc=matchConstr.kindtwith|Lambda({Context.binder_name=Namen'},_,_)whenId.equalnn'->acc|Lambda(_,_,b)->lam_indexnb(succacc)|_->raiseNot_foundletcompute_possible_guardness_evidencesnfixbodyfixtype=matchnwith|Some{CAst.loc;v=n}->[lam_indexnfixbody0]|None->(* If recursive argument was not given by user, we try all args.
An earlier approach was to look only for inductive arguments,
but doing it properly involves delta-reduction, and it finally
doesn't seem to worth the effort (except for huge mutual
fixpoints ?) *)letm=Termops.nb_prodEvd.empty(EConstr.of_constrfixtype)(* FIXME *)inletctx=fst(Term.decompose_prod_n_assummfixtype)inList.map_i(funi_->i)0ctxletdeclare_mutual_definition~pml=letlen=List.lengthlinletfirst=List.hdlinletdefoblx=letoblsubst=obligation_substitutiontruexinletsubs,typ=subst_progoblsubstxinletenv=Global.env()inletsigma=Evd.from_ctxx.prg_uctxinletr=Retyping.relevance_of_typeenvsigma(EConstr.of_constrtyp)inletterm=snd(Reductionops.splay_lam_nenvsigmalen(EConstr.of_constrsubs))inlettyp=snd(Reductionops.splay_prod_nenvsigmalen(EConstr.of_constrtyp))inletterm=EConstr.to_constrsigmaterminlettyp=EConstr.to_constrsigmatypinletdef=(x.prg_reduceterm,r,x.prg_reducetyp,x.prg_cinfo.CInfo.impargs,x.prg_cinfo.CInfo.using)inletoblsubst=List.map(fun(id,(_,c))->(id,c))oblsubstin(def,oblsubst)inletdefs,obls=List.fold_right(funx(defs,obls)->letxdef,xobls=defoblxin(xdef::defs,xobls@obls))l([],[])in(* let fixdefs = List.map reduce_fix fixdefs in *)letfixdefs,fixrs,fixtypes,fixitems=List.fold_right2(fun(d,r,typ,impargs,using)name(a1,a2,a3,a4)->(d::a1,r::a2,typ::a3,CInfo.{name;typ;impargs;args=[];using}::a4))defsfirst.prg_deps([],[],[],[])inletfixkind=Option.getfirst.prg_fixkindinletarrrec,recvec=(Array.of_listfixtypes,Array.of_listfixdefs)inletrvec=Array.of_listfixrsinletnamevec=Array.of_list(List.map(funx->Namex.prg_cinfo.CInfo.name)l)inletrec_declaration=(Array.map2Context.make_annotnamevecrvec,arrrec,recvec)inletpossible_indexes=matchfixkindwith|IsFixpointwfl->Some(List.map3compute_possible_guardness_evidenceswflfixdefsfixtypes)|IsCoFixpoint->Nonein(* Declare the recursive definitions *)letkns=declare_mutually_recursive_core~info:first.prg_info~ntns:first.prg_notations~uctx:first.prg_uctx~rec_declaration~possible_indexes~opaque:first.prg_opaque~restrict_ucontext:false~cinfo:fixitems()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=Hook.call_g?hook:first.prg_hooks_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_definition~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~pmprgoblsnumobl~uctxrem~auto=letobls=Array.copyoblsinlet()=obls.(num)<-oblinletprg={prgwithprg_uctx=uctx}inletpm,_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*progresstypeobligation_qed_info={name:Id.t;num:int;auto:obligation_resolver}letobligation_terminator~pm~entry~uctx~oinfo:{name;num;auto}=letenv=Global.env()inletty=entry.proof_entry_typeinletbody,uctx=inline_private_constants~uctxenventryinletsigma=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,entry.proof_entry_opaque)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)}inletpoly=prg.prg_info.Info.polyinletuctx=ifpolythenuctxelseUState.unionprg.prg_uctxuctxinletdefined,obl,cst=declare_obligationprgobl~body~types:ty~uctxinletprg_ctx=ifpolythen(* Polymorphic *)(* We merge the new universes and constraints of the
polymorphic obligation with the existing ones *)UState.unionprg.prg_uctxuctxelseif(* The first obligation, if defined,
declares the univs of the constant,
each subsequent obligation declares its own additional
universes and constraints if any *)definedthenUState.from_env(Global.env())elseuctxinletpm=update_program_decl_on_defined~pmprgoblsnumobl~uctx:prg_ctxrem~autoinpm,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~pm{name;num;auto}uctx'dref=letprg=Option.get(State.findpmname)inlet{obls;remaining=rem}=prg.prg_obligationsinletobl=obls.(num)inletcst=matchdrefwithGlobRef.ConstRefcst->cst|_->assertfalseinlettransparent=Environ.evaluable_constantcst(Global.env())inlet()=matchobl.obl_statuswith|true,Evar_kinds.Expand|true,Evar_kinds.Definetrue->ifnottransparentthenerr_not_transp()|_->()inletinst,uctx'=ifnotprg.prg_info.Info.poly(* Not polymorphic *)then(* The universe context was declared globally, we continue
from the new global environment. *)letuctx=UState.from_env(Global.env())inletuctx'=UState.merge_substuctx(UState.substuctx')in(Univ.Instance.empty,uctx')else(* We get the right order somehow, but surely it could be enforced in a clearer way. *)letuctx=UState.contextuctx'in(Univ.UContext.instanceuctx,uctx')inletobl={oblwithobl_body=Some(DefinedObl(cst,inst))}inlet()=iftransparentthenadd_hinttrueprgcstinupdate_program_decl_on_defined~pmprgoblsnumobl~uctx:uctx'rem~autoend(************************************************************************)(* Handling of interactive proofs *)(************************************************************************)typelemma_possible_guards=intlistlistmoduleProof_ending=structtypet=|Regular|End_obligationofObls_.obligation_qed_info|End_deriveof{f:Id.t;name:Id.t}|End_equationsof{hook:pm:Obls_.State.t->Constant.tlist->Evd.evar_map->Obls_.State.t;i:Id.t;types:(Environ.env*Evar.t*Evd.evar_info*EConstr.named_context*Evd.econstr)list;sigma:Evd.evar_map}end(* Alias *)moduleProof_=ProofmoduleProof=structmoduleProof_info=structtypet={cinfo:Constr.tCInfo.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 *);compute_guard:lemma_possible_guards(** thms and compute guard are specific only to
start_lemma_with_initialization + regular terminator, so we
could make this per-proof kind *)}letmake~cinfo~info?(compute_guard=[])?(proof_ending=Proof_ending.Regular)()={cinfo;info;compute_guard;proof_ending=CEphemeron.createproof_ending}endtypet={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.nameletget_initial_euctxps=ps.initial_euctxletfold~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}inletGenarg.GenArg(Genarg.Glbwittag,tac)=tacinlettac=Geninterp.interptagisttacinFtactic.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~typ~pinfo?(sign=initialize_named_context_for_proof())sigma=(* 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=[Global.env_of_contextsign,typ]inletproof=Proof.start~name~poly?typing_flagssigmagoalsinletinitial_euctx=Evd.evar_universe_contextProof.((dataproof).sigma)in{proof;endline_tactic=None;using=None;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_endingsigma=let{CInfo.name;typ;_}=cinfoinletcinfo=[{cinfowithCInfo.typ=EConstr.Unsafe.to_constrcinfo.CInfo.typ}]inletpinfo=Proof_info.make~cinfo~info?proof_ending()instart_proof_core~name~typ~pinfo?sign:Nonesigmaletstart=start_core?proof_ending:Noneletstart_dependent~info~name~proof_endinggoals=let{Info.poly;typing_flags;_}=infoinletproof=Proof.dependent_start~name~poly?typing_flagsgoalsinletinitial_euctx=Evd.evar_universe_contextProof.((dataproof).sigma)inletcinfo=[]inletpinfo=Proof_info.make~info~cinfo~proof_ending()in{proof;endline_tactic=None;using=None;initial_euctx;pinfo}letstart_derive~f~name~infogoals=letproof_ending=Proof_ending.End_derive{f;name}instart_dependent~info~name~proof_endinggoalsletstart_equations~name~info~hook~typessigmagoals=letproof_ending=Proof_ending.End_equations{hook;i=name;types;sigma}instart_dependent~name~info~proof_endinggoalsletrec_tac_initializerfiniteguardthmssnl=iffinitethenmatchList.map(fun{CInfo.name;typ}->name,(EConstr.of_constrtyp))thmswith|(id,_)::l->Tactics.mutual_cofixidl0|_->assertfalseelse(* nl is dummy: it will be recomputed at Qed-time *)letnl=matchsnlwith|None->List.mapsucc(List.mapList.lastguard)|Somenl->nlinmatchList.map2(fun{CInfo.name;typ}n->(name,n,(EConstr.of_constrtyp)))thmsnlwith|(id,n,_)::l->Tactics.mutual_fixidnl0|_->assertfalseletstart_with_initialization~info~cinfosigma=let{CInfo.name;typ;args}=cinfoinletinit_tac=Tactics.auto_intros_tacargsinletpinfo=Proof_info.make~cinfo:[cinfo]~info()inletlemma=start_proof_core~name~typ:(EConstr.of_constrtyp)~pinfo?sign:Nonesigmainmaplemma~f:(funp->pi1@@Proof.run_tacticGlobal.(env())init_tacp)typemutual_info=(bool*lemma_possible_guards*Constr.toptionlistoption)letstart_mutual_with_initialization~info~cinfo~mutual_infosigmasnl=letintro_tac{CInfo.args;_}=Tactics.auto_intros_tacargsinletinit_tac,compute_guard=let(finite,guard,init_terms)=mutual_infoinletrec_tac=rec_tac_initializerfiniteguardcinfosnlinletterm_tac=matchinit_termswith|None->List.mapintro_taccinfo|Someinit_terms->(* 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.New.tclIDTAC)init_termsinList.map2(funtacthm->Tacticals.New.tclTHENtac(intro_tacthm))taclcinfoinTacticals.New.tclTHENSrec_tacterm_tac,guardinmatchcinfowith|[]->CErrors.anomaly(Pp.str"No proof to start.")|{CInfo.name;typ;_}::thms->letpinfo=Proof_info.make~cinfo~info~compute_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 *)lettyp=EConstr.of_constrtypinletlemma=start_proof_core~name~typ~pinfosigmainmaplemma~f:(funp->pi1@@Proof.run_tacticGlobal.(env())init_tacp)letget_used_variablespf=pf.usingletget_universe_declpf=pf.pinfo.Proof_info.info.Info.udeclletset_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)}letget_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)typeproof_object={name:Names.Id.t(* [name] only used in the STM *);entries:Evd.side_effectsproof_entrylist;uctx:UState.t;pinfo:Proof_info.t}letget_po_name{name}=nameletprivate_poly_univs=Goptions.declare_bool_option_and_ref~depr:false~key:["Private";"Polymorphic";"Universes"]~value:true(* XXX: This is still separate from close_proof below due to drop_pt in the STM *)(* XXX: Unsafe_typ:true is needed by vio files, see bf0499bc507d5a39c3d5e3bf1f69191339270729 *)letprepare_proof~unsafe_typ{proof}=letProof.{name=pid;entry;poly}=Proof.dataproofinletinitial_goals=Proofview.initial_goalsentryinletevd=Proof.return~pidproofinleteff=Evd.eval_side_effectsevdinletevd=Evd.minimize_universesevdinletto_constr_bodyc=matchEConstr.to_constr_optevdcwith|Somep->Vars.universes_of_constrp,p|None->CErrors.user_errPp.(str"Some unresolved existential variables remain")inletto_constr_typt=ifunsafe_typthenlett=EConstr.Unsafe.to_constrtinVars.universes_of_constrt,telseto_constr_bodytin(* 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_constr_bodybody,eff),to_constr_typtyp)initial_goalsinproofs,Evd.evar_universe_contextevdletmake_univs_deferred~poly~initial_euctx~uctx~udecl(used_univs_typ,typ)(used_univs_body,body)=letused_univs=Univ.LSet.unionused_univs_bodyused_univs_typinletutyp=UState.univ_entry~polyinitial_euctxinletuctx=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_univsinletubody=UState.check_mono_univ_decluctx_bodyudeclinutyp,ubodyletmake_univs_private_poly~poly~uctx~udecl(used_univs_typ,typ)(used_univs_body,body)=letused_univs=Univ.LSet.unionused_univs_bodyused_univs_typinletuctx=UState.restrictuctxused_univsinletuctx'=UState.restrictuctxused_univs_typinletutyp=UState.check_univ_decl~polyuctx'udeclinletubody=Univ.ContextSet.diff(UState.context_setuctx)(UState.context_setuctx')inutyp,ubodyletmake_univs~poly~uctx~udecl(used_univs_typ,typ)(used_univs_body,body)=letused_univs=Univ.LSet.unionused_univs_bodyused_univs_typin(* 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~polyuctxudeclinutyp,Univ.ContextSet.emptyletclose_proof~opaque~keep_body_ucst_separateps=let{using;proof;initial_euctx;pinfo}=psinlet{Proof_info.info={Info.udecl}}=pinfoinlet{Proof.name;poly}=Proof.dataproofinletunsafe_typ=keep_body_ucst_separate&¬polyinletelist,uctx=prepare_proof~unsafe_typpsinletopaque=matchopaquewith|Vernacexpr.Opaque->true|Vernacexpr.Transparent->falseinletmake_entry((((_ub,body)asb),eff),((_ut,typ)ast))=letutyp,ubody=(* allow_deferred case *)ifnotpoly&&(keep_body_ucst_separate||not(Safe_typing.is_empty_private_constantseff.Evd.seff_private))thenmake_univs_deferred~initial_euctx~poly~uctx~udecltb(* private_poly_univs case *)elseifpoly&&opaque&&private_poly_univs()thenmake_univs_private_poly~poly~uctx~udecltbelsemake_univs~poly~uctx~udecltbindefinition_entry_core~opaque?using~univs:utyp~univsbody:ubody~types:typ~effbodyinletentries=CList.mapmake_entryelistin{name;entries;uctx;pinfo}typeclosed_proof_output=(Constr.t*Evd.side_effects)list*UState.tletclose_proof_delayed~feedback_idps(fpl:closed_proof_outputFuture.computation)=let{using;proof;initial_euctx;pinfo}=psinlet{Proof_info.info={Info.udecl}}=pinfoinlet{Proof.name;poly;entry;sigma}=Proof.dataproofin(* We don't allow poly = true in this path *)ifpolythenCErrors.anomaly(Pp.str"Cannot delay universe-polymorphic constants.");letfpl,uctx=Future.split2fplin(* Because of dependent subgoals at the beginning of proofs, we could
have existential variables in the initial types of goals, we need to
normalise them for the kernel. *)letsubst_evark=Evd.existential_opt_value0sigmakinletnf=UnivSubst.nf_evars_and_universes_opt_substsubst_evar(UState.substinitial_euctx)in(* We only support opaque proofs, this will be enforced by using
different entries soon *)letopaque=trueinletmake_entryp(_,types)=(* Already checked the univ_decl for the type universes when starting the proof. *)letunivs=UState.univ_entry~poly:falseinitial_euctxinlettypes=nf(EConstr.Unsafe.to_constrtypes)inFuture.chainp(fun(pt,eff)->(* Deferred proof, we already checked the universe declaration with
the initial universes, ensure that the final universes respect
the declaration as well. If the declaration is non-extensible,
this will prevent the body from adding universes and constraints. *)letuctx=Future.forceuctxinletuctx=UState.constrain_variables(fst(UState.context_setinitial_euctx))uctxinletused_univs=Univ.LSet.union(Vars.universes_of_constrtypes)(Vars.universes_of_constrpt)inletuctx=UState.restrictuctxused_univsinletuctx=UState.check_mono_univ_decluctxudeclin(pt,uctx),eff)|>delayed_definition_entry~opaque~feedback_id~using~univs~typesinletentries=Future.map2make_entryfpl(Proofview.initial_goalsentry)in{name;entries;uctx=initial_euctx;pinfo}letclose_future_proof=close_proof_delayedletreturn_partial_proof{proof}=letproofs=Proof.partial_proofproofinletProof.{sigma=evd}=Proof.dataproofinleteff=Evd.eval_side_effectsevdin(* 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... *)letproofs=List.map(func->EConstr.Unsafe.to_constrc,eff)proofsinproofs,Evd.evar_universe_contextevdletreturn_proofps=letp,uctx=prepare_proof~unsafe_typ:falsepsinList.map(fun(((_ub,body),eff),_)->(body,eff))p,uctxletupdate_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?(opaque=Vernacexpr.Transparent)~uctx~sign~poly(typ:EConstr.t)tac=letevd=Evd.from_ctxuctxinlettyp_=EConstr.Unsafe.to_constrtypinletcinfo=[CInfo.make~name~typ:typ_()]inletinfo=Info.make~poly()inletpinfo=Proof_info.make~cinfo~info()inletpf=start_proof_core~name~typ~pinfo~signevdinletpf,status=bytacpfinlet{entries;uctx}=close_proof~opaque~keep_body_ucst_separate:falsepfinmatchentrieswith|[entry]->entry,status,uctx|_->CErrors.anomalyPp.(str"[build_constant_by_tactic] close_proof returned more than one proof term")letbuild_by_tactic?(side_eff=true)env~uctx~poly~typtac=letname=Id.of_string("temporary_proof"^string_of_int(next()))inletsign=Environ.(val_of_named_context(named_contextenv))inletce,status,uctx=build_constant_by_tactic~name~uctx~sign~polytyptacinletcb,uctx=ifside_efftheninline_private_constants~uctxenvceelse(* GG: side effects won't get reset: no need to treat their universes specially *)let(cb,ctx),_eff=Future.forcece.proof_entry_bodyincb,UState.merge~sideff:falseEvd.univ_rigiductxctxincb,ce.proof_entry_type,ce.proof_entry_universes,status,uctxletdeclare_abstract~name~poly~kind~sign~secsign~opaque~solve_tacsigmaconcl=(* EJGA: flush_and_check_evars is only used in abstract, could we
use a different API? *)letconcl=tryEvarutil.flush_and_check_evarssigmaconclwithEvarutil.Uninstantiated_evar_->CErrors.user_errPp.(str"\"abstract\" cannot handle existentials.")inletsigma,concl=(* FIXME: should be done only if the tactic succeeds *)letsigma=Evd.minimize_universessigmainsigma,Evarutil.nf_evars_universessigmaconclinletconcl=EConstr.of_constrconclinletuctx=Evd.evar_universe_contextsigmainlet(const,safe,uctx)=trybuild_constant_by_tactic~name~opaque:Vernacexpr.Transparent~poly~uctx~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.set_universe_contextsigmauctxinletbody,effs=Future.forceconst.proof_entry_bodyin(* We drop the side-effects from the entry, they already exist in the ambient environment *)letconst=Internal.map_entry_bodyconst~f:(fun_->body,())in(* 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. *)letconst=Internal.set_opacity~opaqueconstinletconst,args=Internal.shrink_entrysignconstinletcst()=(* do not compute the implicit arguments, it may be costly *)let()=Impargs.make_implicit_argsfalsein(* ppedrot: seems legit to have abstracted subproofs as local*)declare_private_constant~local:Locality.ImportNeedQualified~name~kindconstinletcst,eff=Impargs.with_implicit_protectioncst()inletinst=matchconst.proof_entry_universeswith|Entries.Monomorphic_entry_->EConstr.EInstance.empty|Entries.Polymorphic_entry(_,ctx)->(* We mimic what the kernel does, that is ensuring that no additional
constraints appear in the body of polymorphic constants. Ideally this
should be enforced statically. *)let(_,body_uctx),_=Future.forceconst.proof_entry_bodyinlet()=assert(Univ.ContextSet.is_emptybody_uctx)inEConstr.EInstance.make(Univ.UContext.instancectx)inletargs=List.mapEConstr.of_constrargsinletlem=EConstr.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(* Support for mutually proved theorems *)(* XXX: this should be unified with the code for non-interactive
mutuals previously on this file. *)moduleMutualEntry:sigvaldeclare_variable:pinfo:Proof_info.t->uctx:UState.t->sec_vars:Id.Set.toption->univs:Entries.universes_entry->Names.GlobRef.tlistvaldeclare_mutdef(* Common to all recthms *):pinfo:Proof_info.t->uctx:UState.t->entry:Evd.side_effectsproof_entry->Names.GlobRef.tlistend=struct(* XXX: Refactor this with the code in [Declare.declare_mutdef] *)letguess_decreasingenvpossible_indexes((body,ctx),eff)=letopenConstrinmatchConstr.kindbodywith|Fix((nv,0),(_,_,fixdefsasfixdecls))->letenv=Safe_typing.push_private_constantsenveff.Evd.seff_privateinletindexes=Pretyping.search_guardenvpossible_indexesfixdeclsin(mkFix((indexes,0),fixdecls),ctx),eff|_->(body,ctx),effletselect_bodyit=letopenConstrinmatchConstr.kindtwith|Fix((nv,0),decls)->mkFix((nv,i),decls)|CoFix(0,decls)->mkCoFix(i,decls)|_->CErrors.anomalyPp.(str"Not a proof by induction: "++Termops.Internal.debug_print_constr(EConstr.of_constrt)++str".")letdeclare_mutdef~uctx~pinfopeiCInfo.{name;impargs;typ;_}=let{Proof_info.info;compute_guard;_}=pinfoinlet{Info.hook;scope;kind;typing_flags;_}=infoin(* if i = 0 , we don't touch the type; this is for compat
but not clear it is the right thing to do.
*)letpe,ubind=ifi>0&¬(CList.is_emptycompute_guard)thenInternal.map_entry_typepe~f:(fun_->Sometyp),UnivNames.empty_binderselsepe,UState.universe_bindersuctxin(* We when compute_guard was [] in the previous step we should not
substitute the body *)letpe=matchcompute_guardwith|[]->pe|_->Internal.map_entry_bodype~f:(fun((body,ctx),eff)->(select_bodyibody,ctx),eff)indeclare_entry~name~scope~kind?hook~impargs~typing_flags~uctxpeletdeclare_mutdef~pinfo~uctx~entry=letpe=matchpinfo.Proof_info.compute_guardwith|[]->(* Not a recursive statement *)entry|possible_indexes->(* Try all combinations... not optimal *)letenv=Global.env()inlettyping_flags=pinfo.Proof_info.info.Info.typing_flagsinletenv=Environ.update_typing_flags?typing_flagsenvinInternal.map_entry_bodyentry~f:(guess_decreasingenvpossible_indexes)inList.map_i(declare_mutdef~pinfo~uctxpe)0pinfo.Proof_info.cinfoletdeclare_variable~pinfo~uctx~sec_vars~univs=let{Info.scope;hook}=pinfo.Proof_info.infoinList.map_i(funi{CInfo.name;typ;impargs}->lettyp=Evarutil.nf_evars_universes(Evd.from_ctxuctx)typinletpe=(sec_vars,(typ,univs),None)indeclare_assumption~name~scope~hook~impargs~uctxpe)0pinfo.Proof_info.cinfoend(************************************************************************)(* Admitting a lemma-like constant *)(************************************************************************)(* Admitted *)letget_keep_admitted_vars=Goptions.declare_bool_option_and_ref~depr:false~key:["Keep";"Admitted";"Variables"]~value:trueletcompute_proof_using_for_admittedprooftyppproofs=ifnot(get_keep_admitted_vars())thenNoneelsematchget_used_variablesproof,pproofswith|Some_asx,_->x|None,pproof::_->letenv=Global.env()inletids_typ=Environ.global_vars_setenvtypin(* [pproof] is evar-normalized by [partial_proof]. We don't
count variables appearing only in the type of evars. *)letids_def=Environ.global_vars_setenv(EConstr.Unsafe.to_constrpproof)inSome(Environ.really_neededenv(Id.Set.unionids_typids_def))|_->Noneletfinish_admitted~pm~pinfo~uctx~sec_vars~univs=letcst=MutualEntry.declare_variable~pinfo~uctx~sec_vars~univsin(* If the constant was an obligation we need to update the program map *)matchCEphemeron.defaultpinfo.Proof_info.proof_endingProof_ending.Regularwith|Proof_ending.End_obligationoinfo->Obls_.obligation_admitted_terminator~pmoinfouctx(List.hdcst)|_->pmletsave_admitted~pm~proof=letudecl=get_universe_declproofinletProof.{poly;entry}=Proof.data(getproof)inlettyp=matchProofview.initial_goalsentrywith|[typ]->sndtyp|_->CErrors.anomaly~label:"Lemmas.save_lemma_admitted"(Pp.str"more than one statement.")inlettyp=EConstr.Unsafe.to_constrtypinletiproof=getproofinletpproofs=Proof.partial_proofiproofinletsec_vars=compute_proof_using_for_admittedprooftyppproofsinletuctx=get_initial_euctxproofinletunivs=UState.check_univ_decl~polyuctxudeclinfinish_admitted~pm~pinfo:proof.pinfo~uctx~sec_vars~univs(************************************************************************)(* Saving a lemma-like constant *)(************************************************************************)letfinish_derived~f~name~entries=(* [f] and [name] correspond to the proof of [f] and of [suchthat], respectively. *)letf_def,lemma_def=matchentrieswith|[_;f_def;lemma_def]->f_def,lemma_def|_->assertfalsein(* The opacity of [f_def] is adjusted to be [false], as it
must. Then [f] is declared in the global environment. *)letf_def=Internal.set_opacity~opaque:falsef_definletf_kind=Decls.(IsDefinitionDefinition)inletf_def=DefinitionEntryf_definletf_kn=declare_constant~name:f~kind:f_kindf_def~typing_flags:Noneinletf_kn_term=Constr.mkConstf_knin(* In the type and body of the proof of [suchthat] there can be
references to the variable [f]. It needs to be replaced by
references to the constant [f] declared above. This substitution
performs this precise action. *)letsubstfc=Vars.replace_vars[f,f_kn_term]cin(* Extracts the type of the proof of [suchthat]. *)letlemma_pretypetyp=matchtypwith|Somet->Some(substft)|None->assertfalse(* Declare always sets type here. *)in(* The references of [f] are subsituted appropriately. *)letlemma_def=Internal.map_entry_typelemma_def~f:lemma_pretypein(* The same is done in the body of the proof. *)letlemma_def=Internal.map_entry_bodylemma_def~f:(fun((b,ctx),fx)->(substfb,ctx),fx)inletlemma_def=DefinitionEntrylemma_definletct=declare_constant~name~typing_flags:None~kind:Decls.(IsProofProposition)lemma_defin[GlobRef.ConstReff_kn;GlobRef.ConstRefct]letfinish_proved_equations~pm~kind~hookiproof_objtypessigma0=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)inletentry,args=Internal.shrink_entrylocal_contextentryinletcst=declare_constant~name:id~kind~typing_flags:None(DefinitionEntryentry)inletsigma,app=Evarutil.new_globalsigma(GlobRef.ConstRefcst)inletsigma=Evd.defineev(EConstr.applist(app,List.mapEConstr.of_constrargs))sigmainsigma,cst)sigma0typesproof_obj.entriesinletpm=hook~pmrecoblssigmainpm,List.map(funcst->GlobRef.ConstRefcst)recoblsletcheck_single_entry{entries;uctx}label=matchentrieswith|[entry]->entry,uctx|_->CErrors.anomaly~labelPp.(str"close_proof returned more than one proof term")letfinalize_proof~pmproof_objproof_info=letopenProof_endinginmatchCEphemeron.defaultproof_info.Proof_info.proof_endingRegularwith|Regular->letentry,uctx=check_single_entryproof_obj"Proof.save"inpm,MutualEntry.declare_mutdef~entry~uctx~pinfo:proof_info|End_obligationoinfo->letentry,uctx=check_single_entryproof_obj"Obligation.save"inObls_.obligation_terminator~pm~entry~uctx~oinfo|End_derive{f;name}->pm,finish_derived~f~name~entries:proof_obj.entries|End_equations{hook;i;types;sigma}->letkind=proof_info.Proof_info.info.Info.kindinfinish_proved_equations~pm~kind~hookiproof_objtypessigmaleterr_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.pinfoinfinalize_proof~pmproof_objproof_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{entries;uctx;pinfo}=proofinifList.lengthentries<>1thenCErrors.user_errPp.(str"Admitted does not support multiple statements");let{proof_entry_secctx;proof_entry_type;proof_entry_universes}=List.hdentriesinletpoly=matchproof_entry_universeswith|Entries.Monomorphic_entry_->false|Entries.Polymorphic_entry(_,_)->trueinletunivs=UState.univ_entry~polyuctxinletsec_vars=ifget_keep_admitted_vars()thenproof_entry_secctxelseNoneinfinish_admitted~pm~uctx~pinfo~sec_vars~univsletsave_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.pinfoinfinalize_proof~pmproofpinfoend(* 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_flagsCClosure.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())letevar_of_obligationo=Evd.make_evar(Global.named_context_val())(EConstr.of_constro.obl_type)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'oblopenEvdletis_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:"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_polyprginletevi=evar_of_obligationoblin(* the status of [build_by_tactic] is dropped. *)tryletenv=Global.env()inletbody,types,_univs,_,uctx=build_by_tacticenv~uctx~poly~typ:evi.evar_concltacinInductiveops.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~hdr:"solve_obligation"(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)inletpoly=Internal.get_polyprginletprg=ProgramDecl.Internal.set_uctx~uctxprginletdef,obl',_cst=declare_obligationprgobl~body:t~types:ty~uctxinobls.(i)<-obl';ifdef&¬polythen((* Declare the term constraints with the first obligation only *)letuctx_global=UState.from_env(Global.env())inletuctx=UState.merge_substuctx_global(UState.substuctx)inSome(ProgramDecl.Internal.set_uctx~uctxprg))elseSomeprgletsolve_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_programididsletrecsolve_obligationprgnumtac=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_obloblsoblinletscope=Locality.GlobalLocality.ImportNeedQualifiedinletkind=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}inletusing=Internal.get_usingprginletcinfo=CInfo.make~name:obl.obl_name~typ:(EConstr.of_constrobl.obl_type)?using()inletpoly=Internal.get_polyprginletinfo=Info.make~scope~kind~poly()inletlemma=Proof.start_core~cinfo~info~proof_endingevdinletlemma=fst@@Proof.by!default_tacticlemmainletlemma=Option.cata(funtac->Proof.set_endline_tactictaclemma)lemmatacinlemmaandsolve_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'!remandauto_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_obligations~pmntac=letprg=get_unique_prog~pmninsolve_prg_obligations~pmprgtacletsolve_all_obligations~pmtac=State.foldpm~init:pm~f:(funkvpm->solve_prg_obligations~pmvtac|>fst)lettry_solve_obligation~pmnprgtac=letprg=get_unique_prog~pmprginlet{obls;remaining}=Internal.get_obligationsprginletobls'=Array.copyoblsinmatchsolve_obligation_by_tacprgobls'ntacwith|Someprg'->letpm,_=update_obls~pmprg'obls'(predremaining)inpm|None->pmlettry_solve_obligations~pmntac=solve_obligations~pmntac|>fstletobligation(user_num,name,typ)~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_obligationnumletshow_single_obligationinoblsx=letx=subst_deps_obloblsxinletenv=Global.env()inletsigma=Evd.from_envenvinletmsg=str"Obligation"++spc()++int(succi)++spc()++str"of"++spc()++Id.printn++str":"++spc()++hov1(Printer.pr_constr_envenvsigmax.obl_type++str"."++fnl())inFeedback.msg_infomsgletshow_obligations_of_prg?(msg=true)prg=letn=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_obligationinoblsxend|Some_->())oblsletshow_obligations~pm?(msg=true)n=letprogs=matchnwith|None->State.allpm|Somen->(matchState.findpmnwith|Someprg->[prg]|None->Error.no_obligations(Somen))inList.iter(funx->show_obligations_of_prg~msgx)progsletshow_term~pmn=letprg=get_unique_prog~pmninProgramDecl.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~cinfo~info?obl_hook?term~uctx?tactic?(reduce=reduce)?(opaque=false)obls=letprg=ProgramDecl.make~info~cinfo~body:term~opaque~uctx~reduce~ntns:[]~deps:[]~fixpoint_kind:None?obl_hookoblsinletname=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_definitionsl~pm~info?obl_hook~uctx?tactic?(reduce=reduce)?(opaque=false)~ntnsfixkind=letdeps=List.map(fun(ci,_,_)->CInfo.get_nameci)linletpm=List.fold_left(funpm(cinfo,b,obls)->letprg=ProgramDecl.make~info~cinfo~opaque~body:(Someb)~uctx~deps~fixpoint_kind:(Somefixkind)~ntns~reduce?obl_hookoblsinState.addpm(CInfo.get_namecinfo)prg)pmlinletpm,_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)depsinpmletrecadmit_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~pmn=matchnwith|None->admit_all_obligations~pm|Some_->letprg=get_unique_prog~pmninletpm=admit_prog~pmprginpmletnext_obligation~pmntac=letprg=matchnwith|None->beginmatchState.first_pendingpmwith|Someprg->prg|None->Error.no_obligationsNoneend|Some_->get_unique_prog~pmninlet{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->CErrors.anomaly(Pp.str"Could not find a solvable obligation.")insolve_obligationprgitacletcheck_program_libraries()=Coqlib.check_required_libraryCoqlib.datatypes_module_name;Coqlib.check_required_library["Coq";"Init";"Specif"];Coqlib.check_required_library["Coq";"Program";"Tactics"](* aliases *)letprepare_obligation=prepare_obligationletcheck_solved_obligations=Obls_.check_solved_obligationstypefixpoint_kind=Obls_.fixpoint_kind=|IsFixpointoflidentoptionlist|IsCoFixpointtypenonrecprogress=progress=|Remainofint|Dependent|DefinedofGlobRef.tendmoduleOblState=Obls_.Stateletdeclare_constant?local~name~kind?typing_flags=declare_constant?local~name~kind~typing_flagsletdeclare_entry~name~scope~kind=declare_entry~name~scope~kind~typing_flags:None