123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924(************************************************************************)(* * 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) **************)(** Flag governing use of primitive projections. Disabled by default. *)letprimitive_flag=Goptions.declare_bool_option_and_ref~depr:false~key:["Primitive";"Projections"]~value:falselettypeclasses_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.loc;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.loc;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)letcompute_constructor_levelevarsenvl=List.fold_right(fund(env,univ)->letuniv=ifis_local_assumdthenlets=Retyping.get_sort_ofenvevars(RelDecl.get_typed)inUniv.sup(Sorts.univ_of_sorts)univelseunivin(EConstr.push_reldenv,univ))l(env,Univ.Universe.sprop)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~hdr:"record"(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(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:Vernacexpr.decl_notationlistlist(** notations for fields *);fs:Vernacexpr.local_decl_exprlist}endtypeprojection_flags={pf_subclass:bool;pf_canonical:bool;}(** [DataR.t] contains record data after interpretation /
type-inference *)moduleDataR=structtypet={min_univ:Univ.Universe.t;arity:Constr.t;implfs:Impargs.manual_implicitslist;fields:Constr.rel_declarationlist}endmoduleData=structtypet={id:Id.t;idbuild:Id.t;is_coercion:bool;coers:projection_flagslist;rdata:DataR.t}endletbuild_type_telescopenewpsenv0(sigma,template){DataI.arity;_}=matcharitywith|None->letuvarkind=Evd.univ_flexible_alginletsigma,s=Evd.new_sort_variableuvarkindsigmain(sigma,template),(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:truelin(sigma,template),(s,s')|None->(sigma,false),(s,s')else(sigma,false),(s,s'))|_->user_err?loc:(constr_loct)(str"Sort expected."))typetc_result=bool*Impargs.manual_implicits(* Part relative to closing the definitions *)*UnivNames.universe_binders*Entries.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:falseenv0sigmapsinlet(sigma,template),typs=List.fold_left_map(build_type_telescopenewpsenv0)(sigma,true)recordsinletarities=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;_}arity=interp_fields_evarsenv_arsigma~ninds~nparamsimpls_envnotsfsinlet(sigma,data)=List.fold_left2_mapfoldsigmarecordsaritiesinletsigma=Pretyping.solve_remaining_evarsPretyping.all_and_fail_flagsenv_arsigmainletfoldsigma(typ,sort)(_,newfs)=let_,univ=compute_constructor_levelsigmaenv_arnewfsinletuniv=ifSorts.is_spropsortthenunivelseUniv.Universe.supunivUniv.type0m_univinifnotdef&&is_impredicative_sortenv0sortthensigma,(univ,typ)elseletsigma=Evd.set_leq_sortenv_arsigma(Sorts.sort_of_univuniv)sortinifUniv.is_small_univuniv&&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.mkSort(Sorts.sort_of_univuniv))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~polysigmadeclinletubinders=Evd.universe_binderssigmainletcet=Pretyping.check_evarsenv0sigma(EConstr.of_constrt)inlet()=List.iter(iter_constrce)(List.revnewps)intemplate,imps,ubinders,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. Otherwise, we just print an info
message. The user might still want to name the field of the record. *)letwarning_or_error~infocoeindsperr=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(_,_,_,NonInformativeToInformative))->(Id.printfi++strbrk" cannot be defined because it is informative and "++Printer.pr_inductive(Global.env())indsp++strbrk" is not.")|ElimArity(_,_,_,Some(_,_,_,StrongEliminationOnNonSmallType))->(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.")inifcoethenuser_err~hdr:"structure"~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))inTermops.substl_rel_context(subst@subst')fields(* We build projections *)(* 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] *)ifprimitivethenletp=Projection.Repr.makeindsp~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))paramdeclsinletentry=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(_,ci,_)whenprimitive->body|_->applist(mkConstU(kn,uinstance),proj_args)inletrefi=GlobRef.ConstRefkninImpargs.maybe_declare_manual_implicitsfalserefiimpls;ifflags.pf_subclassthenbeginletcl=ComCoercion.class_of_global(GlobRef.IndRefindsp)inComCoercion.try_add_new_coercion_with_sourcerefi~local:false~poly~source:clend;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~infoflags.pf_subclassindspwhy;(None,i,NoProjectionfi::subst)in(nfi-1,i,{Structure.proj_name=fi;proj_true=is_local_assumdecl;proj_canonical=flags.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)binder_nameflagsfieldimplsfields=letenv=Global.env()inlet(mib,mip)=Global.lookup_inductiveindspinletpoly=Declareops.inductive_is_polymorphicmibinletuinstance=matchunivswith|Polymorphic_entry(_,ctx)->Univ.UContext.instancectx|Monomorphic_entryctx->Univ.Instance.emptyinletparamdecls=Inductive.inductive_paramdecls(mib,uinstance)inletr=mkIndU(indsp,uinstance)inletrp=applist(r,Context.Rel.to_extended_listmkRel0paramdecls)inletparamargs=Context.Rel.to_extended_listmkRel1paramdeclsin(*def in [[params;x:rp]]*)letx=make_annot(Namebinder_name)mip.mind_relevanceinletfields=instantiate_possibly_recursive_type(fstindsp)uinstancemib.mind_ntypesparamdeclsfieldsinletlifted_fields=Termops.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_projectionsopenTypeclassesletcheck_template~template~poly~univs~params{Data.id;rdata={DataR.min_univ;fields;_};_}=lettemplate_candidate()=(* we use some dummy values for the arities in the rel_context
as univs_of_constr doesn't care about localassums and
getting the real values is too annoying *)letadd_levelsclevels=Univ.LSet.unionlevels(Vars.universes_of_constrc)inletparam_levels=List.fold_left(funlevelsd->matchdwith|LocalAssum_->levels|LocalDef(_,b,t)->add_levelsb(add_levelstlevels))Univ.LSet.emptyparamsinletctor_levels=List.fold_left(fununivsd->letunivs=RelDecl.fold_constr(funcunivs->add_levelscunivs)dunivsinunivs)param_levelsfieldsinComInductive.template_polymorphism_candidate~ctor_levelsunivsparams(Some(Sorts.sort_of_univmin_univ))inmatchtemplatewith|Sometemplate,_->(* templateness explicitly requested *)ifpoly&&templatethenuser_errPp.(strbrk"template and polymorphism not compatible");template|None,template->(* auto detect template *)ComInductive.should_auto_templateid(template&&template_candidate())letload_structurei(_,structure)=Structure.registerstructureletcache_structureo=load_structure1oletsubst_structure(subst,obj)=Structure.substsubstobjletdischarge_structure(_,x)=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=(funx->Substitutex);discharge_function=discharge_structure;rebuild_function=rebuild_structure;}letdeclare_structure_entryo=Lib.add_anonymous_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_name{Data.id;Data.rdata;_}=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]
*)letdeclare_structure~cumulativefinite~ubind~univs~variancesparamimplsparamstemplate?(kind=Decls.StructureComponent)?name(record_data:Data.tlist)=letnparams=List.lengthparamsinletpoly,ctx=matchunivswith|Monomorphic_entryctx->false,Monomorphic_entryUniv.ContextSet.empty|Polymorphic_entry(nas,ctx)->true,Polymorphic_entry(nas,ctx)inletbinder_name=matchnamewith|None->Array.map_of_listdata_namerecord_data|Somen->ninletntypes=List.lengthrecord_datainletmk_blocki{Data.id;idbuild;rdata={DataR.min_univ;arity;fields;_};_}=letnfields=List.lengthfieldsinletargs=Context.Rel.to_extended_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_blockrecord_datainlettemplate=List.for_all(check_template~template~univs~poly~params)record_datainletprimitive=primitive_flag()&&List.for_all(fun{Data.rdata={DataR.fields;_};_}->List.existsis_local_assumfields)record_datainletmie={mind_entry_params=params;mind_entry_record=Some(ifprimitivethenSomebinder_nameelseNone);mind_entry_finite=finite;mind_entry_inds=blocks;mind_entry_private=None;mind_entry_universes=univs;mind_entry_template=template;mind_entry_variance=ComInductive.variance_of_entry~cumulative~variancesunivs;}inletimpls=List.map(fun_->paramimpls,[])record_datainletkn=DeclareInd.declare_mutual_inductive_with_eliminationsmieubindimpls~primitive_expected:(primitive_flag())inletmapi{Data.is_coercion;coers;rdata={DataR.implfs;fields;_};_}=letrsp=(kn,i)in(* This is ind path of idstruc *)letcstr=(rsp,1)inletprojections=declare_projectionsrspctx~kindbinder_name.(i)coersimplfsfieldsinletbuild=GlobRef.ConstructRefcstrinlet()=ifis_coercionthenComCoercion.try_add_new_coercionbuild~local:false~polyinletstruc=Structure.make(Global.env())rspprojectionsinlet()=declare_structure_entrystrucinrspinList.mapimaprecord_dataletimplicits_of_contextctx=List.map(funname->CAst.make(Some(name,true)))(List.rev(Anonymous::(List.mapRelDecl.get_namectx)))letbuild_class_constant~univs~rdatafieldimplfsparamsparamimplscoersbinderidproj_name=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|Polymorphic_entry(_,uctx)->Univ.UContext.instanceuctx,univs|Monomorphic_entry_->Univ.Instance.empty,Monomorphic_entryUniv.ContextSet.emptyinletcstu=(cst,inst)inletinst_type=appvectc(mkConstUcstu)(Termops.rel_vect0(List.lengthparams))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(Tacred.EvalConstRefcst)falsefalse;letsub=List.hdcoersinletm={meth_name=Nameproj_name;meth_info=sub;meth_const=Someproj_cst;}in[cref,[m]]letbuild_record_constant~rdata~ubind~univs~variances~cumulative~templatefieldsparamsparamimplscoersididbuildbinder_name=letrecord_data={Data.id;idbuild;is_coercion=false;coers=List.map(fun_->{pf_subclass=false;pf_canonical=true})fields;rdata}inletinds=declare_structure~cumulativeDeclarations.BiFinite~ubind~univs~variancesparamimplsparamstemplate~kind:Decls.Method~name:[|binder_name|][record_data]inletmapind=letmapdeclby={meth_name=RelDecl.get_namedecl;meth_info=b;meth_const=y;}inletl=List.map3map(List.revfields)coers(Structure.find_projectionsind)inGlobRef.IndRefind,linList.mapmapinds(** [declare_class] will prepare and declare a [Class]. This is done in
2 steps:
1. two markely different paths are followed depending on whether the
class declaration refers to a constant "definitional classes" or to
a record, 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. declare the class, using the information from 1. in the form of [Classes.typeclass]
*)letdeclare_classdef~cumulative~ubind~univs~variancesididbuildparamimplsparamsrdatatemplate?(kind=Decls.StructureComponent)coers=letimplfs=(* Make the class implicit in the projections, and the params if applicable. *)letimpls=implicits_of_contextparamsinList.map(funx->impls@x)rdata.DataR.implfsinletrdata={rdatawithDataR.implfs}inletbinder_name=Namegen.next_ident_awayid(Termops.vars_of_env(Global.env()))inletfields=rdata.DataR.fieldsinletdata=matchfieldswith|[LocalAssum({binder_name=Nameproj_name}asbinder,field)|LocalDef({binder_name=Nameproj_name}asbinder,_,field)]whendef->letbinder={binderwithbinder_name=Namebinder_name}inbuild_class_constant~rdata~univsfieldimplfsparamsparamimplscoersbinderidproj_name|_->build_record_constant~rdata~ubind~univs~variances~cumulative~templatefieldsparamsparamimplscoersididbuildbinder_nameinletunivs,params,fields=matchunivswith|Polymorphic_entry(nas,univs)->letusubst,auctx=Univ.abstract_universesnasunivsinletusubst=Univ.make_instance_substusubstinletmapc=Vars.subst_univs_level_construsubstcinletfields=Context.Rel.mapmapfieldsinletparams=Context.Rel.mapmapparamsinauctx,params,fields|Monomorphic_entry_->Univ.AUContext.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}inletenv=Global.env()inletsigma=Evd.from_envenvinClasses.add_classenvsigmak;implinList.mapmapdataletadd_constant_classenvsigmacst=letty,univs=Typeops.type_of_global_in_contextenv(GlobRef.ConstRefcst)inletr=(Environ.lookup_constantcstenv).const_relevanceinletctx,_=decompose_prod_assumtyinletargs=Context.Rel.to_extended_vectConstr.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_classenvsigmatc;Classes.set_typeclass_transparency(Tacred.EvalConstRefcst)falsefalseletadd_inductive_classenvsigmaind=letmind,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_classenvsigmakletwarn_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=letenv=Global.env()inletsigma=Evd.from_envenvinifTypeclasses.is_classgthenwarn_already_existing_classgelsematchgwith|GlobRef.ConstRefx->add_constant_classenvsigmax|GlobRef.IndRefx->add_inductive_classenvsigmax|_->user_err~hdr:"declare_existing_class"(Pp.str"Unsupported class type, only constants and inductives are allowed")openVernacexprmoduleAst=structtypet={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}letto_datai{name;is_coercion;cfs;idbuild;sort}=letfs=List.mapfstcfsin{DataI.name=name.CAst.v;arity=sort;nots=List.map(fun(_,{rf_notation})->rf_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))letcheck_prioritieskindrecords=letisnot_class=matchkindwithClassfalse->false|_->trueinlethas_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,data(* declaring structures, common data to refactor *)letclass_struture~cumulative~template~ubind~impargs~univs~paramsdefrecordsdata=let{Ast.name;cfs;idbuild;_},rdata=matchrecords,datawith|[r],[d]->r,d|_,_->CErrors.user_err(str"Mutual definitional classes are not handled")inletcoers=List.map(fun(_,{rf_subclass;rf_priority})->matchrf_subclasswith|Vernacexpr.BackInstance->Some{hint_priority=rf_priority;hint_pattern=None}|Vernacexpr.NoInstance->None)cfsindeclare_classdef~cumulative~ubind~univsname.CAst.vidbuildimpargsparamsrdatatemplatecoersletregular_structure~cumulative~template~ubind~impargs~univs~variances~params~finiterecordsdata=letadjust_implsimpls=impargs@[CAst.makeNone]@implsinletdata=List.map(fun({DataR.implfs;_}asd)->{dwithDataR.implfs=List.mapadjust_implsimplfs})datain(* let map (min_univ, arity, fieldimpls, fields) { Ast.name; is_coercion; cfs; idbuild; _ } = *)letmaprdata{Ast.name;is_coercion;cfs;idbuild;_}=letcoers=List.map(fun(_,{rf_subclass;rf_canonical})->{pf_subclass=(matchrf_subclasswithVernacexpr.BackInstance->true|Vernacexpr.NoInstance->false);pf_canonical=rf_canonical})cfsin{Data.id=name.CAst.v;idbuild;rdata;is_coercion;coers}inletdata=List.map2mapdatarecordsinletinds=declare_structure~cumulativefinite~ubind~univs~variancesimpargsparamstemplatedatainList.map(funind->GlobRef.IndRefind)inds(** [fs] corresponds to fields and [ps] to parameters; [coers] is a
list telling if the corresponding fields must me declared as coercions
or subinstances. *)letdefinition_structureudeclkind~template~cumulative~polyfinite(records:Ast.tlist):GlobRef.tlist=let()=check_unique_namesrecordsinlet()=check_prioritieskindrecordsinletps,data=extract_record_datarecordsinletauto_template,impargs,ubind,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)()inlettemplate=template,auto_templateinmatchkindwith|Classdef->class_struture~template~ubind~impargs~cumulative~params~univs~variancesdefrecordsdata|Inductive_kw|CoInductive|Variant|Record|Structure->regular_structure~cumulative~template~ubind~impargs~univs~variances~params~finiterecordsdatamoduleInternal=structtypenonrecprojection_flags=projection_flags={pf_subclass:bool;pf_canonical:bool;}letdeclare_projections=declare_projectionsletdeclare_structure_entry=declare_structure_entryend