123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588(************************************************************************)(* * 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=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)->ifisRefXsigma(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_foundinifisRefXsigma(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)->ifisRefXsigma(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|])whenisRefXsigma(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)->ifisRefXsigma(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|])whenisRefXsigma(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) *)letbuild_projectionintype(cstr:pconstructor)specialdefaultgls=letopenTacmachinletci=(snd(fstcstr))inletsigma=projectglsinletbody=Equality.build_selector(pf_envgls)sigmaci(mkRel1)intypespecialdefaultinletid=pf_get_new_id(Id.of_string"t")glsinsigma,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))letrecgen_holesenvsigmatnaccu=ifInt.equaln0then(sigma,List.revaccu)elsematchEConstr.kindsigmatwith|Prod(_,u,t)->let(sigma,ev)=Evarutil.new_evarenvsigmauinlett=EConstr.Vars.subst1evtingen_holesenvsigmat(predn)(ev::accu)|_->assertfalseletapp_global_with_holesfargsn=Proofview.Goal.enterbeginfungl->Tacticals.pf_constr_of_global(Lazy.forcef)>>=funfc->letenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinRefine.refine~typecheck:falsebeginfunsigma->letopenEnvironinletfj=Retyping.get_judgment_ofenvsigmafcinletargsj=Array.map(func->Retyping.get_judgment_ofenvsigmac)argsinletsigma,fj=Typing.judge_of_applyenvsigmafjargsjinlet(sigma,holes)=gen_holesenvsigmafj.uj_typen[]inletans=applist(fj.uj_val,holes)inletsigma=Typing.checkenvsigmaansconclin(sigma,ans)endendletassert_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_refreshck=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletevm=Tacmach.projectglin(* XXX is get_type_of enough? *)letevm,ty=Typing.type_ofenvevmcinletevm,ty=refresh_typeenvevmtyinProofview.tclTHEN(Proofview.Unsafe.tclEVARSevm)(kty)endletconstr_of_termc=EConstr.of_constr(ATerm.constrc)letrecproof_tacp:unitProofview.tactic=Proofview.Goal.enterbeginfungl->matchp.p_rulewithAxc->exact_check(EConstr.of_constr(constr_of_axiomc))|SymAxc->letc=EConstr.of_constr(constr_of_axiomc)inletl=constr_of_termp.p_lhsandr=constr_of_termp.p_rhsintype_and_refreshl(funtyp->app_global_sym_eq[|typ;r;l;c|]exact_check)|Reflt->letlr=constr_of_termtintype_and_refreshlr(funtyp->app_global_refl_equal[|typ;constr_of_termt|]exact_check)|Trans(p1,p2)->lett1=constr_of_termp1.p_lhsandt2=constr_of_termp1.p_rhsandt3=constr_of_termp2.p_rhsintype_and_refresht2(funtyp->letprf=app_global_with_holes_trans_eq[|typ;t1;t2;t3;|]2inTacticals.tclTHENSprf[(proof_tacp1);(proof_tacp2)])|Congr(p1,p2)->lettf1=constr_of_termp1.p_lhsandtx1=constr_of_termp2.p_lhsandtf2=constr_of_termp1.p_rhsandtx2=constr_of_termp2.p_rhsintype_and_refreshtf1(funtypf->type_and_refreshtx1(funtypx->type_and_refresh(mkApp(tf1,[|tx1|]))(funtypfx->letid=Tacmach.pf_get_new_id(Id.of_string"f")glinletappx1=mkLambda(make_annot(Nameid)Sorts.Relevant,typf,mkApp(mkRel1,[|tx1|]))inletlemma1=app_global_with_holes_f_equal[|typf;typfx;appx1;tf1;tf2|]1inletlemma2=app_global_with_holes_f_equal[|typx;typfx;tf2;tx1;tx2|]1inletprf=app_global_with_holes_trans_eq[|typfx;mkApp(tf1,[|tx1|]);mkApp(tf2,[|tx1|]);mkApp(tf2,[|tx2|])|]2inTacticals.tclTHENSprf[Tacticals.tclTHENlemma1(proof_tacp1);Tacticals.tclFIRST[Tacticals.tclTHENlemma2(proof_tacp2);reflexivity;Tacticals.tclZEROMSG(Pp.str"I don't know how to handle dependent equality")]])))|Inject(prf,cstr,nargs,argind)->letti=constr_of_termprf.p_lhsinlettj=constr_of_termprf.p_rhsinletdefault=constr_of_termp.p_lhsinletspecial=mkRel(1+nargs-argind)intype_and_refreshti(funintype->type_and_refreshdefault(funouttype->letsigma,proj=build_projectionintypecstrspecialdefaultglinletinjt=app_global_with_holes_f_equal[|intype;outtype;proj;ti;tj|]1inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tacticals.tclTHENinjt(proof_tacprf))))endletrefute_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_tacp;simplest_elimfalse_t]intype_and_refreshtt1kendletrefine_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_tacp;endtrefine_exact_check]intype_and_refreshtt2kendletconvert_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_tacp;Equality.discrHyphid])end(* wrap everything *)letbuild_term_to_completeufpac=letcinfo=get_constructor_infoufpac.cnodeinletreal_args=List.rev_map(funi->constr_of_term(atermufi))pac.argsinlet(kn,u)=cinfo.ci_constrin(applist(mkConstructU(kn,EInstance.makeu),real_args),pac.arity)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|Incomplete->letopenGlob_terminletenv=Proofview.Goal.envglinletterms_to_complete=List.map(build_term_to_completeuf)(epsilonsuf)inlethole=DAst.make@@GHole(Evar_kinds.InternalHole,Namegen.IntroAnonymous,None)inletpr_missing(c,missing)=letc=Detyping.detypeDetyping.Now~lax:truefalseId.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.rulewithGoal->proof_tacp|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)whenisRefXsigma(Lazy.force_False)ff->introf|App(f,[|t|])whenisRefXsigma(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.conclglinletsigma=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'|])whenisRefXsigma(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