123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626(************************************************************************)(* * 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) *)(************************************************************************)openConstropenNamesopenPpopenLazymoduleNamedDecl=Context.Named.Declarationletdebug_zify=CDebug.create~name:"zify"()(* The following [constr] are necessary for constructing the proof terms *)letzifystr=EConstr.of_constr(UnivGen.constr_of_monomorphic_global(Global.env())(Coqlib.lib_ref("ZifyClasses."^str)))(** classes *)letcoq_InjTyp=lazy(Coqlib.lib_ref"ZifyClasses.InjTyp")letcoq_BinOp=lazy(Coqlib.lib_ref"ZifyClasses.BinOp")letcoq_UnOp=lazy(Coqlib.lib_ref"ZifyClasses.UnOp")letcoq_CstOp=lazy(Coqlib.lib_ref"ZifyClasses.CstOp")letcoq_BinRel=lazy(Coqlib.lib_ref"ZifyClasses.BinRel")letcoq_PropBinOp=lazy(Coqlib.lib_ref"ZifyClasses.PropBinOp")letcoq_PropUOp=lazy(Coqlib.lib_ref"ZifyClasses.PropUOp")letcoq_BinOpSpec=lazy(Coqlib.lib_ref"ZifyClasses.BinOpSpec")letcoq_UnOpSpec=lazy(Coqlib.lib_ref"ZifyClasses.UnOpSpec")letcoq_Saturate=lazy(Coqlib.lib_ref"ZifyClasses.Saturate")(* morphism like lemma *)letmkapp2=lazy(zify"mkapp2")letmkapp=lazy(zify"mkapp")leteq_refl=lazy(zify"eq_refl")leteq=lazy(zify"eq")letmkrel=lazy(zify"mkrel")letiff_refl=lazy(zify"iff_refl")leteq_iff=lazy(zify"eq_iff")letrew_iff=lazy(zify"rew_iff")letrew_iff_rev=lazy(zify"rew_iff_rev")(* propositional logic *)letop_and=lazy(zify"and")letop_and_morph=lazy(zify"and_morph")letop_or=lazy(zify"or")letop_or_morph=lazy(zify"or_morph")letop_impl_morph=lazy(zify"impl_morph")letop_iff=lazy(zify"iff")letop_iff_morph=lazy(zify"iff_morph")letop_not=lazy(zify"not")letop_not_morph=lazy(zify"not_morph")letop_True=lazy(zify"True")letop_I=lazy(zify"I")(** [unsafe_to_constr c] returns a [Constr.t] without considering an evar_map.
This is useful for calling Constr.hash *)letunsafe_to_constr=EConstr.Unsafe.to_constrletpr_constrenvevde=Printer.pr_econstr_envenvevdeletgl_pr_constre=letgenv=Global.env()inletevd=Evd.from_envgenvinpr_constrgenvevdeletwhd=Reductionops.clos_whd_flagsCClosure.allletis_convertibleenvevdt1t2=Reductionops.(is_convenvevdt1t2)(** [get_type_of] performs beta reduction ;
Is it ok for Retyping.get_type_of (Zpower_nat n q) to return (fun _ : nat => Z) q ? *)letget_type_ofenvevde=Tacred.cbv_betaenvevd(Retyping.get_type_ofenvevde)(* arguments are dealt with in a second step *)letrecfind_optionpredl=matchlwith|[]->raiseNot_found|e::l->(matchpredewithSomer->r|None->find_optionpredl)moduleConstrMap=structopenNames.GlobReftype'at='alistMap.tletaddgrem=Map.updategr(functionNone->Some[e]|Somel->Some(e::l))mletempty=Map.emptyletfindevdhm=matchMap.find(fst(EConstr.destRefevdh))mwith|e::_->e|[]->assertfalseletfind_allevdhm=Map.find(fst(EConstr.destRefevdh))mletfoldfmacc=Map.fold(funklacc->List.fold_left(funacce->fkeacc)accl)maccendmoduleHConstr=structmoduleM=Map.Make(structtypet=EConstr.tletcomparecc'=Constr.compare(unsafe_to_constrc)(unsafe_to_constrc')end)type'at='aM.tletaddhem=M.addhemletempty=M.emptyletfind=M.findend(** [get_projections_from_constant (evd,c) ]
returns an array of constr [| a1,.. an|] such that [c] is defined as
Definition c := mk a1 .. an with mk a constructor.
ai is therefore either a type parameter or a projection.
*)letget_projections_from_constant(evd,i)=matchEConstr.kindevd(whd(Global.env())evdi)with|App(c,a)->Somea|_->raise(CErrors.user_errPp.(str"The hnf of term "++pr_constr(Global.env())evdi++str" should be an application i.e. (c a1 ... an)"))(** An instance of type, say T, is registered into a hashtable, say TableT. *)type'adecl={decl:EConstr.t;(* Registered type instance *)deriv:'a(* Projections of insterest *)}moduleEInjT=structtypet={isid:bool;(* S = T -> inj = fun x -> x*)source:EConstr.t;(* S *)target:EConstr.t;(* T *)(* projections *)inj:EConstr.t;(* S -> T *)pred:EConstr.t;(* T -> Prop *)cstr:EConstr.toption(* forall x, pred (inj x) *)}end(** [classify_op] classify injected operators and detect special cases. *)typeclassify_op=|OpInj(* e.g. Z.of_nat -> \x.x *)|OpSame(* e.g. Z.add -> Z.add *)|OpConv(* e.g. Pos.ge == \x.y. Z.ge (Z.pos x) (Z.pos y)
\x.y. Z.pos (Pos.add x y) == \x.y. Z.add (Z.pos x) (Z.pos y)
Z.succ == (\x.x + 1)
*)|OpOther(*let pp_classify_op = function
| OpInj -> Pp.str "Identity"
| OpSame -> Pp.str "Same"
| OpConv -> Pp.str "Conv"
| OpOther -> Pp.str "Other"
*)letnamex=Context.make_annot(Name.mk_name(Names.Id.of_stringx))Sorts.Relevantletmkconvert_unopi1i2optop=(* fun x => inj (op x) *)letop=EConstr.mkLambda(name"x",i1.EInjT.source,EConstr.mkApp(i2.EInjT.inj,[|EConstr.mkApp(op,[|EConstr.mkRel1|])|]))in(* fun x => top (inj x) *)lettop=EConstr.mkLambda(name"x",i1.EInjT.source,EConstr.mkApp(top,[|EConstr.mkApp(i1.EInjT.inj,[|EConstr.mkRel1|])|]))in(op,top)letmkconvert_binopi1i2i3optop=(* fun x y => inj (op x y) *)letop=EConstr.mkLambda(name"x",i1.EInjT.source,EConstr.mkLambda(name"y",i1.EInjT.source,EConstr.mkApp(i3.EInjT.inj,[|EConstr.mkApp(op,[|EConstr.mkRel2;EConstr.mkRel1|])|])))in(* fun x y => top (inj x) (inj y) *)lettop=EConstr.mkLambda(name"x",i1.EInjT.source,EConstr.mkLambda(name"y",i2.EInjT.source,EConstr.mkApp(top,[|EConstr.mkApp(i1.EInjT.inj,[|EConstr.mkRel2|]);EConstr.mkApp(i2.EInjT.inj,[|EConstr.mkRel1|])|])))in(op,top)letmkconvert_relirtr=lettr=EConstr.mkLambda(name"x",i.EInjT.source,EConstr.mkLambda(name"y",i.EInjT.source,EConstr.mkApp(tr,[|EConstr.mkApp(i.EInjT.inj,[|EConstr.mkRel2|]);EConstr.mkApp(i.EInjT.inj,[|EConstr.mkRel1|])|])))in(r,tr)(** [classify_op mkconvert op top] takes the injection [inj] for the origin operator [op]
and the destination operator [top] -- both [op] and [top] are closed terms *)letclassify_opmkconvertinjoptop=letenv=Global.env()inletevd=Evd.from_envenvinifis_convertibleenvevdinjopthenOpInjelseifEConstr.eq_constrevdoptopthenOpSameelseletop,top=mkconvertoptopinifis_convertibleenvevdoptopthenOpConvelseOpOther(*let classify_op mkconvert tysrc op top =
let res = classify_op mkconvert tysrc op top in
Feedback.msg_debug
Pp.(
str "classify_op:" ++ gl_pr_constr op ++ str " " ++ gl_pr_constr top
++ str " " ++ pp_classify_op res ++ fnl ());
res
*)moduleEBinOpT=structtypet={(* Op : source1 -> source2 -> source3 *)source1:EConstr.t;source2:EConstr.t;source3:EConstr.t;target1:EConstr.t;target2:EConstr.t;target3:EConstr.t;inj1:EInjT.t(* InjTyp source1 target1 *);inj2:EInjT.t(* InjTyp source2 target2 *);inj3:EInjT.t(* InjTyp source3 target3 *);bop:EConstr.t(* BOP *);tbop:EConstr.t(* TBOP *);tbopinj:EConstr.t(* TBOpInj *);classify_binop:classify_op}endmoduleECstOpT=structtypet={source:EConstr.t;target:EConstr.t;inj:EInjT.t;cst:EConstr.t;cstinj:EConstr.t;is_construct:bool}endmoduleEUnOpT=structtypet={source1:EConstr.t;source2:EConstr.t;target1:EConstr.t;target2:EConstr.t;uop:EConstr.t;inj1_t:EInjT.t;inj2_t:EInjT.t;tuop:EConstr.t;tuopinj:EConstr.t;classify_unop:classify_op;is_construct:bool}endmoduleEBinRelT=structtypet={source:EConstr.t;target:EConstr.t;inj:EInjT.t;brel:EConstr.t;tbrel:EConstr.t;brelinj:EConstr.t;classify_rel:classify_op}endmoduleEPropBinOpT=structtypet={op:EConstr.t;op_iff:EConstr.t}endmoduleEPropUnOpT=structtypet={op:EConstr.t;op_iff:EConstr.t}endmoduleESatT=structtypet={parg1:EConstr.t;parg2:EConstr.t;satOK:EConstr.t}endmoduleESpecT=structtypet={spec:EConstr.t}end(* Different type of declarations *)typedecl_kind=|PropOpofEPropBinOpT.tdecl|PropUnOpofEPropUnOpT.tdecl|InjTypofEInjT.tdecl|BinRelofEBinRelT.tdecl|BinOpofEBinOpT.tdecl|UnOpofEUnOpT.tdecl|CstOpofECstOpT.tdecl|SaturateofESatT.tdecl|UnOpSpecofESpecT.tdecl|BinOpSpecofESpecT.tdecltypeterm_kind=ApplicationofEConstr.constr|OtherTermofEConstr.constrmoduletypeElt=sigtypeelt(** name *)valname:stringvalgref:GlobRef.tLazy.tvaltable:(term_kind*decl_kind)ConstrMap.trefvalcast:eltdecl->decl_kindvaldest:decl_kind->eltdecloption(** [get_key] is the type-index used as key for the instance *)valget_key:int(** [mk_elt evd i [a0,..,an]] returns the element of the table
built from the type-instance i and the arguments (type indexes and projections)
of the type-class constructor. *)valmk_elt:Evd.evar_map->EConstr.t->EConstr.tarray->elt(* val arity : int*)endlettable=Summary.ref~name:"zify_table"ConstrMap.emptyletsaturate=Summary.ref~name:"zify_saturate"ConstrMap.emptyletspecs=Summary.ref~name:"zify_specs"ConstrMap.emptylettable_cache=refConstrMap.emptyletsaturate_cache=refConstrMap.emptyletspecs_cache=refConstrMap.empty(** Each type-class gives rise to a different table.
They only differ on how projections are extracted. *)moduleEInj=structopenEInjTtypeelt=EInjT.tletname="EInj"letgref=coq_InjTyplettable=tableletcastx=InjTypxletdest=functionInjTypx->Somex|_->Noneletis_cstr_trueevdc=matchEConstr.kindevdcwith|Lambda(_,_,c)->EConstr.eq_constr_nounivsevdc(Lazy.forceop_True)|_->falseletmk_eltevdi(a:EConstr.tarray)=letisid=EConstr.eq_constr_nounivsevda.(0)a.(1)in{isid;source=a.(0);target=a.(1);inj=a.(2);pred=a.(3);cstr=(ifis_cstr_trueevda.(3)thenNoneelseSomea.(4))}letget_key=0endletget_injevdc=matchget_projections_from_constant(evd,c)with|None->letenv=Global.env()inlett=string_of_ppcmds(pr_constrenvevdc)infailwith("Cannot register term "^t)|Somea->EInj.mk_eltevdcaletrecdecomp_typeevdty=matchEConstr.kind_of_typeevdtywith|EConstr.ProdType(_,t1,rst)->t1::decomp_typeevdrst|_->[ty]letpp_typeenvevdl=Pp.prlist_with_sep(fun_->Pp.str" -> ")(pr_constrenvevd)lletcheck_typevdexptyop=letenv=Global.env()inletty=Retyping.get_type_ofenvevdopinletty=decomp_typeevdtyinifList.for_all2(EConstr.eq_constr_nounivsevd)tyexptythen()elseraise(CErrors.user_errPp.(str": Cannot register operator "++pr_constrenvevdop++str". It has type "++pp_typeenvevdty++str" instead of expected type "++pp_typeenvevdexpty))moduleEBinOp=structtypeelt=EBinOpT.topenEBinOpTletname="BinOp"letgref=coq_BinOplettable=tableletmk_eltevdia=leti1=get_injevda.(7)inleti2=get_injevda.(8)inleti3=get_injevda.(9)inletbop=a.(6)inlettbop=a.(10)incheck_typevdEInjT.[i1.source;i2.source;i3.source]bop;{source1=a.(0);source2=a.(1);source3=a.(2);target1=a.(3);target2=a.(4);target3=a.(5);inj1=i1;inj2=i2;inj3=i3;bop;tbop;tbopinj=a.(11);classify_binop=classify_op(mkconvert_binopi1i2i3)i3.EInjT.inja.(6)tbop}letget_key=6letcastx=BinOpxletdest=functionBinOpx->Somex|_->Noneend(*let debug_term msg c =
let genv = Global.env () in
Feedback.msg_debug
Pp.(str msg ++ str " " ++ pr_constr genv (Evd.from_env genv) c);
c
*)moduleECstOp=structtypeelt=ECstOpT.topenECstOpTletname="CstOp"letgref=coq_CstOplettable=tableletcastx=CstOpxletdest=functionCstOpx->Somex|_->NoneletisConstructevdc=matchEConstr.kindevdcwith|Construct_|Int_|Float_->true|_->falseletmk_eltevdia={source=a.(0);target=a.(1);inj=get_injevda.(3);cst=a.(4);cstinj=a.(5);is_construct=isConstructevda.(2)}letget_key=2endmoduleEUnOp=structtypeelt=EUnOpT.topenEUnOpTletname="UnOp"letgref=coq_UnOplettable=tableletcastx=UnOpxletdest=functionUnOpx->Somex|_->Noneletmk_eltevdia=leti1=get_injevda.(5)inleti2=get_injevda.(6)inletuop=a.(4)incheck_typevdEInjT.[i1.source;i2.source]uop;lettuop=a.(7)in{source1=a.(0);source2=a.(1);target1=a.(2);target2=a.(3);uop;inj1_t=i1;inj2_t=i2;tuop;tuopinj=a.(8);is_construct=EConstr.isConstructevduop;classify_unop=classify_op(mkconvert_unopi1i2)i2.EInjT.injuoptuop}letget_key=4endmoduleEBinRel=structtypeelt=EBinRelT.topenEBinRelTletname="BinRel"letgref=coq_BinRellettable=tableletcastx=BinRelxletdest=functionBinRelx->Somex|_->Noneletmk_eltevdia=leti=get_injevda.(3)inletbrel=a.(2)inlettbrel=a.(4)incheck_typevdEInjT.[i.source;i.source;EConstr.mkProp]brel;{source=a.(0);target=a.(1);inj=get_injevda.(3);brel;tbrel;brelinj=a.(5);classify_rel=classify_op(mkconvert_reli)i.EInjT.injbreltbrel}letget_key=2endmoduleEPropBinOp=structtypeelt=EPropBinOpT.topenEPropBinOpTletname="PropBinOp"letgref=coq_PropBinOplettable=tableletcastx=PropOpxletdest=functionPropOpx->Somex|_->Noneletmk_eltevdia={op=a.(0);op_iff=a.(1)}letget_key=0endmoduleEPropUnOp=structtypeelt=EPropUnOpT.topenEPropUnOpTletname="PropUOp"letgref=coq_PropUOplettable=tableletcastx=PropUnOpxletdest=functionPropUnOpx->Somex|_->Noneletmk_eltevdia={op=a.(0);op_iff=a.(1)}letget_key=0endletconstr_of_term_kind=functionApplicationc->c|OtherTermc->cmoduletypeS=sigvalregister:Libnames.qualid->unitvalprint:unit->unitendmoduleMakeTable(E:Elt):S=struct(** Given a term [c] and its arguments ai,
we construct a HConstr.t table that is
indexed by ai for i = E.get_key.
The elements of the table are built using E.mk_elt c [|a0,..,an|]
*)letmake_elt(evd,i)=matchget_projections_from_constant(evd,i)with|None->letenv=Global.env()inlett=string_of_ppcmds(pr_constrenvevdi)infailwith("Cannot register term "^t)|Somea->E.mk_eltevdialetsafe_refevdc=tryfst(EConstr.destRefevdc)withDestKO->CErrors.user_errPp.(str"Add Zify "++strE.name++str": the term "++gl_pr_constrc++str" should be a global reference")letregister_hintevdtelt=matchEConstr.kindevdtwith|App(c,_)->letgr=safe_refevdcinE.table:=ConstrMap.addgr(Applicationt,E.castelt)!E.table|_->letgr=safe_refevdtinE.table:=ConstrMap.addgr(OtherTermt,E.castelt)!E.tableletregister_constrenvevdc=letc=EConstr.of_constrcinlett=get_type_ofenvevdcinmatchEConstr.kindevdtwith|App(intyp,args)whenEConstr.isRefXenvevd(Lazy.forceE.gref)intyp->letstyp=args.(E.get_key)inletelt={decl=c;deriv=make_elt(evd,c)}inregister_hintevdstypelt|_->letenv=Global.env()inraise(CErrors.user_errPp.(str"Cannot register "++pr_constrenvevdc++str". It has type "++pr_constrenvevdt++str" instead of type "++Printer.pr_global(Lazy.forceE.gref)++str" X1 ... Xn"))letregister_obj:Constr.constr->Libobject.obj=letcache_constrc=letenv=Global.env()inletevd=Evd.from_envenvinregister_constrenvevdcinletsubst_constr(subst,c)=Mod_subst.subst_mpssubstcinLibobject.declare_object@@Libobject.superglobal_object_nodischarge("register-zify-"^E.name)~cache:cache_constr~subst:(Somesubst_constr)(** [register c] is called from the VERNACULAR ADD [name] reference(t).
The term [c] is interpreted and
registered as a [superglobal_object_nodischarge].
TODO: pre-compute [get_type_of] - [cache_constr] is using another environment.
*)letregisterc=tryletc=UnivGen.constr_of_monomorphic_global(Global.env())(Nametab.locatec)inlet_=Lib.add_leaf(register_objc)in()withNot_found->raise(CErrors.user_errPp.(Libnames.pr_qualidc++str" does not exist."))letpp_keys()=letenv=Global.env()inletevd=Evd.from_envenvinConstrMap.fold(fun_(k,d)acc->matchE.destdwith|None->acc|Some_->Pp.(pr_constrenvevd(constr_of_term_kindk)++str" "++acc))!E.table(Pp.str"")letprint()=Feedback.msg_info(pp_keys())endmoduleInjTable=MakeTable(EInj)moduleESat=structtypeelt=ESatT.topenESatTletname="Saturate"letgref=coq_Saturatelettable=saturateletcastx=Saturatexletdest=functionSaturatex->Somex|_->Noneletmk_eltevdia={parg1=a.(2);parg2=a.(3);satOK=a.(5)}letget_key=1endmoduleEUnopSpec=structopenESpecTtypeelt=ESpecT.tletname="UnopSpec"letgref=coq_UnOpSpeclettable=specsletcastx=UnOpSpecxletdest=functionUnOpSpecx->Somex|_->Noneletmk_eltevdia={spec=a.(4)}letget_key=2endmoduleEBinOpSpec=structopenESpecTtypeelt=ESpecT.tletname="BinOpSpec"letgref=coq_BinOpSpeclettable=specsletcastx=BinOpSpecxletdest=functionBinOpSpecx->Somex|_->Noneletmk_eltevdia={spec=a.(5)}letget_key=3endmoduleBinOp=MakeTable(EBinOp)moduleUnOp=MakeTable(EUnOp)moduleCstOp=MakeTable(ECstOp)moduleBinRel=MakeTable(EBinRel)modulePropBinOp=MakeTable(EPropBinOp)modulePropUnOp=MakeTable(EPropUnOp)moduleSaturate=MakeTable(ESat)moduleUnOpSpec=MakeTable(EUnopSpec)moduleBinOpSpec=MakeTable(EBinOpSpec)letinit_cache()=table_cache:=!table;saturate_cache:=!saturate;specs_cache:=!specsopenEInjT(** Get constr of lemma and projections in ZifyClasses. *)(** Module [CstrTable] records terms [x] injected into [inj x]
together with the corresponding type constraint.
The terms are stored by side-effect during the traversal
of the goal. It must therefore be cleared before calling
the main tactic.
*)moduleCstrTable=structmoduleHConstr=Hashtbl.Make(structtypet=EConstr.tlethashc=Constr.hash(unsafe_to_constrc)letequalcc'=Constr.equal(unsafe_to_constrc)(unsafe_to_constrc')end)lettable:EConstr.tHConstr.t=HConstr.create10letregisterevdt(i:EConstr.t)=HConstr.addtabletiletget()=letl=HConstr.fold(funkiacc->(k,i)::acc)table[]inHConstr.cleartable;l(** [gen_cstr table] asserts (cstr k) for each element of the table (k,cstr).
NB: the constraint is only asserted if it does not already exist in the context.
*)letgen_cstrtable=Proofview.Goal.enter(fungl->letevd=Tacmach.projectglin(* Build the table of existing hypotheses *)lethas_hyp=lethyps_table=HConstr.create20inList.iter(fun(_,(t:EConstr.types))->HConstr.addhyps_tablet())(Tacmach.pf_hyps_typesgl);func->letm=HConstr.memhyps_tablecinifnotmthenHConstr.addhyps_tablec();min(* Add the constraint (cstr k) if it is not already present *)letgenkcstr=Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletterm=EConstr.mkApp(cstr,[|k|])inlettypes=get_type_ofenvevdterminifhas_hyptypesthenTacticals.tclIDTACelseletn=Tactics.fresh_id_in_envId.Set.empty(Names.Id.of_string"cstr")envinTactics.pose_proof(Names.Namen)term)inList.fold_left(funacc(k,i)->Tacticals.tclTHEN(genki)acc)Tacticals.tclIDTACtable)endtypeprf=|Term(* source is built from constructors.
target = compute(inj source)
inj source == target *)|Same(* target = source
inj source == inj target *)|ConvofEConstr.t(* inj source == target *)|PrfofEConstr.t*EConstr.t(** [eq_proof typ source target] returns (target = target : source = target) *)leteq_prooftypsourcetarget=EConstr.mkCast(EConstr.mkApp(forceeq_refl,[|typ;target|]),DEFAULTcast,EConstr.mkApp(forceeq,[|typ;source;target|]))letinterp_prfevdinjsourceprf=letinj_source=ifinj.EInjT.isidthensourceelseEConstr.mkApp(inj.EInjT.inj,[|source|])inmatchprfwith|Term->lettarget=Tacred.compute(Global.env())evdinj_sourcein(target,EConstr.mkApp(forceeq_refl,[|inj.target;target|]))|Same->(inj_source,EConstr.mkApp(forceeq_refl,[|inj.target;inj_source|]))|Convtrm->(trm,eq_proofinj.targetinj_sourcetrm)|Prf(target,prf)->(target,prf)letpp_prfprf=matchprfwith|Term->Pp.str"Term"|Same->Pp.str"Same"|Convt->Pp.(str"Conv "++gl_pr_constrt)|Prf(_,_)->Pp.str"Prf "letinterp_prfevdinjsourceprf=lett,prf'=interp_prfevdinjsourceprfindebug_zify(fun()->Pp.(str"interp_prf "++gl_pr_constrinj.EInjT.inj++str" "++gl_pr_constrsource++str" = "++gl_pr_constrt++str" by "++gl_pr_constrprf'++str" from "++pp_prfprf++fnl()));(t,prf')letmkvarevdinje=(matchinj.cstrwithNone->()|Somectr->CstrTable.registerevdectr);Sameletpp_prfevdinjsrcprf=lett,prf'=interp_prfevdinjsrcprfinPp.(gl_pr_constrinj.EInjT.inj++str" "++gl_pr_constrsrc++str" = "++gl_pr_constrt++str" by "++matchprfwith|Term->Pp.str"Term"|Same->Pp.str"Same"|Convt->Pp.str"Conv"|Prf(_,p)->Pp.str"Prf "++gl_pr_constrp)letconv_of_termevdopisidarg=Tacred.compute(Global.env())evd(ifisidthenargelseEConstr.mkApp(op,[|arg|]))letapp_unopenvevdsrcunopargprf=letcunop=unop.EUnOpT.classify_unopinletdefaulta'prf'=lettarget=EConstr.mkApp(unop.EUnOpT.tuop,[|a'|])inletevd,h=Typing.checked_appvectenvevd(forcemkapp)[|unop.source1;unop.source2;unop.target1;unop.target2|]inevd,EUnOpT.(Prf(target,EConstr.mkApp(h,[|unop.uop;unop.inj1_t.EInjT.inj;unop.inj2_t.EInjT.inj;unop.tuop;unop.tuopinj;arg;a';prf'|])))inmatchprfwith|Term->(ifunop.EUnOpT.is_constructthenevd,Term(* Keep rebuilding *)elsematchcunopwith|OpInj->evd,Conv(conv_of_termevdunop.EUnOpT.uopfalsearg)|OpSame->evd,Same|_->leta',prf=interp_prfevdunop.EUnOpT.inj1_targprfindefaulta'prf)|Same->(matchcunopwith|OpSame->evd,Same|OpInj->evd,Same|OpConv->evd,Conv(EConstr.mkApp(unop.EUnOpT.tuop,[|EConstr.mkApp(unop.EUnOpT.inj1_t.EInjT.inj,[|arg|])|]))|OpOther->leta',prf'=interp_prfevdunop.EUnOpT.inj1_targprfindefaulta'prf')|Conva'->(matchcunopwith|OpSame|OpConv->evd,Conv(EConstr.mkApp(unop.EUnOpT.tuop,[|a'|]))|OpInj->evd,Conva'|_->leta',prf=interp_prfevdunop.EUnOpT.inj1_targprfindefaulta'prf)|Prf(a',prf')->defaulta'prf'letapp_unopenvevdsrcunopargprf=let(evd',r)asres=app_unopenvevdsrcunopargprfindebug_zify(fun()->Pp.(str"\napp_unop "++pp_prfevdunop.EUnOpT.inj1_targprf++str" => "++pp_prfevd'unop.EUnOpT.inj2_tsrcr));resletapp_binopenvevdsrcbinoparg1prf1arg2prf2=EBinOpT.(letmkAppa1a2=EConstr.mkApp(binop.tbop,[|a1;a2|])inletto_convinjarg=function|Term->conv_of_termevdinj.EInjT.injinj.EInjT.isidarg|Same->ifinj.EInjT.isidthenargelseEConstr.mkApp(inj.EInjT.inj,[|arg|])|Convt->t|Prf_->failwith"Prf is not convertible"inletdefaulta1prf1a2prf2=letres=mkAppa1a2inletevd,head=Typing.checked_appvectenvevd(forcemkapp2)[|binop.source1;binop.source2;binop.source3;binop.target1;binop.target2;binop.target3|]inletprf=EBinOpT.(EConstr.mkApp(head,[|binop.bop;binop.inj1.EInjT.inj;binop.inj2.EInjT.inj;binop.inj3.EInjT.inj;binop.tbop;binop.tbopinj;arg1;a1;prf1;arg2;a2;prf2|]))inevd,Prf(res,prf)inmatch(binop.EBinOpT.classify_binop,prf1,prf2)with|OpSame,Same,Same->evd,Same|OpSame,Term,Same|OpSame,Same,Term->evd,Same|OpSame,(Term|Same|Conv_),(Term|Same|Conv_)->lett1=to_convbinop.EBinOpT.inj1arg1prf1inlett2=to_convbinop.EBinOpT.inj1arg2prf2inevd,Conv(mkAppt1t2)|_,_,_->leta1,prf1=interp_prfevdbinop.inj1arg1prf1inleta2,prf2=interp_prfevdbinop.inj2arg2prf2indefaulta1prf1a2prf2)typetyped_constr={constr:EConstr.t;typ:EConstr.t;inj:EInjT.t}letget_injectionenvevdt=trymatchsnd(ConstrMap.findevdt!table_cache)with|InjTypi->i|_->raiseNot_foundwithDestKO->raiseNot_found(* [arrow] is the term (fun (x:Prop) (y : Prop) => x -> y) *)letarrow=letnamex=Context.make_annot(Name.mk_name(Names.Id.of_stringx))Sorts.RelevantinEConstr.mkLambda(name"x",EConstr.mkProp,EConstr.mkLambda(name"y",EConstr.mkProp,EConstr.mkProd(Context.make_annotNames.AnonymousSorts.Relevant,EConstr.mkRel2,EConstr.mkRel2)))letis_propenvsigmaterm=letsort=Retyping.get_sort_ofenvsigmaterminEConstr.ESorts.is_propsigmasortletis_arrowenvevdap1p2=is_propenvevdp1&&is_prop(EConstr.push_rel(Context.Rel.Declaration.LocalAssum(a,p1))env)evdp2&&(a.Context.binder_name=Names.Anonymous||EConstr.Vars.noccurnevd1p2)(** [get_operator env evd e] expresses [e] as an application (c a)
where c is the head symbol and [a] is the array of arguments.
The function also transforms (x -> y) as (arrow x y) *)letget_operatorbarrowenvevde=lete'=EConstr.whd_evarevdeinmatchEConstr.kindevde'with|Prod(a,p1,p2)->ifbarrow&&is_arrowenvevdap1p2then(arrow,[|p1;p2|],false)elseraiseNot_found|App(c,a)->(letc'=EConstr.whd_evarevdcinmatchEConstr.kindevdc'with|Construct_(* e.g. Z0 , Z.pos *)|Const_(* e.g. Z.max *)|Proj_|Lambda_(* e.g projections *)|Ind_(* e.g. eq *)->(c',a,false)|_->raiseNot_found)|Const_->(e',[||],false)|Construct_->(e',[||],true)|Int_|Float_->(e',[||],true)|_->raiseNot_foundletdecompose_appenvevde=matchEConstr.kindevdewith|Prod(a,p1,p2)whenis_arrowenvevdap1p2->(arrow,[|p1;p2|])|App(c,a)->(c,a)|_->(EConstr.whd_evarevde,[||])type'oppropop={op:'op;op_constr:EConstr.t;op_iff:EConstr.t}letmk_propopopc1c2={op;op_constr=c1;op_iff=c2}typeprop_binop=AND|OR|IFF|IMPLtypeprop_unop=NOTtypeprop_op=|BINOPofprop_binoppropop*EConstr.t*EConstr.t|UNOPofprop_unoppropop*EConstr.t|OTHEROPofEConstr.t*EConstr.tarrayletclassify_propenvevde=matchEConstr.kindevdewith|Prod(a,p1,p2)whenis_arrowenvevdap1p2->BINOP(mk_propopIMPLarrow(forceop_impl_morph),p1,p2)|App(c,a)->(matchArray.lengthawith|1->ifEConstr.eq_constr_nounivsevd(forceop_not)cthenUNOP(mk_propopNOTc(forceop_not_morph),a.(0))elseOTHEROP(c,a)|2->ifEConstr.eq_constr_nounivsevd(forceop_and)cthenBINOP(mk_propopANDc(forceop_and_morph),a.(0),a.(1))elseifEConstr.eq_constr_nounivsevd(forceop_or)cthenBINOP(mk_propopORc(forceop_or_morph),a.(0),a.(1))elseifEConstr.eq_constr_nounivsevd(forceop_iff)cthenBINOP(mk_propopIFFc(forceop_iff_morph),a.(0),a.(1))elseOTHEROP(c,a)|_->OTHEROP(c,a))|_->OTHEROP(e,[||])(** [match_operator env evd hd arg (t,d)]
- hd is head operator of t
- If t = OtherTerm _, then t = hd
- If t = Application _, then
we extract the relevant number of arguments from arg
and check for convertibility *)letmatch_operatorenvevdhdargs(t,d)=letdecompti=letn=Array.lengthargsinlett'=EConstr.mkApp(hd,Array.subargs0(n-i))inifis_convertibleenvevdt'tthenSome(d,t)elseNoneinmatchtwith|OtherTermt->Some(d,t)|Applicationt->(matchdwith|CstOp_->decompt0|UnOp_->decompt1|BinOp_->decompt2|BinRel_->decompt2|PropOp_->decompt2|PropUnOp_->decompt1|_->None)letpp_trans_exprenvevderes=let{deriv=inj}=get_injectionenvevde.typindebug_zify(fun()->Pp.(str"\ntrans_expr "++pp_prfevdinje.constrres));resletrectrans_exprenvevde=letinj=e.injinlete=e.constrintryletc,a,is_constant=get_operatorfalseenvevdeinifis_constantthenevd,Termelseletk,t=find_option(match_operatorenvevdca)(ConstrMap.find_allevdc!table_cache)inletn=Array.lengthainmatchkwith|CstOp{deriv=c'}->ECstOpT.(ifc'.is_constructthenevd,Termelseevd,Prf(c'.cst,c'.cstinj))|UnOp{deriv=unop}->letevd,prf=trans_exprenvevd{constr=a.(n-1);typ=unop.EUnOpT.source1;inj=unop.EUnOpT.inj1_t}inapp_unopenvevdeunopa.(n-1)prf|BinOp{deriv=binop}->letevd,prf1=trans_exprenvevd{constr=a.(n-2);typ=binop.EBinOpT.source1;inj=binop.EBinOpT.inj1}inletevd,prf2=trans_exprenvevd{constr=a.(n-1);typ=binop.EBinOpT.source2;inj=binop.EBinOpT.inj2}inapp_binopenvevdebinopa.(n-2)prf1a.(n-1)prf2|d->evd,mkvarevdinjewithNot_found|DestKO->evd,mkvarevdinjelettrans_exprenvevde=tryletevd,prf=trans_exprenvevdeinevd,pp_trans_exprenvevdeprfwithNot_found->raise(CErrors.user_err(Pp.str"Missing injection for type "++Printer.pr_leconstr_envenvevde.typ))typeprfp=|TProofofEConstr.t*EConstr.t(** Proof of tranformed proposition *)|CProofofEConstr.t(** Transformed proposition is convertible *)|IProof(** Transformed proposition is identical *)letpp_prfp=function|TProof(t,prf)->Pp.str"TProof "++gl_pr_constrt++Pp.str" by "++gl_pr_constrprf|CProoft->Pp.str"CProof "++gl_pr_constrt|IProof->Pp.str"IProof"lettrans_binrelenvevdsrcropa1prf1a2prf2=EBinRelT.(match(rop.classify_rel,prf1,prf2)with|OpSame,Same,Same->evd,IProof|(OpSame|OpConv),Convt1,Convt2->evd,CProof(EConstr.mkApp(rop.tbrel,[|t1;t2|]))|(OpSame|OpConv),(Same|Term|Conv_),(Same|Term|Conv_)->leta1',_=interp_prfevdrop.inja1prf1inleta2',_=interp_prfevdrop.inja2prf2inevd,CProof(EConstr.mkApp(rop.tbrel,[|a1';a2'|]))|_,_,_->leta1',prf1=interp_prfevdrop.inja1prf1inleta2',prf2=interp_prfevdrop.inja2prf2in(* XXX do we need to check more of this application or check other applications?
This one found necessary in #16803 *)letevd,h=Typing.checked_appvectenvevd(forcemkrel)[|rop.source;rop.target|]inevd,TProof(EConstr.mkApp(rop.EBinRelT.tbrel,[|a1';a2'|]),EConstr.mkApp(h,[|rop.brel;rop.EBinRelT.inj.EInjT.inj;rop.EBinRelT.tbrel;rop.EBinRelT.brelinj;a1;a1';prf1;a2;a2';prf2|])))lettrans_binrelenvevdsrcropa1prf1a2prf2=letevd,res=trans_binrelenvevdsrcropa1prf1a2prf2indebug_zify(fun()->Pp.(str"\ntrans_binrel "++pp_prfpres));evd,resletmkprftp=EConstr.(matchpwith|IProof->(t,mkApp(forceiff_refl,[|t|]))|CProoft'->(t',mkApp(forceeq_iff,[|t;t';eq_proofmkProptt'|]))|TProof(t',p)->(t',p))letmkprftp=lett',p=mkprftpindebug_zify(fun()->Pp.(str"mkprf "++gl_pr_constrt++str" <-> "++gl_pr_constrt'++str" by "++gl_pr_constrp));(t',p)lettrans_bin_propop_constrop_ifft1p1t2p2=match(p1,p2)with|IProof,IProof->IProof|CProoft1',IProof->CProof(EConstr.mkApp(op_constr,[|t1';t2|]))|IProof,CProoft2'->CProof(EConstr.mkApp(op_constr,[|t1;t2'|]))|CProoft1',CProoft2'->CProof(EConstr.mkApp(op_constr,[|t1';t2'|]))|_,_->lett1',p1=mkprft1p1inlett2',p2=mkprft2p2inTProof(EConstr.mkApp(op_constr,[|t1';t2'|]),EConstr.mkApp(op_iff,[|t1;t2;t1';t2';p1;p2|]))lettrans_bin_propop_constrop_ifft1p1t2p2=letprf=trans_bin_propop_constrop_ifft1p1t2p2indebug_zify(fun()->pp_prfpprf);prflettrans_un_propop_constrop_iffp1prf1=matchprf1with|IProof->IProof|CProofp1'->CProof(EConstr.mkApp(op_constr,[|p1'|]))|TProof(p1',prf)->TProof(EConstr.mkApp(op_constr,[|p1'|]),EConstr.mkApp(op_iff,[|p1;p1';prf|]))letrectrans_propenvevde=matchclassify_propenvevdewith|BINOP({op_constr;op_iff},p1,p2)->letevd,prf1=trans_propenvevdp1inletevd,prf2=trans_propenvevdp2inevd,trans_bin_propop_constrop_iffp1prf1p2prf2|UNOP({op_constr;op_iff},p1)->letevd,prf1=trans_propenvevdp1inevd,trans_un_propop_constrop_iffp1prf1|OTHEROP(c,a)->(tryletk,t=find_option(match_operatorenvevdca)(ConstrMap.find_allevdc!table_cache)inletn=Array.lengthainmatchkwith|BinRel{decl=br;deriv=rop}->letevd,a1=trans_exprenvevd{constr=a.(n-2);typ=rop.EBinRelT.source;inj=rop.EBinRelT.inj}inletevd,a2=trans_exprenvevd{constr=a.(n-1);typ=rop.EBinRelT.source;inj=rop.EBinRelT.inj}intrans_binrelenvevderopa.(n-2)a1a.(n-1)a2|_->evd,IProofwithNot_found|DestKO->evd,IProof)lettrans_check_propenvevdt=ifis_propenvevdtthenletevd,p=trans_propenvevdtinevd,Somepelseevd,Noneletget_hyp_typ=function|NamedDecl.LocalDef(h,_,ty)|NamedDecl.LocalAssum(h,ty)->(h.Context.binder_name,EConstr.of_constrty)lettrans_hypsenvevdl=List.fold_left(fun(evd,acc)decl->leth,ty=get_hyp_typdeclinmatchtrans_check_propenvevdtywith|evd,None->evd,acc|evd,Somep'->evd,(h,ty,p')::acc)(evd,[])llettrans_hypht0prfp=debug_zify(fun()->Pp.(str"trans_hyp: "++pp_prfpprfp++fnl()));matchprfpwith|IProof->Tacticals.tclIDTAC(* Should detect before *)|CProoft'->Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglinlett'=Reductionops.nf_betaiotaenvevdt'inTactics.change_in_hyp~check:trueNone(Tactics.make_change_argt')(h,Locus.InHypTypeOnly))|TProof(t',prf)->Tacticals.(Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglinlettarget=Reductionops.nf_betaiotaenvevdt'inleth'=Tactics.fresh_id_in_envId.Set.emptyhenvinletprf=EConstr.mkApp(forcerew_iff,[|t0;target;prf;EConstr.mkVarh|])intclTHEN(Tactics.pose_proof(Name.Nameh')prf)(tclTRY(tclTHEN(Tactics.clear[h])(Tactics.rename_hyp[(h',h)])))))lettrans_conclprfp=debug_zify(fun()->Pp.(str"trans_concl: "++pp_prfpprfp++fnl()));matchprfpwith|IProof->Tacticals.tclIDTAC|CProoft->Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglinlett'=Reductionops.nf_betaiotaenvevdtinTactics.change_conclt')|TProof(t,prf)->Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglinlettyp=get_type_ofenvevdprfinmatchEConstr.kindevdtypwith|App(c,a)whenArray.lengtha=2->Tactics.apply(EConstr.mkApp(Lazy.forcerew_iff_rev,[|a.(0);a.(1);prf|]))|_->raise(CErrors.anomalyPp.(str"zify cannot transform conclusion")))lettclTHENOptetactac'=matchewithNone->tac'|Somee'->Tacticals.tclTHEN(tace')tac'letassert_injt=init_cache();Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglintryignore(get_injectionenvevdt);Tacticals.tclIDTACwithNot_found->Tacticals.tclFAIL(Pp.str" InjTyp does not exist"))letelim_bindingxtty=Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinleth=Tactics.fresh_id_in_envId.Set.empty(Nameops.add_prefix"heq_"x)envinTacticals.tclTHEN(Tactics.pose_proof(Nameh)(eq_proofty(EConstr.mkVarx)t))(Tacticals.tclTRY(Tactics.clear_body[x])))letdo_lettac(h:Constr.named_declaration)=matchhwith|Context.Named.Declaration.LocalAssum_->Tacticals.tclIDTAC|Context.Named.Declaration.LocalDef(id,t,ty)->Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglintryletx=id.Context.binder_nameinignore(leteq=Lazy.forceeqinfind_option(match_operatorenvevdeq[|EConstr.of_constrty;EConstr.mkVarx;EConstr.of_constrt|])(ConstrMap.find_allevdeq!table_cache));tacx(EConstr.of_constrt)(EConstr.of_constrty)withNot_found->Tacticals.tclIDTAC)letiter_let_auxtac=Proofview.Goal.enter(fungl->letenv=Tacmach.pf_envglinletsign=Environ.named_contextenvininit_cache();Tacticals.tclMAP(do_lettac)sign)letiter_let(tac:Ltac_plugin.Tacinterp.Value.t)=iter_let_aux(fun(id:Names.Id.t)tty->Ltac_plugin.Tacinterp.Value.applytac[Ltac_plugin.Tacinterp.Value.of_constr(EConstr.mkVarid);Ltac_plugin.Tacinterp.Value.of_constrt;Ltac_plugin.Tacinterp.Value.of_constrty])letelim_let=iter_let_auxelim_bindingletzify_tac=Proofview.Goal.enter(fungl->Coqlib.check_required_library["Coq";"micromega";"ZifyClasses"];Coqlib.check_required_library["Coq";"micromega";"ZifyInst"];init_cache();letevd=Tacmach.projectglinletenv=Tacmach.pf_envglinletsign=Environ.named_contextenvinletevd,concl=trans_check_propenvevd(Tacmach.pf_conclgl)inletevd,hyps=trans_hypsenvevdsigninletl=CstrTable.get()inProofview.tclTHEN(Proofview.Unsafe.tclEVARSevd)(tclTHENOptconcltrans_concl(Tacticals.tclTHEN(Tacticals.tclTHENLIST(List.rev_map(fun(h,p,t)->trans_hyphpt)hyps))(CstrTable.gen_cstrl))))typepscript=SetofNames.Id.t*EConstr.t|PoseofNames.Id.t*EConstr.ttypespec_env={map:Names.Id.tHConstr.t;spec_name:Names.Id.t;term_name:Names.Id.t;fresh:Nameops.Subscript.t;proofs:pscriptlist}letregister_constr{map;spec_name;term_name;fresh;proofs}cthm=lettname=Nameops.add_subscriptterm_namefreshinletsname=Nameops.add_subscriptspec_namefreshin(EConstr.mkVartname,{map=HConstr.addctnamemap;spec_name;term_name;fresh=Nameops.Subscript.succfresh;proofs=Set(tname,c)::Pose(sname,thm)::proofs})letfresh_subscriptenv=letctx=(Environ.named_context_valenv).Environ.env_named_mapinNameops.Subscript.succ(Names.Id.Map.fold(funid_s->let_,s'=Nameops.get_subscriptidinletcmp=Nameops.Subscript.comparess'inifcmp=0thenselseifcmp<0thens'elses)ctxNameops.Subscript.zero)letinit_envsnametnames={map=HConstr.empty;spec_name=sname;term_name=tname;fresh=s;proofs=[]}letrecspec_of_termenvevd(senv:spec_env)t=letget_nametenv=tryEConstr.mkVar(HConstr.findtsenv.map)withNot_found->tinletc,a=decompose_appenvevdtinifa=[||]then(* The term cannot be decomposed. *)(get_nametsenv,senv)else(* recursively analyse the sub-terms *)leta',senv'=Array.fold_right(fune(l,senv)->letr,senv=spec_of_termenvevdsenvein(r::l,senv))a([],senv)inleta'=Array.of_lista'inlett'=EConstr.mkApp(c,a')intry(EConstr.mkVar(HConstr.findt'senv'.map),senv')withNot_found->(trymatchsnd(ConstrMap.findevdc!specs_cache)with|UnOpSpecs|BinOpSpecs->letthm=EConstr.mkApp(s.deriv.ESpecT.spec,a')inregister_constrsenv't'thm|_->(get_namet'senv',senv')withNot_found|DestKO->(t',senv'))letinterp_pscripts=matchswith|Set(id,c)->Tacticals.tclTHEN(Tactics.letin_tacNone(Names.Nameid)cNone{Locus.onhyps=None;Locus.concl_occs=Locus.AllOccurrences})(Tactics.clear_body[id])|Pose(id,c)->Tactics.pose_proof(Names.Nameid)cletrecinterp_pscriptsl=matchlwith|[]->Tacticals.tclIDTAC|s::l->Tacticals.tclTHEN(interp_pscripts)(interp_pscriptsl)letspec_of_hyps=Proofview.Goal.enter(fungl->letterms=Tacmach.pf_conclgl::List.mapsnd(Tacmach.pf_hyps_typesgl)inletenv=Tacmach.pf_envglinletevd=Tacmach.projectglinlets=fresh_subscriptenvinletenv=List.fold_left(funacct->snd(spec_of_termenvevdacct))(init_env(Names.Id.of_string"H")(Names.Id.of_string"z")s)termsininterp_pscripts(List.revenv.proofs))letiter_specs=spec_of_hypsletfind_hypevdtl=trySome(EConstr.mkVar(fst(List.find(fun(h,t')->EConstr.eq_constrevdtt')l)))withNot_found->Noneletfind_proofevdtl=ifEConstr.eq_constrevdt(Lazy.forceop_True)thenSome(Lazy.forceop_I)elsefind_hypevdtl(** [sat_constr env evd sub taclist hyps c d]= (sub',taclist',hyps') where
- sub' is a fresh subscript obtained from sub
- taclist' is obtained from taclist by posing the lemma 'd' applied to 'c'
- hyps' is obtained from hyps'
taclist and hyps are threaded to avoid adding duplicates
*)letsat_constrenvevd(sub,taclist,hyps)cd=matchEConstr.kindevdcwith|App(c,args)->ifArray.lengthargs=2thenleth1=Tacred.cbv_betaenvevd(EConstr.mkApp(d.ESatT.parg1,[|args.(0)|]))inleth2=Tacred.cbv_betaenvevd(EConstr.mkApp(d.ESatT.parg2,[|args.(1)|]))inletn=Nameops.add_subscript(Names.Id.of_string"__sat")subinlettrm=match(find_proofevdh1hyps,find_proofevdh2hyps)with|Someh1,Someh2->(EConstr.mkApp(d.ESatT.satOK,[|args.(0);args.(1);h1;h2|]))|Someh1,_->EConstr.mkApp(d.ESatT.satOK,[|args.(0);args.(1);h1|])|_,_->EConstr.mkApp(d.ESatT.satOK,[|args.(0);args.(1)|])inletrtrm=Tacred.cbv_betaenvevdtrminlettyp=Retyping.get_type_ofenvevdrtrminmatchfind_hypevdtyphypswith|None->(Nameops.Subscript.succsub,(Tactics.pose_proof(Names.Namen)rtrm::taclist),(n,typ)::hyps)|Some_->(sub,taclist,hyps)else(sub,taclist,hyps)|_->(sub,taclist,hyps)letget_all_satenvevdc=List.fold_left(funacce->matchewith_,Saturates->s::acc|_->acc)[](tryConstrMap.find_allevdc!saturate_cachewithDestKO|Not_found->[])letsaturate=Proofview.Goal.enter(fungl->init_cache();lettable=CstrTable.HConstr.create20inletconcl=Tacmach.pf_conclglinlethyps=Tacmach.pf_hyps_typesglinletevd=Tacmach.projectglinletenv=Tacmach.pf_envglinletrecsatt=matchEConstr.kindevdtwith|App(c,args)->satc;Array.itersatargs;ifArray.lengthargs=2thenletds=get_all_satenvevdcinifds=[]||CstrTable.HConstr.memtabletthen()elseList.iter(funx->CstrTable.HConstr.addtabletx.deriv)dselse()|Prod(a,t1,t2)whena.Context.binder_name=Names.Anonymous->satt1;satt2|_->()in(* Collect all the potential saturation lemma *)satconcl;List.iter(fun(_,t)->satt)hyps;lets0=fresh_subscriptenvinlet(_,tacs,_)=CstrTable.HConstr.fold(funcdacc->sat_constrenvevdacccd)table(s0,[],hyps)inTacticals.tclTHENLISTtacs)