123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233(************************************************************************)(* * 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) *)(************************************************************************)openNamesopenEnvironopenUtilopenVernacexpropenContext.Named.DeclarationmoduleNamedDecl=Context.Named.Declarationletall_collection_id=Id.of_string"All"letknown_names=Summary.ref[]~name:"proofusing-nameset"letis_known_nameid=CList.mem_assoc_fId.equalid!known_namesletrecclose_fwdenvsigmas=lets'=List.fold_left(funsdecl->letvb=matchdeclwith|LocalAssum_->Id.Set.empty|LocalDef(_,b,_)->Termops.global_vars_setenvsigmabinletvty=Termops.global_vars_setenvsigma(NamedDecl.get_typedecl)inletvbty=Id.Set.unionvbvtyinifId.Set.exists(funv->Id.Set.memvs)vbtythenId.Set.add(NamedDecl.get_iddecl)(Id.Set.unionsvbty)elses)s(EConstr.named_contextenv)inifId.Set.equalss'thenselseclose_fwdenvsigmas'letset_of_typeenvsigmafixnamesty=List.fold_rightId.Set.removefixnames(List.fold_left(funaccty->Id.Set.union(Termops.global_vars_setenvsigmaty)acc)Id.Set.emptyty)letfull_setfixnamesenv=letaddidids=ifList.mem_fId.equalidfixnamesthenidselseId.Set.addididsinList.fold_rightadd(List.mapNamedDecl.get_id(named_contextenv))Id.Set.emptyletwarn_all_collection_precedence=CWarnings.create~name:"all-collection-precedence"~category:Deprecation.Version.v8_15Pp.(fun()->str"Variable "++Id.printall_collection_id++str" is shadowed by Collection named "++Id.printall_collection_id++str" containing all variables.")letwarn_collection_precedence=CWarnings.create~name:"collection-precedence"~category:Deprecation.Version.v8_15Pp.(funid->Id.printid++str" is both name of a Collection and Variable, Collection "++Id.printid++str" takes precedence over Variable.")letwarn_redefine_collection=CWarnings.create~name:"collection-redefinition"~category:Deprecation.Version.v8_15Pp.(funid->str"New Collection definition of "++Id.printid++str" shadows the previous one.")letwarn_variable_shadowing=CWarnings.create~name:"variable-shadowing"~category:Deprecation.Version.v8_15Pp.(funid->Id.printid++str" was already a defined Variable, the name "++Id.printid++str" will refer to Collection when executing \"Proof using\" command.")leterr_redefine_all_collection()=CErrors.user_errPp.(str"\""++Id.printall_collection_id++str"\" is a predefined collection containing all variables. It can't be redefined.")letprocess_exprenvsigmafixnamesev_ty=letvariable_existsid=tryignore(lookup_namedidenv);truewith|Not_found->falseinletrecaux=function|SsEmpty->Id.Set.empty|SsType->v_ty|SsSingl{CAst.v=id}->set_of_idid|SsUnion(e1,e2)->Id.Set.union(auxe1)(auxe2)|SsSubstr(e1,e2)->Id.Set.diff(auxe1)(auxe2)|SsComple->Id.Set.diff(full_setfixnamesenv)(auxe)|SsFwdClosee->close_fwdenvsigma(auxe)andset_of_idid=ifId.equalidall_collection_idthenbeginifvariable_existsall_collection_idthenwarn_all_collection_precedence();full_setfixnamesenvendelseifis_known_nameidthenbeginifvariable_existsidthenwarn_collection_precedenceid;aux(CList.assoc_fId.equalid!known_names)endelseifList.exists(Id.equalid)fixnamesthenCErrors.user_errPp.(str"Invalid recursive variable: "++Id.printid++str".")elseifnot(List.exists(NamedDecl.get_id%>Id.equalid)(named_contextenv))thenCErrors.user_errPp.(str"Unknown variable: "++Id.printid++str".")elseId.Set.singletonidinauxeletprocess_exprenvsigmafixnamesety=letv_ty=set_of_typeenvsigmafixnamestyinlets=Id.Set.unionv_ty(process_exprenvsigmafixnamesev_ty)inId.Set.elementsstypet=Names.Id.Set.tletdefinition_usingenvevd~fixnames~using~terms=letl=process_exprenvevdfixnamesusingtermsinNames.Id.Set.(List.fold_rightaddlempty)letname_setidexpr=ifId.equalidall_collection_idthenerr_redefine_all_collection();ifis_known_nameidthenwarn_redefine_collectionid;ifTermops.is_section_variable(Global.env())idthenwarn_variable_shadowingid;known_names:=(id,expr)::!known_namesletminimize_hypsenvids=letrecauxids=letids'=Id.Set.fold(funidalive->letimpl_by_id=Id.Set.removeid(really_neededenv(Id.Set.singletonid))inifId.Set.is_emptyimpl_by_idthenaliveelseId.Set.diffaliveimpl_by_id)idsidsinifId.Set.equalidsids'thenidselseauxids'inauxidsletremove_ids_and_letsenvsids=letnot_idsid=not(Id.Set.memidids)inletno_bodyid=named_bodyidenv=Noneinletdepsid=really_neededenv(Id.Set.singletonid)in(Id.Set.filter(funid->not_idsid&&(no_bodyid||Id.Set.existsnot_ids(Id.Set.filterno_body(depsid))))s)letrecord_proof_usingexpr=Aux_file.record_in_aux"suggest_proof_using"exprletdebug_proof_using=CDebug.create~name:"proof-using"()(* Variables in [skip] come from after the definition, so don't count
for "All". Used in the variable case since the env contains the
variable itself. *)letsuggest_commonenvppidusedids_typskip=letmoduleS=Id.SetinletopenPpinletpr_setparenss=letwrapppcmds=ifparens&&S.cardinals>1thenstr"("++ppcmds++str")"elseppcmdsinwrap(prlist_with_sep(fun_->str" ")Id.print(S.elementss))inletneeded=minimize_hypsenv(remove_ids_and_letsenvusedids_typ)inletall_needed=really_neededenvneededinletall=List.fold_left(funalld->S.add(NamedDecl.get_idd)all)S.empty(named_contextenv)inletall=S.diffallskipinletfwd_typ=close_fwdenv(Evd.from_envenv)ids_typinlet()=debug_proof_using(fun()->str"All "++pr_setfalseall++fnl()++str"Type "++pr_setfalseids_typ++fnl()++str"needed "++pr_setfalseneeded++fnl()++str"all_needed "++pr_setfalseall_needed++fnl()++str"Type* "++pr_setfalsefwd_typ)inletvalid_exprs=ref[]inletvalide=valid_exprs:=e::!valid_exprsinifS.is_emptyneededthenvalid(str"Type");ifS.equalall_neededfwd_typthenvalid(str"Type*");ifS.equalallall_neededthenvalid(str"All");valid(pr_setfalseneeded);Feedback.msg_info(str"The proof of "++ppid++spc()++str"should start with one of the following commands:"++spc()++v0(prlist_with_sepcut(funx->str"Proof using "++x++str". ")!valid_exprs));ifAux_file.recording()thenlets=string_of_ppcmds(prlist_with_sep(fun_->str";")(funx->x)!valid_exprs)inrecord_proof_usingsletsuggest_proof_using=reffalselet()=Goptions.(declare_bool_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Suggest";"Proof";"Using"];optread=(fun()->!suggest_proof_using);optwrite=((:=)suggest_proof_using)})letsuggest_constantenvkn=if!suggest_proof_usingthenbeginletopenDeclarationsinletbody=lookup_constantknenvinletused=Id.Set.of_list@@List.mapNamedDecl.get_idbody.const_hypsinletids_typ=global_vars_setenvbody.const_typeinsuggest_commonenv(Printer.pr_constantenvkn)usedids_typId.Set.emptyendletsuggest_variableenvid=if!suggest_proof_usingthenbeginmatchlookup_namedidenvwith|LocalDef(_,body,typ)->letids_typ=global_vars_setenvtypinletids_body=global_vars_setenvbodyinletused=Id.Set.unionids_bodyids_typinsuggest_commonenv(Id.printid)usedids_typ(Id.Set.singletonid)|LocalAssum_->assertfalseendletvalue=refNoneletusing_to_stringus=Pp.string_of_ppcmds(Ppvernac.pr_usingus)letentry=Pcoq.eoi_entryG_vernac.section_subset_exprletusing_from_stringus=Pcoq.Entry.parseentry(Pcoq.Parsable.make(Gramlib.Stream.of_string("( "^us^" )")))letproof_using_opt_name=["Default";"Proof";"Using"]let()=Goptions.(declare_stringopt_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=proof_using_opt_name;optread=(fun()->Option.mapusing_to_string!value);optwrite=(funb->value:=Option.mapusing_from_stringb);})letget_default_proof_using()=!value