123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamesmoduleNamedDecl=Context.Named.Declaration(**********************************************************************)(* Shortcut to build a term using tactics *)letrefine_by_tactic~name~polyenvsigmatytac=(* Save the initial side-effects to restore them afterwards. *)leteff=Evd.eval_side_effectssigmainletold_len=Safe_typing.length_private@@Evd.seff_privateeffin(* Save the existing goals *)letsigma=Evd.push_future_goalssigmain(* Start a proof *)letprf=Proof.start~name~polysigma[env,ty]inlet(prf,_,())=tryProof.run_tacticenvtacprfwithLogic_monad.TacticFailureeassrc->(* Catch the inner error of the monad tactic *)let(_,info)=Exninfo.capturesrcinExninfo.iraise(e,info)in(* Plug back the retrieved sigma *)letProof.{goals;stack;sigma;entry}=Proof.dataprfinlet()=assert(stack=[])inletans=matchProofview.initial_goalsentrywith|[_,c,_]->c|_->assertfalseinletans=EConstr.to_constr~abort_on_undefined_evars:falsesigmaansin(* [neff] contains the freshly generated side-effects *)letneff=Evd.seff_private@@Evd.eval_side_effectssigmainletnew_len=Safe_typing.length_privateneffinletneff,_=Safe_typing.pop_privateneff(new_len-old_len)in(* Reset the old side-effects *)letsigma=Evd.set_side_effectseffsigmain(* Restore former goals *)let_goals,sigma=Evd.pop_future_goalssigmain(* Push remaining goals as future_goals which is the only way we
have to inform the caller that there are goals to collect while
not being encapsulated in the monad *)letsigma=List.fold_rightEvd.declare_future_goalgoalssigmain(* Get rid of the fresh side-effects by internalizing them in the term
itself. Note that this is unsound, because the tactic may have solved
other goals that were already present during its invocation, so that
those goals rely on effects that are not present anymore. Hopefully,
this hack will work in most cases. *)let(ans,uctx)=Safe_typing.inline_private_constantsenv((ans,Univ.ContextSet.empty),neff)inletsigma=Evd.merge_universe_context_set~sideff:trueUState.UnivRigidsigmauctxinEConstr.of_constrans,sigma(* Abstract internals *)exceptionOpenProoflet()=CErrors.register_handlerbeginfunction|OpenProof->letopenPpinSome(str"Attempt to save an incomplete proof.")|_->Noneendletrecshrinkctxsignctaccu=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=let(ctx,body,typ)=Term.decompose_lambda_prod_n_decls(List.lengthsign)bodytypinlet(body,typ,args)=shrinkctxsignbodytyp[]inbody,typ,argsletbuild_constant_by_tactic~name~sigma~env~sign~polytyptac=letpfenv=Environ.reset_with_named_contextsignenvinletproof=Proof.start~name~polysigma[pfenv,typ]inletproof,status=Proof.solveenv(Goal_select.select_nth1)Nonetacproofinlet(body,typ,output_ustate)=letProof.{entry;sigma=evd}=Proof.dataproofinletbody,typ=matchProofview.initial_goalsentrywith|[_,body,typ]->body,typ|_->assertfalseinlet()=ifnot@@Proof.is_doneproofthenraiseOpenProofinletevd=Evd.minimize_universesevdinletto_constrc=matchEConstr.to_constr_optevdcwith|Somep->p|None->raiseOpenProofinletbody=to_constrbodyinlettyp=to_constrtypin(body,typ,Evd.ustateevd)inletunivs=letused_univs=Vars.universes_of_constrtypinletused_univs=Vars.universes_of_constrbody~init:used_univsinletuctx=UState.restrictoutput_ustateused_univsinUState.check_univ_decl~polyuctxUState.default_univ_declin(* FIXME: return the locally introduced effects *)let{Proof.sigma}=Proof.dataproofinletsigma=Evd.set_universe_contextsigmaoutput_ustatein(univs,body,typ),status,sigmaletbuild_by_tacticenv~uctx~poly~typtac=letname=Id.of_string"temporary_proof"inletsign=Environ.(val_of_named_context(named_contextenv))inletsigma=Evd.from_ctxuctxinlet(univs,body,typ),status,sigma=build_constant_by_tactic~name~env~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) *)leteffs=Evd.seff_private@@Evd.eval_side_effectssigmainletbody,ctx=Safe_typing.inline_private_constantsenv((body,Univ.ContextSet.empty),effs)inlet_uctx=UState.merge_universe_context~sideff:trueEvd.univ_rigiductxctxinbody,typ,univs,status,uctxletbuild_by_tactic_optenv~uctx~poly~typtac=trySome(build_by_tacticenv~uctx~poly~typtac)withOpenProof->Noneletextract_monomorphic=function|UState.Monomorphic_entryctx->Entries.Monomorphic_entry,ctx|UState.Polymorphic_entryuctx->Entries.Polymorphic_entryuctx,Univ.ContextSet.emptyletdeclare_abstract~name~poly~sign~secsign~opaque~solve_tacenvsigmaconcl=let(const,safe,sigma')=trybuild_constant_by_tactic~name~poly~env~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)inlet(univs,body,typ)=constinletsigma=Evd.drop_new_defined~original:sigmasigma'inletbody,typ,args=shrink_entrysignbodytypinletts=Environ.oracleenvinletcst,effs=(* No side-effects in the entry, they already exist in the ambient environment *)leteffs=Evd.eval_side_effectssigmainletde,ctx=letuniv_entry,ctx=extract_monomorphic(fstunivs)inifnotopaquethenSafe_typing.DefinitionEff{Entries.definition_entry_body=body;definition_entry_secctx=None;definition_entry_type=Sometyp;definition_entry_universes=univ_entry;definition_entry_inline_code=false;},ctxelseletsecctx=letenv=Global.env()inlethyps=ifList.is_empty(Environ.named_contextenv)thenId.Set.emptyelseletids_typ=Environ.global_vars_setenvtypinletvars=Environ.global_vars_setenvbodyinId.Set.unionids_typvarsinEnviron.really_neededenvhypsinSafe_typing.OpaqueEff{Entries.opaque_entry_body=body;opaque_entry_secctx=secctx;opaque_entry_type=typ;opaque_entry_universes=univ_entry;},ctxinEvd.push_side_effects~tsnamedectxeffsinletsigma=Evd.emit_side_effectseffssigmainletinst=matchunivswith|UState.Monomorphic_entry_,_->UVars.Instance.empty|UState.Polymorphic_entryuctx,_->UVars.UContext.instanceuctxinletlem=EConstr.of_constr(Constr.mkConstU(cst,inst))insigma,lem,args,safe