123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614(************************************************************************)(* * 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) *)(************************************************************************)openCErrorsopenUtilopenNamesopenUnivopenSortsopenUVarsmodulePContextSet=structopenPConstraintstypet=Level.Set.tconstrainedletempty=(Level.Set.empty,empty)letis_empty(univs,cst)=Level.Set.is_emptyunivs&&is_emptycstletunion(univs,cstasx)(univs',cst'asy)=ifx==ythenxelseLevel.Set.unionunivsunivs',unioncstcst'letadd_levelu(univs,cst)=Level.Set.adduunivs,cstletprprvprl(univs,cst)=UnivGen.pr_sort_contextprvprl((Sorts.QVar.Set.empty,univs),cst)letuniv_context_set(uvars,(_,uctx))=(uvars,uctx)letuniv_constraints(_,(_,csts))=cstsletlevels(univs,_cst)=univsendlettemplate_default_univs=Summary.ref~name:"template default univs"Univ.Level.Set.emptyletcache_template_default_univsus=template_default_univs:=Univ.Level.Set.union!template_default_univsuslettemplate_default_univs_obj=Libobject.declare_object{(Libobject.default_object"template default univs")withcache_function=cache_template_default_univs;load_function=(fun_us->cache_template_default_univsus);discharge_function=(funx->Somex);classify_function=(fun_->Escape);}letadd_template_default_univsenvkn=match(Environ.lookup_mindknenv).mind_templatewith|None->()|Sometemplate->let_,us=UVars.Instance.levelstemplate.template_defaultsinLib.add_leaf(template_default_univs_objus)lettemplate_default_univs()=!template_default_univsmoduleUnivFlex=UnivFlextypeuniverses_entry=|Monomorphic_entryofUniv.ContextSet.t|Polymorphic_entryofUVars.UContext.tmoduleUNameMap=Id.Maptypeuinfo={uname:Id.toption;uloc:Loc.toption;}openQualityletsort_inconsistency?explaincstlr=letexplain=Option.map(funp->UGraph.Otherp)explaininraise(UGraph.UniverseInconsistency(None,(cst,l,r,explain)))moduleQSet=QVar.SetmoduleQMap=QVar.MapmoduleQState:sigtypettypeelt=QVar.tvalempty:tvalunion:fail:(t->Quality.t->Quality.t->t)->t->t->tvaladd:check_fresh:bool->rigid:bool->elt->t->tvalrepr:elt->t->Quality.tvalis_rigid:t->QVar.t->boolvalis_above_prop:t->QVar.t->boolvalunify_quality:fail:(unit->t)->Conversion.conv_pb->Quality.t->Quality.t->t->tvalundefined:t->QVar.Set.tvalcollapse_above_prop:to_prop:bool->t->tvalcollapse:?except:QVar.Set.t->t->tvalpr:(QVar.t->Libnames.qualidoption)->t->Pp.tvalof_elims:QGraph.t->tvalelims:t->QGraph.tvalset_elims:QGraph.t->t->tvalinitial_elims:t->QGraph.tvalmerge_constraints:(QGraph.t->QGraph.t)->t->tvalnormalize_elim_constraints:t->ElimConstraints.t->ElimConstraints.tend=structtypenode=|EquivofQuality.t|Canonicalof{rigid:bool}(** Rigid variables may not be set to another *)typet={qmap:nodeQMap.t;(* TODO: use a persistent union-find structure *)above_prop:QSet.t;(** Set for quality variables known to be either in Prop or Type.
If q ∈ above_prop then it must map to None in qmap. *)elims:QGraph.t;(** Elimination graph for quality variables. *)initial_elims:QGraph.t;(** Keep the qvar domain without any constraints to optimize computation. *)}typeelt=QVar.tletempty={qmap=QMap.empty;above_prop=QSet.empty;elims=QGraph.initial_graph;initial_elims=QGraph.initial_graph}letrecreprqm=matchQMap.findqm.qmapwith|Canonical_->QVarq|Equiv(QVarq)->reprqm|Equiv(QConstant_asq)->q|exceptionNot_found->QVarqtyperepr=|ReprConstantofQuality.constant|ReprVarofQVar.t*boolletrecrepr_nodeqm=matchQMap.findqm.qmapwith|Canonical{rigid}->ReprVar(q,rigid)|Equiv(QVarq)->repr_nodeqm|Equiv(QConstantqc)->ReprConstantqc|exceptionNot_found->ReprVar(q,true)(* a bit dubious but missing variables are considered rigid *)letis_above_propmq=QSet.memqm.above_propleteliminates_to_propmq=QGraph.eliminates_to_propm.elims(QVarq)letis_rigidmq=matchrepr_nodeqmwith|ReprVar(_,rigid)->rigid|ReprConstant_->trueletsetqqvm=letq=repr_nodeqminletq,rigid=matchqwithReprVar(q,rigid)->q,rigid|ReprConstant_->assertfalseinletqv=matchqvwithQVarqv->repr_nodeqvm|QConstantqc->ReprConstantqcinletenforce_eqq1q2g=letans=QGraph.enforce_eliminates_toq1q2(QGraph.enforce_eliminates_toq2q1g)inlet()=QGraph.check_rigid_pathsansinansinmatchq,qvwith|q,ReprVar(qv,_qvrigd)->ifQVar.equalqqvthenSomemelseifrigidthenNoneelseletabove_prop=ifis_above_propmqthenQSet.addqv(QSet.removeqm.above_prop)elsem.above_propinSome{qmap=QMap.addq(Equiv(QVarqv))m.qmap;above_prop;elims=enforce_eq(QVarqv)(QVarq)m.elims;initial_elims=m.initial_elims}|q,ReprConstantqc->ifqc==QSProp&&(is_above_propmq||eliminates_to_propmq)thenNoneelseifrigidthenNoneelseletqv=QConstantqcinSome{mwithqmap=QMap.addq(Equivqv)m.qmap;above_prop=QSet.removeqm.above_prop;elims=enforce_eqqv(QVarq)m.elims}letset_above_propqm=letq=repr_nodeqminletq,rigid=matchqwithReprVar(q,rigid)->q,rigid|ReprConstant_->assertfalseinifrigidthenNoneelseSome{mwithabove_prop=QSet.addqm.above_prop}letunify_quality~failcq1q2local=matchq1,q2with|QConstantQType,QConstantQType|QConstantQProp,QConstantQProp|QConstantQSProp,QConstantQSProp->local|QConstantQProp,QVarqwhenc==Conversion.CUMUL->beginmatchset_above_propqlocalwith|Somelocal->local|None->fail()end|QVarqv1,QVarqv2->beginmatchsetqv1q2localwith|Somelocal->local|None->matchsetqv2q1localwith|Somelocal->local|None->fail()end|QVarq,(QConstant(QType|QProp|QSProp)asqv)|(QConstant(QType|QProp|QSProp)asqv),QVarq->beginmatchsetqqvlocalwith|Somelocal->local|None->fail()end|(QConstantQType,QConstant(QProp|QSProp))->fail()|(QConstantQProp,QConstantQType)->beginmatchcwith|CONV->fail()|CUMUL->localend|(QConstantQSProp,QConstant(QType|QProp))->fail()|(QConstantQProp,QConstantQSProp)->fail()letnf_qualitym=function|QConstant_asq->q|QVarq->reprqmletadd_qvarsmqmapqs=letg=m.initial_elimsinletfilterv=matchQMap.find_optvqmapwith|None|Some(Canonical_)->true|Some(Equiv_)->falsein(* Here, we filter instead of enforcing equality due to the collapse:
simply enforcing equality may lead to inconsistencies after it *)letqs=QVar.Set.filterfilterqsinletfoldvg=tryQGraph.add_quality(QVarv)gwithQGraph.AlreadyDeclared->ginQVar.Set.foldfoldqsgletunion~fails1s2=letextra=ref[]inletqmap=QMap.union(funqkq1q2->matchq1,q2with|Equivq,(Canonical_)|(Canonical_),Equivq->Some(Equivq)|Canonical{rigid=r1},Canonical{rigid=r2}->(* XXX this looks wrong, but this preserves the previous behaviour *)Some(Canonical{rigid=r1||r2})|Equivq1,Equivq2->let()=ifnot(Quality.equalq1q2)thenextra:=(q1,q2)::!extrainSome(Equivq1))s1.qmaps2.qmapinletextra=!extrainletqs=QVar.Set.union(QGraph.qvar_domains1.elims)(QGraph.qvar_domains2.elims)inletfilterv=matchQMap.find_optvqmapwith|None|Some(Canonical_)->true|Some(Equiv_)->falseinletabove_prop=QSet.filterfilter@@QSet.unions1.above_props2.above_propinletelims=add_qvarss2qmapqsinlets={qmap;above_prop;elims;initial_elims=elims}inList.fold_left(funs(q1,q2)->letq1=nf_qualitysq1andq2=nf_qualitysq2inunify_quality~fail:(fun()->failsq1q2)CONVq1q2s)sextraletadd~check_fresh~rigidqm=ifcheck_freshthenassert(not(QMap.memqm.qmap));letadd_qualityg=tryQGraph.add_quality(QVarq)gwithQGraph.AlreadyDeclaredase->ifcheck_freshthenraiseeelsegin{qmap=QMap.addq(Canonical{rigid})m.qmap;above_prop=m.above_prop;elims=add_qualitym.elims;initial_elims=add_qualitym.initial_elims}letof_elimselims=letqs=QGraph.qvar_domainelimsinletinitial_elims=QSet.fold(funv->QGraph.add_quality(QVarv))qs(QGraph.initial_graph)inletinitial_elims=QGraph.update_rigidselimsinitial_elimsin{emptywithelims;initial_elims}(* XXX what about qvars in the elimination graph? *)letundefinedm=letfilter_v=matchvwith|Canonical_->true|Equiv_->falseinletmq=QMap.filterfilterm.qmapinQMap.domainmqletcollapse_above_prop~to_propm=QMap.fold(funqvm->matchvwith|Equiv_->m|Canonical_->ifnot@@is_above_propmqthenmelseifto_propthenOption.get(setqqpropm)elseOption.get(setqqtypem))m.qmapmletcollapse?(except=QSet.empty)m=QMap.fold(funqvm->matchvwith|Equiv_->m|Canonical{rigid}->ifrigid||QSet.memqexceptthenmelseOption.get(setqqtypem))m.qmapmletprprqvar_opt({qmap;elims}asm)=letopenPpin(* Print the QVar using its name if any, e.g. "α1" or "s" *)letprqvarq=matchprqvar_optqwith|None->QVar.raw_prq|Someqid->Libnames.pr_qualidqidin(* Print the "body" of the QVar, e.g. "α1 := Type", "α2 >= Prop" *)letprbodyu=function|Canonical{rigid}->ifis_above_propmuthenstr" >= Prop"elseifrigidthenstr" (rigid)"elsemt()|Equivq->letq=Quality.prprqvarqinstr" := "++qin(* Print the "name" (given by the user) of the Qvar, e.g. "(named s)" *)letprqvar_nameq=matchprqvar_optqwith|None->mt()|Someqid->str" (named "++Libnames.pr_qualidqid++str")"inletprqvar_full(q1,q2)=QVar.raw_prq1++prbodyq1q2++prqvar_nameq1inhov0(prlist_with_sepfnlprqvar_full(QMap.bindingsqmap)++str" |="++brk(1,2)++hov0(QGraph.pr_qualities(Quality.prprqvar)elims))letelimsm=m.elimsletset_elimselimsm={mwithelims}letinitial_elimsm=m.initial_elimsletmerge_constraintsfm={mwithelims=fm.elims}letnormalize_elim_constraintsmcstrs=letsubstq=matchqwith|QConstant_->q|QVarqv->reprqvminletis_instantiatedq=is_qconstq||is_qglobalqinletcan_drop(q1,_,q2)=not(is_instantiatedq1&&is_instantiatedq2)inletsubst_cst(q1,c,q2)=(substq1,c,substq2)inletcstrs=ElimConstraints.mapsubst_cstcstrsinElimConstraints.filtercan_dropcstrsendmoduleUPairSet=UnivMinim.UPairSettypeuniv_names=UnivNames.universe_binders*(uinfoQVar.Map.t*uinfoLevel.Map.t)(* 2nd part used to check consistency on the fly. *)typet={names:univ_names;(** Printing/location information *)local:PContextSet.t;(** The local graph of universes (variables and constraints) *)univ_variables:UnivFlex.t;(** The local universes that are unification variables *)sort_variables:QState.t;(** Local quality variables. *)universes:UGraph.t;(** The current graph extended with the local constraints *)initial_universes:UGraph.t;(** The graph at the creation of the evar_map + local universes
(but not local constraints) *)minim_extra:UnivMinim.extra;}letempty={names=UnivNames.empty_binders,(QMap.empty,Level.Map.empty);local=PContextSet.empty;univ_variables=UnivFlex.empty;sort_variables=QState.empty;universes=UGraph.initial_universes;initial_universes=UGraph.initial_universes;minim_extra=UnivMinim.empty_extra;}letmake~qualitiesunivs={emptywithuniverses=univs;initial_universes=univs;sort_variables=QState.of_elimsqualities}letis_emptyuctx=PContextSet.is_emptyuctx.local&&UnivFlex.is_emptyuctx.univ_variablesletid_of_leveluctxl=try(Level.Map.findl(snd(snductx.names))).unamewithNot_found->Noneletid_of_qvaructxl=try(QVar.Map.findl(fst(snductx.names))).unamewithNot_found->Noneletis_rigid_qvaructxq=QState.is_rigiductx.sort_variablesqletget_unameinfo=matchinfo.unamewith|None->raiseNot_found|Someid->idletqualid_of_qvar_names(bind,(qrev,_))l=trySome(Libnames.qualid_of_ident(get_uname(QVar.Map.findlqrev)))withNot_found->UnivNames.qualid_of_qualitybindlletqualid_of_level_names(bind,(_,urev))l=trySome(Libnames.qualid_of_ident(get_uname(Level.Map.findlurev)))withNot_found->UnivNames.qualid_of_levelbindlletqualid_of_leveluctxl=qualid_of_level_namesuctx.nameslletpr_uctx_qvar_namesnamesl=matchqualid_of_qvar_namesnameslwith|Someqid->Libnames.pr_qualidqid|None->QVar.raw_prlletpr_uctx_level_namesnamesl=matchqualid_of_level_namesnameslwith|Someqid->Libnames.pr_qualidqid|None->Level.raw_prlletpr_uctx_leveluctxl=pr_uctx_level_namesuctx.nameslletpr_uctx_qvaructxl=pr_uctx_qvar_namesuctx.nameslletmerge_univ_constraintsuctxcstrsg=tryUGraph.merge_constraintscstrsgwithUGraph.UniverseInconsistency(_,i)->letprinters=(pr_uctx_qvaructx,pr_uctx_leveluctx)inraise(UGraph.UniverseInconsistency(Someprinters,i))typeconstraint_source=|Internal|Rigid|Staticletmerge_elim_constraints?(src=Internal)uctxcstrsg=tryletg=QGraph.merge_constraintscstrsginmatchsrcwith|Static->g|Internal->let()=ifnot(ElimConstraints.is_emptycstrs)thenQGraph.check_rigid_pathsging|Rigid->letfold(q1,_,q2)accu=QGraph.add_rigid_pathq1q2accuinSorts.ElimConstraints.foldfoldcstrsgwithQGraph.(EliminationError(QualityInconsistency(_,i)))->letprinter=pr_uctx_qvaructxinraise(QGraph.(EliminationError(QualityInconsistency(Someprinter,i))))letuname_unionst=ifs==tthenselseUNameMap.merge(funklr->matchl,rwith|Some_,_->l|_,_->r)stletnames_union((qbind,ubind),(qrev,urev))((qbind',ubind'),(qrev',urev'))=letqbind=uname_unionqbindqbind'andubind=uname_unionubindubind'andqrev=QVar.Map.union(fun_l_->Somel)qrevqrev'andurev=Level.Map.lunionurevurev'in((qbind,ubind),(qrev,urev))letunionuctxuctx'=ifuctx==uctx'thenuctxelseifis_emptyuctx'thenuctxelseletlocal=PContextSet.unionuctx.localuctx'.localinletnames=names_unionuctx.namesuctx'.namesinletnewus=Level.Set.diff(PContextSet.levelsuctx'.local)(PContextSet.levelsuctx.local)inletnewus=Level.Set.diffnewus(UnivFlex.domainuctx.univ_variables)inletextra=UnivMinim.extra_unionuctx.minim_extrauctx'.minim_extrainletdeclarenewg=Level.Set.fold(funug->UGraph.add_universeu~strict:falseg)newusginletfail_unionsq1q2=ifUGraph.type_in_typeuctx.universesthenselseCErrors.user_errPp.(str"Could not merge universe contexts: could not unify"++spc()++Quality.raw_prq1++strbrk" and "++Quality.raw_prq2++str".")in{names;local=local;univ_variables=UnivFlex.biased_unionuctx.univ_variablesuctx'.univ_variables;(* FIXME: merge constraints from contextset *)sort_variables=QState.union~fail:fail_unionuctx.sort_variablesuctx'.sort_variables;initial_universes=declarenewuctx.initial_universes;universes=(iflocal==uctx.localthenuctx.universeselseletcstrsr=PContextSet.univ_constraintsuctx'.localinmerge_univ_constraintsuctxcstrsr(declarenewuctx.universes));minim_extra=extra}letcontext_setuctx=uctx.localletuniverse_context_setuctx=letus,(_,ucst)=uctx.localinus,ucstletsort_context_setuctx=letus,csts=uctx.localin(QState.undefineductx.sort_variables,us),cstsletconstraintsuctx=snductx.localletcompute_instance_bindersuctxinst=let(qrev,urev)=snductx.namesinletqinst,uinst=Instance.to_arrayinstinletqmap=function|QVarq->begintryName(get_uname(QVar.Map.findqqrev))withNot_found->Anonymousend|QConstant_->assertfalseinletumaplvl=tryName(get_uname(Level.Map.findlvlurev))withNot_found->Anonymousin{quals=Array.mapqmapqinst;univs=Array.mapumapuinst}letcontextuctx=letqvars=QState.undefineductx.sort_variablesinlet(uvars,(qcst,ucst))=uctx.localinUContext.of_context_set(compute_instance_bindersuctx)((qvars,qcst),(uvars,ucst))typenamed_universes_entry=universes_entry*UnivNames.universe_bindersletcheck_mono_sort_constraintsuctx=let(uvar,(qcst,ucst))=uctx.localin(* This looks very stringent but it passes nonetheless all the tests? *)let()=assert(Sorts.ElimConstraints.is_emptyqcst)in(uvar,ucst)letuniv_entry~polyuctx=let(binders,_)=uctx.namesinletentry=ifPolyFlags.univ_polypolythenPolymorphic_entry(contextuctx)elseletuctx=check_mono_sort_constraintsuctxinMonomorphic_entryuctxinentry,binderstypeuniverse_opt_subst=UnivFlex.tletsubstuctx=uctx.univ_variablesletugraphuctx=uctx.universesletelim_graphuctx=QState.elimsuctx.sort_variablesletinitial_elim_graphuctx=QState.initial_elimsuctx.sort_variablesletis_above_propuctxqv=QState.is_above_propuctx.sort_variablesqvletis_algebraicluctx=UnivFlex.is_algebraicluctx.univ_variablesletof_names(ubind,(revqbind,revubind))=letrevqbind=QVar.Map.map(funid->{uname=Someid;uloc=None})revqbindinletrevubind=Level.Map.map(funid->{uname=Someid;uloc=None})revubindinletqgraph=QVar.Map.fold(funv_->QGraph.add_quality(QVarv))revqbindQGraph.initial_graphin{emptywithnames=(ubind,(revqbind,revubind));sort_variables=QState.of_elimsqgraph;}letuniverse_of_nameuctxs=UNameMap.finds(snd(fstuctx.names))letquality_of_nameuctxs=Id.Map.finds(fst(fstuctx.names))letname_levelleveliductx=let((qbind,ubind),(qrev,urev))=uctx.namesinassert(not(Id.Map.memidubind));letubind=Id.Map.addidlevelubindinleturev=Level.Map.addlevel{uname=Someid;uloc=None}urevin{uctxwithnames=((qbind,ubind),(qrev,urev))}letuniverse_bindersuctx=letnamed,_=uctx.namesinnamedletnf_qvaructxq=QState.reprquctx.sort_variablesletinstantiate_variablel(b:Universe.t)v=v:=UnivFlex.definelb!vexceptionUniversesDifferlet{Goptions.get=weak_constraints}=Goptions.declare_bool_option_and_ref~key:["Cumulativity";"Weak";"Constraints"]~value:true()letlevel_inconsistencycstlr=letmku=Sorts.sort_of_univ@@Universe.makeuinraise(UGraph.UniverseInconsistency(None,(cst,mkl,mkr,None)))letnf_universeuctxu=UnivSubst.(subst_univs_universe(UnivFlex.normalize_univ_variableuctx.univ_variables))uletnf_leveluctxu=UnivSubst.(level_subst_of(UnivFlex.normalize_univ_variableuctx.univ_variables))uletnf_instanceuctxu=Instance.subst_fn(nf_qvaructx,nf_leveluctx)uletnf_qualityuctxq=Quality.subst(nf_qvaructx)qletnf_sortuctxs=letnormalizeu=nf_universeuctxuinletqnormalizeq=QState.reprquctx.sort_variablesinSorts.subst_fn(qnormalize,normalize)sletnf_relevanceuctxr=matchrwith|Relevant|Irrelevant->r|RelevanceVarq->matchnf_qvaructxqwith|QConstantQSProp->Sorts.Irrelevant|QConstantQProp|QConstantQType->Sorts.Relevant|QVarq'->(* XXX currently not used in nf_evars_and_universes_opt_subst
does it matter? *)ifQState.is_above_propuctx.sort_variablesq'thenRelevantelseifQVar.equalqq'thenrelseSorts.RelevanceVarq'letnf_universesuctxc=letlsubst=uctx.univ_variablesinletnf_univu=UnivFlex.normalize_univ_variablelsubstuinletrecself()c=matchConstr.kindcwith|Evar(evk,args)->letargs'=SList.Smart.map(self())argsinifargs==args'thencelseConstr.mkEvar(evk,args')|_->UnivSubst.map_universes_opt_subst_with_bindersignoreself(nf_relevanceuctx)(nf_qvaructx)nf_univ()cinself()ctypesmall_universe=USet|UProp|USPropletis_uset=functionUSet->true|UProp|USProp->falsetypesort_classification=|USmallofsmall_universe(* Set, Prop or SProp *)|ULevelofLevel.t(* Var or Global *)|UMaxofUniverse.t*Level.Set.t(* Max of Set, Var, Global without increments *)|UAlgebraicofUniverse.t(* Arbitrary algebraic expression *)letclassifys=matchswith|Prop->USmallUProp|SProp->USmallUSProp|Set->USmallUSet|Typeu|QSort(_,u)->ifUniverse.is_levelsuthenmatchUniverse.leveluwith|None->UMax(u,Universe.levelsu)|Someu->ULeveluelseUAlgebraicutypelocal={local_cst:PConstraints.t;local_above_prop:Level.Set.t;local_weak:UPairSet.t;local_sorts:QState.t;}letadd_univ_localcstlocal={localwithlocal_cst=PConstraints.add_univcstlocal.local_cst}(* Constraint with algebraic on the left and a single level on the right *)letenforce_leq_upuvlocal=letelim_csts=PConstraints.qualitieslocal.local_cstinletuniv_csts=UnivSubst.enforce_lequ(Universe.makev)@@PConstraints.univslocal.local_cstin{localwithlocal_cst=PConstraints.makeelim_cstsuniv_csts}letget_constraint=function|Conversion.CONV->UnivConstraint.Eq|Conversion.CUMUL->UnivConstraint.Leletwarn_template=CWarnings.create_warning~from:[CWarnings.CoreCategories.fragile]~default:Disabled~name:"bad-template-constraint"()letdo_warn_template=CWarnings.create_inwarn_templatePp.(fun(uctx,csts)->str"Adding constraints involving global template univs:"++spc()++UnivConstraints.pr(pr_uctx_leveluctx)csts)letwarn_templateuctxcsts=matchCWarnings.warning_statuswarn_templatewith|Disabled->()|Enabled|AsError->letis_templateu=Level.Set.memu(template_default_univs())inletcsts=UnivConstraints.filter(fun(u,_,vascst)->not(Level.is_setu)&¬(Level.is_setv)&&(is_templateu||is_templatev)&¬(UGraph.check_constraintuctx.universescst))cstsinifnot@@UnivConstraints.is_emptycststhendo_warn_template(uctx,csts)letunify_qualityunivscs1s2l=letfail()=ifUGraph.type_in_typeunivsthenl.local_sortselsesort_inconsistency(get_constraintc)s1s2in{lwithlocal_sorts=QState.unify_quality~failc(Sorts.qualitys1)(Sorts.qualitys2)l.local_sorts;}letprocess_constraintsuctxcstrs=letopenUnivSubstinletopenUnivProbleminletunivs=uctx.universesinletvars=refuctx.univ_variablesinletnormalizeu=UnivFlex.normalize_univ_variable!varsuinletqnormalizesortsq=QState.reprqsortsinletnormalize_sortsortss=Sorts.subst_fn((qnormalizesorts),subst_univs_universenormalize)sinletnf_constraintsorts=function|QElimTo(a,b)->QElimTo(Quality.subst(qnormalizesorts)a,Quality.subst(qnormalizesorts)b)|QLeq(a,b)->QLeq(Quality.subst(qnormalizesorts)a,Quality.subst(qnormalizesorts)b)|QEq(a,b)->QEq(Quality.subst(qnormalizesorts)a,Quality.subst(qnormalizesorts)b)|ULub(u,v)->ULub(level_subst_ofnormalizeu,level_subst_ofnormalizev)|UWeak(u,v)->UWeak(level_subst_ofnormalizeu,level_subst_ofnormalizev)|UEq(u,v)->UEq(normalize_sortsortsu,normalize_sortsortsv)|ULe(u,v)->ULe(normalize_sortsortsu,normalize_sortsortsv)inletis_locall=UnivFlex.meml!varsinletequalize_smalllslocal=letls=matchlwith|USProp->sprop|UProp->prop|USet->setinifUGraph.check_eq_sortSorts.Quality.equalunivslssthenlocalelseifis_usetlthenmatchclassifyswith|USmall_->sort_inconsistencyEqsets|ULevelr->ifis_localrthenlet()=instantiate_variablerUniverse.type0varsinadd_univ_local(Level.set,Eq,r)localelsesort_inconsistencyEqsets|UMax(u,_)|UAlgebraicu->ifuniv_level_memLevel.setuthenletinst=univ_level_remLevel.setuuinenforce_leq_upinstLevel.setlocalelsesort_inconsistencyEqlsselsesort_inconsistencyEqlssinletequalize_variablesfol'r'local=ifLevel.equall'r'thenlocalelselet()=ifis_locall'theninstantiate_variablel'(Universe.maker')varselseifis_localr'theninstantiate_variabler'(Universe.makel')varselseifnot(UnivProblem.check_eq_levelunivsl'r')then(* Two rigid/global levels, none of them being local,
one of them being Prop/Set, disallow *)ifLevel.is_setl'||Level.is_setr'thenlevel_inconsistencyEql'r'elseiffothenraiseUniversesDifferinadd_univ_local(l',Eq,r')localinletequalize_algebraiclrulocal=letalg=UnivFlex.is_algebraicluctx.univ_variablesinletinst=univ_level_remlruruinifalg&¬(Level.Set.meml(Universe.levelsinst))thenlet()=instantiate_variablelinstvarsinlocalelseifuniv_level_memlruthenenforce_leq_upinstllocalelsesort_inconsistencyEq(sort_of_univ(Universe.makel))(sort_of_univru)inletequalize_universeslrlocal=matchclassifyl,classifyrwith|USmalll',(USmall_|ULevel_|UMax_|UAlgebraic_)->equalize_smalll'rlocal|(ULevel_|UMax_|UAlgebraic_),USmallr'->equalize_smallr'llocal|ULevell',ULevelr'->equalize_variablesfalsel'r'local|ULevell',(UAlgebraicr|UMax(r,_))|(UAlgebraicr|UMax(r,_)),ULevell'->equalize_algebraicl'rlocal|(UAlgebraic_|UMax_),(UAlgebraic_|UMax_)->(* both are algebraic *)ifUGraph.check_eq_sortSorts.Quality.equalunivslrthenlocalelsesort_inconsistencyEqlrinletunify_universescstlocal=letcst=nf_constraintlocal.local_sortscstinifUnivProblem.is_trivialcstthenlocalelse(* TODO sort_inconsistency should be able to handle raw
qualities instead of having to make a dummy sort *)letmkq=Sorts.makeqUniverse.type0inmatchcstwith|QEq(a,b)->unify_qualityunivsCONV(mka)(mkb)local|QLeq(a,b)->unify_qualityunivsCUMUL(mka)(mkb)local|QElimTo(a,b)->{localwithlocal_cst=PConstraints.add_quality(a,ElimTo,b)local.local_cst}|ULe(l,r)->letlocal=unify_qualityunivsCUMULlrlocalinletl=normalize_sortlocal.local_sortslinletr=normalize_sortlocal.local_sortsrinbeginmatchclassifyrwith|UAlgebraic_|UMax_->ifUGraph.check_leq_sortSorts.Quality.equalunivslrthenlocalelsesort_inconsistencyLelr~explain:(Pp.str"(cannot handle algebraic on the right)")|USmallr'->(* Invariant: there are no universes u <= Set in the graph. Except for
template levels, Set <= u anyways. Otherwise, for template
levels, any constraint u <= Set is turned into u := Set. *)ifUGraph.type_in_typeunivsthenlocalelsebeginmatchclassifylwith|UAlgebraic_->(* l contains a +1 and r=r' small so l <= r impossible *)sort_inconsistencyLelr|USmalll'->ifUGraph.check_leq_sortSorts.Quality.equalunivslrthenlocalelsesort_inconsistencyLelr|ULevell'->ifis_usetr'&&is_locall'then(* Unbounded universe constrained from above, we equalize it *)let()=instantiate_variablel'Universe.type0varsinadd_univ_local(l',Eq,Level.set)localelsesort_inconsistencyLelr|UMax(_,levels)->ifis_usetr'thenletfoldl'local=letl=sort_of_univ@@Universe.makel'inifLevel.is_setl'||is_locall'thenequalize_variablesfalsel'Level.setlocalelsesort_inconsistencyLelrinLevel.Set.foldfoldlevelslocalelsesort_inconsistencyLelrend|ULevelr'->(* We insert the constraint in the graph even if the graph
already contains it. Indeed, checking the existence of the
constraint is costly when the constraint does not already
exist directly as a single edge in the graph, but adding an
edge in the graph which is implied by others is cheap.
Hence, by doing this, we avoid a costly check here, and
make further checks of this constraint easier since it will
exist directly in the graph. *)matchclassifylwith|USmallUProp->{localwithlocal_above_prop=Level.Set.addr'local.local_above_prop}|USmallUSProp->ifUGraph.type_in_typeunivsthenlocalelsesort_inconsistencyLelr|USmallUSet->add_univ_local(Level.set,Le,r')local|ULevell'->add_univ_local(l',Le,r')local|UAlgebraicl->enforce_leq_uplr'local|UMax(_,l)->Univ.Level.Set.fold(funl'accu->add_univ_local(l',Le,r')accu)llocalend|ULub(l,r)->equalize_variablestruelrlocal|UWeak(l,r)->ifweak_constraints()then{localwithlocal_weak=UPairSet.add(l,r)local.local_weak}elselocal|UEq(l,r)->letlocal=unify_qualityunivsCONVlrlocalinletl=normalize_sortlocal.local_sortslinletr=normalize_sortlocal.local_sortsrinequalize_universeslrlocalinletunify_universescstlocal=ifnot(UGraph.type_in_typeunivs)thenunify_universescstlocalelsetryunify_universescstlocalwithUGraph.UniverseInconsistency_->localinletlocal={local_cst=PConstraints.empty;local_weak=uctx.minim_extra.UnivMinim.weak_constraints;local_above_prop=uctx.minim_extra.UnivMinim.above_prop;local_sorts=uctx.sort_variables;}inletlocal=UnivProblem.Set.foldunify_universescstrslocalinletextra={UnivMinim.above_prop=local.local_above_prop;UnivMinim.weak_constraints=local.local_weak}inlet()=warn_templateuctx(PConstraints.univslocal.local_cst)in!vars,extra,local.local_cst,local.local_sortsletadd_constraints?srcuctxcstrs=letunivs,local=uctx.localinletvars,extra,local',sorts=process_constraintsuctxcstrsin{uctxwithlocal=(univs,PConstraints.unionlocallocal');univ_variables=vars;universes=merge_univ_constraintsuctx(PConstraints.univslocal')uctx.universes;sort_variables=QState.merge_constraints(merge_elim_constraints?srcuctx(PConstraints.qualitieslocal'))sorts;minim_extra=extra;}letproblem_of_univ_constraintscstrs=UnivConstraints.fold(fun(l,d,r)acc->letl=Universe.makelandr=sort_of_univ@@Universe.makerinletcstr'=letopenUnivProbleminmatchdwith|Lt->ULe(sort_of_univ@@Universe.superl,r)|Le->ULe(sort_of_univl,r)|Eq->UEq(sort_of_univl,r)inUnivProblem.Set.addcstr'acc)cstrsUnivProblem.Set.emptyletproblem_of_elim_constraintscstrs=ElimConstraints.fold(fun(l,k,r)pbs->letopenElimConstraintinmatchkwith|ElimTo->UnivProblem.Set.add(QElimTo(l,r))pbs)cstrsUnivProblem.Set.emptyletadd_univ_constraintsuctxcstrs=letcstrs=problem_of_univ_constraintscstrsinadd_constraints~src:Staticuctxcstrsletadd_poly_constraints?srcuctx(qcstrs,ucstrs)=letlvl_pbs=problem_of_univ_constraintsucstrsinletelim_pbs=problem_of_elim_constraintsqcstrsinletuctx=add_constraints?srcuctx(UnivProblem.Set.unionlvl_pbselim_pbs)inletlocal=on_snd(funcst->PConstraints.unioncst(PConstraints.of_qualitiesqcstrs))uctx.localinletsort_variables=QState.merge_constraints(funcst->merge_elim_constraints?srcuctxqcstrscst)uctx.sort_variablesin{uctxwithlocal;sort_variables}letcheck_elim_constraintsuctxcsts=Sorts.ElimConstraints.for_all(fun(l,k,r)->letl=nf_qualityuctxlinletr=nf_qualityuctxrinmatchl,k,rwith|_,ElimTo,_->Inductive.eliminates_to(QState.elimsuctx.sort_variables)lr)cstsletcheck_eq_qualityuctxq1q2=Sorts.Quality.equalq1q2||Sorts.Quality.equal(nf_qualityuctxq1)(nf_qualityuctxq2)letcheck_constraintuctx(c:UnivProblem.t)=matchcwith|QEq(a,b)->leta=nf_qualityuctxainletb=nf_qualityuctxbinQuality.equalab|QLeq(a,b)->leta=nf_qualityuctxainletb=nf_qualityuctxbinQuality.equalab||beginmatcha,bwith|QConstantQProp,QConstantQType->true|QConstantQProp,QVarq->QState.is_above_propuctx.sort_variablesq|(QConstant_|QVar_),_->falseend|QElimTo(a,b)->leta=nf_qualityuctxainletb=nf_qualityuctxbinInductive.eliminates_to(QState.elimsuctx.sort_variables)ab|ULe(u,v)->UGraph.check_leq_sort(funq1q2->check_eq_qualityuctxq1q2)uctx.universesuv|UEq(u,v)->UGraph.check_eq_sort(funq1q2->check_eq_qualityuctxq1q2)uctx.universesuv|ULub(u,v)->UGraph.check_eq_leveluctx.universesuv|UWeak_->trueletcheck_constraintsuctxcsts=UnivProblem.Set.for_all(check_constraintuctx)cstsletconstrain_variablesdiffuctx=let(us,(qcst,ucst))=uctx.localinlet(us,ucst),vars=UnivFlex.constrain_variablesdiffuctx.univ_variables(us,ucst)in{uctxwithlocal=(us,(qcst,ucst));univ_variables=vars}type('a,'b,'c,'d)gen_universe_decl={univdecl_qualities:'a;univdecl_extensible_qualities:bool;univdecl_elim_constraints:'b;univdecl_instance:'c;(* Declared universes *)univdecl_extensible_instance:bool;(* Can new universes be added *)univdecl_univ_constraints:'d;(* Declared univ constraints *)univdecl_extensible_constraints:bool;(* Can new constraints (elim or univ) be added *)}typeuniverse_decl=(QVar.tlist,Sorts.ElimConstraints.t,Level.tlist,Univ.UnivConstraints.t)gen_universe_declletdefault_univ_decl={univdecl_qualities=[];(* in practice non named qualities will get collapsed for toplevel definitions,
but side effects see named qualities from the surrounding definitions
while using default_univ_decl *)univdecl_extensible_qualities=true;univdecl_elim_constraints=ElimConstraints.empty;univdecl_instance=[];univdecl_extensible_instance=true;univdecl_univ_constraints=UnivConstraints.empty;univdecl_extensible_constraints=true}letuniv_decl_cstsdecl=PConstraints.makedecl.univdecl_elim_constraintsdecl.univdecl_univ_constraintsletpr_error_unbound_universesqualsunivsnames=letopenPpinletnqs=QVar.Set.cardinalqualsinletprqvarq=letinfo=QVar.Map.find_optq(fst(sndnames))inh(pr_uctx_qvar_namesnamesq++(matchinfowith|None|Some{uloc=None}->mt()|Some{uloc=Someloc}->spc()++str"("++Loc.prloc++str")"))inletnus=Level.Set.cardinalunivsinletprlevu=letinfo=Level.Map.find_optu(snd(sndnames))inh(pr_uctx_level_namesnamesu++(matchinfowith|None|Some{uloc=None}->mt()|Some{uloc=Someloc}->spc()++str"("++Loc.prloc++str")"))inletppqs=ifnqs>0thenstr(ifnqs=1then"Quality"else"Qualities")++spc()++prlist_with_sepspcprqvar(QVar.Set.elementsquals)elsemt()inletppus=ifnus>0thenletuniverse_s=CString.pluralnus"universe"inletuniverse_s=ifnqs=0thenCString.capitalize_asciiuniverse_selseuniverse_sinstruniverse_s++spc()++prlist_with_sepspcprlev(Level.Set.elementsunivs)elsemt()in(hv0(ppqs++(ifnqs>0&&nus>0thenstrbrk" and "elsemt())++ppus++spc()++str(CString.conjugate_verb_to_be(nus+nqs))++str" unbound."))exceptionUnboundUnivsofQVar.Set.t*Level.Set.t*univ_names(* XXX when we have multi location errors we won't have to pick an arbitrary error *)leterror_unbound_universesqsusuctx=letexceptionFoundofLoc.tinletloc=tryLevel.Set.iter(funu->matchLevel.Map.find_optu(snd(snductx))with|None->()|Someinfo->matchinfo.ulocwith|None->()|Someloc->raise_notrace(Foundloc))us;QVar.Set.iter(funs->matchQVar.Map.find_opts(fst(snductx))with|None->()|Someinfo->matchinfo.ulocwith|None->()|Someloc->raise_notrace(Foundloc))qs;NonewithFoundloc->SomelocinLoc.raise?loc(UnboundUnivs(qs,us,uctx))let()=CErrors.register_handler(function|UnboundUnivs(qs,us,uctx)->Some(pr_error_unbound_universesqsusuctx)|_->None)letuniverse_context_instdeclqvarslevelsnames=letleftqs=List.fold_left(funaccl->QSet.removelacc)qvarsdecl.univdecl_qualitiesinletleftus=List.fold_left(funaccl->Level.Set.removelacc)levelsdecl.univdecl_instanceinlet()=letunboundqs=ifdecl.univdecl_extensible_qualitiesthenQSet.emptyelseleftqsinletunboundus=ifdecl.univdecl_extensible_instancethenLevel.Set.emptyelseleftusinifnot(QSet.is_emptyunboundqs&&Level.Set.is_emptyunboundus)thenerror_unbound_universesunboundqsunboundusnamesinletleftqs=UContext.sort_qualities(Array.map_of_list(funq->Quality.QVarq)(QVar.Set.elementsleftqs))inletleftus=UContext.sort_levels(Array.of_list(Level.Set.elementsleftus))inletinstq=Array.append(Array.map_of_list(funq->QVarq)decl.univdecl_qualities)leftqsinletinstu=Array.append(Array.of_listdecl.univdecl_instance)leftusinletinst=Instance.of_array(instq,instu)ininstletcheck_universe_context_set~prefixlevelsnames=letleft=List.fold_left(funleftl->Level.Set.removelleft)levelsprefixinifnot(Level.Set.is_emptyleft)thenerror_unbound_universesQVar.Set.emptyleftnamesletcheck_univ_implicationuctxcstrscstrs'=letgr=uctx.initial_universesinletgrext=merge_univ_constraintsuctxcstrsgrinletcstrs'=UnivConstraints.filter(func->not(UGraph.check_constraintgrextc))cstrs'inifUnivConstraints.is_emptycstrs'then()elseCErrors.user_errPp.(str"Universe constraints are not implied by the ones declared: "++UnivConstraints.pr(pr_uctx_leveluctx)cstrs')letcheck_elim_implicationuctxcstrscstrs'=letg=initial_elim_graphuctxinletgrext=merge_elim_constraints~src:Rigiductxcstrsginletcstrs'=ElimConstraints.filter(func->not(QGraph.check_constraintgrextc))cstrs'inifElimConstraints.is_emptycstrs'then()elseCErrors.user_errPp.(str"Elimination constraints are not implied by the ones declared: "++ElimConstraints.pr(pr_uctx_qvaructx)cstrs')letcheck_implicationuctx(elim_csts,univ_csts)(elim_csts',univ_csts')=check_univ_implicationuctxuniv_cstsuniv_csts';check_elim_implicationuctxelim_cstselim_csts'letcheck_template_univ_decluctx~template_qvarsdecl=let()=matchList.filter(funq->not@@QSet.memqtemplate_qvars)decl.univdecl_qualitieswith|(_::_)asqvars->CErrors.user_errPp.(str"Qualities "++prlist_with_sepspc(pr_uctx_qvaructx)qvars++str" cannot be template.")|[]->ifnot(QVar.Set.equaltemplate_qvars(QState.undefineductx.sort_variables))thenCErrors.anomalyPp.(str"Bugged template univ declaration.")in(* XXX: when the kernel takes template entries closer to the polymorphic ones,
we should perform some additional checks here. *)let()=assert(Sorts.ElimConstraints.is_emptydecl.univdecl_elim_constraints)inletlevels,csts=uctx.localinlet()=letprefix=decl.univdecl_instanceinifnotdecl.univdecl_extensible_instancethencheck_universe_context_set~prefixlevelsuctx.namesinifdecl.univdecl_extensible_constraintsthenPContextSet.univ_context_setuctx.localelselet()=check_implicationuctx(univ_decl_cstsdecl)cstsin(levels,decl.univdecl_univ_constraints)letcheck_mono_univ_decluctxdecl=(* Note: if [decl] is [default_univ_decl], behave like [uctx.local] *)let()=ifnot(List.is_emptydecl.univdecl_qualities)||not(QSet.is_empty(QState.undefineductx.sort_variables))thenCErrors.user_errPp.(str"Monomorphic declarations may not have sort variables.")inletlevels,csts=uctx.localinlet()=letprefix=decl.univdecl_instanceinifnotdecl.univdecl_extensible_instancethencheck_universe_context_set~prefixlevelsuctx.namesinifdecl.univdecl_extensible_constraintsthencheck_mono_sort_constraintsuctxelselet()=assert(Sorts.ElimConstraints.is_empty(fstcsts))inlet()=check_implicationuctx(univ_decl_cstsdecl)cstsinlevels,decl.univdecl_univ_constraintsletcheck_poly_univ_decluctxdecl=(* Note: if [decl] is [default_univ_decl], behave like [context uctx] *)letlevels,(elim_csts,univ_csts)=uctx.localinletqvars=QState.undefineductx.sort_variablesinletinst=universe_context_instdeclqvarslevelsuctx.namesinletnas=compute_instance_bindersuctxinstinletuniv_csts=ifdecl.univdecl_extensible_constraintsthenuniv_cstselsebegincheck_univ_implicationuctxdecl.univdecl_univ_constraintsuniv_csts;decl.univdecl_univ_constraintsendinletelim_csts=ifdecl.univdecl_extensible_constraintsthenelim_cstselsebegincheck_elim_implicationuctxdecl.univdecl_elim_constraintselim_csts;decl.univdecl_elim_constraintsendinletuctx=UContext.makenas(inst,(elim_csts,univ_csts))inuctxletcheck_univ_decl~polyuctxdecl=let(binders,_)=uctx.namesinletentry=ifPolyFlags.univ_polypolythenPolymorphic_entry(check_poly_univ_decluctxdecl)elseMonomorphic_entry(check_mono_univ_decluctxdecl)inentry,bindersletrestrict_universe_context(univs,univ_csts)keep=letremoved=Level.Set.diffunivskeepinifLevel.Set.is_emptyremovedthenunivs,univ_cstselseletallunivs=UnivConstraints.fold(fun(u,_,v)all->Level.Set.addu(Level.Set.addvall))univ_cstsunivsinletg=UGraph.initial_universesinletg=Level.Set.fold(funvg->ifLevel.is_setvthengelseUGraph.add_universev~strict:falseg)allunivsginletg=UGraph.merge_constraintsuniv_cstsginletallkept=Level.Set.union(UGraph.domainUGraph.initial_universes)(Level.Set.diffallunivsremoved)inletuniv_csts=UGraph.constraints_for~kept:allkeptginletuniv_csts=UnivConstraints.filter(fun(l,d,r)->not(Level.is_setl&&d==Le))univ_cstsin(Level.Set.interunivskeep,univ_csts)letrestrict_universe_pcontext(us,(qcst,ucst))keep=let(us,ucst)=restrict_universe_context(us,ucst)keepin(us,(qcst,ucst))letrestrictuctxvars=letvars=Id.Map.fold(funnalvars->Level.Set.addlvars)(snd(fstuctx.names))varsinletuctx'=restrict_universe_pcontextuctx.localvarsin{uctxwithlocal=uctx'}letrestrict_even_bindersuctxvars=letuctx'=restrict_universe_pcontextuctx.localvarsin{uctxwithlocal=uctx'}letrestrict_univ_constraintsuctxcsts=letlevels,(elim_csts,univ_csts)=uctx.localinletuctx'={uctxwithlocal=(levels,(elim_csts,UnivConstraints.empty));universes=uctx.initial_universes}inadd_univ_constraintsuctx'cstsletrestrict_elim_constraints?srcuctxcsts=letlevels,(elim_csts,univ_csts)=uctx.localinletg=initial_elim_graphuctxin(* XXX we are wreaking havoc with elimination constraints *)letsort_variables=QState.set_elimsguctx.sort_variablesinletsort_variables=QState.merge_constraints(funcst->merge_elim_constraints?srcuctxelim_cstscst)sort_variablesin{uctxwithlocal=(levels,(csts,univ_csts));sort_variables}typerigid=|UnivRigid|UnivFlexibleofbool(** Is substitution by an algebraic ok? *)letuniv_rigid=UnivRigidletuniv_flexible=UnivFlexiblefalseletuniv_flexible_alg=UnivFlexibletrue(** ~sideff indicates that it is ok to redeclare a universe.
Also merges the universe context in the local constraint structures
and not only in the graph. *)letmerge_universe_context?loc~sideffrigiductx(levels,ucst)=letdeclareg=Level.Set.fold(funug->tryUGraph.add_universe~strict:falseugwithUGraph.AlreadyDeclaredwhensideff->g)levelsginletnames=letfolduaccu=letupdate=function|None->Some{uname=None;uloc=loc}|Someinfo->matchinfo.ulocwith|None->Some{infowithuloc=loc}|Some_->SomeinfoinLevel.Map.updateuupdateaccuin(fstuctx.names,(fst(snductx.names),Level.Set.foldfoldlevels(snd(snductx.names))))inletinitial=declareuctx.initial_universesinletunivs=declareuctx.universesinletuniverses=merge_univ_constraintsuctxucstunivsinletuctx=matchrigidwith|UnivRigid->uctx|UnivFlexibleb->assert(notsideff);letuvars'=UnivFlex.add_levelslevels~algebraic:buctx.univ_variablesin{uctxwithuniv_variables=uvars'}inlet(us,(qcst,ucst0))=uctx.localinletlocal=(Univ.Level.Set.unionuslevels,(qcst,Univ.UnivConstraints.unionucst0ucst))in{uctxwithnames;local;universes;initial_universes=initial}letmerge_sort_variables?loc?(sort_rigid=false)?src~sideffuctx(qvars,csts)=letsort_variables=QVar.Set.fold(funqvqstate->QState.add~check_fresh:(notsideff)~rigid:sort_rigidqvqstate)qvarsuctx.sort_variablesinletnames=letfolduaccu=letupdate=function|None->Some{uname=None;uloc=loc}|Someinfo->matchinfo.ulocwith|None->Some{infowithuloc=loc}|Some_->SomeinfoinQVar.Map.updateuupdateaccuinletqrev=QVar.Set.foldfoldqvars(fst(snductx.names))in(fstuctx.names,(qrev,snd(snductx.names)))inletsort_variables=QState.merge_constraints(merge_elim_constraints?srcuctxcsts)sort_variablesinlet(us,(qcst,ucst))=uctx.localinletlocal=(us,(Sorts.ElimConstraints.unionqcstcsts,ucst))in{uctxwithlocal;sort_variables;names}letmerge_sort_context?loc?sort_rigid?src~sideffrigiductx((qvars,levels),(qcst,ucst))=letuctx=merge_sort_variables?loc?sort_rigid?src~sideffuctx(qvars,qcst)inmerge_universe_context?loc~sideffrigiductx(levels,ucst)letdemote_global_univs(lvl_set,univ_csts)uctx=let(local_univs,local_constraints)=uctx.localinletlocal_univs=Level.Set.difflocal_univslvl_setinletuniv_variables=Level.Set.foldUnivFlex.removelvl_setuctx.univ_variablesinletupdate_ugraphg=letg=Level.Set.fold(funug->tryUGraph.add_universeu~strict:truegwithUGraph.AlreadyDeclared->g)lvl_setginUGraph.merge_constraintsuniv_cstsginletinitial_universes=update_ugraphuctx.initial_universesinletuniverses=update_ugraphuctx.universesin{uctxwithlocal=(local_univs,local_constraints);univ_variables;universes;initial_universes}letdemote_global_univ_entryentryuctx=matchentrywith|Monomorphic_entryucst->demote_global_univsucstuctx|Polymorphic_entry_->uctx(* Check bug_4363 bug_6323 bug_3539 and success/rewrite lemma l1
for quick feedback when changing this code *)letemit_side_effectseffu=letuctx=Safe_typing.universes_of_privateeffindemote_global_univsuctxuletmerge_seffuctxuctx'=letlevels=PContextSet.levelsuctx'inletdeclareg=Level.Set.fold(funug->tryUGraph.add_universe~strict:falseugwithUGraph.AlreadyDeclared->g)levelsginletinitial_universes=declareuctx.initial_universesinletunivs=declareuctx.universesinletuniverses=merge_univ_constraintsuctx(PContextSet.univ_constraintsuctx')univsin{uctxwithuniverses;initial_universes}letupdate_sigma_univsuctxunivs=leteunivs={uctxwithinitial_universes=univs;universes=univs}inmerge_seffeunivseunivs.localletadd_qnames?locsl((qnames,unames),(qnames_rev,unames_rev))=ifId.Map.memsqnamesthenuser_err?locPp.(str"Quality "++Id.prints++str" already bound.");((Id.Map.addslqnames,unames),(QVar.Map.addl{uname=Somes;uloc=loc}qnames_rev,unames_rev))letadd_names?locsl((qnames,unames),(qnames_rev,unames_rev))=ifUNameMap.memsunamesthenuser_err?locPp.(str"Universe "++Id.prints++str" already bound.");((qnames,UNameMap.addslunames),(qnames_rev,Level.Map.addl{uname=Somes;uloc=loc}unames_rev))letadd_qloclloc(names,(qnames_rev,unames_rev)asorig)=matchlocwith|None->orig|Some_->(names,(QVar.Map.addl{uname=None;uloc=loc}qnames_rev,unames_rev))letadd_loclloc(names,(qnames_rev,unames_rev)asorig)=matchlocwith|None->orig|Some_->(names,(qnames_rev,Level.Map.addl{uname=None;uloc=loc}unames_rev))letadd_universe?locnamestrictuctxu=letinitial_universes=UGraph.add_universe~strictuuctx.initial_universesinletuniverses=UGraph.add_universe~strictuuctx.universesinletlocal=PContextSet.add_leveluuctx.localinletnames=matchnamewith|Somen->add_names?locnuuctx.names|None->add_loculocuctx.namesin{uctxwithnames;local;initial_universes;universes}letnew_sort_variable?loc?(sort_rigid=false)?nameuctx=letq=UnivGen.fresh_sort_quality()in(* don't need to check_fresh as it's guaranteed new *)letsort_variables=QState.add~check_fresh:false~rigid:(sort_rigid||Option.has_somename)quctx.sort_variablesinletnames=matchnamewith|Somen->add_qnames?locnquctx.names|None->add_qlocqlocuctx.namesin{uctxwithsort_variables;names},qletnew_univ_variable?locrigidnameuctx=letu=UnivGen.fresh_level()inletuctx=matchrigidwith|UnivRigid->uctx|UnivFlexiblealgebraic->letuniv_variables=UnivFlex.addu~algebraicuctx.univ_variablesin{uctxwithuniv_variables}inletuctx=add_universe?locnamefalseuctxuinuctx,uletadd_forgotten_univuctxu=add_universeNonetrueuctxuletmake_with_initial_binders~qualitiesunivsbinders=letuctx=make~qualitiesunivsinList.fold_left(funuctx{CAst.loc;v=id}->fst(new_univ_variable?locuniv_rigid(Someid)uctx))uctxbindersletfrom_env?(binders=[])env=make_with_initial_binders~qualities:(Environ.qualitiesenv)(Environ.universesenv)bindersletmake_nonalgebraic_variableuctxu={uctxwithuniv_variables=UnivFlex.make_nonalgebraic_variableuctx.univ_variablesu}letmake_flexible_nonalgebraicuctx={uctxwithuniv_variables=UnivFlex.make_all_undefined_nonalgebraicuctx.univ_variables}letsubst_univs_context_with_defdefusubst(uctx,(elim_csts,univ_csts))=(Level.Set.diffuctxdef,PConstraints.makeelim_csts@@UnivSubst.subst_univs_constraintsusubstuniv_csts)letnormalize_univ_variablesuctx=letnormalized_variables,def,subst=UnivFlex.normalize_univ_variablesuctx.univ_variablesinletuctx_local=subst_univs_context_with_defdefsubstuctx.localinletunivs=UGraph.merge_constraints(snd(snductx_local))uctx.initial_universesin{uctxwithlocal=uctx_local;univ_variables=normalized_variables;universes=univs}letnormalize_quality_variablesuctx=let(lvls,(elim_cstrs,lvl_cstrs))=uctx.localinletelim_cstrs=QState.normalize_elim_constraintsuctx.sort_variableselim_cstrsin{uctxwithlocal=(lvls,(elim_cstrs,lvl_cstrs))}letnormalize_variablesuctx=letuctx=normalize_univ_variablesuctxinnormalize_quality_variablesuctxletfix_undefined_variablesuctx={uctxwithuniv_variables=UnivFlex.fix_undefined_variablesuctx.univ_variables}letcollapse_above_prop_sort_variables~to_propuctx=letsorts=QState.collapse_above_prop~to_propuctx.sort_variablesinnormalize_quality_variables{uctxwithsort_variables=sorts}letcollapse_sort_variables?exceptuctx=letsorts=QState.collapse?exceptuctx.sort_variablesinnormalize_quality_variables{uctxwithsort_variables=sorts}letminimizeuctx=letopenUnivMiniminlet(us,(qcst,ucst))=uctx.localinlet(vars',(us',ucst'))=normalize_context_setuctx.universes(us,ucst)uctx.univ_variablesuctx.minim_extrainifUniv.ContextSet.equal(us',ucst')(us,ucst)thenuctxelseletuniverses=UGraph.merge_constraintsucst'uctx.initial_universesin{names=uctx.names;local=(us',(qcst,ucst'));univ_variables=vars';sort_variables=uctx.sort_variables;universes=universes;initial_universes=uctx.initial_universes;minim_extra=UnivMinim.empty_extra;(* weak constraints are consumed *)}letuniverse_context_inst_decldeclqvarslevelsnames=letleftqs=List.fold_left(funaccl->QSet.removelacc)qvarsdecl.univdecl_qualitiesinletleftus=List.fold_left(funaccl->Level.Set.removelacc)levelsdecl.univdecl_instanceinlet()=letunboundqs=ifdecl.univdecl_extensible_qualitiesthenQSet.emptyelseleftqsinletunboundus=ifdecl.univdecl_extensible_instancethenLevel.Set.emptyelseleftusinifnot(QSet.is_emptyunboundqs&&Level.Set.is_emptyunboundus)thenerror_unbound_universesunboundqsunboundusnamesinletinstq=Array.map_of_list(funq->QVarq)decl.univdecl_qualitiesinletinstu=Array.of_listdecl.univdecl_instanceinletinst=Instance.of_array(instq,instu)ininstletcheck_univ_decl_revuctxdecl=letlevels,(elim_csts,univ_cstsascsts)=uctx.localinletqvars=QState.undefineductx.sort_variablesinletinst=universe_context_inst_decldeclqvarslevelsuctx.namesinletnas=compute_instance_bindersuctxinstinlet()=check_implicationuctxcsts(univ_decl_cstsdecl)inletuctx=fix_undefined_variablesuctxinletuctx,univ_csts=ifdecl.univdecl_extensible_constraintsthenuctx,univ_cstselserestrict_univ_constraintsuctxdecl.univdecl_univ_constraints,univ_cstsinletuctx,elim_csts=ifdecl.univdecl_extensible_constraintsthenuctx,elim_cstselserestrict_elim_constraints~src:Rigiductxdecl.univdecl_elim_constraints,elim_cstsinletuctx'=UContext.makenas(inst,(elim_csts,univ_csts))inuctx,uctx'letcheck_uctx_impl~failuctxuctx'=letlevels,(elim_csts,univ_csts)=uctx'.localinletqvars_diff=QVar.Set.diff(QState.undefineductx'.sort_variables)(QState.undefineductx.sort_variables)inletlevels_diff=Level.Set.difflevels(fstuctx.local)inlet()=ifnot@@(QVar.Set.is_emptyqvars_diff&&Level.Set.is_emptylevels_diff)thenerror_unbound_universesqvars_difflevels_diffuctx'.namesinlet()=letgrext=ugraphuctxinletcstrs'=UnivConstraints.filter(func->not(UGraph.check_constraintgrextc))univ_cstsinifUnivConstraints.is_emptycstrs'then()elsefail(UnivConstraints.pr(pr_uctx_leveluctx)cstrs')inlet()=letgrext=elim_graphuctxinletcstrs'=ElimConstraints.filter(func->not(QGraph.check_constraintgrextc))elim_cstsinifElimConstraints.is_emptycstrs'then()elsefail(ElimConstraints.pr(pr_uctx_qvaructx)cstrs')in()(* XXX print above_prop too *)letpr_weakprl{minim_extra={UnivMinim.weak_constraints=weak;above_prop}}=letopenPpinv0(prlist_with_sepcut(fun(u,v)->h(prlu++str" ~ "++prlv))(UPairSet.elementsweak)++ifUPairSet.is_emptyweak||Level.Set.is_emptyabove_propthenmt()elsecut()++prlist_with_sepcut(funu->h(str"Prop <= "++prlu))(Level.Set.elementsabove_prop))letpr_sort_opt_substuctx=QState.pr(qualid_of_qvar_namesuctx.names)uctx.sort_variablesletprctx=letopenPpinletprl=pr_uctx_levelctxinletprq=pr_uctx_qvarctxinifis_emptyctxthenmt()elsev0(str"UNIVERSES:"++brk(0,1)++h(PContextSet.prprqprl(context_setctx))++fnl()++UnivFlex.prprl(substctx)++fnl()++str"SORTS:"++brk(0,1)++h(pr_sort_opt_substctx)++fnl()++str"WEAK CONSTRAINTS:"++brk(0,1)++h(pr_weakprlctx)++fnl())moduleInternal=structletrebootenvuctx=letuctx_global=from_envenvin{uctx_globalwithuniv_variables=uctx.univ_variables;sort_variables=uctx.sort_variables}end