123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215(************************************************************************)(* * 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) *)(************************************************************************)openPpletstm_pr_errs=Format.eprintf"%s] %s\n%!"(Spawned.process_id())styperesponse=|RespBuiltSubProofof(Constr.constr*UState.t)|RespErrorofbool*Pp.t|RespKilledofint|RespNoProgressmoduleTacTask:sigtypenonrecresponse=responsetypetask={t_state:Vernacstate.t;t_assign:responseoptionref;t_ast:ComTactic.interpretable;t_goalno:int;t_goal:Evar.t;t_kill:unit->unit;t_name:string}includeAsyncTaskQueue.Taskwithtypetask:=taskandtyperesponse:=responseend=struct(* {{{ *)letforward_feedback{Feedback.doc_id=did;span_id=id;route;contents}=Feedback.feedback~did~id~routecontentstypenonrecresponse=responsetypetask={t_state:Vernacstate.t;t_assign:responseoptionref;t_ast:ComTactic.interpretable;t_goalno:int;t_goal:Evar.t;t_kill:unit->unit;t_name:string}typerequest={r_state:Vernacstate.toption;r_ast:ComTactic.interpretable;r_goalno:int;r_goal:Evar.t;r_name:string}letname="tactic"letextra_env()=[||]typecompetence=unittypeworker_status=Fresh|Oldofcompetencelettask_match__=true(* run by the master, on a thread *)letrequest_of_taskage{t_state;t_ast;t_goalno;t_goal;t_name}=Some{r_state=ifage<>FreshthenNoneelseSomet_state;r_ast=t_ast;r_goalno=t_goalno;r_goal=t_goal;r_name=t_name}letassignrv=let()=assert(Option.is_empty!r)inr:=Somevletuse_response_{t_assign;t_kill}resp=assignt_assignresp;letkill=matchrespwith|RespNoProgress|RespBuiltSubProof_->false|RespError_->true|RespKilled_->assertfalseinifkillthent_kill();`Stay((),[])leton_marshal_errorerr{t_name}=stm_pr_err("Fatal marshal error: "^t_name);flush_all();exit1leton_task_cancellation_or_expiration_or_slave_death=function|Some{t_goalno;t_assign;t_kill}->t_kill();assert(Option.is_empty!t_assign);t_assign:=Some(RespKilledt_goalno)|_->()letcommand_focus=Proof.new_focus_kind"partac_focus"letfocus_cond=Proof.no_condcommand_focusletstate=refNoneletreceive_state=function|None->()|Somest->state:=Somestletperform{r_state=st;r_ast=tactic;r_goal;r_goalno}=receive_statest;Vernacstate.unfreeze_full_state(Option.get!state);tryVernacstate.LemmaStack.with_top(Option.get(Option.get!state).Vernacstate.interp.lemmas)~f:(funpstate->letpstate=Declare.Proof.mappstate~f:(Proof.focusfocus_cond()r_goalno)inletpstate=ComTactic.solve~pstateGoal_select.SelectAll~info:Nonetactic~with_end_tac:falseinlet{Proof.sigma}=Declare.Proof.foldpstate~f:Proof.datainletEvarInfoevi=Evd.findsigmar_goalinmatchEvd.(evar_bodyevi)with|Evd.Evar_empty->RespNoProgress|Evd.Evar_definedt->lett=Evarutil.nf_evarsigmatinletevars=Evarutil.undefined_evars_of_termsigmatinifEvar.Set.is_emptyevarsthenlett=EConstr.Unsafe.to_constrtinRespBuiltSubProof(t,Evd.ustatesigma)elseCErrors.user_errPp.(str"The par: selector requires a tactic that makes no progress or fully"++str" solves the goal and leaves no unresolved existential variables. The following"++str" existentials remain unsolved: "++prlist(Termops.pr_existential_key(Global.env())sigma)(Evar.Set.elementsevars)))withe->letnoncrit=CErrors.noncriticaleinRespError(noncrit,CErrors.printe++spc()++str"(for goal "++intr_goalno++str")")letperformr:response=NewProfile.profile"partac.perform"~args:(fun()->["goalno",`Intlit(string_of_intr.r_goalno)])(fun()->performr)()letname_of_task{t_name}=t_nameletname_of_request{r_name}=r_nameend(* }}} *)moduleTaskQueue=AsyncTaskQueue.MakeQueue(TacTask)()letassign_tac~abstractres:unitProofview.tactic=Proofview.(Goal.enterbeginfung->letgid=Goal.goalginmatchList.assocgidreswith|exceptionNot_found->(* No progress *)tclUNIT()|(pt,uc)->letopenNotationsinletpush_statectx=Proofview.tclEVARMAP>>=funsigma->Proofview.Unsafe.tclEVARS(Evd.merge_universe_contextsigmactx)in(ifabstractthenAbstract.tclABSTRACTNoneelse(funx->x))(push_stateuc<*>Tactics.exact_no_check(EConstr.of_constrpt))end)letget_resultsres=(* If one of the goals failed others may be missing results, so we
need to check for RespError before complaining about missing
results. Also if there are non-RespKilled errors we prefer to
report them. *)letmissing=ref[]inletkilled=ref[]inletres=CList.map_filter_i(funi(g,v)->match!vwith|None->missing:=(succi)::!missing;None|Some(RespBuiltSubProofv)->Some(g,v)|SomeRespNoProgress->None|Some(RespKilledgoalno)->killed:=goalno::!killed;None|Some(RespError(noncrt,msg))->ifnoncrtthenraise(AsyncTaskQueue.RemoteExceptionmsg)elseCErrors.anomalymsg)resinmatch!killed,!missingwith|[],[]->res|killed::_,_->CErrors.anomalyPp.(str"Worker failed (for goal "++intkilled++str")")|[],missing->CErrors.anomaly(str"Missing results (for "++str(CString.plural(List.lengthmissing)"goal")++spc()++prlist_with_sepspcintmissing++str")")letenable_par~spawn_args~nworkers=ComTactic.set_par_implementation(fun~pstate~infot_ast~abstract~with_end_tac->lett_state=Vernacstate.freeze_full_state()inlett_state=Vernacstate.Stm.make_shallowt_stateinTaskQueue.with_n_workers~spawn_argsnworkersCoqworkmgrApi.High(funqueue->Declare.Proof.mappstate~f:(funp->letopenTacTaskinletresults=(Proof.datap).Proof.goals|>CList.map_i(funig->letans=refNoneinTaskQueue.enqueue_taskqueue~cancel_switch:(reffalse){t_state;t_assign=ans;t_ast;t_goalno=i;t_goal=g;t_name=Proof.goal_uidg;t_kill=(fun()->TaskQueue.cancel_allqueue)};g,ans)1inTaskQueue.joinqueue;letresults=get_resultsresultsinletp,_,()=NewProfile.profile"partac.assign"(fun()->Proof.run_tactic(Global.env())(assign_tac~abstractresults)p)()inp)))