1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081(************************************************************************)(* * The Rocq Prover / The Rocq 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) **************)let{Goptions.get=typeclasses_strict}=Goptions.declare_bool_option_and_ref~key:["Typeclasses";"Strict";"Resolution"]~value:false()let{Goptions.get=typeclasses_unique}=Goptions.declare_bool_option_and_ref~key:["Typeclasses";"Unique";"Instances"]~value:false()let{Goptions.get=typeclasses_default_mode}=Goptions.declare_interpreted_string_option_and_refHints.parse_modeHints.string_of_mode~key:["Typeclasses";"Default";"Mode"]~value:Hints.ModeOutput()letinterp_fields_evarsenvsigma~ninds~nparamsimpls_envnotsl=let_,sigma,impls,locs,newfs,_=List.fold_left2(fun(env,sigma,uimpls,locs,params,impls_env)nod->letsigma,(i,b,t),impl,loc=matchdwith|Vernacexpr.AssumExpr({CAst.v=id;loc},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,loc|Vernacexpr.DefExpr({CAst.v=id;loc},bl,b,t)->letsigma,(b,t),impl=ComDefinition.interp_definition~program_mode:falseenvsigmaimpls_envblNonebtinlett=matchtwithSomet->t|None->Retyping.get_type_ofenvsigmabinsigma,(id,Someb,t),impl,locinletr=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,loc::locs,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,locs,newfs)letcheck_anonymous_typeind=matchindwith|{CAst.v=CSorts}->Constrexpr_ops.(sort_expr_eqexpr_Type_sorts)|_->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.Grammar.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:lident;constructor_name:Id.t;arity:Constrexpr.constr_exproption(** declared sort for the record *);nots:Metasyntax.notation_interpretation_decllistlist(** notations for fields *);fs:Vernacexpr.local_decl_exprlist;default_inhabitant_id:Id.toption}endmoduleData=struct(* XXX move coercion_flags to ComCoercion? *)typecoercion_flags={coe_local:bool;coe_reversible:bool;}typeinstance_flags={inst_locality:Hints.hint_locality;inst_priority:intoption;}typeprojection_flags={pf_coercion:coercion_flagsoption;pf_instance:instance_flagsoption;pf_canonical:bool;}typet={is_coercion:Vernacexpr.coercion_flag;proj_flags:projection_flagslist}end(** Is [s] a single local level (type or qsort)? If so return it. *)letis_sort_variablesigmas=matchEConstr.ESorts.kindsigmaswith|SProp|Prop|Set->None|Typeu|QSort(_,u)->matchUniv.Universe.leveluwith|None->None|Somel->ifUniv.Level.Set.meml(fst(Evd.universe_context_setsigma))thenSomelelseNoneletbuild_type_telescope~unconstrained_sortsnewpsenv0sigma{DataI.arity;_}=matcharitywith|None->letsigma,s=Evd.new_sort_variableEvd.univ_flexible_algsigmainsigma,(EConstr.mkSorts,s)|Some{CAst.v=CSorts;loc}whenConstrexpr_ops.(sort_expr_eqexpr_Type_sorts)->(* special case: the user wrote ": Type". We want to allow it to become algebraic
(and Prop but that may change in the future) *)letsigma,s=Evd.new_sort_variable?locUState.univ_flexible_algsigmainsigma,(EConstr.mkSorts,s)|Somet->letenv=EConstr.push_rel_contextnewpsenv0inletimpls=Constrintern.empty_internalization_envinletsigma,s=lett=Constrintern.intern_genIsType~implsenvsigmatinletflags={Pretyping.all_no_fail_flagswithprogram_mode=false;unconstrained_sorts}inPretyping.understand_tcc~flagsenvsigma~expected_type:IsTypetinletsred=Reductionops.whd_allnoletenvsigmasin(matchEConstr.kindsigmasredwith|Sorts'->(sigma,(s,s'))|_->user_err?loc:(constr_loct)(str"Sort expected."))moduleDefClassEntry=structtypet={univs:UState.named_universes_entry;name:lident;projname:lident;params:Constr.rel_context;sort:Sorts.t;typ:Constr.t;(* NB: typ is convertible to sort *)projtyp:Constr.t;inhabitant_id:Id.t;impls:Impargs.manual_implicits;projimpls:Impargs.manual_implicits;}endmoduleRecordEntry=structtypeone_ind_info={(* inhabitant_id not redundant with the entry in non prim record case *)inhabitant_id:Id.t;default_dep_elim:DeclareInd.default_dep_elim;(* implfs includes the param and principal argument info *)implfs:Impargs.manual_implicitslist;fieldlocs:Loc.toptionlist;}letmake_ind_infosidelimsimplfsfieldlocs={inhabitant_id=id;default_dep_elim=elims;implfs;fieldlocs}typet={global_univs:Univ.ContextSet.t;ubinders:UState.named_universes_entry;mie:Entries.mutual_inductive_entry;ind_infos:one_ind_infolist;param_impls:Impargs.manual_implicits;}endtypedefclass_or_record=|DefclassEntryofDefClassEntry.t|RecordEntryofRecordEntry.t(* we currently don't check that defclasses are nonrecursive until we try to declare the definition in the kernel
so we do need env_ar_params (instead of env_params) to avoid unbound rel anomalies *)letdef_class_levels~def~env_ar_paramssigmaaritysortsctors=lets,ctor=matcharitysorts,ctorswith|[s],[ctor]->beginmatchctorwith|[LocalAssum(na,t)]->s,t|_->assertfalseend|_->CErrors.user_errPp.(str"Mutual definitional classes are not supported.")inletctor_sort=Retyping.get_sort_ofenv_ar_paramssigmactorinletis_prop_ctor=EConstr.ESorts.is_propsigmactor_sortinletsigma=Evd.set_leq_sortsigmactor_sortsinifOption.cata(Evd.is_flexible_levelsigma)false(is_sort_variablesigmas)&&is_prop_ctorthen(* We assume that the level in aritysort is not constrained
and clear it, if it is flexible *)letsigma=Evd.set_eq_sortsigmaEConstr.ESorts.setsinsigma,EConstr.ESorts.prop,ctorelsesigma,s,ctorletfinalize_def_classenvsigma~params~sort~projtyp=letsigma,(params,sort,typ,projtyp)=Evarutil.finalize~abort_on_undefined_evars:falsesigma(funnf->lettyp=EConstr.it_mkProd_or_LetIn(EConstr.mkSortsort)paramsinlettyp=nftypin(* we know the context is exactly the params because we built typ from mkSort *)letparams,typ=Term.decompose_prod_declstypinletprojtyp=nfprojtypinletsort=destSort(nf(EConstr.mkSortsort))inparams,sort,typ,projtyp)inletcet=Pretyping.check_evarsenvsigma(EConstr.of_constrt)in(* no need to check evars in typ which is guaranteed to be a sort *)let()=Context.Rel.iterceparamsinlet()=ceprojtypinsigma,params,sort,typ,projtypletadjust_field_implicits~isclass(params,param_impls)(impls:Impargs.manual_implicits)=letmain_arg=ifisclassthenSome(Anonymous,true)elseNoneinletparam_impls=ifisclassthenList.rev(List.filter_map(fund->ifRelDecl.is_local_defdthenNoneelseSome(CAst.make(Some(RelDecl.get_named,true))))params)elseparam_implsinparam_impls@(CAst.makemain_arg::impls)typekind_class=NotClass|RecordClass|DefClass(** Pick a variable name for a record, avoiding names bound in its fields. *)letcanonical_inhabitant_id~isclassind_id=ifisclassthenind_idelseId.of_string(Unicode.lowercase_first_char(Id.to_stringind_id))(** 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_ind_entry(ind:Entries.one_inductive_entry):Id.Set.t=letctor=matchind.mind_entry_lcwith|[ctor]->ctor|_->assertfalseinletfields,_=Term.decompose_prod_declsctorinletadd_namesnamesfield=add_bound_names_constrnames(RelDecl.get_typefield)inList.fold_leftadd_namesId.Set.emptyfieldsletinhabitant_id~isclassbound_namesind{DataI.default_inhabitant_id=id;name}=matchidwith|Someid->id|None->letcanonical_inhabitant_id=canonical_inhabitant_id~isclassname.vin(* 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. *)Namegen.next_ident_awaycanonical_inhabitant_id(bound_namesind)letfix_entry_record~isclass~primitive_projrecordsmie=letids=List.map2(inhabitant_id~isclassbound_names_ind_entry)mie.mind_entry_indsrecordsinifnotprimitive_projthenids,{miewithmind_entry_record=SomeNone}elseids,{miewithmind_entry_record=Some(Some(Array.of_listids))}lettypecheck_params_and_fields~kind~(flags:ComInductive.flags)~primitive_projudeclparams(records:DataI.tlist)=letdef=kind=DefClassinletisclass=kind!=NotClassinletenv0=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)recordsinletunconstrained_sorts=notflags.poly&¬def&&is_templateinletsigma,udecl,variances=Constrintern.interp_cumul_univ_decl_optenv0udeclinlet()=List.itercheck_parameters_must_be_namedparamsinletsigma,(impls_env,((_env1,params),impls,_paramlocs))=Constrintern.interp_context_evars~program_mode:false~unconstrained_sortsenv0sigmaparamsinletsigma,typs=List.fold_left_map(build_type_telescope~unconstrained_sortsparamsenv0)sigmarecordsinlettyps,aritysorts=List.splittypsinletarities=List.map(funtyp->EConstr.it_mkProd_or_LetIntypparams)typsinletrelevances=List.map(funs->EConstr.ESorts.relevance_of_sorts)aritysortsinletfoldaccu{DataI.name;_}arityr=EConstr.push_rel(LocalAssum(make_annot(Namename.v)r,arity))accuinletenv_ar_params=EConstr.push_rel_contextparams(List.fold_left3foldenv0recordsaritiesrelevances)inletimpls_env=letids=List.map(fun{DataI.name;_}->name.v)recordsinletimpls=List.map(fun_->impls)aritiesinConstrintern.compute_internalization_envenv0sigma~impls:impls_envConstrintern.Inductiveidsaritiesimplsinletninds=List.lengtharitiesinletnparams=List.lengthparamsinletfoldsigma{DataI.nots;fs;_}=interp_fields_evarsenv_ar_paramssigma~ninds~nparamsimpls_envnotsfsinlet(sigma,fields)=List.fold_left_mapfoldsigmarecordsinletfield_impls,locs,fields=List.split3fieldsinletfield_impls=List.map(List.map(adjust_field_implicits~isclass(params,impls)))field_implsinletsigma=Pretyping.solve_remaining_evarsPretyping.all_and_fail_flagsenv_ar_paramssigmainifdefthen(* XXX to fix: if we enter [Class Foo : typ := Bar : nat.], [typ] will get unfolded here *)letsigma,sort,projtyp=def_class_levels~def~env_ar_paramssigmaaritysortsfieldsinletsigma,params,sort,typ,projtyp=(* named and rel context in the env don't matter here
(they will be replaced by the ones of the unsolved evars in the error message
which is the env's only use) *)finalize_def_classenv_ar_paramssigma~params~sort~projtypinletname,projname=matchrecordswith|[{name;fs=[AssumExpr(projname,_,_)]}]->name,projname|_->assertfalseinletprojname=CAst.mapNameops.Name.get_idprojnameinletunivs=Evd.check_univ_decl~poly:flags.polysigmaudeclin(* definitional classes are encoded as 1 constructor with 1
field whose type is the projection type *)letprojimpls=matchfield_implswith|[[x]]->x|_->assertfalseinletinhabitant_id=inhabitant_id~isclass(add_bound_names_constrId.Set.empty)projtyp(List.hdrecords)inDefclassEntry{univs;name;projname;params;sort;typ;projtyp;inhabitant_id;impls;projimpls;}else(* each inductive has one constructor *)letninds=List.lengtharitiesinletnparams=List.lengthparamsinletconstructors=List.map2_i(funirecordfields->letopenEConstrinletnfields=List.lengthfieldsinletind_args=Context.Rel.instance_listmkRelnfieldsparamsinletind=applist(mkRel(ninds-i+nparams+nfields),ind_args)inletctor=it_mkProd_or_LetInindfieldsin[record.DataI.constructor_name],[ctor])0recordsfieldsinletindnames=List.map(funx->x.DataI.name.v)recordsinletarities_explicit=List.map(funx->Option.has_somex.DataI.arity)recordsinlettemplate_syntax=List.map(funtyp->ifEConstr.isAritysigmatypthenComInductive.SyntaxAllowsTemplatePolyelseComInductive.SyntaxNoTemplatePoly)typsinletenv_ar=Environ.pop_rel_contextnparamsenv_ar_paramsinletdefault_dep_elim,mie,ubinders,global_univs=ComInductive.interp_mutual_inductive_constr~sigma~flags~udecl~variances~ctx_params:params~indnames~arities_explicit~arities:typs~constructors~template_syntax~env_ar~private_ind:falseinletids,mie=fix_entry_record~isclass~primitive_projrecordsmieinRecordEntry{mie;global_univs;ubinders;ind_infos=List.map4RecordEntry.make_ind_infosidsdefault_dep_elimfield_implslocs;param_impls=impls;}typerecord_error=|MissingProjofId.t*Id.tlist|BadTypedProjofId.t*env*Type_errors.type_errorletwarn_cannot_define_projection=CWarnings.create~name:"cannot-define-projection"~category:CWarnings.CoreCategories.records(funmsg->hov0msg)typearity_error=|NonInformativeToInformativeleterror_elim_explainkpki=letopenSorts.Qualityinmatchkp,kiwith|QConstantQType,QConstantQProp->SomeNonInformativeToInformative|_->None(* 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?loc~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,env,te)->leterr=matchtewith|ElimArity(_,_,Somes)->error_elim_explain(Sorts.qualitys)(Inductiveops.elim_sort(Global.lookup_inductiveindsp))|_->Noneinmatcherrwith|SomeNonInformativeToInformative->(Id.printfi++strbrk" cannot be defined because it is informative and "++Printer.pr_inductive(Global.env())indsp++strbrk" is not.")|None->(Id.printfi++str" cannot be defined because it is not typable:"++spc()++Himsg.explain_type_errorenv(Evd.from_envenv)(Pretype_errors.of_type_errorte))in(* XXX flags.pf_canonical? *)ifOption.has_someflags.Data.pf_coercion||Option.has_someflags.Data.pf_instancethenuser_err?loc~infost;warn_cannot_define_projection?loc(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]. *)letdeclare_proj_coercion_instance~flagsreffrom=let()=matchflags.Data.pf_coercionwith|None->()|Some{coe_local=local;coe_reversible=reversible}->letcl=ComCoercion.class_of_globalfrominComCoercion.try_add_new_coercion_with_sourceref~local~reversible~source:clinlet()=matchflags.Data.pf_instancewith|None->()|Some{inst_locality;inst_priority}->letenv=Global.env()inletsigma=Evd.from_envenvinletinfo=Typeclasses.{hint_priority=inst_priority;hint_pattern=None}inClasses.declare_instance~warn:trueenvsigma(Someinfo)inst_localityrefin()(* 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~univs~uinstance~kindenvparamdeclsparamargsdeclimpls{CAst.v=fid;loc}substnfitiiindspmiblifted_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.makepfalse,rci,mkRel1),Some(p,rci)elseletccl'=liftn12cclinletp=mkLambda(x,lift1rp,ccl')inletbranch=it_mkLambda_or_LetIn(mkRelnfi)lifted_fieldsinletci=Inductiveops.make_case_infoenvindspLetStylein(* Record projections are always NoInvert because they're at
constant relevance *)mkCase(Inductive.contract_caseenv(ci,(p,rci),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=(* XXX more precise loc *)tryDeclare.declare_constant?loc~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|Some(p,r)->let_=DeclareInd.declare_primitive_projectionpkninmkProj(Projection.makepfalse,r,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);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_fieldsparamdeclsparamargs~uinstance~kind~univs(nfi,i,kinds,subst)flagslocdeclimpls=letfi=RelDecl.get_namedeclinletti=RelDecl.get_typedeclinlet(sp_proj,i,subst)=matchfiwith|Anonymous->(None,i,NoProjectionfi::subst)|Namefid->letfid=CAst.make?locfidintrybuild_named_proj~primitive~flags~univs~uinstance~kindenvparamdeclsparamargsdeclimplsfidsubstnfitiiindspmiblifted_fieldsxrpwithNotDefinablewhyasexn->let_,info=Exninfo.captureexninwarning_or_error?loc~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_projectionsindsp~kind~inhabitant_idflags?fieldlocsfieldimpls=letenv=Global.env()inlet(mib,mip)=Global.lookup_inductiveindspinletuinstance=UVars.Instance.abstract_instance@@UVars.AbstractContext.size@@Declareops.inductive_polymorphic_contextmibinletunivs=matchmib.mind_universeswith|Monomorphic->UState.Monomorphic_entryUniv.ContextSet.empty|Polymorphicauctx->UState.Polymorphic_entry(UVars.AbstractContext.reprauctx)inletunivs=univs,UnivNames.empty_bindersinletfields,_=mip.mind_nf_lc.(0)inletfields=List.firstnmip.mind_consnrealdecls.(0)fieldsinletparamdecls=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)(Inductive.relevance_of_ind_bodymipuinstance)inletfields=instantiate_possibly_recursive_type(fstindsp)uinstancemib.mind_ntypesparamdeclsfieldsinletlifted_fields=Vars.lift_rel_context1fieldsinletprimitive=matchmib.mind_recordwith|PrimRecord_->true|FakeRecord|NotRecord->falseinletfieldlocs=matchfieldlocswith|None->List.make(List.lengthfields)None|Somefieldlocs->fieldlocsinlet(_,_,canonical_projections,_)=List.fold_left4(build_projenvmibindspprimitivexrplifted_fieldsparamdeclsparamargs~uinstance~kind~univs)(List.lengthfields,0,[],[])flags(List.revfieldlocs)(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)(** 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={entry:RecordEntry.t;records:Data.tlist;projections_kind:Decls.definition_object_kind;indlocs:DeclareInd.indlocs;}endmoduleAst=structopenVernacexprtypet={name:Names.lident;is_coercion:coercion_flag;binders:local_binder_exprlist;cfs:(local_decl_expr*Data.projection_flags*notation_declarationlist)list;idbuild:lident;sort:constr_exproption;default_inhabitant_id:Id.toption}letto_datai{name;idbuild;cfs;sort;default_inhabitant_id;}=letfs=List.mappi1cfsin{DataI.name=name;constructor_name=idbuild.CAst.v;arity=sort;nots=List.map(fun(_,_,rf_notation)->List.mapMetasyntax.prepare_where_notationrf_notation)cfs;fs;default_inhabitant_id}endletcheck_unique_names~defrecords=letextract_nameacc(rf_decl,_,_)=matchrf_declwithVernacexpr.AssumExpr({CAst.v=Nameid},_,_)->id::acc|Vernacexpr.DefExpr({CAst.v=Nameid},_,_,_)->id::acc|_->accinletindlocs=records|>List.map(fun{Ast.name;idbuild;_}->name,idbuild)inletfields_names=records|>List.fold_left(funacc{Ast.cfs;_}->List.fold_leftextract_nameacccfs)[]inletallnames=(* we don't check the name of the constructor when [def] because
definitional class are encoded as 1 constructor of 1 field
sharing the same name. *)letindnames=indlocs|>List.concat_map(fun(x,y)->x.CAst.v::ifdefthen[]else[y.CAst.v])infields_names@indnamesinmatchList.duplicatesId.equalallnameswith|[]->List.map(fun(x,y)->x.CAst.loc,[y.CAst.loc])indlocs|id::_->user_err(str"Two objects have the same name"++spc()++quote(Id.printid)++str".")letkind_class=letopenVernacexprinfunctionClasstrue->DefClass|Classfalse->RecordClass|Inductive_kw|CoInductive|Variant|Record|Structure->NotClassletextract_record_datarecords=letdata=List.mapAst.to_datairecordsinletdecl_data=List.map(fun{Ast.is_coercion;cfs}->letproj_flags=List.map(fun(_,rf,_)->rf)cfsin{Data.is_coercion;proj_flags})recordsinletps=matchrecordswith|[]->CErrors.anomaly(str"Empty record block.")|r::rem->leteq_local_bindersbl1bl2=List.equallocal_binder_eqbl1bl2inmatchList.find_opt(funr'->not@@eq_local_bindersr.Ast.bindersr'.Ast.binders)remwith|None->r.Ast.binders|Somer'->ComInductive.Internal.error_differing_params~kind:"record"(r.name,(r.binders,None))(r'.name,(r'.binders,None))inps,data,decl_dataletpre_process_structureudeclkind~flags~primitive_proj(records:Ast.tlist)=letdef=(kind=Vernacexpr.Classtrue)inletindlocs=check_unique_names~defrecordsinletps,interp_data,decl_data=extract_record_datarecordsinletentry=(* 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~primitive_proj~kind:(kind_classkind)~flagsudeclpsinterp_data)()inletprojections_kind=Decls.(matchkind_classkindwithNotClass->StructureComponent|_->Method)inentry,projections_kind,decl_data,indlocsletinterp_structure_core(entry:RecordEntry.t)~projections_kind~indlocsdata=letopenRecord_declin{entry;projections_kind;records=data;indlocs;}letinterp_structure~flagsudeclkind~primitive_projrecords=assert(kind<>Vernacexpr.Classtrue);letentry,projections_kind,data,indlocs=pre_process_structureudeclkind~flags~primitive_projrecordsinmatchentrywith|DefclassEntry_->assertfalse|RecordEntryentry->interp_structure_coreentry~projections_kind~indlocsdatamoduleDeclared=structtypet=|Defclassof{class_kn:Constant.t;proj_kn:Constant.t;}|RecordofMutInd.tendletdeclare_structure(decl:Record_decl.t)=Global.push_context_setdecl.entry.global_univs;(* XXX no implicit arguments for constructors? *)letimpls=List.make(List.lengthdecl.entry.mie.mind_entry_inds)(decl.entry.param_impls,[])inletdefault_dep_elim=List.map(funx->x.RecordEntry.default_dep_elim)decl.entry.ind_infosinletkn=DeclareInd.declare_mutual_inductive_with_eliminationsdecl.entry.miedecl.entry.ubindersimpls~indlocs:decl.indlocs~default_dep_eliminletmapi({RecordEntry.inhabitant_id;implfs;fieldlocs},{Data.is_coercion;proj_flags;})=letrsp=(kn,i)in(* This is ind path of idstruc *)letcstr=(rsp,1)inletkind=decl.projections_kindinletprojections=declare_projectionsrsp~kind~inhabitant_idproj_flags~fieldlocsimplfsinletbuild=GlobRef.ConstructRefcstrinlet()=matchis_coercionwith|NoCoercion->()|AddCoercion->ComCoercion.try_add_new_coercionbuild~local:false~reversible:falseinletstruc=Structure.make(Global.env())rspprojectionsinlet()=declare_structure_entrystrucinGlobRef.IndRefrspinletdata=List.combinedecl.entry.ind_infosdecl.recordsinletinds=List.mapimapdatainDeclared.Recordkn,inds(* declare definitional class (typeclasses that are not record) *)(* [data.is_coercion] must be [NoCoercion] and [data.proj_flags] must have exactly 1 element. *)letdeclare_class_constantentry(data:Data.t)=let{DefClassEntry.univs;name;projname;params;sort;typ;projtyp;inhabitant_id;impls;projimpls;}=entryinlet{Data.is_coercion;proj_flags}=datainletproj_flags=matchproj_flagswith|[x]->x|_->assertfalseinlet()=(* should be ensured by caller *)matchis_coercionwith|NoCoercion->()|AddCoercion->assertfalseinletclass_body=it_mkLambda_or_LetInprojtypparamsinletclass_type=it_mkProd_or_LetIntypparamsinletclass_entry=Declare.definition_entry~types:class_type~univsclass_bodyinletcst=Declare.declare_constant?loc:name.loc~name:name.v(Declare.DefinitionEntryclass_entry)~kind:Decls.(IsDefinitionDefinition)inletinst,univs=matchunivswith|UState.Monomorphic_entry_,ubinders->UVars.Instance.empty,(UState.Monomorphic_entryUniv.ContextSet.empty,ubinders)|UState.Polymorphic_entryuctx,_->UVars.UContext.instanceuctx,univsinletcstu=(cst,inst)inletbinder=letr=Sorts.relevance_of_sortsortin{Context.binder_name=Nameinhabitant_id;binder_relevance=r}inletinst_type=appvectc(mkConstUcstu)(Context.Rel.instancemkRel0params)inletproj_type=it_mkProd_or_LetIn(mkProd(binder,inst_type,lift1projtyp))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?loc:projname.loc~name:projname.v(Declare.DefinitionEntryproj_entry)~kind:Decls.(IsDefinitionDefinition)inletcref=GlobRef.ConstRefcstinImpargs.declare_manual_implicitsfalsecrefimpls;Impargs.declare_manual_implicitsfalse(GlobRef.ConstRefproj_cst)projimpls;Classes.set_typeclass_transparency~locality:Hints.SuperGlobal[Evaluable.EvalConstRefcst]false;let()=declare_proj_coercion_instance~flags:proj_flags(GlobRef.ConstRefproj_cst)crefinDeclared.Defclass{class_kn=cst;proj_kn=proj_cst},[cref]letset_class_moderefmodectx=letmodes=matchmodewith|Some(Somem)->Somem|_->letctxl=Context.Rel.nhypsctxinletdef=typeclasses_default_mode()inletmode=matchdefwith|Hints.ModeOutput->None|Hints.ModeInput->Some(List.initctxl(fun_->Hints.ModeInput))|Hints.ModeNoHeadEvar->Some(List.initctxl(fun_->Hints.ModeNoHeadEvar))inletwm=List.initctxl(fun_->def)inClasses.warn_default_mode(ref,wm);modeinmatchmodeswith|None->()|Somemodes->Classes.set_typeclass_mode~locality:Hints.SuperGlobalrefmodes(** [declare_class] declares the typeclass information for a [Class] declaration.
NB: [Class] syntax does not allow [with]. *)letdeclare_class?modedeclared=letenv=Global.env()inletimpl,univs,params,fields,projs=matchdeclaredwith|Declared.Defclass{class_kn;proj_kn}->letclass_cb=Environ.lookup_constantclass_knenvinletproj_cb=Environ.lookup_constantproj_knenvinletunivs=Declareops.constant_polymorphic_contextclass_cbinletclass_body=matchclass_cb.const_bodywith|Defc->c|Undef_|OpaqueDef_|Primitive_|Symbol_->assertfalseinletparams,field=Term.decompose_lambda_declsclass_bodyinletfname=Name(Label.to_id@@Constant.labelproj_kn)inletfrelevance=proj_cb.const_relevanceinletfields=[RelDecl.LocalAssum({binder_name=fname;binder_relevance=frelevance},field)]inletproj={Typeclasses.meth_name=fname;meth_const=Someproj_kn;}inGlobRef.ConstRefclass_kn,univs,params,fields,[proj]|Declared.Recordmind->letmib,mip=Inductive.lookup_mind_specifenv(mind,0)inletunivs=Declareops.inductive_polymorphic_contextmibinletctor_args,_=mip.mind_nf_lc.(0)inletfields=List.firstnmip.mind_consnrealdecls.(0)ctor_argsinletmake_projdeclkn={Typeclasses.meth_name=RelDecl.get_namedecl;meth_const=kn;}inletprojs=List.map2make_proj(List.revfields)(Structure.find_projections(mind,0))inGlobRef.IndRef(mind,0),univs,mib.mind_params_ctxt,fields,projsinletk={cl_univs=univs;cl_impl=impl;cl_strict=typeclasses_strict();cl_unique=typeclasses_unique();cl_context=params;cl_trivial=CList.is_emptyfields;cl_props=fields;cl_projs=projs;}inClasses.add_classk;set_class_modeimplmodeparamsletadd_constant_classcst=letenv=Global.env()inletty,univs=Typeops.type_of_global_in_contextenv(GlobRef.ConstRefcst)inletr=(Environ.lookup_constantcstenv).const_relevanceinletctx,_=decompose_prod_declstyinletargs=Context.Rel.instanceConstr.mkRel0ctxinlett=mkApp(mkConstU(cst,UVars.make_abstract_instanceunivs),args)inlettc={cl_univs=univs;cl_impl=GlobRef.ConstRefcst;cl_context=ctx;cl_trivial=false;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[Evaluable.EvalConstRefcst]falseletadd_inductive_classind=letenv=Global.env()inletmind,oneind=Inductive.lookup_mind_specifenvindinletctx=oneind.mind_arity_ctxtinletunivs=Declareops.inductive_polymorphic_contextmindinletprops,projs=matchStructure.findindwith|exceptionNot_found->letr=oneind.mind_relevanceinletargs=Context.Rel.instancemkRel0ctxinletty=mkApp(mkIndU(ind,UVars.make_abstract_instanceunivs),args)in[LocalAssum(make_annotAnonymousr,ty)],[]|s->letprops,_=oneind.mind_nf_lc.(0)inletprops=List.firstnoneind.mind_consnrealdecls.(0)propsinletprojs=s.projections|>List.map(fun(p:Structure.projection)->{meth_name=p.proj_name;meth_const=p.proj_body})inprops,projsinletk={cl_univs=univs;cl_impl=GlobRef.IndRefind;cl_context=ctx;cl_trivial=false;cl_props=props;cl_projs=projs;cl_strict=typeclasses_strict();cl_unique=typeclasses_unique();}inClasses.add_classkletwarn_already_existing_class=CWarnings.create~name:"already-existing-class"~category:CWarnings.CoreCategories.automationPp.(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_structure~flagsudeclkind~primitive_proj(records:Ast.tlist):GlobRef.tlist=letentry,projections_kind,data,indlocs=pre_process_structureudeclkind~flags~primitive_projrecordsinletdeclared,inds=matchentrywith|DefclassEntryentry->letdata=matchdatawith[x]->x|_->assertfalseindeclare_class_constantentrydata|RecordEntryentry->letstructure=interp_structure_coreentry~projections_kind~indlocsdataindeclare_structurestructureinifkind_classkind<>NotClassthendeclare_class~mode:flags.modedeclared;indsmoduleInternal=structletdeclare_projections=declare_projectionsletdeclare_structure_entry=declare_structure_entryend