123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528(************************************************************************)(* * 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) *)(************************************************************************)openPpopenCErrorsopenUtilopenNamesopenNameopsopenConstropenContextopenTermopsopenEnvironopenEConstropenVarsopenNamegenopenDeclarationsopenInductiveopsopenReductionopsopenEvdopenTacredopenGenredexpropenLogicopenClenvopenTacticalsopenHipatternopenCoqlibopenEvarutilopenIndrecopenPretype_errorsopenUnificationopenLocusopenLocusopsopenTactypesopenProofview.NotationsopenContext.Named.DeclarationmoduleRelDecl=Context.Rel.DeclarationmoduleNamedDecl=Context.Named.DeclarationlettclEVARS=Proofview.Unsafe.tclEVARSlettclEVARSTHENsigmat=Proofview.tclTHEN(tclEVARSsigma)tlettyp_ofenvsigmac=letopenRetypingintryget_type_of~lax:trueenvsigmacwithRetypeErrore->user_err(print_retype_errore)openGoptionsletclear_hyp_by_default=reffalseletuse_clear_hyp_by_default()=!clear_hyp_by_defaultlet()=declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Default";"Clearing";"Used";"Hypotheses"];optread=(fun()->!clear_hyp_by_default);optwrite=(funb->clear_hyp_by_default:=b)}(*********************************************)(* Errors *)(*********************************************)exceptionIntroAlreadyDeclaredofId.texceptionClearDependencyofenv*evar_map*Id.toption*Evarutil.clear_dependency_error*GlobRef.toptionexceptionReplacingDependencyofenv*evar_map*Id.t*Evarutil.clear_dependency_error*GlobRef.toptionexceptionAlreadyUsedofId.texceptionUsedTwiceofId.texceptionVariableHasNoValueofId.texceptionConvertIncompatibleTypesofenv*evar_map*constr*constrexceptionConvertNotATypeexceptionNotConvertibleexceptionNotUnfoldableexceptionNoQuantifiedHypothesisofquantified_hypothesis*boolexceptionCannotFindInstanceofId.texceptionNothingToRewriteofId.texceptionIllFormedEliminationTypeexceptionUnableToApplyLemmaofenv*evar_map*constr*constrexceptionDependsOnBodyofId.tlist*Id.Set.t*Id.toptionexceptionNotRightNumberConstructorsofintexceptionNotEnoughConstructorsexceptionConstructorNumberedFromOneexceptionNoConstructorsexceptionUnexpectedExtraPatternofintoption*delayed_open_constrintro_pattern_exprexceptionCannotFindInductiveArgumentexceptionOneIntroPatternExpectedexceptionKeepAndClearModifierOnlyForHypothesesexceptionFixpointOnNonInductiveTypeexceptionNotEnoughProductsexceptionAllMethodsInCoinductiveTypeexceptionReplacementIllTypedofexnexceptionNotEnoughPremisesexceptionNeedDependentProductleterror?loce=Loc.raise?loceletclear_in_global_msg=function|None->mt()|Someref->str" implicitly in "++Printer.pr_globalrefletclear_dependency_msgenvsigmaiderringlobal=letppidupper=functionSomeid->Id.printid|None->str"This variable"inletppid=functionSomeid->Id.printid|None->str"this variable"inletpp=clear_in_global_msginglobalinmatcherrwith|Evarutil.OccurHypInSimpleClauseNone->ppidupperid++str" is used"++pp++str" in conclusion."|Evarutil.OccurHypInSimpleClause(Someid')->ppidupperid++strbrk" is used"++pp++str" in hypothesis "++Id.printid'++str"."|Evarutil.EvarTypingBreakev->str"Cannot remove "++ppidid++strbrk" without breaking the typing of "++Printer.pr_existentialenvsigmaev++str"."|Evarutil.NoCandidatesLeftev->str"Cannot remove "++ppidid++str" as it would leave the existential "++Printer.pr_existential_keyenvsigmaev++str" without candidates."letreplacing_dependency_msgenvsigmaiderringlobal=letpp=clear_in_global_msginglobalinmatcherrwith|Evarutil.OccurHypInSimpleClauseNone->str"Cannot change "++Id.printid++str", it is used"++pp++str" in conclusion."|Evarutil.OccurHypInSimpleClause(Someid')->str"Cannot change "++Id.printid++strbrk", it is used"++pp++str" in hypothesis "++Id.printid'++str"."|Evarutil.EvarTypingBreakev->str"Cannot change "++Id.printid++strbrk" without breaking the typing of "++Printer.pr_existentialenvsigmaev++str"."|Evarutil.NoCandidatesLeftev->str"Cannot change "++Id.printid++str" as it would leave the existential "++Printer.pr_existential_keyenvsigmaev++str" without candidates."letmsg_quantified_hypothesis=function|NamedHypid->str"quantified hypothesis named "++Id.printid.CAst.v|AnonHypn->pr_nthn++str" non dependent hypothesis"letexplain_unexpected_extra_patternboundpat=letnb=Option.getboundinlets1,s2,s3=matchpatwith|IntroNaming(IntroIdentifier_)->"name",(String.pluralnb" introduction pattern"),"no"|_->"introduction pattern","","none"instr"Unexpected "++strs1++str" ("++(ifInt.equalnb0then(strs3++strs2)else(str"at most "++intnb++strs2))++spc()++str(ifInt.equalnb1then"was"else"were")++strbrk" expected in the branch)."exceptionUnhandledletwrap_unhandledfe=trySome(fe)withUnhandled->Nonelettactic_interp_error_handler=function|IntroAlreadyDeclaredid->Id.printid++str" is already declared."|ClearDependency(env,sigma,id,err,inglobal)->clear_dependency_msgenvsigmaiderringlobal|ReplacingDependency(env,sigma,id,err,inglobal)->replacing_dependency_msgenvsigmaiderringlobal|AlreadyUsedid->Id.printid++str" is already used."|UsedTwiceid->Id.printid++str" is used twice."|VariableHasNoValueid->Id.printid++str" is not a defined hypothesis."|ConvertIncompatibleTypes(env,sigma,t1,t2)->str"The first term has type"++spc()++quote(Termops.Internal.print_constr_envenvsigmat1)++spc()++strbrk"while the second term has incompatible type"++spc()++quote(Termops.Internal.print_constr_envenvsigmat2)++str"."|ConvertNotAType->str"Not a type."|NotConvertible->str"Not convertible."|NotUnfoldable->str"Cannot unfold a non-constant."|NoQuantifiedHypothesis(id,red)->str"No "++msg_quantified_hypothesisid++strbrk" in current goal"++(ifredthenstrbrk" even after head-reduction"elsemt())++str"."|CannotFindInstanceid->str"Cannot find an instance for "++Id.printid++str"."|NothingToRewriteid->str"Nothing to rewrite in "++Id.printid++str"."|IllFormedEliminationType->str"The type of elimination clause is not well-formed."|UnableToApplyLemma(env,sigma,thm,t)->str"Unable to apply lemma of type"++brk(1,1)++quote(Printer.pr_leconstr_envenvsigmathm)++spc()++str"on hypothesis of type"++brk(1,1)++quote(Printer.pr_leconstr_envenvsigmat)++str"."|DependsOnBody(idl,ids,where)->letidl=List.filter(funid->Id.Set.memidids)idlinleton_the_bodies=function|[]->assertfalse|[id]->str" depends on the body of "++Id.printid|l->str" depends on the bodies of "++pr_sequenceId.printlin(matchwherewith|None->str"Conclusion"++on_the_bodiesidl|Someid->str"Hypothesis "++Id.printid++on_the_bodiesidl)|NotRightNumberConstructorsn->str"Not an inductive goal with "++intn++str(String.pluraln" constructor")++str"."|NotEnoughConstructors->str"Not enough constructors."|ConstructorNumberedFromOne->str"The constructors are numbered starting from 1."|NoConstructors->str"The type has no constructors."|UnexpectedExtraPattern(bound,pat)->explain_unexpected_extra_patternboundpat|CannotFindInductiveArgument->str"Cannot find inductive argument of elimination scheme."|OneIntroPatternExpected->str"Introduction pattern for one hypothesis expected."|KeepAndClearModifierOnlyForHypotheses->str"keep/clear modifiers apply only to hypothesis names."|FixpointOnNonInductiveType->str"Cannot do a fixpoint on a non inductive type."|NotEnoughProducts->str"Not enough products."|AllMethodsInCoinductiveType->str"All methods must construct elements in coinductive types."|ReplacementIllTypede->str"Replacement would lead to an ill-typed term:"++spc()++CErrors.printe|NotEnoughPremises->str"Applied theorem does not have enough premises."|NeedDependentProduct->str"Needs a non-dependent product."|_->raiseUnhandledlet_=CErrors.register_handler(wrap_unhandledtactic_interp_error_handler)leterror_clear_dependencyenvsigmaiderringlobal=error(ClearDependency(env,sigma,Someid,err,inglobal))leterror_replacing_dependencyenvsigmaiderringlobal=error(ReplacingDependency(env,sigma,id,err,inglobal))(*********************************************)(* Tactics *)(*********************************************)(******************************************)(* Primitive tactics *)(******************************************)(** This tactic creates a partial proof realizing the introduction rule, but
does not check anything. *)letunsafe_introenvdeclb=Refine.refine~typecheck:falsebeginfunsigma->letctx=named_context_valenvinletnctx=push_named_context_valdeclctxinletinst=EConstr.identity_subst_val(named_context_valenv)inletninst=SList.cons(mkRel1)instinletnb=subst1(mkVar(NamedDecl.get_iddecl))binlet(sigma,ev)=new_pure_evarnctxsigmanb~principal:truein(sigma,mkLambda_or_LetIn(NamedDecl.to_rel_decldecl)(mkEvar(ev,ninst)))endletintroductionid=Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinlethyps=named_context_val(Proofview.Goal.envgl)inletenv=Proofview.Goal.envglinlet()=ifmem_named_context_validhypsthenerror(IntroAlreadyDeclaredid)inletopenContext.Named.DeclarationinmatchEConstr.kindsigmaconclwith|Prod(id0,t,b)->unsafe_introenv(LocalAssum({id0withbinder_name=id},t))b|LetIn(id0,c,t,b)->unsafe_introenv(LocalDef({id0withbinder_name=id},c,t))b|_->raise(RefinerError(env,sigma,IntroNeedsProduct))end(* Not sure if being able to disable [cast] is useful. Uses seem picked somewhat randomly. *)letconvert_concl~cast~checktyk=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletconclty=Proofview.Goal.conclglinRefine.refine~typecheck:falsebeginfunsigma->letsigma=ifcheckthenbeginletsigma,_=Typing.type_ofenvsigmatyinmatchReductionops.infer_convenvsigmatyconcltywith|None->errorNotConvertible|Somesigma->sigmaendelsesigmainlet(sigma,x)=Evarutil.new_evarenvsigma~principal:truetyinletans=ifnotcastthenxelsemkCast(x,k,conclty)in(sigma,ans)endendletconvert_hyp~check~reorderd=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletty=Proofview.Goal.conclglinletsign=convert_hyp~check~reorderenvsigmadinletenv=reset_with_named_contextsignenvinRefine.refine~typecheck:falsebeginfunsigma->Evarutil.new_evarenvsigma~principal:truetyendendletconvert_genpbxy=Proofview.Goal.enterbeginfungl->matchTacmach.pf_apply(Reductionops.infer_conv~pb)glxywith|Somesigma->Proofview.Unsafe.tclEVARSsigma|None->errorNotConvertible|exceptionewhenCErrors.noncriticale->let_,info=Exninfo.captureein(* FIXME: Sometimes an anomaly is raised from conversion *)error?loc:(Loc.get_locinfo)NotConvertibleendletconvertxy=convert_genConversion.CONVxyletconvert_leqxy=convert_genConversion.CUMULxy(* This tactic enables users to remove hypotheses from the signature.
* Some care is taken to prevent them from removing variables that are
* subsequently used in other hypotheses or in the conclusion of the
* goal. *)letclear_genfail=function|[]->Proofview.tclUNIT()|ids->Proofview.Goal.enterbeginfungl->letids=List.fold_rightId.Set.addidsId.Set.emptyin(* clear_hyps_in_evi does not require nf terms *)letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletconcl=Proofview.Goal.conclglinlet(sigma,hyps,concl)=tryclear_hyps_in_evienvsigma(named_context_valenv)conclidswithEvarutil.ClearDependencyError(id,err,inglobal)->failenvsigmaiderringlobalinletenv=reset_with_named_contexthypsenvinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Refine.refine~typecheck:falsebeginfunsigma->Evarutil.new_evarenvsigma~principal:trueconclend)endletclearids=clear_generror_clear_dependencyidsletclear_for_replacingids=clear_generror_replacing_dependencyidsletapply_clear_requestclear_flagdftc=letdoclear=matchclear_flagwith|None->ifdftthencelseNone|Sometrue->beginmatchcwith|None->errorKeepAndClearModifierOnlyForHypotheses|Someid->Someidend|Somefalse->Noneinmatchdoclearwith|None->Proofview.tclUNIT()|Someid->clear[id](* Moving hypotheses *)letmove_hypiddest=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletty=Proofview.Goal.conclglinletsign=named_context_valenvinletsign'=move_hyp_in_named_contextenvsigmaiddestsigninletenv=reset_with_named_contextsign'envinRefine.refine~typecheck:falsebeginfunsigma->Evarutil.new_evarenvsigma~principal:truetyendend(* Renaming hypotheses *)letrename_hyprepl=letfoldaccu(src,dst)=matchaccuwith|None->None|Some(srcs,dsts)->ifId.Set.memsrcsrcsthenNoneelseifId.Set.memdstdststhenNoneelseletsrcs=Id.Set.addsrcsrcsinletdsts=Id.Set.adddstdstsinSome(srcs,dsts)inletinit=Some(Id.Set.empty,Id.Set.empty)inletdom=List.fold_leftfoldinitreplinmatchdomwith|None->letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"Not a one-to-one name mapping")|Some(src,dst)->Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletsign=named_context_valenvinletsigma=Proofview.Goal.sigmaglin(* Check that we do not mess variables *)letvars=ids_of_named_context_valsigninlet()=ifnot(Id.Set.subsetsrcvars)thenlethyp=Id.Set.choose(Id.Set.diffsrcvars)inraise(RefinerError(env,sigma,NoSuchHyphyp))inletmods=Id.Set.diffvarssrcinlet()=tryletelt=Id.Set.choose(Id.Set.interdstmods)inerror(AlreadyUsedelt)withNot_found->()in(* All is well *)letmake_subst(src,dst)=(src,mkVardst)inletsubst=List.mapmake_substreplinletsubstc=Vars.replace_varssigmasubstcinletreplaceid=tryList.assoc_fId.equalidreplwithNot_found->idinletmapdecl=decl|>NamedDecl.map_idreplace|>NamedDecl.map_constrsubstinletohyps=named_context_of_valsigninletnhyps=List.mapmapohypsinletnconcl=substconclinletnctx=val_of_named_contextnhypsinletfoldodeclndeclaccu=ifId.equal(NamedDecl.get_idodecl)(NamedDecl.get_idndecl)thenSList.defaultaccuelseSList.cons(mkVar@@NamedDecl.get_idodecl)accuinletinstance=List.fold_right2foldohypsnhypsSList.emptyinRefine.refine~typecheck:falsebeginfunsigma->letsigma,ev=Evarutil.new_pure_evarnctxsigmanconcl~principal:trueinsigma,mkEvar(ev,instance)endend(**************************************************************)(* Fresh names *)(**************************************************************)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())idavoidletnew_fresh_idavoididgl=fresh_id_in_envavoidid(Proofview.Goal.envgl)letid_of_name_with_defaultid=function|Anonymous->id|Nameid->idletdefault_id_of_sortsigmas=ifESorts.is_smallsigmasthendefault_small_identelsedefault_type_identletdefault_idenvsigmadecl=letopenContext.Rel.Declarationinmatchdeclwith|LocalAssum(name,t)->letdft=default_id_of_sortsigma(Retyping.get_sort_ofenvsigmat)inid_of_name_with_defaultdftname.binder_name|LocalDef(name,b,_)->id_of_name_using_hdcharenvsigmabname.binder_name(* Non primitive introduction tactics are treated by intro_then_gen
There is possibly renaming, with possibly names to avoid and
possibly a move to do after the introduction *)typename_flag=|NamingAvoidofId.Set.t|NamingBasedOnofId.t*Id.Set.t|NamingMustBeoflidentletnaming_of_name=function|Anonymous->NamingAvoidId.Set.empty|Nameid->NamingMustBe(CAst.makeid)letfind_namemayrepldeclnaminggl=matchnamingwith|NamingAvoididl->(* this case must be compatible with [find_intro_names] below. *)letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinnew_fresh_ididl(default_idenvsigmadecl)gl|NamingBasedOn(id,idl)->new_fresh_ididlidgl|NamingMustBe{CAst.loc;v=id}->(* When name is given, we allow to hide a global name *)letids_of_hyps=Tacmach.pf_ids_set_of_hypsglinifnotmayrepl&&Id.Set.memidids_of_hypsthenerror?loc(AlreadyUsedid);id(**************************************************************)(* Computing position of hypotheses for replacing *)(**************************************************************)letget_next_hyp_positionenvsigmaid=letrecaux=function|[]->error_no_such_hypothesisenvsigmaid|decl::right->ifId.equal(NamedDecl.get_iddecl)idthenmatchrightwithdecl::_->MoveBefore(NamedDecl.get_iddecl)|[]->MoveFirstelseauxrightinauxletget_previous_hyp_positionenvsigmaid=letrecauxdest=function|[]->error_no_such_hypothesisenvsigmaid|decl::right->lethyp=NamedDecl.get_iddeclinifId.equalhypidthendestelseaux(MoveAfterhyp)rightinauxMoveLast(**************************************************************)(* Cut rule *)(**************************************************************)letclear_hyps2envsigmaidssigntcl=tryletsigma=Evd.clear_metassigmainEvarutil.clear_hyps2_in_evienvsigmasigntclidswithEvarutil.ClearDependencyError(id,err,inglobal)->error_replacing_dependencyenvsigmaiderringloballetinternal_cut?(check=true)replaceidt=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletconcl=Proofview.Goal.conclglinletsign=named_context_valenvinletr=Retyping.relevance_of_typeenvsigmatinletenv',t,concl,sigma=ifreplacethenletnexthyp=get_next_hyp_positionenvsigmaid(named_context_of_valsign)inletsigma,sign',t,concl=clear_hyps2envsigma(Id.Set.singletonid)signtconclinletsign'=insert_decl_in_named_contextenvsigma(LocalAssum(make_annotidr,t))nexthypsign'inEnviron.reset_with_named_contextsign'env,t,concl,sigmaelse(ifcheck&&mem_named_context_validsignthenerror(IntroAlreadyDeclaredid);push_named(LocalAssum(make_annotidr,t))env,t,concl,sigma)inletnf_t=nf_betaiotaenvsigmatinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Refine.refine~typecheck:falsebeginfunsigma->let(sigma,ev)=Evarutil.new_evarenvsigmanf_tinlet(sigma,ev')=Evarutil.new_evar~principal:trueenv'sigmaconclinletterm=mkLetIn(make_annot(Nameid)r,ev,t,EConstr.Vars.subst_varsigmaidev')in(sigma,term)end)endletassert_before_then_genbnamingttac=letopenContext.Rel.DeclarationinProofview.Goal.enterbeginfungl->letid=find_nameb(LocalAssum(make_annotAnonymousSorts.Relevant,t))namingglinTacticals.tclTHENLAST(internal_cutbidt)(tacid)endletassert_before_genbnamingt=assert_before_then_genbnamingt(fun_->Proofview.tclUNIT())letassert_beforena=assert_before_genfalse(naming_of_namena)letassert_before_replacingid=assert_before_gentrue(NamingMustBe(CAst.makeid))letreplace_error_optionerrtac=matcherrwith|None->tac|Some(e,info)->Proofview.tclORELSEtac(fun_->Proofview.tclZERO~infoe)letassert_after_then_genbnamingttac=letopenContext.Rel.DeclarationinProofview.Goal.enterbeginfungl->letid=find_nameb(LocalAssum(make_annotAnonymousSorts.Relevant,t))namingglinTacticals.tclTHENFIRST(internal_cutbidt<*>Proofview.cycle1)(tacid)endletassert_after_genbnamingt=assert_after_then_genbnamingt(fun_->(Proofview.tclUNIT()))letassert_afterna=assert_after_genfalse(naming_of_namena)letassert_after_replacingid=assert_after_gentrue(NamingMustBe(CAst.makeid))(**************************************************************)(* Fixpoints and CoFixpoints *)(**************************************************************)letrecmk_holesenvsigma=function|[]->(sigma,[])|arg::rem->let(sigma,arg)=Evarutil.new_evarenvsigmaarginlet(sigma,rem)=mk_holesenvsigmaremin(sigma,arg::rem)letreccheck_mutindenvsigmakcl=matchEConstr.kindsigma(strip_outer_castsigmacl)with|Prod(na,c1,b)->ifInt.equalk1thentryignore(find_inductiveenvsigmac1)withNot_found->errorFixpointOnNonInductiveTypeelseletopenContext.Rel.Declarationincheck_mutind(push_rel(LocalAssum(na,c1))env)sigma(predk)b|LetIn(na,c1,t,b)->letopenContext.Rel.Declarationincheck_mutind(push_rel(LocalDef(na,c1,t))env)sigmakb|_->errorNotEnoughProducts(* Refine as a fixpoint *)letmutual_fixfnrestj=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletconcl=Proofview.Goal.conclglinlet()=check_mutindenvsigmanconclinletfirsts,lasts=List.chopjrestinletall=firsts@(f,n,concl)::lastsinletall=List.map(fun(f,n,ar)->letr=Retyping.relevance_of_typeenvsigmaarin(f,r,n,ar))allinletrecmk_signsign=function|[]->sign|(f,r,n,ar)::oth->letopenContext.Named.Declarationinlet()=check_mutindenvsigmanarinifmem_named_context_valfsignthenerror(IntroAlreadyDeclaredf);mk_sign(push_named_context_val(LocalAssum(make_annotfr,ar))sign)othinletnenv=reset_with_named_context(mk_sign(named_context_valenv)all)envinRefine.refine~typecheck:falsebeginfunsigma->let(sigma,evs)=mk_holesnenvsigma(List.map(fun(_,_,_,ar)->ar)all)inletids,rs,_,ars=List.split4allinletevs=List.map(Vars.subst_varssigma(List.revids))evsinletindxs=Array.of_list(List.map(funn->n-1)(List.map(fun(_,_,n,_)->n)all))inletfunnames=Array.of_list(List.map2(funir->make_annot(Namei)r)idsrs)inletbodies=Array.of_listevsinlettyparray=Array.of_listarsinletoterm=mkFix((indxs,0),(funnames,typarray,bodies))in(sigma,oterm)endendletfixidn=mutual_fixidn[]0letreccheck_is_mutcoindenvsigmacl=letb=whd_allenvsigmaclinmatchEConstr.kindsigmabwith|Prod(na,c1,b)->letopenContext.Rel.Declarationincheck_is_mutcoind(push_rel(LocalAssum(na,c1))env)sigmab|_->trylet_=find_coinductiveenvsigmabin()withNot_found->errorAllMethodsInCoinductiveType(* Refine as a cofixpoint *)letmutual_cofixfothersj=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletconcl=Proofview.Goal.conclglinletfirsts,lasts=List.chopjothersinletall=firsts@(f,concl)::lastsinList.iter(fun(_,c)->check_is_mutcoindenvsigmac)all;letall=List.map(fun(id,t)->(id,Retyping.relevance_of_typeenvsigmat,t))allinletrecmk_signsign=function|[]->sign|(f,r,ar)::oth->letopenContext.Named.Declarationinifmem_named_context_valfsignthenerror(AlreadyUsedf);mk_sign(push_named_context_val(LocalAssum(make_annotfr,ar))sign)othinletnenv=reset_with_named_context(mk_sign(named_context_valenv)all)envinRefine.refine~typecheck:falsebeginfunsigma->let(ids,rs,types)=List.split3allinlet(sigma,evs)=mk_holesnenvsigmatypesinletevs=List.map(Vars.subst_varssigma(List.revids))evsin(* TODO relevance *)letfunnames=Array.of_list(List.map2(funir->make_annot(Namei)r)idsrs)inlettyparray=Array.of_listtypesinletbodies=Array.of_listevsinletoterm=mkCoFix(0,(funnames,typarray,bodies))in(sigma,oterm)endendletcofixid=mutual_cofixid[]0(**************************************************************)(* Reduction and conversion tactics *)(**************************************************************)typetactic_reduction=Reductionops.reduction_functiontypee_tactic_reduction=Reductionops.e_reduction_functionlete_pf_change_decl(redfun:bool->e_reduction_function)whereenvsigmadecl=letopenContext.Named.Declarationinmatchdeclwith|LocalAssum(id,ty)->ifwhere==InHypValueOnlythenerror(VariableHasNoValueid.binder_name);let(sigma,ty')=redfunfalseenvsigmatyin(sigma,LocalAssum(id,ty'))|LocalDef(id,b,ty)->let(sigma,b')=ifwhere!=InHypTypeOnlythenredfuntrueenvsigmabelse(sigma,b)inlet(sigma,ty')=ifwhere!=InHypValueOnlythenredfunfalseenvsigmatyelse(sigma,ty)in(sigma,LocalDef(id,b',ty'))letbind_change_occurrencesoccs=function|None->None|Somec->Some(Redexpr.out_with_occurrences(occs,c))(* The following two tactics apply an arbitrary
reduction function either to the conclusion or to a
certain hypothesis *)(** Tactic reduction modulo evars (for universes essentially) *)lete_change_in_concl~cast~check(redfun,sty)=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinlet(sigma,c')=redfun(Tacmach.pf_envgl)sigma(Tacmach.pf_conclgl)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(convert_concl~cast~checkc'sty)endlete_change_in_hyp~check~reorderredfun(id,where)=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinlethyp=Tacmach.pf_get_hypidglinlet(sigma,c)=e_pf_change_declredfunwhere(Proofview.Goal.envgl)sigmahypinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(convert_hyp~check~reorderc)endtypehyp_conversion=|AnyHypConv(** Arbitrary conversion *)|StableHypConv(** Does not introduce new dependencies on variables *)|LocalHypConv(** Same as above plus no dependence on the named environment *)lete_change_in_hyps~check~reorderfargs=matchargswith|[]->Proofview.tclUNIT()|_::_->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinlet(env,sigma)=matchreorderwith|LocalHypConv->(* If the reduction function is known not to depend on the named
context, then we can perform it in parallel. *)letfoldaccuarg=let(id,redfun)=farginletold=tryId.Map.findidaccuwithNot_found->[]inId.Map.addid(redfun::old)accuinletreds=List.fold_leftfoldId.Map.emptyargsinletevdref=refsigmainletmapd=letid=NamedDecl.get_iddinmatchId.Map.findidredswith|reds->letd=EConstr.of_named_decldinletfoldredfun(sigma,d)=redfunenvsigmadinlet(sigma,d)=List.fold_rightfoldreds(sigma,d)inlet()=evdref:=sigmainEConstr.Unsafe.to_named_decld|exceptionNot_found->dinletsign=Environ.map_named_valmap(Environ.named_context_valenv)inletenv=reset_with_named_contextsignenvin(env,!evdref)|StableHypConv|AnyHypConv->letreorder=reorder==AnyHypConvinletfold(env,sigma)arg=let(id,redfun)=farginlethyp=trylookup_namedidenvwithNot_found->raise(RefinerError(env,sigma,NoSuchHypid))inlet(sigma,d)=redfunenvsigmahypinletsign=Logic.convert_hyp~check~reorderenvsigmadinletenv=reset_with_named_contextsignenvin(env,sigma)inList.fold_leftfold(env,sigma)argsinletty=Proofview.Goal.conclglinProofview.Unsafe.tclEVARSsigma<*>Refine.refine~typecheck:falsebeginfunsigma->Evarutil.new_evarenvsigma~principal:truetyendendlete_reduct_in_concl=e_change_in_conclletreduct_in_concl~cast~check(redfun,sty)=letredfunenvsigmac=(sigma,redfunenvsigmac)ine_change_in_concl~cast~check(redfun,sty)lete_reduct_in_hyp~check~reorderredfun(id,where)=letredfun_envsigmac=redfunenvsigmacine_change_in_hyp~check~reorderredfun(id,where)letreduct_in_hyp~check~reorderredfun(id,where)=letredfun_envsigmac=(sigma,redfunenvsigmac)ine_change_in_hyp~check~reorderredfun(id,where)lete_reduct_option~checkredfun=function|Someid->e_reduct_in_hyp~check~reorder:check(fstredfun)id|None->e_change_in_concl~cast:true~checkredfunletreduct_option~check(redfun,sty)where=letredfunenvsigmac=(sigma,redfunenvsigmac)ine_reduct_option~check(redfun,sty)wheretypechange_arg=Ltac_pretype.patvar_map->env->evar_map->evar_map*EConstr.constrletmake_change_argcpatsenvsigma=(sigma,replace_varssigma(Id.Map.bindingspats)c)letcheck_typesenvsigmamayneedglobalcheckdeepnewcorigc=lett1=Retyping.get_type_ofenvsigmanewcinifdeepthenbeginlett2=Retyping.get_type_ofenvsigmaorigcinletsigma,t2=Evarsolve.refresh_universes~onlyalg:true(Somefalse)envsigmat2inmatchinfer_conv~pb:Conversion.CUMULenvsigmat1t2with|None->ifisSortsigma(whd_allenvsigmat1)&&isSortsigma(whd_allenvsigmat2)then(mayneedglobalcheck:=true;sigma)elseerror(ConvertIncompatibleTypes(env,sigma,t2,t1))|Somesigma->sigmaendelseifnot(isSortsigma(whd_allenvsigmat1))thenerrorConvertNotATypeelsesigma(* Now we introduce different instances of the previous tacticals *)letchange_and_checkcv_pbmayneedglobalcheckdeeptenvsigmac=let(sigma,t')=tenvsigmainletsigma=check_typesenvsigmamayneedglobalcheckdeept'cinmatchinfer_conv~pb:cv_pbenvsigmat'cwith|None->errorNotConvertible|Somesigma->(sigma,t')(* Use cumulativity only if changing the conclusion not a subterm *)letchange_on_subterm~checkcv_pbdeeptwhereenvsigmac=letmayneedglobalcheck=reffalseinlet(sigma,c)=matchwherewith|None->ifcheckthenchange_and_checkcv_pbmayneedglobalcheckdeep(tId.Map.empty)envsigmacelsetId.Map.emptyenvsigma|Someoccl->e_contextuallyfalseoccl(funsubst->ifcheckthenchange_and_checkConversion.CONVmayneedglobalchecktrue(tsubst)elsefunenvsigma_c->tsubstenvsigma)envsigmacinletsigma=if!mayneedglobalcheckthenbegintryfst(Typing.type_ofenvsigmac)withewhennoncriticale->error(ReplacementIllTypede)endelsesigmain(sigma,c)letchange_in_concl~checkocclt=(* No need to check in e_change_in_concl, the check is done in change_on_subterm *)e_change_in_concl~cast:false~check:false((change_on_subterm~checkConversion.CUMULfalsetoccl),DEFAULTcast)letchange_in_hyp~checkoccltid=(* Same as above *)e_change_in_hyp~check:false~reorder:check(funx->change_on_subterm~checkConversion.CONVxtoccl)idletconcrete_clause_ofenum_hypscl=matchcl.onhypswith|None->letfid=(id,AllOccurrences,InHyp)inList.mapf(enum_hyps())|Somel->List.map(fun((occs,id),w)->(id,occs,w))lletchange~checkchgccls=Proofview.Goal.enterbeginfungl->lethyps=concrete_clause_of(fun()->Tacmach.pf_ids_of_hypsgl)clsinbeginmatchcls.concl_occswith|NoOccurrences->Proofview.tclUNIT()|occs->change_in_concl~check(bind_change_occurrencesoccschg)cend<*>letf(id,occs,where)=letoccl=bind_change_occurrencesoccschginletredfundeepenvsigmat=change_on_subterm~checkConversion.CONVdeepcocclenvsigmatinletredfunenvsigmad=e_pf_change_declredfunwhereenvsigmadin(id,redfun)inletreorder=ifcheckthenAnyHypConvelseStableHypConvin(* Don't check, we do it already in [change_on_subterm] *)e_change_in_hyps~check:false~reorderfhypsendletchange_conclt=change_in_concl~check:trueNone(make_change_argt)letred_product_exnenvsigmac=matchred_productenvsigmacwith|None->user_errPp.(str"No head constant to reduce.")|Somec->c(* Pour usage interne (le niveau User est pris en compte par reduce) *)letred_in_concl=reduct_in_concl~cast:true~check:false(red_product_exn,DEFAULTcast)letred_in_hyp=reduct_in_hyp~check:false~reorder:falsered_product_exnletred_option=reduct_option~check:false(red_product_exn,DEFAULTcast)lethnf_in_concl=reduct_in_concl~cast:true~check:false(hnf_constr,DEFAULTcast)lethnf_in_hyp=reduct_in_hyp~check:false~reorder:falsehnf_constrlethnf_option=reduct_option~check:false(hnf_constr,DEFAULTcast)letsimpl_in_concl=reduct_in_concl~cast:true~check:false(simpl,DEFAULTcast)letsimpl_in_hyp=reduct_in_hyp~check:false~reorder:falsesimplletsimpl_option=reduct_option~check:false(simpl,DEFAULTcast)letnormalise_in_concl=reduct_in_concl~cast:true~check:false(compute,DEFAULTcast)letnormalise_in_hyp=reduct_in_hyp~check:false~reorder:falsecomputeletnormalise_option=reduct_option~check:false(compute,DEFAULTcast)letnormalise_vm_in_concl=reduct_in_concl~cast:true~check:false(Redexpr.cbv_vm,VMcast)letunfold_in_conclloccname=reduct_in_concl~cast:true~check:false(unfoldnloccname,DEFAULTcast)letunfold_in_hyploccname=reduct_in_hyp~check:false~reorder:false(unfoldnloccname)letunfold_optionloccname=reduct_option~check:false(unfoldnloccname,DEFAULTcast)letpattern_optionl=e_reduct_option~check:false(pattern_occsl,DEFAULTcast)(* The main reduction function *)letis_local_flagenvflags=ifflags.rDeltathenfalseelseletcheck=function|Evaluable.EvalVarRef_->false|Evaluable.EvalConstRefc->Id.Set.is_empty(Environ.vars_of_globalenv(GlobRef.ConstRefc))|Evaluable.EvalProjectionRefc->false(* FIXME *)inList.for_allcheckflags.rConstletis_local_unfoldenvflags=letcheck(_,c)=matchcwith|Evaluable.EvalVarRef_->false|Evaluable.EvalConstRefc->Id.Set.is_empty(Environ.vars_of_globalenv(GlobRef.ConstRefc))|Evaluable.EvalProjectionRefc->false(* FIXME *)inList.for_allcheckflagsletreduceredexpcl=lettraceenvsigma=letopenPrinterinletpr=((fune->pr_econstr_enve),(fune->pr_leconstr_enve),pr_evaluable_reference,pr_constr_pattern_env,int)inPp.(hov2(Ppred.pr_red_expr_envenvsigmaprstrredexp))inProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlethyps=concrete_clause_of(fun()->Tacmach.pf_ids_of_hypsgl)clinletnbcl=(ifcl.concl_occs=NoOccurrencesthen0else1)+List.lengthhypsinletcheck=matchredexpwithFold_|Pattern_->true|_->falseinletreorder=matchredexpwith|Fold_|Pattern_->AnyHypConv|Simpl(flags,_)|Cbvflags|Cbnflags|Lazyflags->ifis_local_flagenvflagsthenLocalHypConvelseStableHypConv|Unfoldflags->ifis_local_unfoldenvflagsthenLocalHypConvelseStableHypConv|Red|Hnf|CbvVm_|CbvNative_->StableHypConv|ExtraRedExpr_->StableHypConv(* Should we be that lenient ?*)inletredexp=Redexpr.eval_red_exprenvredexpinProofview.Trace.name_tactic(fun()->traceenvsigma)beginbeginmatchcl.concl_occswith|NoOccurrences->Proofview.tclUNIT()|occs->letoccs=Redexpr.out_occurrencesoccsinletredfun=Redexpr.reduction_of_red_expr_val~occs:(occs,nbcl)redexpine_change_in_concl~cast:true~checkredfunend<*>letf(id,occs,where)=letoccs=Redexpr.out_occurrencesoccsinlet(redfun,_)=Redexpr.reduction_of_red_expr_val~occs:(occs,nbcl)redexpinletredfun_envsigmac=redfunenvsigmacinletredfunenvsigmad=e_pf_change_declredfunwhereenvsigmadin(id,redfun)ine_change_in_hyps~check~reorderfhypsendend(* Unfolding occurrences of a constant *)letunfold_constr=function|GlobRef.ConstRefsp->unfold_in_concl[AllOccurrences,EvalConstRefsp]|GlobRef.VarRefid->unfold_in_concl[AllOccurrences,EvalVarRefid]|_->errorNotUnfoldable(*******************************************)(* Introduction tactics *)(*******************************************)(* Returns the names that would be created by intros, without doing
intros. This function is supposed to be compatible with an
iteration of [find_name] above. As [default_id] checks the sort of
the type to build hyp names, we maintain an environment to be able
to type dependent hyps. *)letfind_intro_namesenv0sigmactxt=let_,res,_=List.fold_right(fundeclacc->letenv,idl,avoid=accinletname=fresh_id_in_envavoid(default_idenvsigmadecl)env0inletnewenv=push_reldeclenvin(newenv,name::idl,Id.Set.addnameavoid))ctxt(env0,[],Id.Set.empty)inList.revresletbuild_intro_taciddesttac=matchdestwith|MoveLast->Tacticals.tclTHEN(introductionid)(tacid)|dest->Tacticals.tclTHENLIST[introductionid;move_hypiddest;tacid]letrecintro_then_genname_flagmove_flag~force~deptac=letopenContext.Rel.DeclarationinProofview.Goal.enterbeginfungl->letsigma=Tacmach.projectglinletenv=Tacmach.pf_envglinletconcl=Proofview.Goal.conclglinmatchEConstr.kindsigmaconclwith|Prod(name,t,u)whennotdep||not(noccurnsigma1u)->letname=find_namefalse(LocalAssum(name,t))name_flagglinbuild_intro_tacnamemove_flagtac|LetIn(name,b,t,u)whennotdep||not(noccurnsigma1u)->letname=find_namefalse(LocalDef(name,b,t))name_flagglinbuild_intro_tacnamemove_flagtac|Evarevwhenforce->letname=find_namefalse(LocalAssum(anonR,concl))name_flagglinletsigma,t=Evardefine.define_evar_as_productenvsigma~nameevinTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(intro_then_genname_flagmove_flag~force~deptac)|_->beginifnotforcethenletinfo=Exninfo.reify()inProofview.tclZERO~info(RefinerError(env,sigma,IntroNeedsProduct))(* Note: red_in_concl includes betaiotazeta and this was like *)(* this since at least V6.3 (a pity *)(* that intro do betaiotazeta only when reduction is needed; and *)(* probably also a pity that intro does zeta *)elseProofview.tclUNIT()end<*>Proofview.tclORELSE(Tacticals.tclTHENhnf_in_concl(intro_then_genname_flagmove_flag~force:false~deptac))beginfunction(e,info)->matchewith|RefinerError(env,sigma,IntroNeedsProduct)->Tacticals.tclZEROMSG~info(str"No product even after head-reduction.")|e->Proofview.tclZERO~infoeendendletdrop_intro_name(_:Id.t)=Proofview.tclUNIT()letintro_gennm~force~dep=intro_then_gennm~force~depdrop_intro_nameletintro_mustbe_forceid=intro_gen(NamingMustBe(CAst.makeid))MoveLast~force:true~dep:falseletintro_using_thenid=intro_then_gen(NamingBasedOn(id,Id.Set.empty))MoveLast~force:false~dep:falseletintro_usingid=intro_using_theniddrop_intro_nameletintro_then=intro_then_gen(NamingAvoidId.Set.empty)MoveLast~force:false~dep:falseletintro=intro_thendrop_intro_nameletintrof=intro_gen(NamingAvoidId.Set.empty)MoveLast~force:true~dep:falseletintro_avoidingl=intro_gen(NamingAvoidl)MoveLast~force:false~dep:falseletintro_move_avoididoptavoidhto=matchidoptwith|None->intro_gen(NamingAvoidavoid)hto~force:true~dep:false|Someid->intro_gen(NamingMustBe(CAst.makeid))hto~force:true~dep:falseletintro_moveidopthto=intro_move_avoididoptId.Set.emptyhto(**** Multiple introduction tactics ****)letrecintros_using=function|[]->Proofview.tclUNIT()|str::l->Tacticals.tclTHEN(intro_usingstr)(intros_usingl)letrecintros_mustbe_force=function|[]->Proofview.tclUNIT()|str::l->Tacticals.tclTHEN(intro_mustbe_forcestr)(intros_mustbe_forcel)letrecintros_using_then_helpertacacc=function|[]->tac(List.revacc)|str::l->intro_using_thenstr(funstr'->intros_using_then_helpertac(str'::acc)l)letintros_using_thenltac=intros_using_then_helpertac[]lletis_overboundboundn=matchboundwithNone->false|Somep->n>=pletintro_forthcoming_last_then_genavoiddep_flagboundntac=letopenRelDeclinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletavoid=letavoid'=ids_of_named_context_val(named_context_valenv)inifId.Set.is_emptyavoidthenavoid'elseId.Set.unionavoid'avoidinletrecdecomposeenvavoidnconclsubstdeclsndecls=letdecl=ifis_overboundboundnthenNoneelsematchEConstr.kindsigmaconclwith|Prod(na,t,u)whennotdep_flag||not(noccurnsigma1u)->Some(LocalAssum(na,t),u)|LetIn(na,b,t,u)whennotdep_flag||not(noccurnsigma1u)->Some(LocalDef(na,b,t),u)|_->Noneinmatchdeclwith|None->ndecls,decls,Vars.esubstVars.lift_substituendsubstconcl|Some(decl,concl)->letid=default_idenvsigmadeclinletid=next_ident_away_in_goal(Global.env())idavoidinletavoid=Id.Set.addidavoidinletenv=EConstr.push_reldeclenvinletndecl=NamedDecl.of_rel_decl(fun_->id)declinletndecl=NamedDecl.map_constr(func->Vars.esubstVars.lift_substituendsubstc)ndeclinletsubst=Esubst.subs_cons(make_substituend@@mkVarid)substindecomposeenvavoid(n+1)conclsubst(decl::decls)(ndecl::ndecls)inlet(ndecls,decls,nconcl)=decomposeenvavoidnconcl(Esubst.subs_id0)[][]inletids=List.mapNamedDecl.get_idndeclsinifList.is_emptyidsthentac[]elseRefine.refine~typecheck:falsebeginfunsigma->letctx=named_context_valenvinletnctx=List.fold_rightpush_named_context_valndeclsctxinletinst=SList.defaultn(List.length@@Environ.named_contextenv)SList.emptyinletrels=List.init(List.lengthdecls)(funi->mkRel(i+1))inletninst=List.fold_right(funcaccu->SList.conscaccu)relsinstinlet(sigma,ev)=new_pure_evarnctxsigmanconcl~principal:truein(sigma,it_mkLambda_or_LetIn(mkEvar(ev,ninst))decls)end<*>tacidsendletintros=intro_forthcoming_last_then_genId.Set.emptyfalseNone0(fun_->tclIDTAC)letintro_forthcoming_then_genavoidmove_flag~depboundntac=matchmove_flagwith|MoveLast->(* Fast path *)intro_forthcoming_last_then_genavoiddepboundntac|MoveFirst|MoveAfter_|MoveBefore_->letrecauxnids=(* Note: we always use the bound when there is one for "*" and "**" *)ifnot(is_overboundboundn)thenProofview.tclORELSEbeginintro_then_gen(NamingAvoidavoid)move_flag~force:false~dep(funid->aux(n+1)(id::ids))endbeginfunction(e,info)->matchewith|RefinerError(env,sigma,IntroNeedsProduct)->tacids|e->Proofview.tclZERO~infoeendelsetacidsinauxn[]letintro_replacingid=Proofview.Goal.enterbeginfungl->letenv,sigma=Proofview.Goal.(envgl,sigmagl)inlethyps=Proofview.Goal.hypsglinletnext_hyp=get_next_hyp_positionenvsigmaidhypsinTacticals.tclTHENLIST[clear_for_replacing[id];introductionid;move_hypidnext_hyp;]end(* We have e.g. [x, y, y', x', y'' |- forall y y' y'', G] and want to
reintroduce y, y,' y''. Note that we have to clear y, y' and y''
before introducing y because y' or y'' can e.g. depend on old y. *)(* This version assumes that replacement is actually possible *)(* (ids given in the introduction order) *)(* We keep a sub-optimality in cleaing for compatibility with *)(* the behavior of inversion *)letintros_possibly_replacingids=letsuboptimal=trueinProofview.Goal.enterbeginfungl->letenv,sigma=Proofview.Goal.(envgl,sigmagl)inlethyps=Proofview.Goal.hypsglinletposl=List.map(funid->(id,get_next_hyp_positionenvsigmaidhyps))idsinTacticals.tclTHEN(Tacticals.tclMAP(funid->Tacticals.tclTRY(clear_for_replacing[id]))(ifsuboptimalthenidselseList.revids))(Tacticals.tclMAP(fun(id,pos)->Tacticals.tclORELSE(intro_move(Someid)pos)(intro_usingid))posl)end(* This version assumes that replacement is actually possible *)letintros_replacingids=Proofview.Goal.enterbeginfungl->lethyps=Proofview.Goal.hypsglinletenv,sigma=Proofview.Goal.(envgl,sigmagl)inletposl=List.map(funid->(id,get_next_hyp_positionenvsigmaidhyps))idsinTacticals.tclTHEN(clear_for_replacingids)(Tacticals.tclMAP(fun(id,pos)->intro_move(Someid)pos)posl)end(* The standard for implementing Automatic Introduction *)letauto_intros_tacids=letfoldused=function|Nameid->Id.Set.addidused|Anonymous->usedinletavoid=NamingAvoid(List.fold_leftfoldId.Set.emptyids)inletnaming=function|Nameid->NamingMustBeCAst.(makeid)|Anonymous->avoidinTacticals.tclMAP(funname->intro_gen(namingname)MoveLast~force:true~dep:false)(List.revids)(* User-level introduction tactics *)letlookup_hypothesis_as_renamedenvsigmaccl=function|AnonHypn->Detyping.lookup_index_as_renamedenvsigmaccln|NamedHypid->Detyping.lookup_name_as_displayedenvsigmacclid.CAst.vletlookup_hypothesis_as_renamed_genredhgl=letenv=Proofview.Goal.envglinletrecauxccl=matchlookup_hypothesis_as_renamedenv(Tacmach.projectgl)cclhwith|Nonewhenred->beginmatchred_productenv(Proofview.Goal.sigmagl)cclwith|None->None|Somec->auxcend|x->xinaux(Proofview.Goal.conclgl)letis_quantified_hypothesisidgl=matchlookup_hypothesis_as_renamed_genfalse(NamedHyp(CAst.makeid))glwith|Some_->true|None->falseletwarn_deprecated_intros_until_0=CWarnings.create~name:"deprecated-intros-until-0"~category:CWarnings.CoreCategories.tactics(fun()->strbrk"\"intros until 0\" is deprecated, use \"intros *\"; instead of \"induction 0\" and \"destruct 0\" use explicitly a name.\"")letdepth_of_quantified_hypothesisredhgl=ifh=AnonHyp0thenwarn_deprecated_intros_until_0();matchlookup_hypothesis_as_renamed_genredhglwith|Somedepth->depth|None->error(NoQuantifiedHypothesis(h,red))letintros_until_genredh=Proofview.Goal.enterbeginfungl->letn=depth_of_quantified_hypothesisredhglinTacticals.tclDOn(ifredthenintrofelseintro)endletintros_until_idid=intros_until_genfalse(NamedHyp(CAst.makeid))letintros_until_n_genredn=intros_until_genred(AnonHypn)letintros_until=intros_until_gentrueletintros_until_n=intros_until_n_gentruelettclCHECKVARid=Proofview.Goal.enterbeginfungl->let_=Tacmach.pf_get_hypidglinProofview.tclUNIT()endlettry_intros_until_id_checkid=Tacticals.tclORELSE(intros_until_idid)(tclCHECKVARid)lettry_intros_untiltac=function|NamedHyp{CAst.v=id}->Tacticals.tclTHEN(try_intros_until_id_checkid)(tacid)|AnonHypn->Tacticals.tclTHEN(intros_until_nn)(Tacticals.onLastHypIdtac)letrecintros_move=function|[]->Proofview.tclUNIT()|(hyp,destopt)::rest->Tacticals.tclTHEN(intro_gen(NamingMustBe(CAst.makehyp))destopt~force:false~dep:false)(intros_moverest)(* Apply a tactic on a quantified hypothesis, an hypothesis in context
or a term with bindings *)lettactic_infer_flagswith_evar=Pretyping.{use_coercions=true;use_typeclasses=UseTC;solve_unification_constraints=true;fail_evar=notwith_evar;expand_evars=true;program_mode=false;polymorphic=false;undeclared_evars_patvars=false;patvars_abstract=false;unconstrained_sorts=false;}typeevars_flag=bool(* true = pose evars false = fail on evars *)typerec_flag=bool(* true = recursive false = not recursive *)typeadvanced_flag=bool(* true = advanced false = basic *)typeclear_flag=booloption(* true = clear hyp, false = keep hyp, None = use default *)type'acore_destruction_arg=|ElimOnConstrof'a|ElimOnIdentoflident|ElimOnAnonHypofinttype'adestruction_arg=clear_flag*'acore_destruction_argletonInductionArgtac=function|clear_flag,ElimOnConstrcbl->tacclear_flagcbl|clear_flag,ElimOnAnonHypn->Tacticals.tclTHEN(intros_until_nn)(Tacticals.onLastHyp(func->tacclear_flag(c,NoBindings)))|clear_flag,ElimOnIdent{CAst.v=id}->(* A quantified hypothesis *)Tacticals.tclTHEN(try_intros_until_id_checkid)(tacclear_flag(mkVarid,NoBindings))letmap_destruction_argfsigma=function|clear_flag,ElimOnConstrg->letsigma,x=fsigmagin(sigma,(clear_flag,ElimOnConstrx))|clear_flag,ElimOnAnonHypnasx->(sigma,x)|clear_flag,ElimOnIdentidasx->(sigma,x)letfinish_evar_resolution?(flags=Pretyping.all_and_fail_flags)envcurrent_sigma(pending,c)=letsigma=Pretyping.solve_remaining_evarsflagsenvcurrent_sigma?initial:pendingin(sigma,nf_evarsigmac)letfinish_delayed_evar_resolutionwith_evarsenvsigmaf=let(sigma',(c,lbind))=fenvsigmainletflags=tactic_infer_flagswith_evarsinlet(sigma',c)=finish_evar_resolution~flagsenvsigma'(Somesigma,c)in(sigma',(c,lbind))letforce_destruction_argwith_evarsenvsigmac=map_destruction_arg(finish_delayed_evar_resolutionwith_evarsenv)sigmac(****************************************)(* tactic "cut" (actually modus ponens) *)(****************************************)letcutc=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletconcl=Proofview.Goal.conclglin(* Backward compat: ensure that [c] is well-typed. Plus we need to
know the relevance *)matchTyping.sort_ofenvsigmacwith|exceptionewhennoncriticale->let_,info=Exninfo.captureeinTacticals.tclZEROMSG~info(str"Not a proposition or a type.")|sigma,s->letr=ESorts.relevance_of_sortsinletid=next_name_away_with_default"H"Anonymous(Tacmach.pf_ids_set_of_hypsgl)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Refine.refine~typecheck:falsebeginfunh->let(h,f)=Evarutil.new_evar~principal:trueenvh(mkArrowcrconcl)inlet(h,x)=Evarutil.new_evarenvhcinletf=mkLetIn(make_annot(Nameid)r,x,c,mkApp(f,[|mkRel1|]))in(h,f)end)endletcheck_unresolved_evars_of_metassigmaclenv=(* This checks that Metas turned into Evars by *)(* Refiner.pose_all_metas_as_evars are resolved *)Metamap.iter(funmvb->matchbwith|Clval(na,(c,_),_)->(matchConstr.kind(EConstr.Unsafe.to_constrc.rebus)with|Evar(evk,_)whenEvd.is_undefined(clenv_evdclenv)evk&¬(Evd.memsigmaevk)->letid=matchnawithNameid->id|_->anomaly(Pp.str"unnamed dependent meta.")inerror(CannotFindInstanceid)|_->())|_->())(meta_list(clenv_evdclenv))letdo_replaceid=function|NamingMustBe{CAst.v=id'}whenOption.equalId.equalid(Someid')->true|_->false(* For a clenv expressing some lemma [C[?1:T1,...,?n:Tn] : P] and some
goal [G], [clenv_refine_in] returns [n+1] subgoals, the [n] last
ones (resp [n] first ones if [sidecond_first] is [true]) being the
[Ti] and the first one (resp last one) being [G] whose hypothesis
[id] is replaced by P using the proof given by [tac] *)letclenv_refine_inwith_evarstargetidreplaceenvsigma0clenv=letclenv=Clenv.clenv_pose_dependent_evars~with_evarsclenvinletevd=Typeclasses.resolve_typeclasses~fail:(notwith_evars)env(clenv_evdclenv)inletclenv=Clenv.update_clenv_evdclenvevdinletnew_hyp_typ=clenv_typeclenvinifnotwith_evarsthencheck_unresolved_evars_of_metassigma0clenv;let[@ocaml.warning"-3"]exact_tac=Clenv.Internal.refinerclenvinletnaming=NamingMustBe(CAst.maketargetid)inProofview.Unsafe.tclEVARS(clear_metasevd)<*>Proofview.Goal.enterbeginfungl->letid=find_namereplace(LocalAssum(make_annotAnonymousSorts.Relevant,new_hyp_typ))namingglinTacticals.tclTHENLAST(internal_cutreplaceidnew_hyp_typ<*>Proofview.cycle1)exact_tacend(********************************************)(* Elimination tactics *)(********************************************)letnth_argic=matchiwith|None->List.lastc|Somei->List.nthciletindex_of_ind_argsigmat=letrecauxijt=matchEConstr.kindsigmatwith|LetIn(_,_,_,t)->auxijt|Prod(_,t,u)->(* heuristic *)ifisIndsigma(fst(decompose_appsigmat))thenaux(Somej)(j+1)uelseauxi(j+1)u|_->matchiwith|Somei->i|None->errorCannotFindInductiveArgumentinauxNone0t(*
* Elimination tactic with bindings and using an arbitrary
* elimination constant called elimc. This constant should end
* with a clause (x:I)(P .. ), where P is a bound variable.
* The term c is of type t, which is a product ending with a type
* matching I, lbindc are the expected terms for c arguments
*)typeeliminator=|ElimConstantof(Constant.t*EInstance.t)(* Constant generated by a scheme function *)|ElimClauseofEConstr.constrwith_bindings(* Arbitrary expression provided by the user *)letgeneral_elim_clause0with_evarsflags(submetas,c,ty)elim=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletclause,bindings,index=matchelimwith|ElimConstantcst->letelimc=mkConstUcstinletelimt=Retyping.get_type_ofenvsigmaelimcinleti=index_of_ind_argsigmaelimtin(elimc,elimt),NoBindings,Somei|ElimClause(elimc,lbindelimc)->letelimt=Retyping.get_type_ofenvsigmaelimcin(elimc,elimt),lbindelimc,Noneinletelimclause=make_clenv_bindingenvsigmaclausebindingsinletindmv=trynth_argindex(clenv_argumentselimclause)withFailure_|Invalid_argument_->errorIllFormedEliminationTypeinletelimclause=clenv_instantiate~flags~submetasindmvelimclause(c,ty)inClenv.res_pfelimclause~with_evars~with_classes:true~flagsendletgeneral_elim_clause_in0with_evarsflagsid(submetas,c,ty)elim=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletelimc=mkConstUeliminletelimt=Retyping.get_type_ofenvsigmaelimcinleti=index_of_ind_argsigmaelimtinletelimclause=mk_clenv_fromenvsigma(elimc,elimt)inletindmv=trynth_arg(Somei)(clenv_argumentselimclause)withFailure_|Invalid_argument_->errorIllFormedEliminationTypein(* Assumes that the metas of [c] are part of [sigma] already *)lethypmv=matchList.removeInt.equalindmv(clenv_independentelimclause)with|[a]->a|_->errorIllFormedEliminationTypeinletelimclause=clenv_instantiate~flags~submetasindmvelimclause(c,ty)inlethyp=mkVaridinlethyp_typ=Retyping.get_type_ofenvsigmahypinletelimclause=tryclenv_instantiate~flagshypmvelimclause(hyp,hyp_typ)withPretypeError(env,evd,NoOccurrenceFound(op,_))->(* Set the hypothesis name in the message *)raise(PretypeError(env,evd,NoOccurrenceFound(op,Someid)))inletnew_hyp_typ=clenv_typeelimclauseinifEConstr.eq_constrsigmahyp_typnew_hyp_typthenerror(NothingToRewriteid);clenv_refine_inwith_evarsidtrueenvsigmaelimclauseendletgeneral_elimwith_evarsclear_flag(c,lbindc)elim=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletct=Retyping.get_type_ofenvsigmacinletid=trySome(destVarsigmac)withDestKO->Noneinlett=trysnd(reduce_to_quantified_indenvsigmact)withUserError_->ctinletindclause=make_clenv_bindingenvsigma(c,t)lbindcinletflags=elim_flags()inletmetas=Evd.meta_list(clenv_evdindclause)inletsubmetas=List.map(funmv->mv,Metamap.findmvmetas)(clenv_argumentsindclause)inProofview.Unsafe.tclEVARS(Evd.clear_metas(clenv_evdindclause))<*>Tacticals.tclTHEN(general_elim_clause0with_evarsflags(submetas,c,clenv_typeindclause)elim)(apply_clear_requestclear_flag(use_clear_hyp_by_default())id)endletgeneral_elim_clausewith_evarsflagswhereargelim=Proofview.tclENV>>=funenv->Proofview.tclEVARMAP>>=funsigma->let(sigma,(elim,u))=Evd.fresh_constant_instanceenvsigmaeliminProofview.Unsafe.tclEVARSsigma<*>matchwherewith|None->general_elim_clause0with_evarsflagsarg(ElimConstant(elim,EInstance.makeu))|Someid->general_elim_clause_in0with_evarsflagsidarg(elim,EInstance.makeu)(* Case analysis tactics *)letgeneral_case_analysis_in_contextwith_evarsclear_flag(c,lbindc)=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinletstate=Proofview.Goal.stateglinletct=Retyping.get_type_ofenvsigmacinlet(mind,_),t=reduce_to_quantified_indenvsigmactinletdep=ifdependentsigmacconclthentrueelsedefault_case_analysis_dependenceenvmindinletid=trySome(destVarsigmac)withDestKO->Noneinletindclause=make_clenv_bindingenvsigma(c,t)lbindcinletindclause=Clenv.clenv_pose_dependent_evars~with_evars:trueindclauseinletargtype=clenv_typeindclausein(* Guaranteed to be meta-free *)lettac=Proofview.tclEVARMAP>>=funsigma->letsigma=Evd.push_future_goalssigmainlet(sigma,ev)=Evarutil.new_evarenvsigmaargtypeinlet_,sigma=Evd.pop_future_goalssigmainletevk,_=destEvarsigmaevinletindclause=Clenv.update_clenv_evdindclause(meta_merge(meta_list@@Clenv.clenv_evdindclause)sigma)inProofview.Unsafe.tclEVARSsigma<*>Proofview.Unsafe.tclNEWGOALS~before:true[Proofview.goal_with_stateevkstate]<*>Proofview.tclDISPATCH[Clenv.res_pf~with_evars:trueindclause;tclIDTAC]<*>Proofview.tclEXTEND[]tclIDTAC[Clenv.case_pf~with_evars~dep(ev,argtype)]inletsigma=Evd.clear_metas(clenv_evdindclause)inTacticals.tclTHENLIST[Tacticals.tclWITHHOLESwith_evarstacsigma;apply_clear_requestclear_flag(use_clear_hyp_by_default())id;]endletgeneral_case_analysiswith_evarsclear_flag(c,lbindcascx)=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmacwith|Varidwhenlbindc==NoBindings->Tacticals.tclTHEN(try_intros_until_id_checkid)(general_case_analysis_in_contextwith_evarsclear_flagcx)|_->general_case_analysis_in_contextwith_evarsclear_flagcxletsimplest_casec=general_case_analysisfalseNone(c,NoBindings)letsimplest_ecasec=general_case_analysistrueNone(c,NoBindings)(* Elimination tactic with bindings but using the default elimination
* constant associated with the type. *)exceptionIsNonrecletis_nonrecenvmind=(Environ.lookup_mind(fstmind)env).mind_finite==Declarations.BiFiniteletfind_ind_eliminatorenvsigmainds=letc=lookup_eliminatorenvindsinletsigma,c=EConstr.fresh_globalenvsigmacinsigma,destConstsigmacletdefault_elimwith_evarsclear_flag(c,_ascx)=Proofview.tclORELSE(Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletsigma,t=Typing.type_ofenvsigmacinlet(ind,u)=eval_to_quantified_indenvsigmatinifis_nonrecenvindthenraiseIsNonrec;letsigma,elim=find_ind_eliminatorenvsigmaind(Retyping.get_sort_family_ofenvsigmaconcl)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(general_elimwith_evarsclear_flagcx(ElimConstantelim))end)beginfunction(e,info)->matchewith|IsNonrec->(* For records, induction principles aren't there by default
anymore. Instead, we do a case analysis. *)general_case_analysiswith_evarsclear_flagcx|e->Proofview.tclZERO~infoeendletelim_in_contextwith_evarsclear_flagc=function|Someelim->general_elimwith_evarsclear_flagc(ElimClauseelim)|None->default_elimwith_evarsclear_flagcletelimwith_evarsclear_flag(c,lbindcascx)elim=Proofview.tclEVARMAP>>=funsigma->matchEConstr.kindsigmacwith|Varidwhenlbindc==NoBindings->Tacticals.tclTHEN(try_intros_until_id_checkid)(elim_in_contextwith_evarsclear_flagcxelim)|_->elim_in_contextwith_evarsclear_flagcxelim(* The simplest elimination tactic, with no substitutions at all. *)letsimplest_elimc=default_elimfalseNone(c,NoBindings)(* Elimination in hypothesis *)(* Typically, elimclause := (eq_ind ?x ?P ?H ?y ?Heq : ?P ?y)
indclause : forall ..., hyps -> a=b (to take place of ?Heq)
id : phi(a) (to take place of ?H)
and the result is to overwrite id with the proof of phi(b)
but this generalizes to any elimination scheme with one constructor
(e.g. it could replace id:A->B->C by id:C, knowing A/\B)
*)(* Apply a tactic below the products of the conclusion of a lemma *)typeconjunction_status=|DefinedRecordofConstant.toptionlist|NotADefinedRecordUseSchemeletmake_projectionenvsigmaparamscstrsigneliminc(ind,u)=letopenContext.Rel.Declarationinletelim=matchelimwith|NotADefinedRecordUseScheme->(* bugs: goes from right to left when i increases! *)letcs_args=cstr.cs_argsinletdecl=List.nthcs_argsiinlett=RelDecl.get_typedeclinletb=matchdeclwithLocalAssum_->mkRel(i+1)|LocalDef(_,b,_)->binif(* excludes dependent projection types *)noccur_betweensigma1(n-i-1)t(* to avoid surprising unifications, excludes flexible
projection types or lambda which will be instantiated by Meta/Evar *)&¬(isEvarsigma(fst(whd_betaiota_stackenvsigmat)))&&(not(isRelsigmat))thenlet(_,mip)asspecif=Inductive.lookup_mind_specifenvindinlett=lift(i+1-n)tinletksort=Retyping.get_sort_family_of(push_rel_contextsignenv)sigmatinifSorts.family_leqksort(Inductiveops.elim_sortspecif)thenletarity=List.firstnmip.mind_nrealdeclsmip.mind_arity_ctxtinletmknasctx=Array.of_list(List.rev_mapget_annotctx)inletci=Inductiveops.make_case_infoenvindRegularStyleinletbr=[|mknascs_args,b|]inletargs=Context.Rel.instancemkRel0signinletindr=ERelevance.make@@Inductive.relevance_of_ind_bodymip(EConstr.Unsafe.to_instanceu)inletpnas=Array.append(mknas(EConstr.of_rel_contextarity))[|make_annotAnonymousindr|]inletp=(pnas,lift(Array.lengthpnas)t)inletc=mkCase(ci,u,Array.of_listparams,(p,get_relevancedecl),NoInvert,mkApp(c,args),br)inSome(it_mkLambda_or_LetIncsign,it_mkProd_or_LetIntsign)elseNoneelseNone|DefinedRecordl->(* goes from left to right when i increases! *)matchList.nthliwith|Someproj->letargs=Context.Rel.instancemkRel0signinletproj=matchStructures.PrimitiveProjections.find_opt_with_relevance(proj,u)with|Some(proj,r)->mkProj(Projection.makeprojfalse,r,mkApp(c,args))|None->mkApp(mkConstU(proj,u),Array.append(Array.of_listparams)[|mkApp(c,args)|])inletapp=it_mkLambda_or_LetInprojsigninlett=Retyping.get_type_ofenvsigmaappinSome(app,t)|None->Noneinelimletdescend_in_conjunctionsavoidtac(err,info)c=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglintrylett=Retyping.get_type_ofenvsigmacinlet((ind,u),t)=reduce_to_quantified_indenvsigmatinletsign,ccl=EConstr.decompose_prod_declssigmatinmatchmatch_with_tupleenvsigmacclwith|Some(_,_,isrec)->(* At this point, ind is known to be an index-free one-constructor
inductive type, potentially recursive. *)letn=(constructors_nrealargsenvind).(0)inletIndType(indf,_)=find_rectypeenvsigmacclinlet(_,inst),params=dest_ind_familyindfinletcstr=(get_constructorsenvindf).(0)inletelim=tryDefinedRecord(Structures.Structure.find_projectionsind)withNot_found->NotADefinedRecordUseSchemeinletor_tact1t2e=Proofview.tclORELSE(t1e)t2inList.fold_rightor_tac(List.initn(funi(err,info)->Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinmatchmake_projectionenvsigmaparamscstrsigneliminc(ind,u)with|None->Proofview.tclZERO~infoerr|Some(p,pt)->Tacticals.tclTHENS(Proofview.tclORELSE(assert_before_genfalse(NamingAvoidavoid)pt)(fun_->Proofview.tclZERO~infoerr))[Proofview.tclORELSE(Refine.refine~typecheck:false(funh->(h,p)))(fun_->Proofview.tclZERO~infoerr);(* Might be ill-typed due to forbidden elimination. *)Tacticals.onLastHypId(tac(err,info)(notisrec))]end))(fun(err,info)->Proofview.tclZERO~infoerr)(err,info)|None->Proofview.tclZERO~infoerrwithRefinerError_|UserError_->Proofview.tclZERO~infoerrend(****************************************************)(* Resolution tactics *)(****************************************************)letgeneral_apply?(with_classes=true)?(respect_opaque=false)with_deltawith_destructwith_evarsclear_flag{CAst.loc;v=(c,lbind:EConstr.constrwith_bindings)}=Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinletid=trySome(destVarsigmac)withDestKO->Nonein(* The actual type of the theorem. It will be matched against the
goal. If this fails, then the head constant will be unfolded step by
step. *)letconcl_nprod=nb_prod_modulo_zetasigmaconclinletrectry_main_applywith_destructc=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletts=ifrespect_opaquethenConv_oracle.get_transp_state(oracleenv)elseTransparentState.fullinletflags=ifwith_deltathendefault_unify_flags()elsedefault_no_delta_unify_flagstsinletthm_ty=nf_betaiotaenvsigma(Retyping.get_type_ofenvsigmac)inletsigma,thm_ty=Evarsolve.refresh_universes~onlyalg:trueNoneenvsigmathm_tyinlettry_applythm_tynprod=tryletn=nb_prod_modulo_zetasigmathm_ty-nprodinifn<0thenerrorNotEnoughPremises;letclause=make_clenv_binding_applyenvsigma(Somen)(c,thm_ty)lbindinClenv.res_pfclause~with_classes~with_evars~flagswithexnwhennoncriticalexn->letexn,info=Exninfo.captureexninProofview.tclZERO~infoexninletrectry_red_applythm_ty(exn0,info)=matchred_productenvsigmathm_tywith|Somered_thm->(* Try to head-reduce the conclusion of the theorem *)Proofview.tclORELSE(try_applyred_thmconcl_nprod)(fun_->try_red_applyred_thm(exn0,info))|None->(* Last chance: if the head is a variable, apply may try
second order unification *)letinfo=Option.cata(funloc->Loc.add_locinfoloc)infolocinlettac=ifwith_destructthenProofview.tclORELSE(descend_in_conjunctionsId.Set.empty(fun_bid->Tacticals.tclTHEN(try_main_applyb(mkVarid))(clear[id]))(exn0,info)c)(fun_->Proofview.tclZERO~infoexn0)elseProofview.tclZERO~infoexn0inifnot(Int.equalconcl_nprod0)thenTacticals.tclORELSE0(try_applythm_ty0)tacelsetacinProofview.tclORELSE(try_applythm_tyconcl_nprod)(try_red_applythm_ty)endinTacticals.tclTHEN(try_main_applywith_destructc)(apply_clear_requestclear_flag(use_clear_hyp_by_default())id)endletrecapply_with_bindings_gen?with_classesbe=function|[]->Proofview.tclUNIT()|[k,cb]->general_apply?with_classesbbekcb|(k,cb)::cbl->Tacticals.tclTHENLAST(general_apply?with_classesbbekcb)(apply_with_bindings_gen?with_classesbecbl)letapply_with_delayed_bindings_genbel=letonek{CAst.loc;v=cb}=Proofview.Goal.enterbeginfun_->Tacticals.tclRUNWITHHOLESecb(funcb->general_apply~respect_opaque:(notb)bbekCAst.(make?loccb))endinletrecaux=function|[]->Proofview.tclUNIT()|[k,f]->onekf|(k,f)::cbl->Tacticals.tclTHENLAST(onekf)(auxcbl)inauxlletapply_with_bindingscb=apply_with_bindings_genfalsefalse[None,(CAst.makecb)]leteapply_with_bindings?with_classescb=apply_with_bindings_gen?with_classesfalsetrue[None,(CAst.makecb)]letapplyc=apply_with_bindings_genfalsefalse[None,(CAst.make(c,NoBindings))]leteapply?with_classesc=apply_with_bindings_gen?with_classesfalsetrue[None,(CAst.make(c,NoBindings))]letapply_list=function|c::l->apply_with_bindings(c,ImplicitBindingsl)|_->assertfalse(* [apply_in hyp c] replaces
hyp : forall y1, ti -> t hyp : rho(u)
======================== with ============ and the =======
goal goal rho(ti)
assuming that [c] has type [forall x1..xn -> t' -> u] for some [t]
unifiable with [t'] with unifier [rho]
*)exceptionUnableToApplyletprogress_with_clauseenvflags(id,t)clausemvs=letinnerclause=mk_clenv_from_nenv(clenv_evdclause)0(mkVarid,t)inifList.is_emptymvsthenraiseUnableToApply;letfmv=letrecfindinnerclause=letmetas=Evd.meta_list(clenv_evdinnerclause)inletsubmetas=List.map(funmv->mv,Metamap.findmvmetas)(clenv_argumentsinnerclause)intrySome(clenv_instantiatemv~flags~submetasclause(mkVarid,clenv_typeinnerclause))withewhennoncriticale->matchclenv_push_prodinnerclausewith|Some(_,_,innerclause)->findinnerclause|None->NoneinfindinnerclauseinmatchList.find_mapfmvswith|Somev->v|None->raiseUnableToApplyletapply_in_once_mainflags(id,t)envsigma(loc,d,lbind)=letthm=nf_betaiotaenvsigma(Retyping.get_type_ofenvsigmad)inletrecauxclausemvs=tryprogress_with_clauseenvflags(id,t)clausemvswithewhenCErrors.noncriticale->lete'=Exninfo.captureeinmatchclenv_push_prodclausewith|Some(mv,dep,clause)->auxclause(ifdepthen[]else[mv])|None->matchewith|UnableToApply->error?loc(UnableToApplyLemma(env,sigma,thm,t))|_->Exninfo.iraisee'inletclenv=make_clenv_bindingenvsigma(d,thm)lbindinletmvs=List.rev(clenv_independentclenv)inauxclenvmvsletapply_in_once?(respect_opaque=false)with_deltawith_destructwith_evarsnamingid(clear_flag,{CAst.loc;v=d,lbind})tac=letopenContext.Rel.DeclarationinProofview.Goal.enterbeginfungl->lett'=Tacmach.pf_get_hyp_typidglinlettargetid=find_nametrue(LocalAssum(make_annotAnonymousSorts.Relevant,t'))namingglinletreplace=Id.equalidtargetidinletrecaux?erridstoclearwith_destructc=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinletidc=trySome(destVar(Tacmach.projectgl)c)withDestKO->Noneinletts=ifrespect_opaquethenConv_oracle.get_transp_state(oracleenv)elseTransparentState.fullinletflags=ifwith_deltathendefault_unify_flags()elsedefault_no_delta_unify_flagstsintryletclause=apply_in_once_mainflags(id,t')envsigma(loc,c,lbind)inletcleartac=apply_clear_requestclear_flagfalseidc<*>clearidstoclearinletrefine=Tacticals.tclTHENFIRST(clenv_refine_inwith_evarstargetidreplaceenvsigmaclause)cleartacinTacticals.tclTHENFIRST(replace_error_optionerrrefine)(tactargetid)withewhenwith_destruct&&CErrors.noncriticale->leterr=Option.default(Exninfo.capturee)errin(descend_in_conjunctions(Id.Set.singletontargetid)(funerrbid->aux~err(id::idstoclear)b(mkVarid))errc)endinaux[]with_destructdendletapply_in_delayed_once?(respect_opaque=false)with_deltawith_destructwith_evarsnamingid(clear_flag,{CAst.loc;v=f})tac=Proofview.Goal.enterbeginfun_->Tacticals.tclRUNWITHHOLESwith_evarsf(func->apply_in_once~respect_opaquewith_deltawith_destructwith_evarsnamingid(clear_flag,CAst.(make?locc))tac)end(* A useful resolution tactic which, if c:A->B, transforms |- C into
|- B -> C and |- A
-------------------
Gamma |- c : A -> B Gamma |- ?2 : A
----------------------------------------
Gamma |- B Gamma |- ?1 : B -> C
-----------------------------------------------------
Gamma |- ? : C
Ltac lapply c :=
let ty := check c in
match eval hnf in ty with
?A -> ?B => cut B; [ idtac | apply c ]
end.
*)letcut_and_applyc=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletconcl=Proofview.Goal.conclglinletsigma,t=Typing.type_ofenvsigmacinmatchEConstr.kindsigma(hnf_constrenvsigmat)with|Prod(_,c1,c2)whenVars.noccurnsigma1c2->Proofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Refine.refine~typecheck:falsebeginfunsigma->lettyp=mkProd(make_annotAnonymousERelevance.relevant,c2,concl)inlet(sigma,f)=Evarutil.new_evarenvsigmatypinlet(sigma,x)=Evarutil.new_evarenvsigmac1in(sigma,mkApp(f,[|mkApp(c,[|x|])|]))end)|_->errorNeedDependentProductend(********************************************************************)(* Exact tactics *)(********************************************************************)letexact_no_checkc=Refine.refine~typecheck:false(funh->(h,c))letexact_checkc=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglin(* We do not need to normalize the goal because we just check convertibility *)letconcl=Proofview.Goal.conclglinletenv=Proofview.Goal.envglinletsigma,ct=Typing.type_ofenvsigmacinTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Tacticals.tclTHEN(convert_leqctconcl)(exact_no_checkc))endletcast_no_checkcastc=Proofview.Goal.enterbeginfungl->letconcl=Proofview.Goal.conclglinexact_no_check(mkCast(c,cast,concl))endletvm_cast_no_checkc=cast_no_checkVMcastcletnative_cast_no_checkc=cast_no_checkNATIVEcastcletexact_proofc=letopenTacmachinProofview.Goal.enterbeginfungl->Refine.refine~typecheck:falsebeginfunsigma->let(c,ctx)=Constrintern.interp_casted_constr(pf_envgl)sigmac(pf_conclgl)inletsigma=Evd.set_universe_contextsigmactxin(sigma,c)endendletassumption=letrecarecglonly_eq=function|[]->ifonly_eqthenlethyps=Proofview.Goal.hypsglinarecglfalsehypselseletinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"No such assumption.")|decl::rest->lett=NamedDecl.get_typedeclinletconcl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinletans=ifonly_eqthenifEConstr.eq_constrsigmatconclthenSomesigmaelseNoneelseletenv=Proofview.Goal.envglininfer_convenvsigmatconclinmatchanswith|Somesigma->(Proofview.Unsafe.tclEVARSsigma)<*>exact_no_check(mkVar(NamedDecl.get_iddecl))|None->arecglonly_eqrestinletassumption_tacgl=lethyps=Proofview.Goal.hypsglinarecgltruehypsinProofview.Goal.enterassumption_tac(*****************************************************************)(* Modification of a local context *)(*****************************************************************)letcheck_is_typeenvsigmaidlidsty=tryletsigma,_=Typing.sort_ofenvsigmatyinsigmawithewhenCErrors.noncriticale->raise(DependsOnBody(idl,ids,None))letcheck_declenvsigmaidlidsdecl=letopenContext.Named.Declarationinletty=NamedDecl.get_typedeclintryletsigma,_=Typing.sort_ofenvsigmatyinletsigma=matchdeclwith|LocalAssum_->sigma|LocalDef(_,c,_)->Typing.checkenvsigmactyinsigmawithewhenCErrors.noncriticale->letid=NamedDecl.get_iddeclinraise(DependsOnBody(idl,ids,Someid))letclear_bodyidl=letopenContext.Named.DeclarationinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletconcl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinletctx=named_contextenvinletids=Id.Set.of_listidlin(* We assume the context to respect dependencies *)letrecfoldidsctx=ifId.Set.is_emptyidsthenletbase_env=reset_contextenvinletenv=push_named_contextctxbase_envinenv,sigma,Id.Set.emptyelsematchctxwith|[]->assertfalse|decl::ctx->letdecl,ids,found=matchdeclwith|LocalAssum(id,t)->let()=ifId.Set.memid.binder_nameidsthenerror(VariableHasNoValueid.binder_name)indecl,ids,false|LocalDef(id,_,t)asdecl->ifId.Set.memid.binder_nameidsthenLocalAssum(id,t),Id.Set.removeid.binder_nameids,trueelsedecl,ids,falseinletenv,sigma,ids=foldidsctxinifId.Set.exists(funid->occur_var_in_declenvsigmaiddecl)idsthenletsigma=check_declenvsigmaidlidsdeclin(* can sigma really change? *)letids=Id.Set.add(get_iddecl)idsinpush_nameddeclenv,sigma,Id.Set.add(get_iddecl)idselsepush_nameddeclenv,sigma,iffoundthenId.Set.add(get_iddecl)idselseidsintryletenv,sigma,ids=foldidsctxinletsigma=ifId.Set.exists(funid->occur_varenvsigmaidconcl)idsthencheck_is_typeenvsigmaidlidsconclelsesigmainProofview.Unsafe.tclEVARSsigma<*>Refine.refine~typecheck:falsebeginfunsigma->Evarutil.new_evarenvsigma~principal:trueconclendwithDependsOnBody_asexn->let_,info=Exninfo.captureexninProofview.tclZERO~infoexnendletclear_wildcardsids=letclear_wildcards_msg?locenvsigma_iderringlobal=user_err?loc(clear_dependency_msgenvsigmaNoneerringlobal)inTacticals.tclMAP(fun{CAst.loc;v=id}->clear_gen(clear_wildcards_msg?loc)[id])ids(* Takes a list of booleans, and introduces all the variables
* quantified in the goal which are associated with a value
* true in the boolean list. *)letrecintros_clearing=function|[]->Proofview.tclUNIT()|(false::tl)->Tacticals.tclTHENintro(intros_clearingtl)|(true::tl)->Tacticals.tclTHENLIST[intro;Tacticals.onLastHypId(funid->clear[id]);intros_clearingtl](* Keeping only a few hypotheses *)letkeephyps=Proofview.Goal.enterbeginfungl->Proofview.tclENV>>=funenv->letccl=Proofview.Goal.conclglinletsigma=Tacmach.projectglinletcl,_=fold_named_context_reverse(fun(clear,keep)decl->letdecl=EConstr.of_named_decldeclinlethyp=NamedDecl.get_iddeclinifId.List.memhyphyps||List.exists(occur_var_in_declenvsigmahyp)keep||occur_varenvsigmahypcclthen(clear,decl::keep)else(hyp::clear,keep))~init:([],[])(Proofview.Goal.envgl)inclearclend(*********************************)(* 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] *)letapply_type~typechecknewclargs=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinRefine.refine~typecheckbeginfunsigma->letnewcl=nf_betaiotaenvsigmanewcl(* As in former Logic.refine *)inlet(sigma,ev)=Evarutil.new_evarenvsigma~principal:truenewclin(sigma,applist(ev,args))endend(************************)(* Introduction tactics *)(************************)letcheck_number_of_constructorsexpctdnumoptinconstr=ifInt.equali0thenerrorConstructorNumberedFromOne;beginmatchexpctdnumoptwith|Somenwhennot(Int.equalnnconstr)->error(NotRightNumberConstructorsn)|_->()end;ifi>nconstrthenerrorNotEnoughConstructorsletconstructor_corewith_evarscstrlbind=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinlet(sigma,(cons,u))=Evd.fresh_constructor_instanceenvsigmacstrinletcons=mkConstructU(cons,EInstance.makeu)inletapply_tac=general_applytruefalsewith_evarsNone(CAst.make(cons,lbind))inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)apply_tacendletconstructor_tacwith_evarsexpctdnumoptilbind=Proofview.Goal.enterbeginfungl->letcl=Tacmach.pf_conclglinletenv=Proofview.Goal.envglinlet((ind,_),redcl)=Tacmach.pf_applyTacred.reduce_to_quantified_indglclinletnconstr=Array.length(snd(Inductive.lookup_mind_specifenvind)).mind_consnamesincheck_number_of_constructorsexpctdnumoptinconstr;Tacticals.tclTHENLIST[convert_concl~cast:false~check:falseredclDEFAULTcast;intros;constructor_corewith_evars(ind,i)lbind]endletone_constructorilbind=constructor_tacfalseNoneilbind(* Try to apply the constructor of the inductive definition followed by
a tactic t given as an argument.
Should be generalize in Constructor (Fun c : I -> tactic)
*)letany_constructorwith_evarstacopt=letone_constr=lettaccstr=constructor_corewith_evarscstrNoBindingsinmatchtacoptwith|None->tac|Somet->funcstr->Tacticals.tclTHEN(taccstr)tinletrecany_constrindni()=ifInt.equalinthenone_constr(ind,i)elseTacticals.tclORD(one_constr(ind,i))(any_constrindn(i+1))inProofview.Goal.enterbeginfungl->letcl=Tacmach.pf_conclglinletenv=Proofview.Goal.envglinlet(ind,_),redcl=Tacmach.pf_applyTacred.reduce_to_quantified_indglclinletnconstr=Array.length(snd(Inductive.lookup_mind_specifenvind)).mind_consnamesinifInt.equalnconstr0thenerrorNoConstructors;Tacticals.tclTHENLIST[convert_concl~cast:false~check:falseredclDEFAULTcast;intros;any_constrindnconstr1()]endletleft_with_bindingswith_evars=constructor_tacwith_evars(Some2)1letright_with_bindingswith_evars=constructor_tacwith_evars(Some2)2letsplit_with_bindingswith_evarsl=Tacticals.tclMAP(constructor_tacwith_evars(Some1)1)lletsplit_with_delayed_bindingswith_evarsbl=Tacticals.tclMAPDELAYEDWITHHOLESwith_evarsbl(constructor_tacwith_evars(Some1)1)letleft=left_with_bindingsfalseletsimplest_left=leftNoBindingsletright=right_with_bindingsfalseletsimplest_right=rightNoBindingsletsplit=constructor_tacfalse(Some1)1letsimplest_split=splitNoBindings(*****************************)(* Decomposing introductions *)(*****************************)(* Rewriting function for rewriting one hypothesis at the time *)let(forward_general_rewrite_clause,general_rewrite_clause)=Hook.make()(* Rewriting function for substitution (x=t) everywhere at the same time *)let(forward_subst_one,subst_one)=Hook.make()letintro_decomp_eq_function=ref(fun_->failwith"Not implemented")letdeclare_intro_decomp_eqf=intro_decomp_eq_function:=fletmy_find_eq_data_decomposeenvsigmat=trySome(find_eq_data_decomposeenvsigmat)withewhenis_anomalye(* Hack in case equality is not yet defined... one day, maybe,
known equalities will be dynamically registered *)->None|Constr_matching.PatternMatchingFailure->Noneletintro_decomp_eq?loclthintacid=Proofview.Goal.enterbeginfungl->letc=mkVaridinletenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlet{uj_type=t}=Typing.judge_of_variableenvidinlet_,t=reduce_to_atomic_indenvsigmatinmatchmy_find_eq_data_decomposeenvsigmatwith|Some(eq,u,eq_args)->!intro_decomp_eq_function(funn->tac((CAst.makeid)::thin)(Somen)l)(eq,t,eq_args)(c,t)|None->letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"Not a primitive equality here.")endletintro_or_and_pattern?locwith_evarsllthintacid=Proofview.Goal.enterbeginfungl->letc=mkVaridinletenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlet{uj_type=t}=Typing.judge_of_variableenvidinletind=eval_to_quantified_indenvsigmatinletbranchsigns=compute_constructor_signaturesenv~rec_flag:falseindinletnv_with_let=Array.mapList.lengthbranchsignsinletll=fix_empty_or_and_pattern(Array.lengthbranchsigns)llinletll=get_and_check_or_and_pattern?locllbranchsignsinletcase=ifwith_evarsthensimplest_ecaseelsesimplest_caseinTacticals.tclTHENLASTn(Tacticals.tclTHEN(casec)(clear[id]))(Array.map2(funnl->tacthin(Somen)l)nv_with_letll)endletrewrite_hyp_thenwith_evarsthinl2ridtac=letrew_onl2r=Hook.getforward_general_rewrite_clausel2rwith_evars(mkVarid,NoBindings)inletsubst_onl2rxrhs=Hook.getforward_subst_onetruex(id,rhs,l2r)inletclear_var_and_eqid'=clear[id';id]inletearly_clearid'thin=List.filter(fun{CAst.v=id}->not(Id.equalidid'))thininProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinlet{uj_type=t}=Typing.judge_of_variableenvidinlett=whd_allenvsigmatinleteqtac,thin=matchmatch_with_equality_typeenvsigmatwith|Some(hdcncl,[_;lhs;rhs])->ifl2r&&isVarsigmalhs&¬(occur_varenvsigma(destVarsigmalhs)rhs)thenletid'=destVarsigmalhsinsubst_onl2rid'rhs,early_clearid'thinelseifnotl2r&&isVarsigmarhs&¬(occur_varenvsigma(destVarsigmarhs)lhs)thenletid'=destVarsigmarhsinsubst_onl2rid'lhs,early_clearid'thinelseTacticals.tclTHEN(rew_onl2ronConcl)(clear[id]),thin|Some(hdcncl,[c])->letl2r=notl2rin(* equality of the form eq_true *)ifisVarsigmacthenletid'=destVarsigmacinTacticals.tclTHEN(rew_onl2rallHypsAndConcl)(clear_var_and_eqid'),early_clearid'thinelseTacticals.tclTHEN(rew_onl2ronConcl)(clear[id]),thin|_->Tacticals.tclTHEN(rew_onl2ronConcl)(clear[id]),thinin(* Skip the side conditions of the rewriting step *)Tacticals.tclTHENFIRSTeqtac(tacthin)endletreccollect_intro_names=letopenCAstinfunction|{v=IntroForthcoming_}::l->collect_intro_namesl|{v=IntroNaming(IntroIdentifierid)}::l->letids1,ids2=collect_intro_nameslinId.Set.addidids1,ids2|{v=IntroAction(IntroOrAndPatternl)}::l'->letll=matchlwithIntroAndPatternl->[l]|IntroOrPatternll->llinletfold(ids1',ids2')l=letids1,ids2=collect_intro_names(l@l')inId.Set.unionids1ids1',Id.Set.unionids2ids2'inList.fold_leftfold(Id.Set.empty,Id.Set.empty)ll|{v=IntroAction(IntroInjectionl)}::l'->collect_intro_names(l@l')|{v=IntroAction(IntroApplyOn(c,pat))}::l'->collect_intro_names(pat::l')|{v=IntroNaming(IntroFreshid)}::l->letids1,ids2=collect_intro_nameslinids1,Id.Set.addidids2|{v=(IntroNamingIntroAnonymous|IntroAction(IntroWildcard|IntroRewrite_))}::l->collect_intro_namesl|[]->Id.Set.empty,Id.Set.emptyletexplicit_intro_namesl=fst(collect_intro_namesl)letexplicit_all_intro_namesl=letids1,ids2=collect_intro_nameslinId.Set.unionids1ids2letreccheck_name_unicityenvokseen=letopenCAstinfunction|{v=IntroForthcoming_}::l->check_name_unicityenvokseenl|{loc;v=IntroNaming(IntroIdentifierid)}::l->(tryignore(ifList.mem_fId.equalidokthenraiseNot_foundelselookup_namedidenv);error?loc(AlreadyUsedid)withNot_found->ifList.mem_fId.equalidseenthenerror?loc(UsedTwiceid)elsecheck_name_unicityenvok(id::seen)l)|{v=IntroAction(IntroOrAndPatternl)}::l'->letll=matchlwithIntroAndPatternl->[l]|IntroOrPatternll->llinList.iter(funl->check_name_unicityenvokseen(l@l'))ll|{v=IntroAction(IntroInjectionl)}::l'->check_name_unicityenvokseen(l@l')|{v=IntroAction(IntroApplyOn(c,pat))}::l'->check_name_unicityenvokseen(pat::l')|{v=(IntroNaming(IntroAnonymous|IntroFresh_)|IntroAction(IntroWildcard|IntroRewrite_))}::l->check_name_unicityenvokseenl|[]->()letmake_naming?locavoidl=function|IntroIdentifierid->NamingMustBe(CAst.make?locid)|IntroAnonymous->NamingAvoid(Id.Set.unionavoid(explicit_intro_namesl))|IntroFreshid->NamingBasedOn(id,Id.Set.unionavoid(explicit_intro_namesl))letrecmake_naming_actionavoidl=function(* In theory, we could use a tmp id like "wild_id" for all actions
but we prefer to avoid it to avoid this kind of "ugly" names *)|IntroWildcard->NamingBasedOn(Id.of_string"_H",Id.Set.unionavoid(explicit_all_intro_namesl))|IntroApplyOn(_,{CAst.v=pat;loc})->make_naming_patternavoid?loclpat|(IntroOrAndPattern_|IntroInjection_|IntroRewrite_)aspat->NamingAvoid(Id.Set.unionavoid(explicit_intro_names((CAst.make@@IntroActionpat)::l)))andmake_naming_pattern?locavoidl=function|IntroNamingpat->make_naming?locavoidlpat|IntroActionpat->make_naming_actionavoidlpat|IntroForthcoming_->NamingAvoid(Id.Set.unionavoid(explicit_intro_namesl))letprepare_naming?locpat=make_naming?locId.Set.empty[]patletfit_boundn=function|None->true|Somen'->n=n'letexceed_boundn=function|None->false|Somen'->n>=n'(* We delay thinning until the completion of the whole intros tactic
to ensure that dependent hypotheses are cleared in the right
dependency order (see BZ#1000); we use fresh names, not used in
the tactic, for the hyps to clear *)(* In [intro_patterns_core b avoid ids thin destopt bound n tac patl]:
[b]: compatibility flag, if false at toplevel, do not complete incomplete
trailing toplevel or_and patterns (as in "intros []", see
[bracketing_last_or_and_intro_pattern])
[avoid]: names to avoid when creating an internal name
[ids]: collect introduced names for possible use by the [tac] continuation
[thin]: collect names to erase at the end
[destopt]: position in the context where to introduce the hypotheses
[bound]: number of pending intros to do in the current or-and pattern,
with remembering of [b] flag if at toplevel
[n]: number of introduction done in the current or-and pattern
[tac]: continuation tactic
[patl]: introduction patterns to interpret
*)letrecintro_patterns_corewith_evarsavoididsthindestoptboundntac=function|[]whenfit_boundnbound->tacidsthin|[]->(* Behave as IntroAnonymous *)intro_patterns_corewith_evarsavoididsthindestoptboundntac[CAst.make@@IntroNamingIntroAnonymous]|{CAst.loc;v=pat}::l->ifexceed_boundnboundthenerror?loc(UnexpectedExtraPattern(bound,pat))elsematchpatwith|IntroForthcomingonlydeps->letnaming=Id.Set.unionavoid(explicit_intro_namesl)inintro_forthcoming_then_gennamingdestopt~dep:onlydepsboundn(funids->intro_patterns_corewith_evarsavoididsthindestoptbound(n+List.lengthids)tacl)|IntroActionpat->letnaming=make_naming_actionavoidlpatinintro_then_gennamingdestopt~force:true~dep:false(intro_pattern_action?locwith_evarspatthindestopt(funthinbound'->intro_patterns_corewith_evarsavoididsthindestoptbound'0(funidsthin->intro_patterns_corewith_evarsavoididsthindestoptbound(n+1)tacl)))|IntroNamingpat->letnaming=make_namingavoidlpatinintro_then_gennamingdestopt~force:true~dep:false(funid->intro_patterns_corewith_evarsavoid(id::ids)thindestoptbound(n+1)tacl)andintro_pattern_action?locwith_evarspatthindestopttacid=matchpatwith|IntroWildcard->tac(CAst.(make?locid)::thin)None[]|IntroOrAndPatternll->intro_or_and_pattern?locwith_evarsllthintacid|IntroInjectionl'->intro_decomp_eq?locl'thintacid|IntroRewritel2r->rewrite_hyp_thenwith_evarsthinl2rid(funthin->tacthinNone[])|IntroApplyOn({CAst.loc=loc';v=f},{CAst.loc;v=pat})->letnaming=NamingMustBe(CAst.make?locid)inlettac_ipat=prepare_action?locwith_evarsdestoptpatinletf=tactic_of_delayedf>>=func->Proofview.tclUNIT(c,NoBindings)inapply_in_delayed_oncetruetruewith_evarsnamingid(None,CAst.make?loc:loc'f)(funid->Tacticals.tclTHENLIST[tac_ipatid;tacthinNone[]])andprepare_action?locwith_evarsdestopt=function|IntroNamingipat->(fun_->Proofview.tclUNIT())|IntroActionipat->(lettacthinbound=intro_patterns_corewith_evarsId.Set.empty[]thindestoptbound0(fun_l->clear_wildcardsl)infunid->intro_pattern_action?locwith_evarsipat[]destopttacid)|IntroForthcoming_->error?locOneIntroPatternExpectedletintro_patterns_head_corewith_evarsdestoptboundpat=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglincheck_name_unicityenv[][]pat;intro_patterns_corewith_evarsId.Set.empty[][]destoptbound0(fun_l->clear_wildcardsl)patendletintro_patterns_bound_towith_evarsndestopt=intro_patterns_head_corewith_evarsdestopt(Somen)letintro_patterns_towith_evarsdestopt=intro_patterns_head_corewith_evarsdestoptNoneletintro_pattern_towith_evarsdestoptpat=intro_patterns_towith_evarsdestopt[CAst.makepat]letintro_patternswith_evars=intro_patterns_towith_evarsMoveLast(* Implements "intros" *)letintros_patternswith_evars=function|[]->intros|l->intro_patterns_towith_evarsMoveLastl(**************************)(* Forward reasoning *)(**************************)letprepare_intros_optwith_evarsdftdestoptipat=letnaming,loc,ipat=matchipatwith|None->letpat=IntroNamingdftinmake_naming_patternId.Set.empty[]pat,None,pat|Some{CAst.loc;v=(IntroNamingpatasipat)}->(* "apply ... in H as id" needs to use id and H is kept iff id<>H *)prepare_naming?locpat,loc,ipat|Some{CAst.loc;v=(IntroActionpatasipat)}->(* "apply ... in H as pat" reuses H so that old H is always cleared *)(matchdftwithIntroIdentifier_->prepare_naming?locdft|_->make_naming_actionId.Set.empty[]pat),loc,ipat|Some{CAst.loc;v=(IntroForthcoming_)}->assertfalseinnaming,prepare_action?locwith_evarsdestoptipatletipat_of_name=function|Anonymous->None|Nameid->Some(CAst.make@@IntroNaming(IntroIdentifierid))lethead_identsigmac=letc=fst(decompose_appsigma(snd(decompose_lambda_declssigmac)))inifisVarsigmacthenSome(destVarsigmac)elseNone(* apply in as *)letgeneral_apply_in?(respect_opaque=false)with_deltawith_destructwith_evarsidlemmasipatthen_tac=lettac(naming,lemma)tacid=apply_in_delayed_once~respect_opaquewith_deltawith_destructwith_evarsnamingidlemmatacinProofview.Goal.enterbeginfungl->letdestopt=ifwith_evarsthenMoveLast(* evars would depend on the whole context *)else(letenv,sigma=Proofview.Goal.(envgl,sigmagl)inget_previous_hyp_positionenvsigmaid(Proofview.Goal.hypsgl))inletnaming,ipat_tac=prepare_intros_optwith_evars(IntroIdentifierid)destoptipatinletlemmas_target,last_lemma_target=letlast,first=List.sep_lastlemmasinList.map(funlem->(NamingMustBe(CAst.makeid),lem))first,(naming,last)in(* We chain apply_in_once, ending with an intro pattern *)List.fold_righttaclemmas_target(taclast_lemma_target(funid->Tacticals.tclTHEN(ipat_tacid)then_tac))idend(*
if sidecond_first then
(* Skip the side conditions of the applied lemma *)
Tacticals.tclTHENLAST (tclMAPLAST tac lemmas_target) (ipat_tac id)
else
Tacticals.tclTHENFIRST (tclMAPFIRST tac lemmas_target) (ipat_tac id)
*)letapply_insimplewith_evarsidlemmasipat=letlemmas=List.map(fun(k,{CAst.loc;v=l})->k,CAst.make?loc(Proofview.tclUNITl))lemmasingeneral_apply_insimplesimplewith_evarsidlemmasipatTacticals.tclIDTACletapply_delayed_insimplewith_evarsidlemmasipatthen_tac=general_apply_in~respect_opaque:truesimplesimplewith_evarsidlemmasipatthen_tac(*****************************)(* Tactics abstracting terms *)(*****************************)(* Implementation without generalisation: abbrev will be lost in hyps in *)(* in the extracted proof *)letdecode_hyp=function|None->MoveLast|Someid->MoveAfterid(* [letin_tac b (... abstract over c ...) gl] transforms
[...x1:T1(c),...,x2:T2(c),... |- G(c)] into
[...x:T;Heqx:(x=c);x1:T1(x),...,x2:T2(x),... |- G(x)] if [b] is false or
[...x:=c:T;x1:T1(x),...,x2:T2(x),... |- G(x)] if [b] is true
*)letletin_tac_genwith_eq(id,depdecls,lastlhyp,ccl,c)ty=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinlet(sigma,t)=matchtywith|Somet->(sigma,t)|None->lett=typ_ofenvsigmacinEvarsolve.refresh_universes~onlyalg:true(Somefalse)envsigmatinletrel=Retyping.relevance_of_termenvsigmacinlet(sigma,(newcl,eq_tac))=matchwith_eqwith|Some(lr,{CAst.loc;v=ido})->letheq=matchidowith|IntroAnonymous->new_fresh_id(Id.Set.singletonid)(add_prefix"Heq"id)gl|IntroFreshheq_base->new_fresh_id(Id.Set.singletonid)heq_basegl|IntroIdentifierid->idinleteqdata=build_coq_eq_data()inletargs=iflrthen[mkVarid;c]else[c;mkVarid]inlet(sigma,eq)=Evd.fresh_globalenvsigmaeqdata.eqinlet(sigma,refl)=Evd.fresh_globalenvsigmaeqdata.reflinletsigma,eq=Typing.checked_applistenvsigmaeq[t]inletsigma,refl=Typing.checked_applistenvsigmarefl[t]inleteq=applist(eq,args)inletrefl=applist(refl,[mkVarid])inletr=Retyping.relevance_of_termenvsigmareflinletterm=mkNamedLetInsigma(make_annotidrel)ct(mkLetIn(make_annot(Nameheq)r,refl,eq,ccl))inletans=term,Tacticals.tclTHENLIST[intro_gen(NamingMustBeCAst.(make?locheq))(decode_hyplastlhyp)~force:true~dep:false;clear_body[heq;id]]in(sigma,ans)|None->(sigma,(mkNamedLetInsigma(make_annotidrel)ctccl,Proofview.tclUNIT()))inTacticals.tclTHENLIST[Proofview.Unsafe.tclEVARSsigma;convert_concl~cast:false~check:falsenewclDEFAULTcast;intro_gen(NamingMustBe(CAst.makeid))(decode_hyplastlhyp)~force:true~dep:false;Tacticals.tclMAP(convert_hyp~check:false~reorder:false)depdecls;eq_tac]endletpose_tacnac=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinlethyps=named_context_valenvinletconcl=Proofview.Goal.conclglinlett=typ_ofenvsigmacinletrel=Retyping.relevance_of_termenvsigmacinlet(sigma,t)=Evarsolve.refresh_universes~onlyalg:true(Somefalse)envsigmatinletid=matchnawith|Nameid->let()=ifmem_named_context_validhypsthenerror(IntroAlreadyDeclaredid)inid|Anonymous->letid=id_of_name_using_hdcharenvsigmatAnonymousinnext_ident_away_in_goal(Global.env())id(ids_of_named_context_valhyps)inProofview.Unsafe.tclEVARSsigma<*>Refine.refine~typecheck:falsebeginfunsigma->letid=make_annotidrelinletnhyps=EConstr.push_named_context_val(NamedDecl.LocalDef(id,c,t))hypsinlet(sigma,ev)=Evarutil.new_pure_evarnhypssigmaconclinletinst=EConstr.identity_subst_valhypsinletbody=mkEvar(ev,SList.cons(mkRel1)inst)in(sigma,mkLetIn(map_annotName.mk_nameid,c,t,body))endendletletin_tacwith_eqidctyoccs=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletccl=Proofview.Goal.conclglinletabs=AbstractExact(id,c,ty,occs,true)inlet(id,_,depdecls,lastlhyp,ccl,res)=make_abstractionenvsigmacclabsin(* We keep the original term to match but record the potential side-effects
of unifying universes. *)let(sigma,c)=matchreswith|None->(sigma,c)|Some(sigma,_)->(sigma,c)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(letin_tac_genwith_eq(id,depdecls,lastlhyp,ccl,c)ty)endletletin_pat_tacwith_evarswith_eqidcoccs=Proofview.Goal.enterbeginfungl->letsigma=Proofview.Goal.sigmaglinletenv=Proofview.Goal.envglinletccl=Proofview.Goal.conclglinletcheckt=trueinletabs=AbstractPattern(false,check,id,c,occs)inlet(id,_,depdecls,lastlhyp,ccl,res)=make_abstractionenvsigmacclabsinlet(sigma,c)=matchreswith|None->finish_evar_resolution~flags:(tactic_infer_flagswith_evars)envsigmac|Someres->resinProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(letin_tac_genwith_eq(id,depdecls,lastlhyp,ccl,c)None)end(* Tactics "pose proof" (usetac=None) and "assert"/"enough" (otherwise) *)letforwardbusetacipatc=matchusetacwith|None->Proofview.Goal.enterbeginfungl->lett=Tacmach.pf_get_type_ofglcinletsigma=Tacmach.projectglinlethd=head_identsigmacinletassert_as=letnaming,tac=prepare_intros_optfalseIntroAnonymousMoveLastipatinletrepl=do_replacehdnaminginifreplthenassert_before_gentruenamingtelseassert_before_then_genfalsenamingttacinTacticals.tclTHENFIRSTassert_as(exact_no_checkc)end|Sometac->lettac=matchtacwith|None->Tacticals.tclIDTAC|Sometac->Tacticals.tclCOMPLETEtacinletnaming,assert_tac=prepare_intros_optfalseIntroAnonymousMoveLastipatinifbthenTacticals.tclTHENFIRST(assert_before_then_genfalsenamingcassert_tac)tacelseTacticals.tclTHENS3PARTS(assert_after_then_genfalsenamingcassert_tac)[||]tac[|Tacticals.tclIDTAC|]letpose_proofnac=forwardtrueNone(ipat_of_namena)cletassert_bynattac=forwardtrue(Some(Sometac))(ipat_of_namena)tletenough_bynattac=forwardfalse(Some(Sometac))(ipat_of_namena)t(* Instantiating some arguments (whatever their position) of an hypothesis
or any term, leaving other arguments quantified. If operating on an
hypothesis of the goal, the new hypothesis replaces it.
(c,lbind) are supposed to be of the form
((H t1 t2 ... tm) , someBindings)
whete t1..tn are user given args, to which someBinding must be combined.
The goal is to pose a proof with body
(fun y1...yp => H t1 t2 ... tm u1 ... uq)
where yi are the remaining arguments of H that lbind could not
solve, ui are a mix of inferred args and yi. The overall effect
is to remove from H as much quantification as possible given
lbind. *)moduleSpecialize:sigvalunify_bindings:evar_map->(evar_map->int->'a->evar_map)->types->'abindings->evar_map(* Unfortunate small code duplication with EClause *)end=structtypehole={hole_evar:int;hole_deps:bool;hole_name:Name.t;}letmake_evar_clausesigmat=letopenEConstrinletopenVarsinletrecclrecholesnt=matchEConstr.kindsigmatwith|Cast(t,_,_)->clrecholesnt|Prod(na,t1,t2)->letdep=not(noccurnsigma1t2)inlethole={hole_evar=n;hole_deps=dep;hole_name=na.binder_name;}inclrec(hole::holes)(n+1)t2|LetIn(na,b,_,t)->clrecholesn(subst1bt)|_->holesinletholes=clrec[]0tinList.revholesletevar_with_nameholes({CAst.v=id}aslid)=letmaph=matchh.hole_namewith|Anonymous->None|Nameid'->ifId.equalidid'thenSomehelseNoneinlethole=List.map_filtermapholesinmatchholewith|[]->letfoldhaccu=matchh.hole_namewith|Anonymous->accu|Nameid->id::accuinletmvl=List.fold_rightfoldholes[]inEClause.explain_no_such_bound_variablemvllid|h::_->h.hole_evarletevar_of_binderholes=function|NamedHyps->evar_with_nameholess|AnonHypn->tryletnondeps=List.filter(funhole->nothole.hole_deps)holesinleth=List.nthnondeps(predn)inh.hole_evarwithewhenCErrors.noncriticale->user_errPp.(str"No such binder.")letsolve_evar_clausesigmaunifyholes=function|NoBindings->sigma|ImplicitBindingslargs->letmaph=ifh.hole_depsthenSomeh.hole_evarelseNoneinletevs=List.map_filtermapholesinletlen=List.lengthevsinifInt.equallen(List.lengthlargs)thenletfoldsigmaevarg=unifysigmaevarginletsigma=List.fold_left2foldsigmaevslargsinsigmaelseEClause.error_not_right_number_missing_argumentslen|ExplicitBindingslbind->let()=EClause.check_bindingslbindinletfoldsigma{CAst.v=(binder,c)}=letev=evar_of_binderholesbinderinunifysigmaevcinletsigma=List.fold_leftfoldsigmalbindinsigmaletunify_bindingssigmaunifyty=letholes=make_evar_clausesigmatyinsolve_evar_clausesigmaunifyholesendletspecialize(c,lbind)ipat=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlettyp_of_c=Retyping.get_type_ofenvsigmacinletsigma,term,typ=matchlbindwith|NoBindings->sigma,c,typ_of_c|ExplicitBindings_|ImplicitBindings_->letctx,ty=decompose_prod_declssigmatyp_of_cin(* Create a new context where variables mentioned further in the telescope
are turned into evars that live in the telescope context. This allows
instantiating each evar with the original variable as a default value.
For instance, on Γ := [x : A, y : B{x}, z : C{x, y}] it produces evars
[x : A ⊢ ?X : A]
[x : A, y : B{?X{x}} ⊢ ?Y : B{?X{x}}]
[x : A, y : B{?X{x}}, z : C{?X{x}, ?Y{x, y}} ⊢ ?Z : C{?X{x}, ?Y{x, y}}]
and returns the context
Δ := [x : A, y : B{?X{x}}, z : C{?X{x}, ?Y{x, y}}]
together with a substitution [?X, ?Y, ?Z] : Γ ⊢ Δ.
*)letopenRelDeclinletrecinstantiatesigmaenvsubstaccu=function|[]->sigma,subst,rel_contextenv,List.revaccu|LocalAssum(na,t)::decls->lett=Vars.esubstVars.lift_substituendsubsttinletenv=push_rel(LocalAssum(na,t))envinletsigma,ev=Evarutil.new_evarenvsigma(lift1t)inletsubst=Esubst.subs_cons(Vars.make_substituendev)(Esubst.subs_shft(1,subst))ininstantiatesigmaenvsubst((env,ev)::accu)decls|LocalDef(na,b,t)::decls->letb=Vars.esubstVars.lift_substituendsubstbinlett=Vars.esubstVars.lift_substituendsubsttinletenv=push_rel(LocalDef(na,b,t))envinletsubst=Esubst.subs_liftsubstininstantiatesigmaenvsubstaccudeclsinletsigma,subst,nctx,holes=instantiatesigmaenv(Esubst.subs_id0)[](List.revctx)inletnty=Vars.esubstVars.lift_substituendsubsttyin(* Solve holes with the provided bindings *)letunifysigmanc=letenv,ev=List.nthholesninEvarconv.unifyenvsigmaCONVevcinletsigma=Specialize.unify_bindingssigmaunifytyp_of_clbindin(* Instantiate unsolved holes with their default value *)letfoldsigma(env,ev)=ifisEvarsigmaevthenEvarconv.unifyenvsigmaCONVev(mkRel1)elsesigmainletsigma=List.fold_leftfoldsigmaholesin(* Requantify the proof term and its type *)letargs=Context.Rel.instance_listmkRel0ctxinletnc=applist(c,List.map(func->Vars.esubstVars.lift_substituendsubstc)args)inletrecrebuildrelsctxcty=matchctxwith|[]->c,ty|decl::ctx->letlifts=Int.Set.fold(funnaccu->Int.Set.add(n-1)accu)sInt.Set.emptyinletc,ty,rels=(* We always keep let bindings *)ifRelDecl.is_local_defdecl||Int.Set.mem1relsthenletrels=lift(Int.Set.remove1rels)inletrels=RelDecl.fold_constr(funcaccu->Int.Set.unionaccu(free_relssigmac))declrelsinmkLambda_or_LetIndeclc,mkProd_or_LetIndeclty,relselsesubst1mkProp(* dummy *)c,subst1mkPropty,liftrelsinrebuildrelsctxctyinletrels=Int.Set.union(free_relssigmanc)(free_relssigmanty)inletnc,nty=rebuildrelsnctxncntyinsigma,nc,ntyinlettac=matchEConstr.kindsigma(fst(EConstr.decompose_appsigma(snd(EConstr.decompose_lambda_declssigmac))))with|VaridwhenId.List.memid(Tacmach.pf_ids_of_hypsgl)->(* Like assert (id:=id args) but with the concept of specialization *)letipat=matchipatwithNone->Some(CAst.make(IntroNaming(IntroIdentifierid)))|_->ipatinletnaming,tac=prepare_intros_optfalseIntroAnonymousMoveLastipatinletrepl=do_replace(Someid)namingin(* "specialize H ... as H", "specialize H ...": do not clear (cleared implicitly at replacing time) *)(* "specialize H ... as H'", "specialize H ... as ?H": keep a copy by convention *)(* "specialize H ... as any_other_pattern": clear *)letdoclear=matchipatwith|Some{CAst.v=IntroNaming(IntroIdentifier_|IntroFresh_)}->false|_->trueinlettac=ifdoclearthenfunid'->Tacticals.tclTHEN(clear[id])(tacid')elsetacinTacticals.tclTHENFIRST(assert_before_then_genreplnamingtyptac)(exact_no_checkterm)|_->matchipatwith|None->(* Like generalize with extra support for "with" bindings *)(* even though the "with" bindings forces full application *)(* TODO: add intro to be more homogeneous. It will break
scripts but will be easy to fix *)(Tacticals.tclTHENLAST(cuttyp)(exact_no_checkterm))|Some_asipat->(* Like pose proof with extra support for "with" bindings *)(* even though the "with" bindings forces full application *)letnaming,tac=prepare_intros_optfalseIntroAnonymousMoveLastipatinTacticals.tclTHENFIRST(assert_before_then_genfalsenamingtyptac)(exact_no_checkterm)inTacticals.tclTHEN(Proofview.Unsafe.tclEVARSsigma)tacend(*****************************)(* Ad hoc unfold *)(*****************************)(* The two following functions should already exist, but found nowhere *)(* Unfolds x by its definition everywhere *)letunfold_bodyx=letopenContext.Named.DeclarationinProofview.Goal.enterbeginfungl->(* We normalize the given hypothesis immediately. *)letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinletxval=matchEnviron.lookup_namedxenvwith|LocalAssum_->error(VariableHasNoValuex)|LocalDef(_,xval,_)->xvalinletxval=EConstr.of_constrxvalinTacticals.afterHypxbeginfunaft->lethl=List.fold_right(fundeclcl->(NamedDecl.get_iddecl,InHyp)::cl)aft[]inletrfun__c=replace_varssigma[x,xval]cinletreducthh=reduct_in_hyp~check:false~reorder:falserfunhinletreductc=reduct_in_concl~cast:false~check:false(rfun,DEFAULTcast)inTacticals.tclTHENLIST[Tacticals.tclMAPreducthhl;reductc]endendletdest_intro_patternswith_evarsavoidthindestpattac=intro_patterns_corewith_evarsavoid[]thindestNone0tacpatletcoq_heq_ref=lazy(Coqlib.lib_ref"core.JMeq.type")letcompare_upto_variablessigmaxy=letreccomparexy=if(isVarsigmax||isRelsigmax)&&(isVarsigmay||isRelsigmay)thentrueelsecompare_constrsigmacomparexyincomparexyletspecialize_eqsid=letopenContext.Rel.DeclarationinProofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletty=Tacmach.pf_get_hyp_typidglinletevars=ref(Proofview.Goal.sigmagl)inletunifenvevarsc1c2=compare_upto_variables!evarsc1c2&&(matchEvarconv.unify_delayenv!evarsc1c2with|sigma->evars:=sigma;true|exceptionEvarconv.UnableToUnify_->false)inletrecauxin_eqsctxaccty=matchEConstr.kind!evarstywith|Prod(na,t,b)->(matchEConstr.kind!evarstwith|App(eq,[|eqty;x;y|])whenis_lib_refenv!evars"core.eq.type"eq->letc=ifnoccur_between!evars1(List.lengthctx)xthenyelsexinletpt=mkApp(eq,[|eqty;c;c|])inletind=destInd!evarseqinletp=mkApp(mkConstructUi(ind,0),[|eqty;c|])inifunif(push_rel_contextctxenv)evarspttthenauxtruectx(mkApp(acc,[|p|]))(subst1pb)elseacc,in_eqs,ctx,ty|App(heq,[|eqty;x;eqty';y|])whenisRefXenv!evars(Lazy.forcecoq_heq_ref)heq->leteqt,c=ifnoccur_between!evars1(List.lengthctx)xtheneqty',yelseeqty,xinletpt=mkApp(heq,[|eqt;c;eqt;c|])inletind=destInd!evarsheqinletp=mkApp(mkConstructUi(ind,0),[|eqt;c|])inifunif(push_rel_contextctxenv)evarspttthenauxtruectx(mkApp(acc,[|p|]))(subst1pb)elseacc,in_eqs,ctx,ty|_->ifin_eqsthenacc,in_eqs,ctx,tyelseletsigma,e=Evarutil.new_evar(push_rel_contextctxenv)!evarstinevars:=sigma;auxfalse(LocalDef(na,e,t)::ctx)(mkApp(lift1acc,[|mkRel1|]))b)|t->acc,in_eqs,ctx,tyinletacc,worked,ctx,ty=auxfalse[](mkVarid)tyinletctx'=nf_rel_context_evar!evarsctxinletctx''=List.map(function|LocalDef(n,k,t)whenisEvar!evarsk->LocalAssum(n,t)|decl->decl)ctx'inletty'=it_mkProd_or_LetIntyctx''inletacc'=it_mkLambda_or_LetInaccctx''inletty'=Tacred.whd_simplenv!evarsty'andacc'=Tacred.whd_simplenv!evarsacc'inletty'=Evarutil.nf_evar!evarsty'inifworkedthenTacticals.tclTHENFIRST(internal_cuttrueidty')(exact_no_check((* refresh_universes_strict *)acc'))elseletinfo=Exninfo.reify()inTacticals.tclFAIL~info(str"Nothing to do in hypothesis "++Id.printid)endletspecialize_eqsid=Proofview.Goal.enterbeginfungl->letmsg=str"Specialization not allowed on dependent hypotheses"inProofview.tclOR(clear[id])(fun(_,info)->Tacticals.tclZEROMSG~infomsg)>>=fun()->specialize_eqsidendletexfalso=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglinlet(sigma,f)=Evd.fresh_globalenvsigma(Coqlib.lib_ref"core.False.type")inlet(ind,_)=reduce_to_atomic_indenvsigmafinlets=Retyping.get_sort_family_ofenvsigma(Proofview.Goal.conclgl)inletsigma,elimc=find_ind_eliminatorenvsigma(fstind)sinletelimc=mkConstUelimcinletelimt=Retyping.get_type_ofenvsigmaelimcinletclause=mk_clenv_fromenvsigma(elimc,elimt)inProofview.tclTHEN(Proofview.Unsafe.tclEVARSsigma)(Clenv.res_pfclause~flags:(elim_flags())~with_evars:false)end(************************************************)(* Tactics related with logic connectives *)(************************************************)(* Reflexivity tactics *)let(forward_setoid_reflexivity,setoid_reflexivity)=Hook.make()letmaybe_betadeltaiota_conclallowredgl=letconcl=Tacmach.pf_conclglinletsigma=Tacmach.projectglinifnotallowredthenconclelseletenv=Proofview.Goal.envglinwhd_allenvsigmaconclletreflexivity_redallowred=Proofview.Goal.enterbeginfungl->(* PL: usual reflexivity don't perform any reduction when searching
for an equality, but we may need to do some when called back from
inside setoid_reflexivity (see Optimize cases in setoid_replace.ml). *)letenv=Tacmach.pf_envglinletsigma=Tacmach.projectglinletconcl=maybe_betadeltaiota_conclallowredglinmatchmatch_with_equality_typeenvsigmaconclwith|None->letinfo=Exninfo.reify()inProofview.tclZERO~infoNoEquationFound|Some_->one_constructor1NoBindingsendletreflexivity=Proofview.tclORELSE(reflexivity_redfalse)beginfunction(e,info)->matchewith|NoEquationFound->Hook.getforward_setoid_reflexivity|e->Proofview.tclZERO~infoeendletintros_reflexivity=(Tacticals.tclTHENintrosreflexivity)(* Symmetry tactics *)(* This tactic first tries to apply a constant named sym_eq, where eq
is the name of the equality predicate. If this constant is not
defined and the conclusion is a=b, it solves the goal doing (Cut
b=a;Intro H;Case H;Constructor 1) *)let(forward_setoid_symmetry,setoid_symmetry)=Hook.make()(* This is probably not very useful any longer *)letprove_symmetryhdcncleq_kind=letsymc=matcheq_kindwith|MonomorphicLeibnizEq(c1,c2)->mkApp(hdcncl,[|c2;c1|])|PolymorphicLeibnizEq(typ,c1,c2)->mkApp(hdcncl,[|typ;c2;c1|])|HeterogenousEq(t1,c1,t2,c2)->mkApp(hdcncl,[|t2;c2;t1;c1|])inTacticals.tclTHENFIRST(cutsymc)(Tacticals.tclTHENLIST[intro;Tacticals.onLastHypsimplest_case;one_constructor1NoBindings])letmatch_with_equationc=Proofview.tclEVARMAP>>=funsigma->Proofview.tclENV>>=funenv->tryletres=match_with_equationenvsigmacinProofview.tclUNITreswithNoEquationFoundasexn->let_,info=Exninfo.captureexninProofview.tclZERO~infoNoEquationFoundletsymmetry_redallowred=Proofview.Goal.enterbeginfungl->(* PL: usual symmetry don't perform any reduction when searching
for an equality, but we may need to do some when called back from
inside setoid_reflexivity (see Optimize cases in setoid_replace.ml). *)letconcl=maybe_betadeltaiota_conclallowredglinmatch_with_equationconcl>>=funwith_eqn->matchwith_eqnwith|Someeq_data,_,_->Tacticals.tclTHEN(convert_concl~cast:false~check:falseconclDEFAULTcast)(Tacticals.pf_constr_of_globaleq_data.sym>>=apply)|None,eq,eq_kind->prove_symmetryeqeq_kindendletsymmetry=Proofview.tclORELSE(symmetry_redfalse)beginfunction(e,info)->matchewith|NoEquationFound->Hook.getforward_setoid_symmetry|e->Proofview.tclZERO~infoeendlet(forward_setoid_symmetry_in,setoid_symmetry_in)=Hook.make()letsymmetry_inid=Proofview.Goal.enterbeginfungl->letsigma,ctype=Tacmach.pf_type_ofgl(mkVarid)inletsign,t=decompose_prod_declssigmactypeintclEVARSTHENsigma(Proofview.tclORELSEbeginmatch_with_equationt>>=fun(_,hdcncl,eq)->letsymccl=matcheqwith|MonomorphicLeibnizEq(c1,c2)->mkApp(hdcncl,[|c2;c1|])|PolymorphicLeibnizEq(typ,c1,c2)->mkApp(hdcncl,[|typ;c2;c1|])|HeterogenousEq(t1,c1,t2,c2)->mkApp(hdcncl,[|t2;c2;t1;c1|])inTacticals.tclTHENS(cut(EConstr.it_mkProd_or_LetInsymcclsign))[intro_replacingid;Tacticals.tclTHENLIST[intros;symmetry;apply(mkVarid);assumption]]endbeginfunction(e,info)->matchewith|NoEquationFound->Hook.getforward_setoid_symmetry_inid|e->Proofview.tclZERO~infoeend)endletintros_symmetry=Tacticals.onClause(function|None->Tacticals.tclTHENintrossymmetry|Someid->symmetry_inid)(* Transitivity tactics *)(* This tactic first tries to apply a constant named eq_trans, where eq
is the name of the equality predicate. If this constant is not
defined and the conclusion is a=b, it solves the goal doing
Cut x1=x2;
[Cut x2=x3; [Intros e1 e2; Case e2;Assumption
| Idtac]
| Idtac]
--Eduardo (19/8/97)
*)let(forward_setoid_transitivity,setoid_transitivity)=Hook.make()(* This is probably not very useful any longer *)letprove_transitivityhdcncleq_kindt=Proofview.Goal.enterbeginfungl->leteq1,eq2=matcheq_kindwith|MonomorphicLeibnizEq(c1,c2)->mkApp(hdcncl,[|c1;t|]),mkApp(hdcncl,[|t;c2|])|PolymorphicLeibnizEq(typ,c1,c2)->mkApp(hdcncl,[|typ;c1;t|]),mkApp(hdcncl,[|typ;t;c2|])|HeterogenousEq(typ1,c1,typ2,c2)->letenv=Proofview.Goal.envglinletsigma=Tacmach.projectglinlettypt=Retyping.get_type_ofenvsigmatinmkApp(hdcncl,[|typ1;c1;typt;t|]),mkApp(hdcncl,[|typt;t;typ2;c2|])inTacticals.tclTHENFIRST(cuteq2)(Tacticals.tclTHENFIRST(cuteq1)(Tacticals.tclTHENLIST[Tacticals.tclDO2intro;Tacticals.onLastHypsimplest_case;assumption]))endlettransitivity_redallowredt=Proofview.Goal.enterbeginfungl->(* PL: usual transitivity don't perform any reduction when searching
for an equality, but we may need to do some when called back from
inside setoid_reflexivity (see Optimize cases in setoid_replace.ml). *)letconcl=maybe_betadeltaiota_conclallowredglinmatch_with_equationconcl>>=funwith_eqn->matchwith_eqnwith|Someeq_data,_,_->Tacticals.tclTHEN(convert_concl~cast:false~check:falseconclDEFAULTcast)(matchtwith|None->Tacticals.pf_constr_of_globaleq_data.trans>>=eapply|Somet->Tacticals.pf_constr_of_globaleq_data.trans>>=funtrans->apply_list[trans;t])|None,eq,eq_kind->matchtwith|None->letinfo=Exninfo.reify()inTacticals.tclZEROMSG~info(str"etransitivity not supported for this relation.")|Somet->prove_transitivityeqeq_kindtendlettransitivity_gent=Proofview.tclORELSE(transitivity_redfalset)beginfunction(e,info)->matchewith|NoEquationFound->Hook.getforward_setoid_transitivityt|e->Proofview.tclZERO~infoeendletetransitivity=transitivity_genNonelettransitivityt=transitivity_gen(Somet)letintros_transitivityn=Tacticals.tclTHENintros(transitivity_genn)letconstr_eq~strictxy=letfail~info=Tacticals.tclFAIL~info(str"Not equal")inletfail_universes~info=Tacticals.tclFAIL~info(str"Not equal (due to universes)")inProofview.Goal.enterbeginfungl->letenv=Tacmach.pf_envglinletevd=Tacmach.projectglinmatchEConstr.eq_constr_universesenvevdxywith|Somecsts->ifstrictthenifUState.check_universe_constraints(Evd.evar_universe_contextevd)cststhenProofview.tclUNIT()elseletinfo=Exninfo.reify()infail_universes~infoelseletcsts=UnivProblem.Set.forcecstsinbeginmatchEvd.add_universe_constraintsevdcstswith|evd->Proofview.Unsafe.tclEVARSevd|exception(UGraph.UniverseInconsistency_ase)->let_,info=Exninfo.captureeinfail_universes~infoend|None->letinfo=Exninfo.reify()infail~infoendletunify?(state=TransparentState.full)xy=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglintryletcore_flags={(default_unify_flags()).core_unify_flagswithmodulo_delta=state;modulo_conv_on_closed_terms=Somestate}in(* What to do on merge and subterm flags?? *)letflags={(default_unify_flags())withcore_unify_flags=core_flags;merge_unify_flags=core_flags;subterm_unify_flags={core_flagswithmodulo_delta=TransparentState.empty}}inletsigma=w_unify(Tacmach.pf_envgl)sigmaConversion.CONV~flagsxyinProofview.Unsafe.tclEVARSsigmawithewhennoncriticale->lete,info=Exninfo.captureeinProofview.tclZERO~info(PretypeError(env,sigma,CannotUnify(x,y,None)))endletevarconv_unify?(state=TransparentState.full)?(with_ho=true)xy=Proofview.Goal.enterbeginfungl->letenv=Proofview.Goal.envglinletsigma=Proofview.Goal.sigmaglintryletflags=Evarconv.default_flags_ofstateinletsigma=Evarconv.unify~flags~with_hoenvsigmaConversion.CONVxyinProofview.Unsafe.tclEVARSsigmawithewhennoncriticale->lete,info=Exninfo.captureeinProofview.tclZERO~info(PretypeError(env,sigma,CannotUnify(x,y,None)))end(** [tclWRAPFINALLY before tac finally] runs [before] before each
entry-point of [tac] and passes the result of [before] to
[finally], which is then run at each exit-point of [tac],
regardless of whether it succeeds or fails. Said another way, if
[tac] succeeds, then it behaves as [before >>= fun v -> tac >>= fun
ret -> finally v <*> tclUNIT ret]; otherwise, if [tac] fails with
[e], it behaves as [before >>= fun v -> finally v <*> tclZERO
e]. Note that if [tac] succeeds [n] times before finally failing,
[before] and [finally] are both run [n+1] times (once around each
succuess, and once more around the final failure). *)(* We should probably export this somewhere, but it's not clear
where. As per
https://github.com/coq/coq/pull/12197#discussion_r418480525 and
https://gitter.im/coq/coq?at=5ead5c35347bd616304e83ef, we don't
export it from Proofview, because it seems somehow not primitive
enough. We don't export it from this file because it is more of a
tactical than a tactic. But we also don't export it from Tacticals
because all of the non-New tacticals there operate on `tactic`, not
`Proofview.tactic`, and all of the `New` tacticals that deal with
multi-success things are focussing, i.e., apply their arguments on
each goal separately (and it even says so in the comment on `New`),
whereas it's important that `tclWRAPFINALLY` doesn't introduce
extra focussing. *)letrectclWRAPFINALLYbeforetacfinally=letopenProofviewinletopenProofview.Notationsinbefore>>=funv->tclCASEtac>>=function|Fail(e,info)->finallyv>>=fun()->tclZERO~infoe|Next(ret,tac')->tclOR(finallyv>>=fun()->tclUNITret)(fune->tclWRAPFINALLYbefore(tac'e)finally)letwith_set_strategylvl_qlk=letglob_keyr=matchrwith|GlobRef.ConstRefsp->beginmatchStructures.PrimitiveProjections.find_optspwith|None->Evaluable.EvalConstRefsp|Somep->Evaluable.EvalProjectionRefpend|GlobRef.VarRefid->Evaluable.EvalVarRefid|_->user_errPp.(str"cannot set an inductive type or a constructor as transparent")inletkl=List.concat(List.map(fun(lvl,ql)->List.map(funq->(lvl,glob_keyq))ql)lvl_ql)intclWRAPFINALLY(Proofview.tclENV>>=funenv->letorig_kl=List.map(fun(_lvl,k)->(Conv_oracle.get_strategy(Environ.oracleenv)(Evaluable.to_kevaluablek),k))klin(* Because the global env might be desynchronized from the
proof-local env, we need to update the global env to have this
tactic play nicely with abstract.
TODO: When abstract no longer depends on Global, delete this
let orig_kl_global = ... in *)letorig_kl_global=List.map(fun(_lvl,k)->(Conv_oracle.get_strategy(Environ.oracle(Global.env()))(Evaluable.to_kevaluablek),k))klinletenv=List.fold_left(funenv(lvl,k)->Environ.set_oracleenv(Conv_oracle.set_strategy(Environ.oracleenv)(Evaluable.to_kevaluablek)lvl))envklinProofview.Unsafe.tclSETENVenv<*>(* TODO: When abstract no longer depends on Global, remove this
[Proofview.tclLIFT] block *)Proofview.tclLIFT(Proofview.NonLogical.make(fun()->List.iter(fun(lvl,k)->Global.set_strategy(Evaluable.to_kevaluablek)lvl)kl))<*>Proofview.tclUNIT(orig_kl,orig_kl_global))k(fun(orig_kl,orig_kl_global)->(* TODO: When abstract no longer depends on Global, remove this
[Proofview.tclLIFT] block *)Proofview.tclLIFT(Proofview.NonLogical.make(fun()->List.iter(fun(lvl,k)->Global.set_strategy(Evaluable.to_kevaluablek)lvl)orig_kl_global))<*>Proofview.tclENV>>=funenv->letenv=List.fold_left(funenv(lvl,k)->Environ.set_oracleenv(Conv_oracle.set_strategy(Environ.oracleenv)(Evaluable.to_kevaluablek)lvl))envorig_klinProofview.Unsafe.tclSETENVenv)moduleSimple=struct(** Simplified version of some of the above tactics *)letintrox=intro_move(Somex)MoveLastletapplyc=apply_with_bindings_genfalsefalse[None,(CAst.make(c,NoBindings))]leteapplyc=apply_with_bindings_genfalsetrue[None,(CAst.make(c,NoBindings))]letelimc=elimfalseNone(c,NoBindings)Noneletcasec=general_case_analysisfalseNone(c,NoBindings)letapply_inidc=apply_infalsefalseid[None,(CAst.make(c,NoBindings))]Noneend(** Tacticals defined directly in term of Proofview *)letreduce_after_refine=(* For backward compatibility reasons, we do not contract let-ins, but we unfold them. *)letredfunenvt=letflags=RedFlags.red_add_transparentRedFlags.allnoletTransparentState.emptyinclos_norm_flagsflagsenvtinreduct_in_concl~cast:false~check:false(redfun,DEFAULTcast)letrefine~typecheckc=Refine.refine~typecheckc<*>reduce_after_refinemoduleInternal=structletexplicit_intro_names=explicit_intro_namesletcheck_name_unicity=check_name_unicityletclear_gen=clear_genletclear_wildcards=clear_wildcardsletdest_intro_patterns=dest_intro_patternsend