123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579(************************************************************************)(* * 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) *)(************************************************************************)(* This file is the interface between the c-c algorithm and Coq *)openNamesopenInductiveopsopenDeclarationsopenConstropenContextopenEConstropenVarsopenTacticsopenTypingopenCcalgoopenCcproofopenPpopenUtilopenProofview.NotationsmoduleRelDecl=Context.Rel.DeclarationmoduleNamedDecl=Context.Named.Declarationlet_f_equal=lazy(Coqlib.lib_ref"core.eq.congr")let_eq_rect=lazy(Coqlib.lib_ref"core.eq.rect")let_refl_equal=lazy(Coqlib.lib_ref"core.eq.refl")let_sym_eq=lazy(Coqlib.lib_ref"core.eq.sym")let_trans_eq=lazy(Coqlib.lib_ref"core.eq.trans")let_eq=lazy(Coqlib.lib_ref"core.eq.type")let_False=lazy(Coqlib.lib_ref"core.False.type")let_not=lazy(Coqlib.lib_ref"core.not.type")letwhdenvsigmat=Reductionops.clos_whd_flagsCClosure.betaiotazetaenvsigmatletwhd_deltaenvsigmat=Reductionops.clos_whd_flagsCClosure.allenvsigmatletwhd_in_concl=reduct_in_concl~cast:true~check:false(Reductionops.whd_all,DEFAULTcast)(* decompose member of equality in an applicative format *)(** FIXME: evar leak *)letsf_ofenvsigmac=ESorts.kindsigma(snd(sort_ofenvsigmac))letrecdecompose_termenvsigmat=matchEConstr.kindsigma(whdenvsigmat)withApp(f,args)->lettf=decompose_termenvsigmafinlettargs=Array.map(decompose_termenvsigma)argsinArray.fold_left(funst->ATerm.mkAppli(s,t))tftargs|Prod(_,a,_b)whennoccurnsigma1_b->letb=Termops.pop_binletsort_b=sf_ofenvsigmabinletsort_a=sf_ofenvsigmaainATerm.mkAppli(ATerm.mkAppli(ATerm.mkProduct(sort_a,sort_b),decompose_termenvsigmaa),decompose_termenvsigmab)|Constructc->let(((mind,i_ind),i_con),u)=cinletu=EInstance.kindsigmauinletcanon_mind=MutInd.make1(MutInd.canonicalmind)inletcanon_ind=canon_mind,i_indinlet(oib,_)=Global.lookup_inductive(canon_ind)inletnargs=constructor_nallargsenv(canon_ind,i_con)inATerm.mkConstructor{ci_constr=((canon_ind,i_con),u);ci_arity=nargs;ci_nhyps=nargs-oib.mind_nparams}|Indc->let(mind,i_ind),u=cinletu=EInstance.kindsigmauinletcanon_mind=MutInd.make1(MutInd.canonicalmind)inletcanon_ind=canon_mind,i_indinATerm.mkSymb(Constr.mkIndU(canon_ind,u))|Const(c,u)->letu=EInstance.kindsigmauinletcanon_const=Constant.make1(Constant.canonicalc)inATerm.mkSymb(Constr.mkConstU(canon_const,u))|Proj(p,c)->letcanon_mindkn=MutInd.make1(MutInd.canonicalkn)inletp'=Projection.mapcanon_mindpinletc=Retyping.expand_projectionenvsigmap'c[]indecompose_termenvsigmac|_->lett=Termops.strip_outer_castsigmatinifclosed0sigmatthenATerm.mkSymb(EConstr.to_constr~abort_on_undefined_evars:falsesigmat)elseraiseNot_found(* decompose equality in members and type *)letatom_of_constrbenvsigmaterm=letwh=(ifbthenwhdelsewhd_delta)envsigmaterminletkot=EConstr.kindsigmawhinmatchkotwithApp(f,args)->ifisRefXenvsigma(Lazy.force_eq)f&&Int.equal(Array.lengthargs)3then`Eq(args.(0),decompose_termenvsigmaargs.(1),decompose_termenvsigmaargs.(2))else`Other(decompose_termenvsigmaterm)|_->`Other(decompose_termenvsigmaterm)letrecpattern_of_constrenvsigmac=matchEConstr.kindsigma(whdenvsigmac)withApp(f,args)->letpargs,lrels=List.split(Array.map_to_list(pattern_of_constrenvsigma)args)inbeginmatchEConstr.kindsigmafwithReli->PVar(i,List.revpargs),List.fold_leftInt.Set.union(Int.Set.singletoni)lrels|_->letpf=decompose_termenvsigmafinPApp(pf,List.revpargs),List.fold_leftInt.Set.unionInt.Set.emptylrelsend|Prod(_,a,_b)whennoccurnsigma1_b->letb=Termops.pop_binletpa,sa=pattern_of_constrenvsigmaainletpb,sb=pattern_of_constrenvsigmabinletsort_b=sf_ofenvsigmabinletsort_a=sf_ofenvsigmaainPApp(ATerm.mkProduct(sort_a,sort_b),[pa;pb]),(Int.Set.unionsasb)|Reli->PVar(i,[]),Int.Set.singletoni|_->letpf=decompose_termenvsigmacinPApp(pf,[]),Int.Set.emptyletnon_trivial=functionPVar(_,[])->false|_->trueletrechas_open_head=functionPVar(_,_::_)->true|PApp(_,args)->List.existshas_open_headargs|_->falseletpatterns_of_constrbenvsigmanrelsterm=letf,args=trydestAppsigma((ifbthenwhdelsewhd_delta)envsigmaterm)withDestKO->raiseNot_foundinifisRefXenvsigma(Lazy.force_eq)f&&Int.equal(Array.lengthargs)3thenletpatt1,rels1=pattern_of_constrenvsigmaargs.(1)andpatt2,rels2=pattern_of_constrenvsigmaargs.(2)inletvalid1=ifnot(Int.equal(Int.Set.cardinalrels1)nrels)thenCreates_variableselseifhas_open_headpatt1thenCreates_variables(* consider open head as variable-creating *)elseifnon_trivialpatt1thenNormalelseTrivial(EConstr.to_constr~abort_on_undefined_evars:falsesigmaargs.(0))andvalid2=ifnot(Int.equal(Int.Set.cardinalrels2)nrels)thenCreates_variableselseifhas_open_headpatt2thenCreates_variables(* consider open head as variable-creating *)elseifnon_trivialpatt2thenNormalelseTrivial(EConstr.to_constr~abort_on_undefined_evars:falsesigmaargs.(0))inifvalid1!=Creates_variables||valid2!=Creates_variablesthennrels,valid1,patt1,valid2,patt2elseraiseNot_foundelseraiseNot_foundletrecquantified_atom_of_constrbenvsigmanrelsterm=matchEConstr.kindsigma((ifbthenwhdelsewhd_delta)envsigmaterm)withProd(id,atom,ff)->ifisRefXenvsigma(Lazy.force_False)ffthenletpatts=patterns_of_constrbenvsigmanrelsatomin`Nrulepattselsequantified_atom_of_constrb(EConstr.push_rel(RelDecl.LocalAssum(id,atom))env)sigma(succnrels)ff|App(f,[|atom|])whenisRefXenvsigma(Lazy.force_not)f->letpatts=patterns_of_constrbenvsigmanrelsatomin`Nrulepatts|_->letpatts=patterns_of_constrbenvsigmanrelstermin`Rulepattsletlitteral_of_constrbenvsigmaterm=matchEConstr.kindsigma((ifbthenwhdelsewhd_delta)envsigmaterm)with|Prod(id,atom,ff)->ifisRefXenvsigma(Lazy.force_False)ffthenmatch(atom_of_constrbenvsigmaatom)with`Eq(t,a,b)->`Neq(t,a,b)|`Other(p)->`Nother(p)elsebegintryquantified_atom_of_constrb(EConstr.push_rel(RelDecl.LocalAssum(id,atom))env)sigma1ffwithNot_found->`Other(decompose_termenvsigmaterm)end|App(f,[|atom|])whenisRefXenvsigma(Lazy.force_not)f->beginmatch(atom_of_constrbenvsigmaatom)with`Eq(t,a,b)->`Neq(t,a,b)|`Other(p)->`Nother(p)end|_->atom_of_constrbenvsigmaterm(* store all equalities from the context *)letmake_prbglsdepthadditional_termsb=letopenTacmachinletenv=pf_envglsinletsigma=projectglsinletstate=emptyenvsigmadepthinletpos_hyps=ref[]inletneg_hyps=ref[]inList.iter(func->lett=decompose_termenvsigmacinignore(add_atermstatet))additional_terms;List.iter(fundecl->letid=NamedDecl.get_iddeclinbeginmatchlitteral_of_constrbenvsigma(NamedDecl.get_typedecl)with`Eq(t,a,b)->add_equalitystateidab|`Neq(t,a,b)->add_disequalitystate(Hyp(Constr.mkVarid))ab|`Otherph->List.iter(fun(idn,nh)->add_disequalitystate(HeqnH(id,idn))phnh)!neg_hyps;pos_hyps:=(id,ph)::!pos_hyps|`Nothernh->List.iter(fun(idp,ph)->add_disequalitystate(HeqnH(idp,id))phnh)!pos_hyps;neg_hyps:=(id,nh)::!neg_hyps|`Rulepatts->add_quantstateidtruepatts|`Nrulepatts->add_quantstateidfalsepattsend)(Proofview.Goal.hypsgls);beginmatchatom_of_constrbenvsigma(pf_conclgls)with`Eq(t,a,b)->add_disequalitystateGoalab|`Otherg->List.iter(fun(idp,ph)->add_disequalitystate(HeqGidp)phg)!pos_hypsend;state(* indhyps builds the array of arrays of constructor hyps for (ind largs) *)letfresh_idenvid=Namegen.next_ident_awayid(Environ.ids_of_named_context_val@@Environ.named_context_valenv)letbuild_projectionenvsigmaintype(cstr:pconstructor)specialdefault=letci=(snd(fstcstr))inletbody=Equality.build_selectorenvsigmaci(mkRel1)intypespecialdefaultinletid=fresh_idenv(Id.of_string"t")insigma,mkLambda(make_annot(Nameid)Sorts.Relevant,intype,body)(* generate an adhoc tactic following the proof tree *)letapp_globalfargsk=Tacticals.pf_constr_of_global(Lazy.forcef)>>=funfc->k(mkApp(fc,args))letassert_beforenc=Proofview.Goal.enterbeginfungl->letevm,_=Tacmach.pf_applytype_ofglcinProofview.tclTHEN(Proofview.Unsafe.tclEVARSevm)(assert_beforenc)endletrefresh_typeenvevmty=Evarsolve.refresh_universes~status:Evd.univ_flexible~refreshset:true(Somefalse)envevmtylettype_and_refreshc=Proofview.Goal.enter_one~__LOC__beginfungl->letenv=Proofview.Goal.envglinletevm=Tacmach.projectglin(* XXX is get_type_of enough? *)letevm,ty=Typing.type_ofenvevmcinletevm,ty=refresh_typeenvevmtyinProofview.tclTHEN(Proofview.Unsafe.tclEVARSevm)(Proofview.tclUNITty)endlettype_and_refresh_envsigmac=letsigma,ty=Typing.type_ofenvsigmacinletsigma,ty=refresh_typeenvsigmatyinsigma,tyletconstr_of_termc=EConstr.of_constr(ATerm.constrc)letapp_global_envsigmarefargs=let(sigma,c)=Evd.fresh_globalenvsigma(Lazy.forceref)inTyping.checked_appvectenvsigmacargs(* Assumes ⊢ typ : Sort, ⊢ lhs : typ and ⊢ rhs : typ
and p is a reified proof of "@eq typ lhs rhs" *)letrecproof_termenvsigma(typ,lhs,rhs)p=matchp.p_rulewith|Axc->letc=EConstr.of_constr@@constr_of_axiomcinletsigma,expected=app_global_envsigma_eq[|typ;lhs;rhs|]inletsigma=Typing.checkenvsigmacexpectedinsigma,c|SymAxc->letc=EConstr.of_constr@@constr_of_axiomcinletsigma,expected=app_global_envsigma_eq[|typ;rhs;lhs|]inletsigma=Typing.checkenvsigmacexpectedinapp_global_envsigma_sym_eq[|typ;rhs;lhs;c|]|Reflt->lett=constr_of_termtinapp_global_envsigma_refl_equal[|typ;t|]|Trans(p1,p2)->lett1=constr_of_termp1.p_lhsinlett2=constr_of_termp1.p_rhsinlett3=constr_of_termp2.p_rhsinletsigma,p1=proof_termenvsigma(typ,t1,t2)p1inletsigma,p2=proof_termenvsigma(typ,t2,t3)p2inapp_global_envsigma_trans_eq[|typ;t1;t2;t3;p1;p2|]|Congr(p1,p2)->(* p1 : ⊢ f = g : forall x : A, B *)(* p2 : ⊢ t = u : A *)letf=constr_of_termp1.p_lhsinletg=constr_of_termp1.p_rhsinlett=constr_of_termp2.p_lhsinletu=constr_of_termp2.p_rhsinletsigma,funty=type_and_refresh_envsigmafinletsigma,argty=type_and_refresh_envsigmatinletid=fresh_idenv(Id.of_string"f")inletappf=mkLambda(make_annot(Nameid)Sorts.Relevant,funty,mkApp(mkRel1,[|t|]))inletsigma,p1=proof_termenvsigma(funty,f,g)p1inletsigma,p2=proof_termenvsigma(argty,t,u)p2in(* lemma1 : ⊢ f t = g t : B{t} *)letsigma,lemma1=app_global_envsigma_f_equal[|funty;typ;appf;f;g;p1|]in(* lemma2 : ⊢ g t = g u : B{t}, this only type-checks when B{t} ≡ B{u} *)letsigma,lemma2=tryapp_global_envsigma_f_equal[|argty;typ;g;t;u;p2|]withewhenCErrors.noncriticale->(* Fallback if ⊢ g t ≡ g u *)beginmatchEvarconv.unify_delayenvsigma(mkApp(g,[|t|]))(mkApp(g,[|u|]))with|sigma->app_global_envsigma_refl_equal[|typ;mkApp(g,[|t|])|]|exceptionEvarconv.UnableToUnify_->CErrors.user_err(Pp.str"I don't know how to handle dependent equality")endinapp_global_envsigma_trans_eq[|typ;mkApp(f,[|t|]);mkApp(g,[|t|]);mkApp(g,[|u|]);lemma1;lemma2|]|Inject(prf,cstr,nargs,argind)->(* prf : ⊢ ci v = ci w : Ind(args) *)letti=constr_of_termprf.p_lhsinlettj=constr_of_termprf.p_rhsinletdefault=constr_of_termp.p_lhsinletspecial=mkRel(1+nargs-argind)inletsigma,argty=type_and_refresh_envsigmatiinletsigma,proj=build_projectionenvsigmaargtycstrspecialdefaultinletsigma,prf=proof_termenvsigma(argty,ti,tj)prfinapp_global_envsigma_f_equal[|argty;typ;proj;ti;tj;prf|]letproof_tac(typ,lhs,rhs)p:unitProofview.tactic=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletsigma,p=proof_termenvsigma(typ,lhs,rhs)pinletsigma=Typing.checkenvsigmapconclinProofview.Unsafe.tclEVARSsigma<*>exact_no_checkpendletrefute_tacct1t2p=Proofview.Goal.enterbeginfungl->lettt1=constr_of_termt1andtt2=constr_of_termt2inlethid=Tacmach.pf_get_new_id(Id.of_string"Heq")glinletfalse_t=mkApp(c,[|mkVarhid|])inletkintype=letneweq=app_global_eq[|intype;tt1;tt2|]inTacticals.tclTHENS(neweq(assert_before(Namehid)))[proof_tac(intype,tt1,tt2)p;simplest_elimfalse_t]intype_and_refreshtt1>>=kendletrefine_exact_checkc=Proofview.Goal.enterbeginfungl->letevm,_=Tacmach.pf_applytype_ofglcinProofview.tclTHEN(Proofview.Unsafe.tclEVARSevm)(exact_checkc)endletconvert_to_goal_tacct1t2p=Proofview.Goal.enterbeginfungl->lettt1=constr_of_termt1andtt2=constr_of_termt2inletksort=letneweq=app_global_eq[|sort;tt1;tt2|]inlete=Tacmach.pf_get_new_id(Id.of_string"e")glinletx=Tacmach.pf_get_new_id(Id.of_string"X")glinletidentity=mkLambda(make_annot(Namex)Sorts.Relevant,sort,mkRel1)inletendt=app_global_eq_rect[|sort;tt1;identity;mkVarc;tt2;mkVare|]inTacticals.tclTHENS(neweq(assert_before(Namee)))[proof_tac(sort,tt1,tt2)p;endtrefine_exact_check]intype_and_refreshtt2>>=kendletconvert_to_hyp_tacc1t1c2t2p=Proofview.Goal.enterbeginfungl->lettt2=constr_of_termt2inleth=Tacmach.pf_get_new_id(Id.of_string"H")glinletfalse_t=mkApp(mkVarc2,[|mkVarh|])inTacticals.tclTHENS(assert_before(Nameh)tt2)[convert_to_goal_tacc1t1t2p;simplest_elimfalse_t]end(* Essentially [assert (Heq : lhs = rhs) by proof_tac p; discriminate Heq] *)letdiscriminate_taccstrup=Proofview.Goal.enterbeginfungl->letlhs=constr_of_termp.p_lhsandrhs=constr_of_termp.p_rhsinletenv=Proofview.Goal.envglinletevm=Tacmach.projectglinletevm,intype=Typing.type_ofenvevmlhsinletevm,intype=refresh_typeenvevmintypeinlethid=Tacmach.pf_get_new_id(Id.of_string"Heq")glinletneweq=app_global_eq[|intype;lhs;rhs|]inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSevm)(Tacticals.tclTHENS(neweq(assert_before(Namehid)))[proof_tac(intype,lhs,rhs)p;Equality.discrHyphid])end(* wrap everything *)letcc_tacticdepthadditional_termsb=Proofview.Goal.enterbeginfungl->letsigma=Tacmach.projectglinCoqlib.(check_required_librarylogic_module_name);let_=debug_congruence(fun()->Pp.str"Reading goal ...")inletstate=make_prbgldepthadditional_termsbinlet_=debug_congruence(fun()->Pp.str"Problem built, solving ...")inletsol=executetruestateinlet_=debug_congruence(fun()->Pp.str"Computation completed.")inletuf=foreststateinmatchsolwithNone->Tacticals.tclFAIL(str(ifbthen"simple congruence failed"else"congruence failed"))|Somereason->debug_congruence(fun()->Pp.str"Goal solved, generating proof ...");matchreasonwithDiscrimination(i,ipac,j,jpac)->letp=build_proof(Tacmach.pf_envgl)sigmauf(`Discr(i,ipac,j,jpac))inletcstr=(get_constructor_infoufipac.cnode).ci_constrindiscriminate_taccstrp|Incompleteterms_to_complete->letopenGlob_terminletenv=Proofview.Goal.envglinlethole=DAst.make@@GHole(Evar_kinds.InternalHole,Namegen.IntroAnonymous)inletpr_missing(c,missing)=letc=Detyping.detypeDetyping.NowId.Set.emptyenvsigmacinletholes=List.initmissing(fun_->hole)inPrinter.pr_glob_constr_envenvsigma(DAst.make@@GApp(c,holes))inletmsg=Pp.(str"Goal is solvable by congruence but some arguments are missing."++fnl()++str" Try "++hov8beginstr"\"congruence with ("++prlist_with_sep(fun()->str")"++spc()++str"(")pr_missingterms_to_complete++str")\","end++fnl()++str" replacing metavariables by arbitrary terms")inTacticals.tclFAILmsg|Contradictiondis->letenv=Proofview.Goal.envglinletp=build_proofenvsigmauf(`Prove(dis.lhs,dis.rhs))inletta=atermufdis.lhsandtb=atermufdis.rhsinmatchdis.rulewith|Goal->letlhs=constr_of_termtainletrhs=constr_of_termtbinletsigma,typ=type_and_refresh_envsigmalhsinProofview.Unsafe.tclEVARSsigma<*>proof_tac(typ,lhs,rhs)p|Hypid->refute_tac(EConstr.of_constrid)tatbp|HeqGid->convert_to_goal_tacidtatbp|HeqnH(ida,idb)->convert_to_hyp_tacidataidbtbpendletidt=mkLambda(make_annotAnonymousSorts.Relevant,t,mkRel1)(* convertible to (not False) -> P -> not P *)letmk_neg_tyfftnt=mkArrowR(mkArrowRffff)(mkArrowRtnt)(* proof of ((not False) -> P -> not P) -> not P *)letmk_neg_tmfftnt=mkLambda(make_annotAnonymousSorts.Relevant,mk_neg_tyfftnt,mkLambda(make_annotAnonymousSorts.Relevant,t,mkApp(mkRel2,[|idff;mkRel1;mkRel1|])))(* for [simple congruence] process conclusion (not P) *)letnegative_concl_introf=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinletnt=whdenvsigmaconclinmatchEConstr.kindsigmantwithProd(_,_,ff)whenisRefXenvsigma(Lazy.force_False)ff->introf|App(f,[|t|])whenisRefXenvsigma(Lazy.force_not)f->Tacticals.pf_constr_of_global(Lazy.force_False)>>=funff->Refine.refine~typecheck:truebeginfunsigma->letsigma,e=Evarutil.new_evarenvsigma(mk_neg_tyfftnt)insigma,(mkApp(mk_neg_tmfftnt,[|e|]))end>>=fun_->intro>>=fun_->intro|_->Tacticals.tclIDTACendletcongruence_tacdepthl=Tacticals.tclTHEN(Tacticals.tclREPEAT(Tacticals.tclFIRST[intro;Tacticals.tclTHENwhd_in_conclintro]))(cc_tacticdepthlfalse)letsimple_congruence_tacdepthl=Tacticals.tclTHENLIST[Tacticals.tclREPEATintro;negative_concl_introf;cc_tacticdepthltrue](* Beware: reflexivity = constructor 1 = apply refl_equal
might be slow now, let's rather do something equivalent
to a "simple apply refl_equal" *)(* The [f_equal] tactic.
It mimics the use of lemmas [f_equal], [f_equal2], etc.
This isn't particularly related with congruence, apart from
the fact that congruence is called internally.
*)letmk_eqfc1c2k=Tacticals.pf_constr_of_global(Lazy.forcef)>>=funfc->Proofview.Goal.enterbeginfungl->letopenTacmachinletevm,ty=pf_applytype_ofglc1inletevm,ty=Evarsolve.refresh_universes(Somefalse)(pf_envgl)evmtyinletterm=mkApp(fc,[|ty;c1;c2|])inletevm,_=type_of(pf_envgl)evmterminProofview.tclTHEN(Proofview.Unsafe.tclEVARSevm)(kterm)endletf_equal=Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletcut_eqc1c2=Tacticals.tclTHENS(mk_eq_eqc1c2Tactics.cut)[Proofview.tclUNIT();Tacticals.tclTRY((app_global_refl_equal[||])apply)]inProofview.tclORELSEbeginmatchEConstr.kindsigmaconclwith|App(r,[|_;t;t'|])whenisRefXenvsigma(Lazy.force_eq)r->beginmatchEConstr.kindsigmat,EConstr.kindsigmat'with|App(f,v),App(f',v')whenInt.equal(Array.lengthv)(Array.lengthv')->letreccutsi=ifi<0thenTacticals.tclTRY(congruence_tac1000[])elseTacticals.tclTHENFIRST(cut_eqv.(i)v'.(i))(cuts(i-1))incuts(Array.lengthv-1)|_->Proofview.tclUNIT()end|_->Proofview.tclUNIT()endbeginfunction(e,info)->matchewith|Pretype_errors.PretypeError_|Type_errors.TypeError_->Proofview.tclUNIT()|e->Proofview.tclZERO~infoeendend