1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627(************************************************************************)(* * 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.DeclarationmoduleERelevance=EConstr.ERelevanceletdebug_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_flagsRedFlags.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)->a|_->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) *)}leteq_injevdi1i2=i1.isid=i2.isid&&EConstr.eq_constrevdi1.inji2.injend(** [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))ERelevance.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.tdecllettarget_injd=matchdwith|BinOpd->Somed.deriv.EBinOpT.inj3|UnOpd->Somed.deriv.EUnOpT.inj2_t|CstOpd->Somed.deriv.inj|_->Nonetypeterm_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=leta=get_projections_from_constant(evd,c)inEInj.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)=leta=get_projections_from_constant(evd,i)inE.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}(* [arrow] is the term (fun (x:Prop) (y : Prop) => x -> y) *)letarrow=letnamex=Context.make_annot(Name.mk_name(Names.Id.of_stringx))ERelevance.relevantinEConstr.mkLambda(name"x",EConstr.mkProp,EConstr.mkLambda(name"y",EConstr.mkProp,EConstr.mkProd(Context.make_annotNames.AnonymousERelevance.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,[||])letcheck_target_injevdinjd=matchinj,target_injdwith|None,_->true|Some_,None->false|Somei1,Somei2->EInjT.eq_injevdi1i2(** [match_operator env evd hd arg inj (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_operatorenvevdhdargsinj(t,d)=letdecompti=letn=Array.lengthargsinlett'=EConstr.mkApp(hd,Array.subargs0(n-i))inifis_convertibleenvevdt'tthenSome(d,t)elseNoneinifcheck_target_injevdinjdthenmatchtwith|OtherTermt->Some(d,t)|Applicationt->(matchdwith|CstOp_->decompt0|UnOp_->decompt1|BinOp_->decompt2|BinRel_->decompt2|PropOp_->decompt2|PropUnOp_->decompt1|_->None)elseNoneletpp_trans_exprenvevderes=debug_zify(fun()->Pp.(str"\ntrans_expr "++pp_prfevde.inje.constrres));resletrectrans_exprenvevde=letinj=e.injinlete=e.constrintryletc,a,is_constant=get_operatorfalseenvevdeinifis_constantthenevd,Termelseletk,t=find_option(match_operatorenvevdca(Someinj))(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_operatorenvevdcaNone)(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'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|]None)(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_constrenvevdhyps(sub,taclist,prfs)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_hypevdtypprfswith|None->(Nameops.Subscript.succsub,(Tactics.pose_proof(Names.Namen)rtrm::taclist),(n,typ)::prfs)|Some_->(sub,taclist,prfs)else(sub,taclist,prfs)|_->(sub,taclist,prfs)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_constrenvevdhypsacccd)table(s0,[],[])inTacticals.tclTHENLISTtacs)