12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301(************************************************************************)(* * 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) *)(************************************************************************)openCErrorsopenUtilopenNamesopenUnivopenSortsopenUVarsmoduleUnivFlex=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)))moduleQState:sigtypettypeelt=QVar.tvalempty:tvalunion:fail:(t->Quality.t->Quality.t->t)->t->t->tvaladd:check_fresh:bool->named:bool->elt->t->tvalrepr:elt->t->Quality.tvalunify_quality:fail:(unit->t)->Conversion.conv_pb->Quality.t->Quality.t->t->tvalis_above_prop:elt->t->boolvalundefined:t->QVar.Set.tvalcollapse_above_prop:to_prop:bool->t->tvalcollapse:t->tvalpr:(QVar.t->Pp.t)->t->Pp.tvalof_set:QVar.Set.t->tend=structmoduleQSet=QVar.SetmoduleQMap=QVar.Maptypet={named:QSet.t;(** Named variables, may not be set to another *)qmap:Quality.toptionQMap.t;(* TODO: use a persistent union-find structure *)above:QSet.t;(** Set of quality variables known to be either in Prop or Type.
If q ∈ above then it must map to None in qmap. *)}typeelt=QVar.tletempty={named=QSet.empty;qmap=QMap.empty;above=QSet.empty}letrecreprqm=matchQMap.findqm.qmapwith|None->QVarq|Some(QVarq)->reprqm|Some(QConstant_asq)->q|exceptionNot_found->(* let () = assert !Flags.in_debugger in *)(* FIXME *)QVarqletis_above_propqm=QSet.memqm.aboveletsetqqvm=letq=reprqminletq=matchqwithQVarq->q|QConstant_->assertfalseinletqv=matchqvwithQVarqv->reprqvm|(QConstant_asqv)->qvinmatchq,qvwith|q,QVarqv->ifQVar.equalqqvthenSomemelseifQSet.memqm.namedthenNoneelseletabove=ifQSet.memqm.abovethenQSet.addqv(QSet.removeqm.above)elsem.aboveinSome{named=m.named;qmap=QMap.addq(Some(QVarqv))m.qmap;above}|q,(QConstantqcasqv)->ifqc==QSProp&&QSet.memqm.abovethenNoneelseifQSet.memqm.namedthenNoneelseSome{named=m.named;qmap=QMap.addq(Someqv)m.qmap;above=QSet.removeqm.above}letset_above_propqm=letq=reprqminletq=matchqwithQVarq->q|QConstant_->assertfalseinifQSet.memqm.namedthenNoneelseSome{named=m.named;qmap=m.qmap;above=QSet.addqm.above}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->reprqmletunion~fails1s2=letextra=ref[]inletqmap=QMap.union(funqkq1q2->matchq1,q2with|Someq,None|None,Someq->Some(Someq)|None,None->SomeNone|Someq1,Someq2->let()=ifnot(Quality.equalq1q2)thenextra:=(q1,q2)::!extrainSome(Someq1))s1.qmaps2.qmapinletextra=!extrainletfilterq=matchQMap.findqqmapwith|None->true|Some_->false|exceptionNot_found->falseinletabove=QSet.filterfilter@@QSet.unions1.aboves2.aboveinlets={named=QSet.unions1.nameds2.named;qmap;above}inList.fold_left(funs(q1,q2)->letq1=nf_qualitysq1andq2=nf_qualitysq2inunify_quality~fail:(fun()->failsq1q2)CONVq1q2s)sextraletadd~check_fresh~namedqm=ifcheck_freshthenassert(not(QMap.memqm.qmap));{named=ifnamedthenQSet.addqm.namedelsem.named;qmap=QMap.addqNonem.qmap;above=m.above}letof_setqs={named=QSet.empty;qmap=QMap.bind(fun_->None)qs;above=QSet.empty}(* XXX what about [above]? *)letundefinedm=letm=QMap.filter(fun_v->Option.is_emptyv)m.qmapinQMap.domainmletcollapse_above_prop~to_propm=letmapqv=matchvwith|None->ifnot@@QSet.memqm.abovethenNoneelseifto_propthenSome(QConstantQProp)elseSome(QConstantQType)|Some_->vin{named=m.named;qmap=QMap.mapimapm.qmap;above=QSet.empty}letcollapsem=letmapqv=matchvwith|None->ifQSet.memqm.namedthenNoneelseSome(QConstantQType)|Some_->vin{named=m.named;qmap=QMap.mapimapm.qmap;above=QSet.empty}letprprqvar{qmap;above;named}=letopenPpinletprbodyu=function|None->ifQSet.memuabovethenstr" >= Prop"elseifQSet.memunamedthenstr" (internal name "++QVar.raw_pru++str")"elsemt()|Someq->letq=Quality.prprqvarqinstr" := "++qinh(prlist_with_sepfnl(fun(u,v)->prqvaru++prbodyuv)(QMap.bindingsqmap))endmoduleUPairSet=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:ContextSet.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,(QVar.Map.empty,Level.Map.empty);local=ContextSet.empty;univ_variables=UnivFlex.empty;sort_variables=QState.empty;universes=UGraph.initial_universes;initial_universes=UGraph.initial_universes;minim_extra=UnivMinim.empty_extra;}letmake~lboundunivs={emptywithuniverses=univs;initial_universes=univs}letis_emptyuctx=ContextSet.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->Noneletqualid_of_qvar_names(bind,(qrev,_))l=trySome(Libnames.qualid_of_ident(Option.get(QVar.Map.findlqrev).uname))withNot_found|Option.IsNone->None(* no global qvars *)letqualid_of_level_names(bind,(_,urev))l=trySome(Libnames.qualid_of_ident(Option.get(Level.Map.findlurev).uname))withNot_found|Option.IsNone->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_constraintsuctxcstrsg=tryUGraph.merge_constraintscstrsgwithUGraph.UniverseInconsistency(_,i)->letprinters=(pr_uctx_qvaructx,pr_uctx_leveluctx)inraise(UGraph.UniverseInconsistency(Someprinters,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=ContextSet.unionuctx.localuctx'.localinletnames=names_unionuctx.namesuctx'.namesinletnewus=Level.Set.diff(ContextSet.levelsuctx'.local)(ContextSet.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~lbound:UGraph.Bound.Set~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;sort_variables=QState.union~fail:fail_unionuctx.sort_variablesuctx'.sort_variables;initial_universes=declarenewuctx.initial_universes;universes=(iflocal==uctx.localthenuctx.universeselseletcstrsr=ContextSet.constraintsuctx'.localinmerge_constraintsuctxcstrsr(declarenewuctx.universes));minim_extra=extra}letcontext_setuctx=uctx.localletsort_context_setuctx=letus,csts=uctx.localin(QState.undefineductx.sort_variables,us),cstsletconstraintsuctx=snductx.localletcompute_instance_binders(qrev,urev)inst=letqinst,uinst=Instance.to_arrayinstinletqmap=function|QVarq->begintryName(Option.get(QVar.Map.findqqrev).uname)withOption.IsNone|Not_found->Anonymousend|QConstant_->assertfalseinletumaplvl=tryName(Option.get(Level.Map.findlvlurev).uname)withOption.IsNone|Not_found->AnonymousinArray.mapqmapqinst,Array.mapumapuinstletcontextuctx=letqvars=QState.undefineductx.sort_variablesinUContext.of_context_set(compute_instance_binders(snductx.names))qvarsuctx.localtypenamed_universes_entry=universes_entry*UnivNames.universe_bindersletuniv_entry~polyuctx=let(binders,_)=uctx.namesinletentry=ifpolythenPolymorphic_entry(contextuctx)elseMonomorphic_entry(context_setuctx)inentry,bindersletof_context_set((qs,us),csts)=letsort_variables=QState.of_setqsin{emptywithlocal=(us,csts);sort_variables;}typeuniverse_opt_subst=UnivFlex.tletsubstuctx=uctx.univ_variablesletugraphuctx=uctx.universesletis_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})revubindin{emptywithnames=(ubind,(revqbind,revubind))}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_propq'uctx.sort_variablesthenRelevantelseifQVar.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_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:Constraints.t;local_above_prop:Level.Set.t;local_weak:UPairSet.t;local_sorts:QState.t;}letadd_localcstlocal={localwithlocal_cst=Constraints.addcstlocal.local_cst}(* Constraint with algebraic on the left and a single level on the right *)letenforce_leq_upuvlocal={localwithlocal_cst=UnivSubst.enforce_lequ(Universe.makev)local.local_cst}letget_constraint=function|Conversion.CONV->Eq|Conversion.CUMUL->Leletunify_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_universe_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|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_sortunivslssthenlocalelseifis_usetlthenmatchclassifyswith|USmall_->sort_inconsistencyEqsets|ULevelr->ifis_localrthenlet()=instantiate_variablerUniverse.type0varsinadd_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_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_sortunivslrthenlocalelsesort_inconsistencyEqlrinletunify_universescstlocal=letcst=nf_constraintlocal.local_sortscstinifUnivProblem.is_trivialcstthenlocalelsematchcstwith|QEq(a,b)->(* TODO sort_inconsistency should be able to handle raw
qualities instead of having to make a dummy sort *)letmkq=Sorts.makeqUniverse.type0inunify_qualityunivsCONV(mka)(mkb)local|QLeq(a,b)->(* TODO sort_inconsistency should be able to handle raw
qualities instead of having to make a dummy sort *)letmkq=Sorts.makeqUniverse.type0inunify_qualityunivsCUMUL(mka)(mkb)local|ULe(l,r)->letlocal=unify_qualityunivsCUMULlrlocalinletl=normalize_sortlocal.local_sortslinletr=normalize_sortlocal.local_sortsrinbeginmatchclassifyrwith|UAlgebraic_|UMax_->ifUGraph.check_leq_sortunivslrthenlocalelsesort_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_sortunivslrthenlocalelsesort_inconsistencyLelr|ULevell'->ifis_usetr'&&is_locall'then(* Unbounded universe constrained from above, we equalize it *)let()=instantiate_variablel'Universe.type0varsinadd_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_local(Level.set,Le,r')local|ULevell'->add_local(l',Le,r')local|UAlgebraicl->enforce_leq_uplr'local|UMax(_,l)->Univ.Level.Set.fold(funl'accu->add_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=Constraints.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}in!vars,extra,local.local_cst,local.local_sortsletadd_universe_constraintsuctxcstrs=letunivs,local=uctx.localinletvars,extra,local',sorts=process_universe_constraintsuctxcstrsin{uctxwithlocal=(univs,Constraints.unionlocallocal');univ_variables=vars;universes=merge_constraintsuctxlocal'uctx.universes;sort_variables=sorts;minim_extra=extra;}letproblem_of_constraintscstrs=Constraints.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.emptyletadd_constraintsuctxcstrs=letcstrs=problem_of_constraintscstrsinadd_universe_constraintsuctxcstrsletadd_quconstraintsuctx(qcstrs,ucstrs)=letcstrs=problem_of_constraintsucstrsinletcstrs=QConstraints.fold(fun(l,d,r)cstrs->matchdwith|Equal->UnivProblem.Set.add(QEq(l,r))cstrs|Leq->UnivProblem.Set.add(QLeq(l,r))cstrs)qcstrscstrsinadd_universe_constraintsuctxcstrsletcheck_qconstraintsuctxcsts=Sorts.QConstraints.for_all(fun(l,k,r)->letl=nf_qualityuctxlinletr=nf_qualityuctxrinifQuality.equallrthentrueelsematchl,k,rwith|_,Equal,_->false|QConstantQProp,Leq,QConstantQType->true|QConstantQProp,Leq,QVarq->QState.is_above_propquctx.sort_variables|_,Leq,_->false)cstsletcheck_universe_constraintuctx(c:UnivProblem.t)=matchcwith|QEq(a,b)->leta=nf_qualityuctxainletb=nf_qualityuctxbinQuality.equalab|QLeq(a,b)->leta=nf_qualityuctxainletb=nf_qualityuctxbinifQuality.equalabthentrueelsebeginmatcha,bwith|QConstantQProp,QConstantQType->true|QConstantQProp,QVarq->QState.is_above_propquctx.sort_variables|_->falseend|ULe(u,v)->UGraph.check_leq_sortuctx.universesuv|UEq(u,v)->UGraph.check_eq_sortuctx.universesuv|ULub(u,v)->UGraph.check_eq_leveluctx.universesuv|UWeak_->trueletcheck_universe_constraintsuctxcsts=UnivProblem.Set.for_all(check_universe_constraintuctx)cstsletconstrain_variablesdiffuctx=letlocal,vars=UnivFlex.constrain_variablesdiffuctx.univ_variablesuctx.localin{uctxwithlocal;univ_variables=vars}type('a,'b,'c)gen_universe_decl={univdecl_qualities:'a;univdecl_extensible_qualities:bool;univdecl_instance:'b;(* Declared universes *)univdecl_extensible_instance:bool;(* Can new universes be added *)univdecl_constraints:'c;(* Declared constraints *)univdecl_extensible_constraints:bool(* Can new constraints be added *)}typeuniverse_decl=(QVar.tlist,Level.tlist,Constraints.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_instance=[];univdecl_extensible_instance=true;univdecl_constraints=Constraints.empty;univdecl_extensible_constraints=true}letpr_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->QVar.Set.removelacc)qvarsdecl.univdecl_qualitiesinletleftus=List.fold_left(funaccl->Level.Set.removelacc)levelsdecl.univdecl_instanceinlet()=letunboundqs=ifdecl.univdecl_extensible_qualitiesthenQVar.Set.emptyelseleftqsinletunboundus=ifdecl.univdecl_extensible_instancethenLevel.Set.emptyelseleftusinifnot(QVar.Set.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->Quality.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_implicationuctxcstrscstrs'=letgr=uctx.initial_universesinletgrext=merge_constraintsuctxcstrsgrinletcstrs'=Constraints.filter(func->not(UGraph.check_constraintgrextc))cstrs'inifConstraints.is_emptycstrs'then()elseCErrors.user_errPp.(str"Universe constraints are not implied by the ones declared: "++Constraints.pr(pr_uctx_leveluctx)cstrs')letcheck_mono_univ_decluctxdecl=(* Note: if [decl] is [default_univ_decl], behave like [uctx.local] *)let()=ifnot(List.is_emptydecl.univdecl_qualities)||not(QVar.Set.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_constraintsthenuctx.localelsebegincheck_implicationuctxdecl.univdecl_constraintscsts;levels,decl.univdecl_constraintsendletcheck_poly_univ_decluctxdecl=(* Note: if [decl] is [default_univ_decl], behave like [context uctx] *)letlevels,csts=uctx.localinletqvars=QState.undefineductx.sort_variablesinletinst=universe_context_instdeclqvarslevelsuctx.namesinletnas=compute_instance_binders(snductx.names)instinletcsts=ifdecl.univdecl_extensible_constraintsthencstselsebegincheck_implicationuctxdecl.univdecl_constraintscsts;decl.univdecl_constraintsendinletuctx=UContext.makenas(inst,csts)inuctxletcheck_univ_decl~polyuctxdecl=let(binders,_)=uctx.namesinletentry=ifpolythenPolymorphic_entry(check_poly_univ_decluctxdecl)elseMonomorphic_entry(check_mono_univ_decluctxdecl)inentry,bindersletis_boundllbound=matchlboundwith|UGraph.Bound.Prop->false|UGraph.Bound.Set->Level.is_setlletrestrict_universe_context?(lbound=UGraph.Bound.Set)(univs,csts)keep=letremoved=Level.Set.diffunivskeepinifLevel.Set.is_emptyremovedthenunivs,cstselseletallunivs=Constraints.fold(fun(u,_,v)all->Level.Set.addu(Level.Set.addvall))cstsunivsinletg=UGraph.initial_universesinletg=Level.Set.fold(funvg->ifLevel.is_setvthengelseUGraph.add_universev~lbound~strict:falseg)allunivsginletg=UGraph.merge_constraintscstsginletallkept=Level.Set.union(UGraph.domainUGraph.initial_universes)(Level.Set.diffallunivsremoved)inletcsts=UGraph.constraints_for~kept:allkeptginletcsts=Constraints.filter(fun(l,d,r)->not(is_boundllbound&&d==Le))cstsin(Level.Set.interunivskeep,csts)letrestrict?lbounductxvars=letvars=Id.Map.fold(funnalvars->Level.Set.addlvars)(snd(fstuctx.names))varsinletuctx'=restrict_universe_context?lbounductx.localvarsin{uctxwithlocal=uctx'}letrestrict_even_binders?lbounductxvars=letuctx'=restrict_universe_context?lbounductx.localvarsin{uctxwithlocal=uctx'}letrestrict_constraintsuctxcsts=letlevels,_=uctx.localinletuctx'={uctxwithlocal=ContextSet.of_setlevels;universes=uctx.initial_universes}inadd_constraintsuctx'cststyperigid=|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?loc~sideffrigiductxuctx'=letlevels=ContextSet.levelsuctx'inletlocal=ContextSet.appenductx'uctx.localinletdeclareg=Level.Set.fold(funug->tryUGraph.add_universe~lbound:UGraph.Bound.Set~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_constraintsuctx(ContextSet.constraintsuctx')univsinletuctx=matchrigidwith|UnivRigid->uctx|UnivFlexibleb->assert(notsideff);letuvars'=UnivFlex.add_levelslevels~algebraic:buctx.univ_variablesin{uctxwithuniv_variables=uvars'}in{uctxwithnames;local;universes;initial_universes=initial}letmerge_sort_variables?loc~sideffuctxqvars=letsort_variables=QVar.Set.fold(funqvqstate->QState.add~check_fresh:(notsideff)~named:falseqvqstate)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)))in{uctxwithsort_variables;names}letmerge_sort_context?loc~sideffrigiductx((qvars,levels),csts)=letuctx=merge_sort_variables?loc~sideffuctxqvarsinmerge?loc~sideffrigiductx(levels,csts)letdemote_global_univs(lvl_set,csts_set)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~lbound:Set~strict:truegwithUGraph.AlreadyDeclared->g)lvl_setginUGraph.merge_constraintscsts_setginletinitial_universes=update_ugraphuctx.initial_universesinletuniverses=update_ugraphuctx.universesin{uctxwithlocal=(local_univs,local_constraints);univ_variables;universes;initial_universes}letdemote_global_univ_entryentryuctx=matchentrywith|Monomorphic_entryentry->demote_global_univsentryuctx|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=ContextSet.levelsuctx'inletdeclareg=Level.Set.fold(funug->tryUGraph.add_universe~lbound:UGraph.Bound.Set~strict:falseugwithUGraph.AlreadyDeclared->g)levelsginletinitial_universes=declareuctx.initial_universesinletunivs=declareuctx.universesinletuniverses=merge_constraintsuctx(ContextSet.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=letlbound=UGraph.Bound.Setinletinitial_universes=UGraph.add_universe~lbound~strictuuctx.initial_universesinletuniverses=UGraph.add_universe~lbound~strictuuctx.universesinletlocal=ContextSet.add_universeuuctx.localinletnames=matchnamewith|Somen->add_names?locnuuctx.names|None->add_loculocuctx.namesin{uctxwithnames;local;initial_universes;universes}letnew_sort_variable?loc?nameuctx=letq=UnivGen.new_sort_global()in(* don't need to check_fresh as it's guaranteed new *)letsort_variables=QState.add~check_fresh:false~named:(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~lboundunivsbinders=letuctx=make~lboundunivsinList.fold_left(funuctx{CAst.loc;v=id}->fst(new_univ_variable?locuniv_rigid(Someid)uctx))uctxbindersletfrom_env?(binders=[])env=make_with_initial_binders~lbound:UGraph.Bound.Set(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,cst)=(Level.Set.diffuctxdef,UnivSubst.subst_univs_constraintsusubstcst)letnormalize_variablesuctx=letnormalized_variables,def,subst=UnivFlex.normalize_univ_variablesuctx.univ_variablesinletuctx_local=subst_univs_context_with_defdefsubstuctx.localinletunivs=UGraph.merge_constraints(snductx_local)uctx.initial_universesin{uctxwithlocal=uctx_local;univ_variables=normalized_variables;universes=univs}letfix_undefined_variablesuctx={uctxwithuniv_variables=UnivFlex.fix_undefined_variablesuctx.univ_variables}letcollapse_above_prop_sort_variables~to_propuctx={uctxwithsort_variables=QState.collapse_above_prop~to_propuctx.sort_variables}letcollapse_sort_variablesuctx={uctxwithsort_variables=QState.collapseuctx.sort_variables}letminimize?(lbound=UGraph.Bound.Set)uctx=letopenUnivMiniminlet(vars',us')=normalize_context_set~lbounductx.universesuctx.localuctx.univ_variablesuctx.minim_extrainifContextSet.equalus'uctx.localthenuctxelseletuniverses=UGraph.merge_constraints(sndus')uctx.initial_universesin{names=uctx.names;local=us';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->QVar.Set.removelacc)qvarsdecl.univdecl_qualitiesinletleftus=List.fold_left(funaccl->Level.Set.removelacc)levelsdecl.univdecl_instanceinlet()=letunboundqs=ifdecl.univdecl_extensible_qualitiesthenQVar.Set.emptyelseleftqsinletunboundus=ifdecl.univdecl_extensible_instancethenLevel.Set.emptyelseleftusinifnot(QVar.Set.is_emptyunboundqs&&Level.Set.is_emptyunboundus)thenerror_unbound_universesunboundqsunboundusnamesinletinstq=Array.map_of_list(funq->Quality.QVarq)decl.univdecl_qualitiesinletinstu=Array.of_listdecl.univdecl_instanceinletinst=Instance.of_array(instq,instu)ininstletcheck_univ_decl_revuctxdecl=letlevels,csts=uctx.localinletqvars=QState.undefineductx.sort_variablesinletinst=universe_context_inst_decldeclqvarslevelsuctx.namesinletnas=compute_instance_binders(snductx.names)instinlet()=check_implicationuctxcstsdecl.univdecl_constraintsinletuctx=fix_undefined_variablesuctxinletuctx,csts=ifdecl.univdecl_extensible_constraintsthenuctx,cstselserestrict_constraintsuctxdecl.univdecl_constraints,decl.univdecl_constraintsinletuctx'=UContext.makenas(inst,csts)inuctx,uctx'letcheck_uctx_impl~failuctxuctx'=letlevels,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'=Constraints.filter(func->not(UGraph.check_constraintgrextc))cstsinifConstraints.is_emptycstrs'then()elsefail(Constraints.pr(pr_uctx_leveluctx)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(pr_uctx_qvaructx)uctx.sort_variablesletprctx=letopenPpinletprl=pr_uctx_levelctxinifis_emptyctxthenmt()elsev0(str"UNIVERSES:"++brk(0,1)++h(Univ.pr_universe_context_setprl(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