123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005(************************************************************************)(* * 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) *)(************************************************************************)openPpopenCErrorsopenTermopenUtilopenNamesopenConstropenContextopenEnvironopenDeclarationsopenEntriesopenType_errorsopenConstrexpropenConstrexpr_opsopenContext.Rel.DeclarationopenStructuresmoduleRelDecl=Context.Rel.Declaration(********** definition d'un record (structure) **************)lettypeclasses_strict=Goptions.declare_bool_option_and_ref~depr:false~key:["Typeclasses";"Strict";"Resolution"]~value:falselettypeclasses_unique=Goptions.declare_bool_option_and_ref~depr:false~key:["Typeclasses";"Unique";"Instances"]~value:falseletinterp_fields_evarsenvsigma~ninds~nparamsimpls_envnotsl=let_,sigma,impls,newfs,_=List.fold_left2(fun(env,sigma,uimpls,params,impls_env)nod->letsigma,(i,b,t),impl=matchdwith|Vernacexpr.AssumExpr({CAst.v=id},bl,t)->(* Temporary compatibility with the type-classes heuristics *)(* which are applied after the interpretation of bl and *)(* before the one of t otherwise (see #13166) *)lett=ifbl=[]thentelsemkCProdNbltinletsigma,t,impl=ComAssumption.interp_assumption~program_mode:falseenvsigmaimpls_env[]tinsigma,(id,None,t),impl|Vernacexpr.DefExpr({CAst.v=id},bl,b,t)->letsigma,(b,t),impl=ComDefinition.interp_definition~program_mode:falseenvsigmaimpls_envblNonebtinlett=matchtwithSomet->t|None->Retyping.get_type_ofenvsigmabinsigma,(id,Someb,t),implinletr=Retyping.relevance_of_typeenvsigmatinletimpls_env=matchiwith|Anonymous->impls_env|Nameid->Id.Map.addid(Constrintern.compute_internalization_dataenvsigmaidConstrintern.Methodtimpl)impls_envinletd=matchbwith|None->LocalAssum(make_annotir,t)|Someb->LocalDef(make_annotir,b,t)inList.iter(Metasyntax.set_notation_for_interpretationenvimpls_env)no;(EConstr.push_reldenv,sigma,impl::uimpls,d::params,impls_env))(env,sigma,[],[],impls_env)notslinlet_,_,sigma=Context.Rel.fold_outside~init:(env,0,sigma)(funf(env,k,sigma)->letsigma=RelDecl.fold_constr(funcsigma->ComInductive.maybe_unify_params_inenvsigma~ninds~nparams~binders:kc)fsigmainEConstr.push_relfenv,k+1,sigma)newfsinsigma,(impls,newfs)letcheck_anonymous_typeind=matchindwith|{CAst.v=CSort(Glob_term.UAnonymous{rigid=true})}->true|_->falseleterror_parameters_must_be_namedbk{CAst.loc;v=name}=matchbk,namewith|Default_,Anonymous->CErrors.user_err?loc(str"Record parameters must be named.")|_->()letcheck_parameters_must_be_named=function|CLocalDef(b,_,_)->error_parameters_must_be_nameddefault_binder_kindb|CLocalAssum(ls,bk,_ce)->List.iter(error_parameters_must_be_namedbk)ls|CLocalPattern{CAst.loc}->Loc.raise?loc(Gramlib.Stream.Error"pattern with quote not allowed in record parameters")(** [DataI.t] contains the information used in record interpretation,
it is a strict subset of [Ast.t] thus this should be
eventually removed or merged with [Ast.t] *)moduleDataI=structtypet={name:Id.t;arity:Constrexpr.constr_exproption(** declared sort for the record *);nots:Metasyntax.where_decl_notationlistlist(** notations for fields *);fs:Vernacexpr.local_decl_exprlist}end(** [DataR.t] contains record data after interpretation /
type-inference *)moduleDataR=structtypet={min_univ:Sorts.t;arity:Constr.t;implfs:Impargs.manual_implicitslist;fields:Constr.rel_declarationlist}endmoduleData=structtypeprojection_flags={pf_coercion:bool;pf_reversible:bool;pf_instance:bool;pf_priority:intoption;pf_locality:Goptions.option_locality;pf_canonical:bool;}typeraw_data=DataR.ttypet={id:Id.t;idbuild:Id.t;is_coercion:bool;proj_flags:projection_flagslist;rdata:raw_data;inhabitant_id:Id.t}endletbuild_type_telescopenewpsenv0sigma{DataI.arity;_}=matcharitywith|None->letuvarkind=Evd.univ_flexible_alginletsigma,s=Evd.new_sort_variableuvarkindsigmainsigma,(EConstr.mkSorts,s)|Somet->letenv=EConstr.push_rel_contextnewpsenv0inletpoly=matchtwith|{CAst.v=CSort(Glob_term.UAnonymous{rigid=true})}->true|_->falseinletimpls=Constrintern.empty_internalization_envinletsigma,s=Constrintern.interp_type_evars~program_mode:falseenvsigma~implstinletsred=Reductionops.whd_allnoletenvsigmasin(matchEConstr.kindsigmasredwith|Sorts'->lets'=EConstr.ESorts.kindsigmas'in(ifpolythenmatchEvd.is_sort_variablesigmas'with|Somel->letsigma=Evd.make_flexible_variablesigma~algebraic:truelinsigma,(s,s')|None->sigma,(s,s')elsesigma,(s,s'))|_->user_err?loc:(constr_loct)(str"Sort expected."))typetc_result=Impargs.manual_implicits(* Part relative to closing the definitions *)*UState.named_universes_entry*Entries.variance_entry*Constr.rel_context*DataR.tlist(* ps = parameter list *)lettypecheck_params_and_fieldsdefpolyudeclps(records:DataI.tlist):tc_result=letenv0=Global.env()in(* Special case elaboration for template-polymorphic inductives,
lower bound on introduced universes is Prop so that we do not miss
any Set <= i constraint for universes that might actually be instantiated with Prop. *)letis_template=List.exists(fun{DataI.arity;_}->Option.catacheck_anonymous_typetruearity)recordsinletenv0=ifnotpoly&&is_templatethenEnviron.set_universes_lboundenv0UGraph.Bound.Propelseenv0inletsigma,decl,variances=Constrintern.interp_cumul_univ_decl_optenv0udeclinlet()=List.itercheck_parameters_must_be_namedpsinletsigma,(impls_env,((_env1,newps),imps))=Constrintern.interp_context_evars~program_mode:falseenv0sigmapsinletsigma,typs=List.fold_left_map(build_type_telescopenewpsenv0)sigmarecordsinletarities=List.map(fun(typ,_)->EConstr.it_mkProd_or_LetIntypnewps)typsinletrelevances=List.map(fun(_,s)->Sorts.relevance_of_sorts)typsinletfoldaccu{DataI.name;_}arityr=EConstr.push_rel(LocalAssum(make_annot(Namename)r,arity))accuinletenv_ar=EConstr.push_rel_contextnewps(List.fold_left3foldenv0recordsaritiesrelevances)inletimpls_env=letids=List.map(fun{DataI.name;_}->name)recordsinletimps=List.map(fun_->imps)aritiesinConstrintern.compute_internalization_envenv0sigma~impls:impls_envConstrintern.Inductiveidsaritiesimpsinletninds=List.lengtharitiesinletnparams=List.lengthnewpsinletfoldsigma{DataI.nots;fs;_}=interp_fields_evarsenv_arsigma~ninds~nparamsimpls_envnotsfsinlet(sigma,data)=List.fold_left_mapfoldsigmarecordsinletsigma=Pretyping.solve_remaining_evarsPretyping.all_and_fail_flagsenv_arsigmainletfoldsigma(typ,sort)(_,newfs)=letuniv=ComInductive.Internal.compute_constructor_levelenv_arsigmanewfsinletuniv=ifSorts.is_spropsortthenunivelseifSorts.is_spropunivthenSorts.propelseunivinifnotdef&&is_impredicative_sortenv0sortthensigma,(sort,typ)elseletsigma=Evd.set_leq_sortenv_arsigmaunivsortinifSorts.is_smalluniv&&Option.cata(Evd.is_flexible_levelsigma)false(Evd.is_sort_variablesigmasort)then(* We can assume that the level in aritysort is not constrained
and clear it, if it is flexible *)Evd.set_eq_sortenv_arsigmaSorts.setsort,(univ,EConstr.mkSortuniv)elsesigma,(univ,typ)inlet(sigma,typs)=List.fold_left2_mapfoldsigmatypsdatain(* TODO: Have this use Declaredef.prepare_definition *)letsigma,(newps,ans)=Evarutil.finalizesigma(funnf->letnewps=List.map(RelDecl.map_constr_hetnf)newpsinletmap(implfs,fields)(min_univ,typ)=letfields=List.map(RelDecl.map_constr_hetnf)fieldsinletarity=nftypin{DataR.min_univ;arity;implfs;fields}inletans=List.map2mapdatatypsinnewps,ans)inletunivs=Evd.check_univ_decl~polysigmadeclinletcet=Pretyping.check_evarsenv0sigma(EConstr.of_constrt)inlet()=List.iter(iter_constrce)(List.revnewps)inimps,univs,variances,newps,anstyperecord_error=|MissingProjofId.t*Id.tlist|BadTypedProjofId.t*env*Type_errors.type_errorletwarn_cannot_define_projection=CWarnings.create~name:"cannot-define-projection"~category:"records"(funmsg->hov0msg)(* If a projection is not definable, we throw an error if the user
asked it to be a coercion or instance. Otherwise, we just print an info
message. The user might still want to name the field of the record. *)letwarning_or_error~infoflagsindsperr=letst=matcherrwith|MissingProj(fi,projs)->lets,have=ifList.lengthprojs>1then"s","were"else"","was"in(Id.printfi++strbrk" cannot be defined because the projection"++strs++spc()++prlist_with_seppr_commaId.printprojs++spc()++strhave++strbrk" not defined.")|BadTypedProj(fi,_ctx,te)->matchtewith|ElimArity(_,_,Some(_,_,(InType|InSet),InProp))->(Id.printfi++strbrk" cannot be defined because it is informative and "++Printer.pr_inductive(Global.env())indsp++strbrk" is not.")|ElimArity(_,_,Some(_,_,InType,InSet))->(Id.printfi++strbrk" cannot be defined because it is large and "++Printer.pr_inductive(Global.env())indsp++strbrk" is not.")|_->(Id.printfi++strbrk" cannot be defined because it is not typable.")inifflags.Data.pf_coercion||flags.Data.pf_instancethenuser_err~infost;warn_cannot_define_projection(hov0st)typefield_status=|NoProjectionofName.t|ProjectionofconstrexceptionNotDefinableofrecord_error(* This replaces previous projection bodies in current projection *)(* Undefined projs are collected and, at least one undefined proj occurs *)(* in the body of current projection then the latter can not be defined *)(* [c] is defined in ctxt [[params;fields]] and [l] is an instance of *)(* [[fields]] defined in ctxt [[params;x:ind]] *)letsubst_projectionfidlc=letlv=List.lengthlinletbad_projs=ref[]inletrecsubstrecdepthc=matchConstr.kindcwith|Relk->(* We are in context [[params;fields;x:ind;...depth...]] *)ifk<=depth+1thencelseifk-depth-1<=lvthenmatchList.nthl(k-depth-2)with|Projectiont->liftdeptht|NoProjection(Nameid)->bad_projs:=id::!bad_projs;mkRelk|NoProjectionAnonymous->user_err(str"Field "++Id.printfid++str" depends on the "++pr_nth(k-depth-1)++str" field which has no name.")elsemkRel(k-lv)|_->Constr.map_with_binderssuccsubstrecdepthcinletc'=lift1cin(* to get [c] defined in ctxt [[params;fields;x:ind]] *)letc''=substrec0c'inifnot(List.is_empty!bad_projs)thenraise(NotDefinable(MissingProj(fid,List.rev!bad_projs)));c''letinstantiate_possibly_recursive_typeinduntypesparamdeclsfields=letsubst=List.map_i(funi_->mkReli)1paramdeclsinletsubst'=List.initntypes(funi->mkIndU((ind,ntypes-i-1),u))inVars.substl_rel_context(subst@subst')fields(* We build projections *)(** Declare projection [ref] over [from] a coercion
or a typeclass instance according to [flags]. *)(* remove the last argument (it will become alway true) after deprecation phase
(started in 8.17, c.f. https://github.com/coq/coq/pull/16230) *)letdeclare_proj_coercion_instance~flagsreffrom~poly~with_coercion=ifwith_coercion&&flags.Data.pf_coercionthenbeginletcl=ComCoercion.class_of_globalfrominletlocal=flags.Data.pf_locality=Goptions.OptLocalinComCoercion.try_add_new_coercion_with_sourceref~local~poly~nonuniform:false~reversible:flags.Data.pf_reversible~source:clend;ifflags.Data.pf_instancethenbeginletenv=Global.env()inletsigma=Evd.from_envenvinletinfo=Typeclasses.{hint_priority=flags.Data.pf_priority;hint_pattern=None}inletlocal=matchflags.Data.pf_localitywith|Goptions.OptLocal->Hints.Local|Goptions.(OptDefault|OptExport)->Hints.Export|Goptions.OptGlobal->Hints.SuperGlobalinClasses.declare_instance~warn:trueenvsigma(Someinfo)localrefend(* TODO: refactor the declaration part here; this requires some
surgery as Evarutil.finalize is called too early in the path *)(** This builds and _declares_ a named projection, the code looks
tricky due to the term manipulation. It also handles declaring the
implicits parameters, coercion status, etc... of the projection;
this could be refactored as noted above by moving to the
higher-level declare constant API *)letbuild_named_proj~primitive~flags~poly~univs~uinstance~kindenvparamdeclsparamargsdeclimplsfidsubstnfitiiindspmiblifted_fieldsxrp=letccl=subst_projectionfidsubsttiinletbody,p_opt=matchdeclwith|LocalDef(_,ci,_)->subst_projectionfidsubstci,None|LocalAssum({binder_relevance=rci},_)->(* [ccl] is defined in context [params;x:rp] *)(* [ccl'] is defined in context [params;x:rp;x:rp] *)ifprimitivethenletproj_relevant=matchrciwithSorts.Irrelevant->false|Sorts.Relevant->trueinletp=Projection.Repr.makeindsp~proj_relevant~proj_npars:mib.mind_nparams~proj_arg:i(Label.of_idfid)inmkProj(Projection.makeptrue,mkRel1),Somepelseletccl'=liftn12cclinletp=mkLambda(x,lift1rp,ccl')inletbranch=it_mkLambda_or_LetIn(mkRelnfi)lifted_fieldsinletci=Inductiveops.make_case_infoenvindsprciLetStylein(* Record projections are always NoInvert because they're at
constant relevance *)mkCase(Inductive.contract_caseenv(ci,p,NoInvert,mkRel1,[|branch|])),Noneinletproj=it_mkLambda_or_LetIn(mkLambda(x,rp,body))paramdeclsinletprojtyp=it_mkProd_or_LetIn(mkProd(x,rp,ccl))paramdeclsinletunivs=matchfstunivswith|Entries.Monomorphic_entry->UState.Monomorphic_entryUniv.ContextSet.empty,sndunivs|Entries.Polymorphic_entryuctx->UState.Polymorphic_entryuctx,sndunivsinletentry=Declare.definition_entry~univs~types:projtypprojinletkind=Decls.IsDefinitionkindinletkn=tryDeclare.declare_constant~name:fid~kind(Declare.DefinitionEntryentry)withType_errors.TypeError(ctx,te)asexnwhennotprimitive->let_,info=Exninfo.captureexninExninfo.iraise(NotDefinable(BadTypedProj(fid,ctx,te)),info)inDeclare.definition_messagefid;letterm=matchp_optwith|Somep->let_=DeclareInd.declare_primitive_projectionpkninmkProj(Projection.makepfalse,mkRel1)|None->letproj_args=(*Rel 1 refers to "x"*)paramargs@[mkRel1]inmatchdeclwith|LocalDef_whenprimitive->body|_->applist(mkConstU(kn,uinstance),proj_args)inletrefi=GlobRef.ConstRefkninImpargs.maybe_declare_manual_implicitsfalserefiimpls;declare_proj_coercion_instance~flagsrefi(GlobRef.IndRefindsp)~poly~with_coercion:true;leti=ifis_local_assumdecltheni+1elseiin(Somekn,i,Projectionterm::subst)(** [build_proj] will build a projection for each field, or skip if
the field is anonymous, i.e. [_ : t] *)letbuild_projenvmibindspprimitivexrplifted_fields~polyparamdeclsparamargs~uinstance~kind~univs(nfi,i,kinds,subst)flagsdeclimpls=letfi=RelDecl.get_namedeclinletti=RelDecl.get_typedeclinlet(sp_proj,i,subst)=matchfiwith|Anonymous->(None,i,NoProjectionfi::subst)|Namefid->trybuild_named_proj~primitive~flags~poly~univs~uinstance~kindenvparamdeclsparamargsdeclimplsfidsubstnfitiiindspmiblifted_fieldsxrpwithNotDefinablewhyasexn->let_,info=Exninfo.captureexninwarning_or_error~infoflagsindspwhy;(None,i,NoProjectionfi::subst)in(nfi-1,i,{Structure.proj_name=fi;proj_true=is_local_assumdecl;proj_canonical=flags.Data.pf_canonical;proj_body=sp_proj}::kinds,subst)(** [declare_projections] prepares the common context for all record
projections and then calls [build_proj] for each one. *)letdeclare_projectionsindspunivs?(kind=Decls.StructureComponent)inhabitant_idflagsfieldimplsfields=letenv=Global.env()inlet(mib,mip)=Global.lookup_inductiveindspinletpoly=Declareops.inductive_is_polymorphicmibinletuinstance=matchfstunivswith|Polymorphic_entryuctx->Univ.UContext.instanceuctx|Monomorphic_entry->Univ.Instance.emptyinletparamdecls=Inductive.inductive_paramdecls(mib,uinstance)inletr=mkIndU(indsp,uinstance)inletrp=applist(r,Context.Rel.instance_listmkRel0paramdecls)inletparamargs=Context.Rel.instance_listmkRel1paramdeclsin(*def in [[params;x:rp]]*)letx=make_annot(Nameinhabitant_id)mip.mind_relevanceinletfields=instantiate_possibly_recursive_type(fstindsp)uinstancemib.mind_ntypesparamdeclsfieldsinletlifted_fields=Vars.lift_rel_context1fieldsinletprimitive=matchmib.mind_recordwith|PrimRecord_->true|FakeRecord|NotRecord->falseinlet(_,_,canonical_projections,_)=List.fold_left3(build_projenvmibindspprimitivexrplifted_fields~polyparamdeclsparamargs~uinstance~kind~univs)(List.lengthfields,0,[],[])flags(List.revfields)(List.revfieldimpls)inList.revcanonical_projectionsopenTypeclassesletload_structure_structure=Structure.registerstructureletcache_structureo=load_structure1oletsubst_structure(subst,obj)=Structure.substsubstobjletdischarge_structurex=Somexletrebuild_structures=Structure.rebuild(Global.env())sletinStruc:Structure.t->Libobject.obj=letopenLibobjectindeclare_object{(default_object"STRUCTURE")withcache_function=cache_structure;load_function=load_structure;subst_function=subst_structure;classify_function=(fun_->Substitute);discharge_function=discharge_structure;rebuild_function=rebuild_structure;}letdeclare_structure_entryo=Lib.add_leaf(inStruco)(** In the type of every projection, the record is bound to a variable named
using the first character of the record type. We rename it to avoid
collisions with names already used in the field types.
*)(** Get all names bound at the head of [t]. *)letrecadd_bound_names_constr(names:Id.Set.t)(t:constr):Id.Set.t=matchdestProdtwith|(b,_,t)->letnames=matchb.binder_namewith|Name.Anonymous->names|Name.Namen->Id.Set.addnnamesinadd_bound_names_constrnamest|exceptionDestKO->names(** Get all names bound in any record field. *)letbound_names_rdata{DataR.fields;_}:Id.Set.t=letadd_namesnamesfield=add_bound_names_constrnames(RelDecl.get_typefield)inList.fold_leftadd_namesId.Set.emptyfields(** Pick a variable name for a record, avoiding names bound in its fields. *)letdata_nameidrdata=letname=Id.of_string(Unicode.lowercase_first_char(Id.to_stringid))inNamegen.next_ident_awayname(bound_names_rdatardata)(** Main record declaration part:
The entry point is [definition_structure], which will match on the
declared [kind] and then either follow the regular record
declaration path to [declare_structure] or handle the record as a
class declaration with [declare_class].
*)(** [declare_structure] does two principal things:
- prepares and declares the low-level (mutual) inductive corresponding to [record_data]
- prepares and declares the corresponding record projections, mainly taken care of by
[declare_projections]
*)moduleRecord_decl=structtypet={mie:Entries.mutual_inductive_entry;records:Data.tlist;primitive_proj:bool;impls:DeclareInd.one_inductive_implslist;globnames:UState.named_universes_entry;global_univ_decls:Univ.ContextSet.toption;projunivs:Entries.universes_entry;ubinders:UnivNames.universe_binders;projections_kind:Decls.definition_object_kind;poly:bool;}endmoduleAst=structopenVernacexprtypet={name:Names.lident;is_coercion:coercion_flag;binders:local_binder_exprlist;cfs:(local_decl_expr*record_field_attr)list;idbuild:Id.t;sort:constr_exproption;default_inhabitant_id:Id.toption}letto_datai{name;cfs;sort;_}=letfs=List.mapfstcfsin{DataI.name=name.CAst.v;arity=sort;nots=List.map(fun(_,{rf_notation})->List.mapMetasyntax.prepare_where_notationrf_notation)cfs;fs}endletcheck_unique_namesrecords=letextract_nameacc(rf_decl,_)=matchrf_declwithVernacexpr.AssumExpr({CAst.v=Nameid},_,_)->id::acc|Vernacexpr.DefExpr({CAst.v=Nameid},_,_,_)->id::acc|_->accinletallnames=List.fold_left(funacc{Ast.name;cfs;_}->name.CAst.v::(List.fold_leftextract_nameacccfs))[]recordsinmatchList.duplicatesId.equalallnameswith|[]->()|id::_->user_err(str"Two objects have the same name"++spc()++quote(Id.printid)++str".")typekind_class=NotClass|RecordClass|DefClassletkind_class=letopenVernacexprinfunctionClasstrue->DefClass|Classfalse->RecordClass|Inductive_kw|CoInductive|Variant|Record|Structure->NotClassletcheck_prioritieskindrecords=letopenVernacexprinletisnot_class=kind_classkind<>RecordClassinlethas_priority{Ast.cfs;_}=List.exists(fun(_,{rf_priority})->not(Option.is_emptyrf_priority))cfsinifisnot_class&&List.existshas_priorityrecordsthenuser_errPp.(str"Priorities only allowed for type class substructures.")letextract_record_datarecords=letdata=List.mapAst.to_datairecordsinletpss=List.map(fun{Ast.binders;_}->binders)recordsinletps=matchpsswith|[]->CErrors.anomaly(str"Empty record block.")|ps::rem->leteq_local_bindersbl1bl2=List.equallocal_binder_eqbl1bl2inlet()=ifnot(List.for_all(eq_local_bindersps)rem)thenuser_err(str"Parameters should be syntactically the \
same for each inductive type.")inpsinps,dataletimplicits_of_contextctx=List.map(funname->CAst.make(Some(name,true)))(List.rev(Anonymous::(List.filter_map(function|LocalDef_->None|LocalAssum_asd->Some(RelDecl.get_named))ctx)))(* deprecated in 8.16, to be removed at the end of the deprecation phase
(c.f., https://github.com/coq/coq/pull/15802 ) *)letwarn_future_coercion_class_constructor=CWarnings.create~name:"future-coercion-class-constructor"~category:"records"~default:CWarnings.AsErrorPp.(fun()->str"'Class >' currently does nothing. Use 'Class' instead.")(* deprecated in 8.17, to be removed at the end of the deprecation phase
(c.f., https://github.com/coq/coq/pull/16230 ) *)letwarn_future_coercion_class_field=CWarnings.create~name:"future-coercion-class-field"~category:"records"Pp.(fundefinitional->strbrk"A coercion will be introduced instead of an instance in future versions when using ':>' in 'Class' declarations. "++strbrk"Replace ':>' with '::' (or use '#[global] Existing Instance field.' for compatibility with Coq < 8.17). Beware that the default locality for '::' is #[export], as opposed to #[global] for ':>' currently."++strbrk(ifdefinitionalthen""else" Add an explicit #[global] attribute to the field if you need to keep the current behavior. For example: \"Class foo := { #[global] field :: bar }.\""))letcheck_proj_flagskindrf=letopenVernacexprinletpf_coercion,pf_reversible=matchrf.rf_coercionwith(* replace "kind_class kind = NotClass" with true after deprecation phase *)|AddCoercion->kind_classkind=NotClass,Option.defaulttruerf.rf_reversible|NoCoercion->ifrf.rf_reversible<>NonethenAttributes.(unsupported_attributes[CAst.make("reversible (without :>)",VernacFlagEmpty)]);false,falseinletpf_instance=matchrf.rf_instancewithNoInstance->false|BackInstance->true|BackInstanceWarning->kind_classkind<>NotClassinletpf_priority=rf.rf_priorityinletpf_locality=beginmatchrf.rf_coercion,rf.rf_instancewith|NoCoercion,NoInstance->ifrf.rf_locality<>Goptions.OptDefaultthenAttributes.(unsupported_attributes[CAst.make("locality (without :> or ::)",VernacFlagEmpty)])|AddCoercion,NoInstance->ifrf.rf_locality=Goptions.OptExportthenAttributes.(unsupported_attributes[CAst.make("export (without ::)",VernacFlagEmpty)])|_->()end;rf.rf_localityin(* remove following let after deprecation phase (started in 8.17,
c.f., https://github.com/coq/coq/pull/16230 ) *)letpf_locality=matchrf.rf_instance,rf.rf_localitywith|BackInstanceWarning,Goptions.OptDefault->Goptions.OptGlobal|_->pf_localityinletpf_canonical=rf.rf_canonicalinData.{pf_coercion;pf_reversible;pf_instance;pf_priority;pf_locality;pf_canonical}(* remove the definitional argument at the end of the deprecation phase
(started in 8.17)
(c.f., https://github.com/coq/coq/pull/16230 ) *)letpre_process_structure?(definitional=false)udeclkind~poly(records:Ast.tlist)=let()=check_unique_namesrecordsinlet()=check_prioritieskindrecordsinletps,data=extract_record_datarecordsinletimpargs,univs,variances,params,data=(* In theory we should be able to use
[Notation.with_notation_protection], due to the call to
Metasyntax.set_notation_for_interpretation, however something
is messing state beyond that.
*)Vernacstate.System.protect(fun()->typecheck_params_and_fields(kind=Classtrue)polyudeclpsdata)()inletadjust_implsimpls=matchkind_classkindwith|NotClass->impargs@[CAst.makeNone]@impls|_->implicits_of_contextparams@implsinletdata=List.map(fun({DataR.implfs;_}asd)->{dwithDataR.implfs=List.mapadjust_implsimplfs})datainletmaprdata{Ast.name;is_coercion;cfs;idbuild;default_inhabitant_id;_}=letproj_flags=List.map(fun(_,rf)->check_proj_flagskindrf)cfsinletinhabitant_id=matchdefault_inhabitant_id,kind_classkindwith|None,NotClass->data_namename.CAst.vrdata|None,_->Namegen.next_ident_awayname.CAst.v(Termops.vars_of_env(Global.env()))|Somen,_->ninletis_coercion=matchis_coercionwithAddCoercion->true|NoCoercion->falseinifkind_classkind<>NotClassthenbeginifis_coercionthenwarn_future_coercion_class_constructor();ifList.exists(function(_,Vernacexpr.{rf_instance=BackInstanceWarning;_})->true|_->false)cfsthenwarn_future_coercion_class_fielddefinitionalend;{Data.id=name.CAst.v;idbuild;rdata;is_coercion;proj_flags;inhabitant_id}inletdata=List.map2mapdatarecordsinletprojections_kind=Decls.(matchkind_classkindwithNotClass->StructureComponent|_->Method)inimpargs,params,univs,variances,projections_kind,dataletinterp_structure_core~cumulativefinite~univs~variances~primitive_projimpargsparamstemplate~projections_kinddata=letnparams=List.lengthparamsinlet(univs,ubinders)=univsinletpoly,projunivs=matchunivswith|UState.Monomorphic_entry_->false,Entries.Monomorphic_entry|UState.Polymorphic_entryuctx->true,Entries.Polymorphic_entryuctxinletntypes=List.lengthdatainletmk_blocki{Data.id;idbuild;rdata={DataR.arity;fields;_};_}=letnfields=List.lengthfieldsinletargs=Context.Rel.instance_listmkRelnfieldsparamsinletind=applist(mkRel(ntypes-i+nparams+nfields),args)inlettype_constructor=it_mkProd_or_LetInindfieldsin{mind_entry_typename=id;mind_entry_arity=arity;mind_entry_consnames=[idbuild];mind_entry_lc=[type_constructor]}inletblocks=List.mapimk_blockdatainletind_univs,global_univ_decls=matchblocks,datawith|[entry],[data]->letconcl=Somedata.Data.rdata.DataR.min_univinletenv_ar_params=Environ.push_rel_contextparams(Global.env())inComInductive.compute_template_inductive~user_template:template~env_ar_params~ctx_params:params~univ_entry:univsentryconcl|_->beginmatchtemplatewith|Sometrue->user_errPp.(str"Template-polymorphism not allowed with mutual records.")|Somefalse|None->matchunivswith|UState.Polymorphic_entryuctx->Polymorphic_ind_entryuctx,Univ.ContextSet.empty|UState.Monomorphic_entryuctx->Monomorphic_ind_entry,uctxendinletprimitive=primitive_proj&&List.for_all(fun{Data.rdata={DataR.fields;_};_}->List.existsis_local_assumfields)datainletglobnames,global_univ_decls=matchind_univswith|Monomorphic_ind_entry->(univs,ubinders),Someglobal_univ_decls|Template_ind_entry_->(univs,ubinders),Someglobal_univ_decls|Polymorphic_ind_entry_->(univs,UnivNames.empty_binders),Noneinletunivs=ind_univsinletvariance=ComInductive.variance_of_entry~cumulative~variancesunivsinletmie={mind_entry_params=params;mind_entry_record=Some(ifprimitivethenSome(Array.map_of_list(funa->a.Data.inhabitant_id)data)elseNone);mind_entry_finite=finite;mind_entry_inds=blocks;mind_entry_private=None;mind_entry_universes=univs;mind_entry_variance=variance;}inletimpls=List.map(fun_->impargs,[])datainletopenRecord_declin{mie;primitive_proj;impls;globnames;global_univ_decls;projunivs;ubinders;projections_kind;poly;records=data}letinterp_structureudeclkind~template~cumulative~poly~primitive_projfiniterecords=letimpargs,params,univs,variances,projections_kind,data=pre_process_structureudeclkind~polyrecordsininterp_structure_core~cumulativefinite~univs~variances~primitive_projimpargsparamstemplate~projections_kinddataletdeclare_structure{Record_decl.mie;primitive_proj;impls;globnames;global_univ_decls;projunivs;ubinders;projections_kind;poly;records}=Option.iter(DeclareUctx.declare_universe_context~poly:false)global_univ_decls;letkn=DeclareInd.declare_mutual_inductive_with_eliminationsmieglobnamesimpls~primitive_expected:primitive_projinletmapi{Data.is_coercion;proj_flags;rdata={DataR.implfs;fields;_};inhabitant_id;_}=letrsp=(kn,i)in(* This is ind path of idstruc *)letcstr=(rsp,1)inletprojections=declare_projectionsrsp(projunivs,ubinders)~kind:projections_kindinhabitant_idproj_flagsimplfsfieldsinletbuild=GlobRef.ConstructRefcstrinlet()=ifis_coercionthenComCoercion.try_add_new_coercionbuild~local:false~poly~nonuniform:false~reversible:trueinletstruc=Structure.make(Global.env())rspprojectionsinlet()=declare_structure_entrystrucinGlobRef.IndRefrspinList.mapimaprecords,[]letget_class_params:Data.tlist->Data.t=function|[data]->data|_->CErrors.user_err(str"Mutual definitional classes are not supported.")(* declare definitional class (typeclasses that are not record) *)(* [data] is a list with a single [Data.t] with a single field (in [Data.rdata])
and [Data.is_coercion] must be [NoCoercion] *)letdeclare_class_constant~univsparamimplsparamsdata=let{Data.id;rdata;is_coercion;proj_flags;inhabitant_id}=get_class_paramsdatainassert(notis_coercion);(* should be ensured by caller *)letimplfs=rdata.DataR.implfsinletfield,binder,proj_name,proj_flags=matchrdata.DataR.fields,proj_flagswith|[LocalAssum({binder_name=Nameproj_name}asbinder,field)|LocalDef({binder_name=Nameproj_name}asbinder,_,field)],[proj_flags]->letbinder={binderwithbinder_name=Nameinhabitant_id}infield,binder,proj_name,proj_flags|_->assertfalsein(* should be ensured by caller *)letclass_body=it_mkLambda_or_LetInfieldparamsinletclass_type=it_mkProd_or_LetInrdata.DataR.arityparamsinletclass_entry=Declare.definition_entry~types:class_type~univsclass_bodyinletcst=Declare.declare_constant~name:id(Declare.DefinitionEntryclass_entry)~kind:Decls.(IsDefinitionDefinition)inletinst,univs=matchunivswith|UState.Monomorphic_entry_,ubinders->Univ.Instance.empty,(UState.Monomorphic_entryUniv.ContextSet.empty,ubinders)|UState.Polymorphic_entryuctx,_->Univ.UContext.instanceuctx,univsinletcstu=(cst,inst)inletinst_type=appvectc(mkConstUcstu)(Context.Rel.instancemkRel0params)inletproj_type=it_mkProd_or_LetIn(mkProd(binder,inst_type,lift1field))paramsinletproj_body=it_mkLambda_or_LetIn(mkLambda(binder,inst_type,mkRel1))paramsinletproj_entry=Declare.definition_entry~types:proj_type~univsproj_bodyinletproj_cst=Declare.declare_constant~name:proj_name(Declare.DefinitionEntryproj_entry)~kind:Decls.(IsDefinitionDefinition)inletcref=GlobRef.ConstRefcstinImpargs.declare_manual_implicitsfalsecrefparamimpls;Impargs.declare_manual_implicitsfalse(GlobRef.ConstRefproj_cst)(List.hdimplfs);Classes.set_typeclass_transparency~locality:Hints.SuperGlobal[Tacred.EvalConstRefcst]false;let()=letcsb=Global.lookup_constantcstinletpoly=Declareops.constant_is_polymorphiccsbindeclare_proj_coercion_instance~flags:proj_flags(GlobRef.ConstRefproj_cst)cref~poly~with_coercion:falseinletm={meth_name=Nameproj_name;meth_info=None;meth_const=Someproj_cst;}in[cref],[m](** [declare_class] will prepare and declare a [Class]. This is done in
2 steps:
1. two markedly different paths are followed depending on whether the
class declaration refers to a constant "definitional classes"
(with [declare_class_constant]) or to a record (with [declare_structure]),
that is to say:
Class foo := bar : T.
which is equivalent to
Definition foo := T.
Definition bar (x:foo) : T := x.
Existing Class foo.
vs
Class foo := { ... }.
2. now, declare the class, using the information ([inds] and [def]) from 1.
in the form of [Classes.typeclass]
*)letdeclare_class~univsparamsindsdefdata=let{Data.rdata}=get_class_paramsdatainletfields=rdata.DataR.fieldsinletmapind=letmapdecly={meth_name=RelDecl.get_namedecl;meth_info=None;meth_const=y;}inletl=matchindwith|GlobRef.IndRefind->List.map2map(List.revfields)(Structure.find_projectionsind)|_->definind,linletdata=List.mapmapindsinletunivs,params,fields=matchfstunivswith|UState.Polymorphic_entryuctx->letusubst,auctx=Univ.abstract_universesuctxinletusubst=Univ.make_instance_substusubstinletmapc=Vars.subst_univs_level_construsubstcinletfields=Context.Rel.mapmapfieldsinletparams=Context.Rel.mapmapparamsinauctx,params,fields|UState.Monomorphic_entry_->Univ.AbstractContext.empty,params,fieldsinletmap(impl,projs)=letk={cl_univs=univs;cl_impl=impl;cl_strict=typeclasses_strict();cl_unique=typeclasses_unique();cl_context=params;cl_props=fields;cl_projs=projs}inClasses.add_classkinList.itermapdataletadd_constant_classcst=letenv=Global.env()inletty,univs=Typeops.type_of_global_in_contextenv(GlobRef.ConstRefcst)inletr=(Environ.lookup_constantcstenv).const_relevanceinletctx,_=decompose_prod_assumtyinletargs=Context.Rel.instanceConstr.mkRel0ctxinlett=mkApp(mkConstU(cst,Univ.make_abstract_instanceunivs),args)inlettc={cl_univs=univs;cl_impl=GlobRef.ConstRefcst;cl_context=ctx;cl_props=[LocalAssum(make_annotAnonymousr,t)];cl_projs=[];cl_strict=typeclasses_strict();cl_unique=typeclasses_unique()}inClasses.add_classtc;Classes.set_typeclass_transparency~locality:Hints.SuperGlobal[Tacred.EvalConstRefcst]falseletadd_inductive_classind=letenv=Global.env()inletmind,oneind=Inductive.lookup_mind_specifenvindinletk=letctx=oneind.mind_arity_ctxtinletunivs=Declareops.inductive_polymorphic_contextmindinletinst=Univ.make_abstract_instanceunivsinletty=Inductive.type_of_inductive((mind,oneind),inst)inletr=oneind.mind_relevancein{cl_univs=univs;cl_impl=GlobRef.IndRefind;cl_context=ctx;cl_props=[LocalAssum(make_annotAnonymousr,ty)];cl_projs=[];cl_strict=typeclasses_strict();cl_unique=typeclasses_unique()}inClasses.add_classkletwarn_already_existing_class=CWarnings.create~name:"already-existing-class"~category:"automation"Pp.(fung->Printer.pr_globalg++str" is already declared as a typeclass.")letdeclare_existing_classg=ifTypeclasses.is_classgthenwarn_already_existing_classgelsematchgwith|GlobRef.ConstRefx->add_constant_classx|GlobRef.IndRefx->add_inductive_classx|_->user_err(Pp.str"Unsupported class type, only constants and inductives are allowed.")(** [fs] corresponds to fields and [ps] to parameters; [proj_flags] is a
list telling if the corresponding fields must me declared as coercions
or subinstances. *)letdefinition_structureudeclkind~template~cumulative~poly~primitive_projfinite(records:Ast.tlist):GlobRef.tlist=letimpargs,params,univs,variances,projections_kind,data=letdefinitional=kind_classkind=DefClassinpre_process_structure~definitionaludeclkind~polyrecordsinletinds,def=matchkind_classkindwith|DefClass->declare_class_constant~univsimpargsparamsdata|RecordClass|NotClass->(* remove the following block after deprecation phase
(started in 8.16, c.f., https://github.com/coq/coq/pull/15802 ) *)letdata=ifkind_classkind=NotClassthendataelseList.map(fund->{dwithData.is_coercion=false})datainletstructure=interp_structure_core~cumulativefinite~univs~variances~primitive_projimpargsparamstemplate~projections_kinddataindeclare_structurestructureinifkind_classkind<>NotClassthendeclare_class~univsparamsindsdefdata;indsmoduleInternal=structtypenonrecprojection_flags=Data.projection_flags={pf_coercion:bool;pf_reversible:bool;pf_instance:bool;pf_priority:intoption;pf_locality:Goptions.option_locality;pf_canonical:bool;}letdeclare_projections=declare_projectionsletdeclare_structure_entry=declare_structure_entryend