123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenNamesopenConstropenEConstropenNamegenopenTactypesopenGenargopenStdargopenTacargopenGeninterpopenPpexceptionCannotCoerceToofstringletpr_argument_typearg=letVal.Dyn(tag,_)=arginVal.prtag(** TODO: unify printing of generic Ltac values in case of coercion failure. *)(* Displays a value *)letpr_valueenvv=letppty=spc()++str"of type"++spc()++pr_argument_typevinletpr_with_envpr=matchenvwith|Some(env,sigma)->prenvsigma++ppty|None->str"a value"++pptyinletopenGenprintinmatchgeneric_val_printvwith|TopPrinterBasicpr->pr()++ppty|TopPrinterNeedsContextpr->pr_with_envpr|TopPrinterNeedsContextAndLevel{default_already_surrounded;printer}->pr_with_env(funenvsigma->printerenvsigmadefault_already_surrounded)(** Abstract application, to print ltac functions *)typeappl=|UnnamedAppl(** For generic applications: nothing is printed *)|GlbApplof(Names.KerName.t*Val.tlist)list(** For calls to global constants, some may alias other. *)(* Values for interpretation *)typetacvalue=|VFunofappl*Tacexpr.ltac_trace*Loc.toption*(* when executing a global Ltac function: the location where this function was called *)Val.tId.Map.t*(* closure *)Name.tlist*(* binders *)Tacexpr.glob_tactic_expr(* body *)|VRecofVal.tId.Map.tref*Tacexpr.glob_tactic_exprlettacvalue_tag:tacvalueVal.typ=lettag=Val.create"tacvalue"inletpr=function|VFun(a,_,loc,ids,l,tac)->lettac=ifList.is_emptylthentacelseCAst.make?loc@@Tacexpr.TacFun(l,tac)inletpr_envenvsigma=ifId.Map.is_emptyidsthenmt()elsecut()++str"where"++Id.Map.fold(funidcpp->cut()++Id.printid++str" := "++pr_value(Some(env,sigma))c++pp)ids(mt())inGenprint.TopPrinterNeedsContext(funenvsigma->v0(hov0(Pptactic.pr_glob_tacticenvtac)++pr_envenvsigma))|_->Genprint.TopPrinterBasic(fun_->str"<tactic closure>")inlet()=Genprint.register_val_print0tagprintagletconstr_context_tag:Constr_matching.contextVal.typ=lettag=Val.create"constr_context"inletprenvsigmalevc:Pp.t=Printer.pr_econstr_n_envenvsigmalev(Constr_matching.repr_contextc)inlet()=Genprint.register_val_print0tag(Pptactic.make_constr_printerpr)intag(* includes idents known to be bound and references *)letconstr_under_binders_tag:Ltac_pretype.constr_under_bindersVal.typ=lettag=Val.create"constr_under_binders"inlet()=Genprint.register_val_print0tag(func->Genprint.TopPrinterNeedsContext(funenvsigma->Printer.pr_constr_under_binders_envenvsigmac))intag(** All the types considered here are base types *)letval_tagwit=matchval_tagwitwith|Val.Baset->t|_->assertfalselethas_type:typea.Val.t->atyped_abstract_argument_type->bool=funvwit->letVal.Dyn(t,_)=vinmatchVal.eqt(val_tagwit)with|None->false|SomeRefl->trueletprj:typea.aVal.typ->Val.t->aoption=funtv->letVal.Dyn(t',x)=vinmatchVal.eqtt'with|None->None|SomeRefl->Somexletin_genwitv=Val.Dyn(val_tagwit,v)letout_genwitv=matchprj(val_tagwit)vwithNone->assertfalse|Somex->xmoduleValue=structtypet=Val.tletof_tacvaluev=Val.Dyn(tacvalue_tag,v)letto_tacvaluev=prjtacvalue_tagvletof_constrc=in_gen(topwitwit_constr)cletto_constrv=ifhas_typev(topwitwit_constr)thenletc=out_gen(topwitwit_constr)vinSomecelsematchprjconstr_under_binders_tagvwith|Some(vars,c)->beginmatchvarswith[]->Somec|_->Noneend|None->Noneletof_uconstrc=in_gen(topwitwit_uconstr)cletto_uconstrv=ifhas_typev(topwitwit_uconstr)thenSome(out_gen(topwitwit_uconstr)v)elseNoneletof_constr_contextv=Val.Dyn(constr_context_tag,v)letto_constr_contextv=prjconstr_context_tagv(* XXX should we do [of_constr] when the vars are empty? *)letof_constr_under_bindersv=Val.Dyn(constr_under_binders_tag,v)letof_inti=in_gen(topwitwit_int)iletto_intv=ifhas_typev(topwitwit_int)thenSome(out_gen(topwitwit_int)v)elseNoneletof_identid=in_gen(topwitwit_ident)idletto_identv=ifhas_typev(topwitwit_ident)thenSome(out_gen(topwitwit_ident)v)elseNoneletto_listv=prjVal.typ_listvletto_optionv=prjVal.typ_optvletto_pairv=prjVal.typ_pairvletcast_errorwitv=letpr_v=Pptactic.pr_valuePptactic.ltopvinletVal.Dyn(tag,_)=vinlettag=Val.prtaginCErrors.user_err(str"Type error: value "++pr_v++str" is a "++tag++str" while type "++Val.prwit++str" was expected.")letunboxwitvans=matchanswith|None->cast_errorwitv|Somex->xletrecprj:typea.aVal.tag->Val.t->a=funtagv->matchtagwith|Val.Listtag->List.map(funv->prjtagv)(unboxVal.typ_listv(to_listv))|Val.Opttag->Option.map(funv->prjtagv)(unboxVal.typ_optv(to_optionv))|Val.Pair(tag1,tag2)->let(x,y)=unboxVal.typ_pairv(to_pairv)in(prjtag1x,prjtag2y)|Val.Baset->letVal.Dyn(t',x)=vinmatchVal.eqtt'with|None->cast_errortv|SomeRefl->xletrectag_of_arg:typeabc.(a,b,c)genarg_type->cVal.tag=funwit->matchwitwith|ExtraArg_->Geninterp.val_tag(topwitwit)|ListArgt->Val.List(tag_of_argt)|OptArgt->Val.Opt(tag_of_argt)|PairArg(t1,t2)->Val.Pair(tag_of_argt1,tag_of_argt2)letval_castargv=prj(tag_of_argarg)vletcast(Topwitwit)v=val_castwitvendletis_variableenvid=Id.List.memid(Termops.ids_of_named_context(Environ.named_contextenv))(* Transforms an id into a constr if possible, or fails with Not_found *)letconstr_of_idenvid=EConstr.mkVar(let_=Environ.lookup_namedidenvinid)(* Gives the Value.t corresponding to a Constr_context tactic_arg *)letcoerce_to_constr_contextv=matchValue.to_constr_contextvwith|Somev->v|None->raise(CannotCoerceTo"a term context")letis_intro_patternv=ifhas_typev(topwitwit_intro_pattern)thenSome(out_gen(topwitwit_intro_pattern)v).CAst.velseNone(* Interprets an identifier which must be fresh *)letcoerce_var_to_identfreshenvsigmav=letfail()=raise(CannotCoerceTo"a fresh identifier")inmatchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))->id|Some_->fail()|None->ifhas_typev(topwitwit_intro_pattern)thenmatchout_gen(topwitwit_intro_pattern)vwith|{CAst.v=IntroNaming(IntroIdentifierid)}->id|_->fail()elseifhas_typev(topwitwit_hyp)thenout_gen(topwitwit_hyp)velsematchValue.to_constrvwith|None->fail()|Somec->(* We need it fresh for intro e.g. in "Tac H = clear H; intro H" *)ifisVarsigmac&¬(fresh&&is_variableenv(destVarsigmac))thendestVarsigmacelsefail()(* Interprets, if possible, a constr to an identifier which may not
be fresh but suitable to be given to the fresh tactic. Works for
vars, constants, inductive, constructors and sorts. *)letcoerce_to_ident_not_freshsigmav=letfail()=raise(CannotCoerceTo"an identifier")inmatchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))->id|Some_->fail()|None->ifhas_typev(topwitwit_hyp)thenout_gen(topwitwit_hyp)velsematchValue.to_constrvwith|None->fail()|Somec->matchEConstr.kindsigmacwith|Varid->id|Metam->Id.of_string"x"|Evar(kn,_)->beginmatchEvd.evar_identknsigmawith|None->fail()|Someid->idend|Const(cst,_)->Label.to_id(Constant.labelcst)|Construct(cstr,_)->letref=GlobRef.ConstructRefcstrinletbasename=Nametab.basename_of_globalrefinbasename|Ind(ind,_)->letref=GlobRef.IndRefindinletbasename=Nametab.basename_of_globalrefinbasename|Sorts->beginmatchESorts.kindsigmaswith|Sorts.SProp->Label.to_id(Label.make"SProp")|Sorts.Prop->Label.to_id(Label.make"Prop")|Sorts.Set->Label.to_id(Label.make"Set")|Sorts.Type_|Sorts.QSort_->Label.to_id(Label.make"Type")end|_->fail()letcoerce_to_intro_patternsigmav=matchis_intro_patternvwith|Somepat->pat|None->ifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vinIntroNaming(IntroIdentifierid)elsematchValue.to_constrvwith|SomecwhenisVarsigmac->(* This happens e.g. in definitions like "Tac H = clear H; intro H" *)(* but also in "destruct H as (H,H')" *)IntroNaming(IntroIdentifier(destVarsigmac))|_->raise(CannotCoerceTo"an introduction pattern")letcoerce_to_intro_pattern_namingsigmav=matchcoerce_to_intro_patternsigmavwith|IntroNamingpat->pat|_->raise(CannotCoerceTo"a naming introduction pattern")letcoerce_to_hint_basev=matchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))->Id.to_stringid|Some_|None->raise(CannotCoerceTo"a hint base name")letcoerce_to_intv=ifhas_typev(topwitwit_int)thenout_gen(topwitwit_int)velseraise(CannotCoerceTo"an integer")letcoerce_to_constrenvv=letfail()=raise(CannotCoerceTo"a term")inmatchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))->(try([],constr_of_idenvid)withNot_found->fail())|Some_->fail()|None->ifhas_typev(topwitwit_constr)thenletc=out_gen(topwitwit_constr)vin([],c)elsematchprjconstr_under_binders_tagvwith|Somev->v|None->ifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vin(try[],constr_of_idenvidwithNot_found->fail())elsefail()letcoerce_to_uconstrv=ifhas_typev(topwitwit_uconstr)thenout_gen(topwitwit_uconstr)velseraise(CannotCoerceTo"an untyped term")letcoerce_to_closed_constrenvv=letids,c=coerce_to_constrenvvinlet()=ifnot(List.is_emptyids)thenraise(CannotCoerceTo"a term")incletcoerce_to_evaluable_refenvsigmav=letopenEvaluableinletfail()=raise(CannotCoerceTo"an evaluable reference")inletev=matchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))whenis_variableenvid->EvalVarRefid|Some_->fail()|None->ifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vinifId.List.memid(Termops.ids_of_contextenv)thenEvalVarRefidelsefail()elseifhas_typev(topwitwit_ref)thenletopenGlobRefinletr=out_gen(topwitwit_ref)vinmatchrwith|VarRefvar->EvalVarRefvar|ConstRefc->EvalConstRefc|IndRef_|ConstructRef_->fail()elseifhas_typev(topwitwit_smart_global)thenletopenGlobRefinletr=out_gen(topwitwit_smart_global)vinmatchrwith|VarRefvar->EvalVarRefvar|ConstRefc->EvalConstRefc|IndRef_|ConstructRef_->fail()elsematchValue.to_constrvwith|SomecwhenisConstsigmac->EvalConstRef(fst(destConstsigmac))|SomecwhenisVarsigmac->EvalVarRef(destVarsigmac)|_->fail()inifTacred.is_evaluableenvevthenevelsefail()letcoerce_to_constr_listenvv=letv=Value.to_listvinmatchvwith|Somel->letmapv=coerce_to_closed_constrenvvinList.mapmapl|None->raise(CannotCoerceTo"a term list")letcoerce_to_intro_pattern_list?locsigmav=matchValue.to_listvwith|None->raise(CannotCoerceTo"an intro pattern list")|Somel->letmapv=CAst.make?loc@@coerce_to_intro_patternsigmavinList.mapmaplletcoerce_to_hypenvsigmav=letfail()=raise(CannotCoerceTo"a variable")inmatchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))whenis_variableenvid->id|Some_->fail()|None->ifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vinifis_variableenvidthenidelsefail()elsematchValue.to_constrvwith|SomecwhenisVarsigmac->destVarsigmac|_->fail()letcoerce_to_hyp_listenvsigmav=letv=Value.to_listvinmatchvwith|Somel->letmapn=coerce_to_hypenvsigmaninList.mapmapl|None->raise(CannotCoerceTo"a variable list")(* Interprets a qualified name *)letcoerce_to_referencesigmav=matchValue.to_constrvwith|Somec->begintryfst(EConstr.destRefsigmac)withDestKO->raise(CannotCoerceTo"a reference")end|None->raise(CannotCoerceTo"a reference")(* Quantified named or numbered hypothesis or hypothesis in context *)(* (as in Inversion) *)letcoerce_to_quantified_hypothesissigmav=matchis_intro_patternvwith|Some(IntroNaming(IntroIdentifierid))->NamedHyp(CAst.makeid)|Some_->raise(CannotCoerceTo"a quantified hypothesis")|None->ifhas_typev(topwitwit_hyp)thenletid=out_gen(topwitwit_hyp)vinNamedHyp(CAst.makeid)elseifhas_typev(topwitwit_int)thenAnonHyp(out_gen(topwitwit_int)v)elsematchValue.to_constrvwith|SomecwhenisVarsigmac->NamedHyp(CAst.make@@destVarsigmac)|_->raise(CannotCoerceTo"a quantified hypothesis")(* Quantified named or numbered hypothesis or hypothesis in context *)(* (as in Inversion) *)letcoerce_to_decl_or_quant_hypsigmav=ifhas_typev(topwitwit_int)thenAnonHyp(out_gen(topwitwit_int)v)elsetrycoerce_to_quantified_hypothesissigmavwithCannotCoerceTo_->raise(CannotCoerceTo"a declared or quantified hypothesis")letcoerce_to_int_listv=matchValue.to_listvwith|None->raise(CannotCoerceTo"an int list")|Somel->List.mapcoerce_to_intlexceptionCoercionErrorofId.t*(Environ.env*Evd.evar_map)option*Val.t*stringlet()=CErrors.register_handlerbeginfunction|CoercionError(id,env,v,s)->Some(str"Ltac variable "++Id.printid++strbrk" is bound to"++spc()++pr_valueenvv++spc()++strbrk"which cannot be coerced to "++strs++str".")|_->Noneendleterror_ltac_variable?locidenvvs=Loc.raise?loc(CoercionError(id,env,v,s))