123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534(************************************************************************)(* * 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) *)(************************************************************************)(* module CVars = Vars *)openPpopenUtilopenNamesopenConstropenContextopenTermopsopenEnvironopenEConstropenVarsopenFind_subtermopenNamegenopenLocusopenProofview.NotationsopenContext.Named.DeclarationmoduleNamedDecl=Context.Named.Declaration(*********************************************)(* Errors *)(*********************************************)exceptionAlreadyUsedofId.tleterror?loce=Loc.raise?loceexceptionUnhandledletwrap_unhandledfe=trySome(fe)withUnhandled->Nonelettactic_interp_error_handler=function|AlreadyUsedid->Id.printid++str" is already used."|_->raiseUnhandledlet_=CErrors.register_handler(wrap_unhandledtactic_interp_error_handler)letfresh_id_in_envavoididenv=letavoid'=ids_of_named_context_val(named_context_valenv)inletavoid=ifId.Set.is_emptyavoidthenavoid'elseId.Set.unionavoid'avoidinnext_ident_away_in_goal(Global.env())idavoid(*********************************)(* Basic generalization tactics *)(*********************************)(* Given a type [T] convertible to [forall x1..xn:A1..An(x1..xn-1), G(x1..xn)]
and [a1..an:A1..An(a1..an-1)] such that the goal is [G(a1..an)],
this generalizes [hyps |- goal] into [hyps |- T] *)(* Given a context [hyps] with domain [x1..xn], possibly with let-ins,
and well-typed in the current goal, [bring_hyps hyps] generalizes
[ctxt |- G(x1..xn] into [ctxt |- forall hyps, G(x1..xn)] *)letbring_hypshyps=ifList.is_emptyhypsthenTacticals.tclIDTACelselethyps=List.revhypsinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Tacmach.pf_conclglinletnewcl=it_mkNamedProd_or_LetInsigmaconclhypsinletargs=Context.Named.instancemkVarhypsinRefine.refine~typecheck:falsebeginfunsigma->let(sigma,ev)=Evarutil.new_evarenvsigma~principal:truenewclin(sigma,mkApp(ev,args))endendletreverthyps=Proofview.Goal.enterbeginfungl->letctx=List.map(funid->Tacmach.pf_get_hypidgl)hypsin(bring_hypsctx)<*>(Tactics.clearhyps)end(***************************)(* Generalization tactics *)(***************************)(* Compute a name for a generalization *)letgeneralized_nameenvsigmactidscl=function|Nameidasna->ifId.List.memididsthenerror(AlreadyUsedid);na|Anonymous->matchEConstr.kindsigmacwith|Varid->(* Keep the name even if not occurring: may be used by intros later *)Nameid|_->ifnoccurnsigma1clthenAnonymouselse(* On ne s'etait pas casse la tete : on avait pris pour nom de
variable la premiere lettre du type, meme si "c" avait ete une
constante dont on aurait pu prendre directement le nom *)named_hdenvsigmatAnonymous(* Abstract over [c] in [forall x1:A1(c)..xi:Ai(c).T(c)] producing
[forall x, x1:A1(x1), .., xi:Ai(x). T(x)] with all [c] abtracted in [Ai]
but only those at [occs] in [T] *)letgeneralize_goal_genenvsigmaidsi((occs,c,b),na)tcl=letopenContext.Rel.Declarationinletdecls,cl=decompose_prod_n_declssigmaiclinletdummy_prod=it_mkProd_or_LetInmkPropdeclsinletnewdecls,_=letarity=Array.length(snd(EConstr.decompose_appsigmac))inletcache=refInt.Map.emptyinleteqsigmakt=letc=tryInt.Map.findk!cachewithNot_found->letc=EConstr.Vars.liftkcinlet()=cache:=Int.Map.addkc!cacheincin(* We use a nounivs equality because generalize morally takes a pattern as
argument, so we have to ignore freshly generated sorts. *)EConstr.eq_constr_nounivssigmactindecompose_prod_n_declssigmai(replace_term_gensigmaeqarity(mkRel1)dummy_prod)inletcl',sigma'=subst_closed_term_occenvsigma(AtOccsoccs)c(it_mkProd_or_LetInclnewdecls)inletna=generalized_nameenvsigmactidscl'nainletr=Retyping.relevance_of_typeenvsigmatinletdecl=matchbwith|None->LocalAssum(make_annotnar,t)|Someb->LocalDef(make_annotnar,b,t)inmkProd_or_LetIndeclcl',sigma'letgeneralize_goalgli((occs,c,b),naaso)(cl,sigma)=letopenTacmachinletenv=pf_envglinletids=pf_ids_of_hypsglinletsigma,t=Typing.type_ofenvsigmacingeneralize_goal_genenvsigmaidsiotclletgeneralize_dep?(with_let=false)c=letopenTacmachinletopenTacticalsinProofview.Goal.enterbeginfungl->letenv=pf_envglinletsign=named_context_valenvinletsigma=projectglinletinit_ids=ids_of_named_context(Global.named_context())inletseek(d:named_declaration)(toquant:named_context)=ifList.exists(fund'->occur_var_in_declenvsigma(NamedDecl.get_idd')d)toquant||dependent_in_declsigmacdthend::toquantelsetoquantinletto_quantify=Context.Named.fold_outsideseek(named_context_of_valsign)~init:[]inletqhyps=List.mapNamedDecl.get_idto_quantifyinlettothin=List.filter(funid->not(Id.List.memidinit_ids))qhypsinlettothin'=matchEConstr.kindsigmacwith|Varidwhenmem_named_context_validsign&¬(Id.List.memidinit_ids)->tothin@[id]|_->tothininletcl'=it_mkNamedProd_or_LetInsigma(pf_conclgl)to_quantifyinletis_var,body=matchEConstr.kindsigmacwith|Varid->letbody=NamedDecl.get_value(pf_get_hypidgl)inletis_var=Option.is_emptybody&¬(List.memidinit_ids)inifwith_letthenis_var,bodyelseis_var,None|_->false,Noneinletcl'',evd=generalize_goalgl0((AllOccurrences,c,body),Anonymous)(cl',projectgl)in(* Check that the generalization is indeed well-typed *)letevd=(* No need to retype for variables, term is statically well-typed *)ifis_varthenevdelsefst(Typing.type_ofenvevdcl'')inletargs=Array.to_list(Context.Named.instancemkVarto_quantify)intclTHENLIST[Proofview.Unsafe.tclEVARSevd;Tactics.apply_type~typecheck:falsecl''(ifOption.is_emptybodythenc::argselseargs);Tactics.cleartothin']end(** *)letgeneralize_gen_letlconstr=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletnewcl,evd=List.fold_right_i(generalize_goalgl)0lconstr(Tacmach.pf_conclgl,Tacmach.projectgl)inlet(evd,_)=Typing.type_ofenvevdnewclinletmap((_,c,b),_)=ifOption.is_emptybthenSomecelseNoneinProofview.tclTHEN(Proofview.Unsafe.tclEVARSevd)(Tactics.apply_type~typecheck:falsenewcl(List.map_filtermaplconstr))endletnew_generalize_gen_letlconstr=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletids=Tacmach.pf_ids_of_hypsglinletnewcl,sigma,args=List.fold_right_i(funi((_,c,b),_aso)(cl,sigma,args)->letsigma,t=Typing.type_ofenvsigmacinletargs=ifOption.is_emptybthenc::argselseargsinletcl,sigma=generalize_goal_genenvsigmaidsiotclin(cl,sigma,args))0lconstr(concl,sigma,[])inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Refine.refine~typecheck:falsebeginfunsigma->let(sigma,ev)=Evarutil.new_evarenvsigma~principal:truenewclin(sigma,applist(ev,args))end)endletgeneralize_genlconstr=generalize_gen_let(List.map(fun((occs,c),na)->(occs,c,None),na)lconstr)letnew_generalize_genlconstr=new_generalize_gen_let(List.map(fun((occs,c),na)->(occs,c,None),na)lconstr)letgeneralizel=new_generalize_gen_let(List.map(func->((AllOccurrences,c,None),Anonymous))l)(* Faudra-t-il une version avec plusieurs args de generalize_dep ?
Cela peut-être troublant de faire "Generalize Dependent H n" dans
"n:nat; H:n=n |- P(n)" et d'échouer parce que H a disparu après la
généralisation dépendante par n.
let quantify lconstr =
List.fold_right
(fun com tac -> tclTHEN tac (tactic_com generalize_dep c))
lconstr
tclIDTAC
*)letcoq_eqenvsigma=Evd.fresh_globalenvsigmaCoqlib.(lib_ref"core.eq.type")letcoq_eq_reflenvsigma=Evd.fresh_globalenvsigmaCoqlib.(lib_ref"core.eq.refl")letcoq_heq_ref=lazy(Coqlib.lib_ref"core.JMeq.type")letcoq_heqenvsigma=Evd.fresh_globalenvsigma(Lazy.forcecoq_heq_ref)letcoq_heq_reflenvsigma=Evd.fresh_globalenvsigma(Coqlib.lib_ref"core.JMeq.refl")(* let coq_heq_refl = lazy (glob (lib_ref "core.JMeq.refl")) *)letmkEqenvsigmatxy=letsigma,eq=coq_eqenvsigmainsigma,mkApp(eq,[|t;x;y|])letmkReflenvsigmatx=letsigma,refl=coq_eq_reflenvsigmainsigma,mkApp(refl,[|t;x|])letmkHEqenvsigmatxuy=letsigma,c=coq_heqenvsigmainsigma,mkApp(c,[|t;x;u;y|])letmkHReflenvsigmatx=letsigma,c=coq_heq_reflenvsigmainsigma,mkApp(c,[|t;x|])letlift_togethernnl=letl',_=List.fold_right(funx(acc,n)->(liftnx::acc,succn))l([],n)inl'letlift_listl=List.map(lift1)lletids_of_constrenvsigma?(all=false)varsc=letrecauxvarsc=matchEConstr.kindsigmacwith|Varid->Id.Set.addidvars|App(f,args)->(matchEConstr.kindsigmafwith|Construct((ind,_),_)|Ind(ind,_)->let(mib,mip)=Inductive.lookup_mind_specifenvindinArray.fold_left_from(ifallthen0elsemib.Declarations.mind_nparams)auxvarsargs|_->EConstr.foldsigmaauxvarsc)|_->EConstr.foldsigmaauxvarscinauxvarscletdecompose_indappenvsigmafargs=matchEConstr.kindsigmafwith|Construct((ind,_),_)|Ind(ind,_)->let(mib,mip)=Inductive.lookup_mind_specifenvindinletfirst=mib.Declarations.mind_nparams_recinletpars,args=Array.chopfirstargsinmkApp(f,pars),args|_->f,argsletmk_term_eqhomogeneousenvsigmatytty't'=ifhomogeneousthenletsigma,eq=mkEqenvsigmatytt'inletsigma,refl=mkReflenvsigmaty't'insigma,(eq,refl)elseletsigma,heq=mkHEqenvsigmatytty't'inletsigma,hrefl=mkHReflenvsigmaty't'insigma,(heq,hrefl)letmake_abstract_generalizeenvidtypconcldepctxbodyceqsargsrefls=letopenContext.Rel.DeclarationinRefine.refine~typecheck:truebeginfunsigma->leteqslen=List.lengtheqsin(* Abstract by the "generalized" hypothesis equality proof if necessary. *)letsigma,abshypeq,abshypt=ifdepthenletty=lift1cinlethomogeneous=Reductionops.is_convenvsigmatytypinletsigma,(eq,refl)=mk_term_eqhomogeneous(push_rel_contextctxenv)sigmaty(mkRel1)typ(mkVarid)insigma,mkProd(make_annotAnonymousERelevance.relevant,eq,lift1concl),[|refl|]elsesigma,concl,[||]in(* Abstract by equalities *)leteqs=lift_togethern1eqsin(* lift together and past genarg *)letabseqs=it_mkProd_or_LetIn(lifteqslenabshypeq)(List.map(funx->LocalAssum(make_annotAnonymousERelevance.relevant,x))eqs)inletr=ERelevance.relevantin(* TODO relevance *)letdecl=matchbodywith|None->LocalAssum(make_annot(Nameid)r,c)|Somebody->LocalDef(make_annot(Nameid)r,body,c)in(* Abstract by the "generalized" hypothesis. *)letgenarg=mkProd_or_LetIndeclabseqsin(* Abstract by the extension of the context *)letgenctyp=it_mkProd_or_LetIngenargctxin(* The goal will become this product. *)let(sigma,genc)=Evarutil.new_evarenvsigma~principal:truegenctypin(* Apply the old arguments giving the proper instantiation of the hyp *)letinstc=mkApp(genc,Array.of_listargs)in(* Then apply to the original instantiated hyp. *)letinstc=Option.cata(fun_->instc)(mkApp(instc,[|mkVarid|]))bodyin(* Apply the reflexivity proofs on the indices. *)letappeqs=mkApp(instc,Array.of_listrefls)in(* Finally, apply the reflexivity proof for the original hyp, to get a term of type gl again. *)(sigma,mkApp(appeqs,abshypt))endlethyps_of_varsenvsigmasignnogenhyps=ifId.Set.is_emptyhypsthen[]elselet(_,lh)=Context.Named.fold_inside(fun(hs,hl)d->letx=NamedDecl.get_iddinifId.Set.memxnogenthen(hs,hl)elseifId.Set.memxhsthen(hs,x::hl)elseletxvars=global_vars_set_of_declenvsigmadinifnot(Id.Set.is_empty(Id.Set.diffxvarshs))then(Id.Set.addxhs,x::hl)else(hs,hl))~init:(hyps,[])signinlhexceptionSeenletlinearenvsigmavarsargs=letseen=refvarsintryArray.iter(funi->letrels=ids_of_constrenvsigma~all:trueId.Set.emptyiinletseen'=Id.Set.fold(funidacc->ifId.Set.memidaccthenraiseSeenelseId.Set.addidacc)rels!seeninseen:=seen')args;truewithSeen->falseletis_defined_variableenvid=env|>lookup_namedid|>is_local_defletabstract_argsglgeneralize_varsdepiddefinedfargs=letopenContext.Rel.Declarationinletsigma=Tacmach.projectglinletenv=Tacmach.pf_envglinletconcl=Tacmach.pf_conclglinlethyps=Proofview.Goal.hypsglinletdep=dep||local_occur_varsigmaidconclinletavoid=refId.Set.emptyinletget_idname=letid=fresh_id_in_env!avoid(matchnamewithNamen->n|Anonymous->Id.of_string"gen_x")envinavoid:=Id.Set.addid!avoid;idin(* Build application generalized w.r.t. the argument plus the necessary eqs.
From env |- c : forall G, T and args : G we build
(T[G'], G' : ctx, env ; G' |- args' : G, eqs := G'_i = G_i, refls : G' = G, vars to generalize)
eqs are not lifted w.r.t. each other yet. (* will be needed when going to dependent indexes *)
*)letaux(sigma,prod,ctx,ctxenv,c,args,eqs,refls,nongenvars,vars)arg=letname,ty_relevance,ty,arity=letrel,c=Reductionops.whd_decompose_prod_nenvsigma1prodinlet({binder_name=na;binder_relevance=r},t)=List.hdrelinna,r,t,cinletargty=Retyping.get_type_ofenvsigmaarginletsigma,ty=Evarsolve.refresh_universes(Sometrue)envsigmatyinletlenctx=List.lengthctxinletliftargty=liftlenctxargtyinletleq=constr_cmpctxenvsigmaConversion.CUMULliftargtytyinmatchEConstr.kindsigmaargwith|Varidwhennot(is_defined_variableenvid)&&leq&¬(Id.Set.memidnongenvars)->(sigma,subst1argarity,ctx,ctxenv,mkApp(c,[|arg|]),args,eqs,refls,Id.Set.addidnongenvars,Id.Set.removeidvars)|_->letname=get_idnameinletdecl=LocalAssum(make_annot(Namename)ty_relevance,ty)inletctx=decl::ctxinletc'=mkApp(lift1c,[|mkRel1|])inletargs=arg::argsinletliftarg=lift(List.lengthctx)arginletsigma,eq,refl=ifleqthenletsigma,eq=mkEqenvsigma(lift1ty)(mkRel1)liftarginletsigma,refl=mkReflenvsigma(lift(-lenctx)ty)arginsigma,eq,reflelseletsigma,eq=mkHEqenvsigma(lift1ty)(mkRel1)liftargtyliftarginletsigma,refl=mkHReflenvsigmaargtyarginsigma,eq,reflinleteqs=eq::lift_listeqsinletrefls=refl::reflsinletargvars=ids_of_constrenvsigmavarsargin(sigma,arity,ctx,push_reldeclctxenv,c',args,eqs,refls,nongenvars,Id.Set.unionargvarsvars)inletf',args'=decompose_indappenvsigmafargsinletdogen,f',args'=letparvars=ids_of_constrenvsigma~all:trueId.Set.emptyf'inifnot(linearenvsigmaparvarsargs')thentrue,f,argselsematchArray.findi(funix->not(isVarsigmax)||is_defined_variableenv(destVarsigmax))args'with|None->false,f',args'|Somenonvar->letbefore,after=Array.chopnonvarargs'intrue,mkApp(f',before),afterinifdogenthenlettyf'=Retyping.get_type_ofenvsigmaf'inletsigma,arity,ctx,ctxenv,c',args,eqs,refls,nogen,vars=Array.fold_leftaux(sigma,tyf',[],env,f',[],[],[],Id.Set.empty,Id.Set.empty)args'inletargs,refls=List.revargs,List.revreflsinletvars=ifgeneralize_varsthenletnogen=Id.Set.addidnogeninhyps_of_varsenvsigmahypsnogenvarselse[]inletbody,c'=ifdefinedthenSomec',Retyping.get_type_ofctxenvsigmac'elseNone,c'inlettyp=Tacmach.pf_get_hyp_typidglinlettac=make_abstract_generalizeenvidtypconcldepctxbodyc'eqsargsreflsinlettac=Proofview.Unsafe.tclEVARSsigma<*>tacinSome(tac,dep,succ(List.lengthctx),vars)elseNoneletabstract_generalize?(generalize_vars=true)?(force_dep=false)id=letopenContext.Named.DeclarationinProofview.Goal.enterbeginfungl->Coqlib.(check_required_libraryjmeq_module_name);letsigma=Tacmach.projectglinlet(f,args,def,id,oldid)=letoldid=Tacmach.pf_get_new_ididglinmatchTacmach.pf_get_hypidglwith|LocalAssum(_,t)->letf,args=decompose_appsigmatin(f,args,false,id,oldid)|LocalDef(_,t,_)->letf,args=decompose_appsigmatin(f,args,true,id,oldid)inifArray.is_emptyargsthenProofview.tclUNIT()elseletnewc=abstract_argsglgeneralize_varsforce_depiddeffargsinmatchnewcwith|None->Proofview.tclUNIT()|Some(tac,dep,n,vars)->lettac=ifdepthenTacticals.tclTHENLIST[tac;Tactics.rename_hyp[(id,oldid)];Tacticals.tclDOnTactics.intro;generalize_dep~with_let:true(mkVaroldid)]elseTacticals.tclTHENLIST[tac;Tactics.clear[id];Tacticals.tclDOnTactics.intro]inifList.is_emptyvarsthentacelseTacticals.tclTHENtac(Tacticals.tclFIRST[revertvars;Tacticals.tclMAP(funid->Tacticals.tclTRY(generalize_dep~with_let:true(mkVarid)))vars])end