123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595includeLanguage_extension_kerneltype'alanguage_extension='at(* operations we want on every extension level *)moduletypeExtension_level=sigtypetvalcompare:t->t->intvalmax:t->t->tvalmax_value:tvalall:tlistvalto_command_line_suffix:t->stringendmoduleUnit=structtypet=unitletcompare=Unit.compareletmax__=()letmax_value=()letall=[()]letto_command_line_suffix()=""endmoduleMaturity=structtypet=maturity=|Stable|Beta|Alphaletcomparet1t2=letrank=functionStable->1|Beta->2|Alpha->3incompare(rankt1)(rankt2)letmaxt1t2=ifcomparet1t2>=0thent1elset2letmax_value=Alphaletall=[Stable;Beta;Alpha]letto_command_line_suffix =function|Stable ->""|Beta->"_beta"|Alpha->"_alpha"endletmaturity_to_string=function|Alpha->"alpha"|Beta->"beta"|Stable->"stable"letget_level_ops:typea.at->(moduleExtension_levelwithtypet=a)=function|Comprehensions->(moduleUnit)|Mode->(moduleMaturity)|Unique->(moduleMaturity)|Overwriting ->(moduleUnit)|Include_functor->(moduleUnit)|Polymorphic_parameters->(moduleUnit)|Immutable_arrays->(moduleUnit)|Module_strengthening->(moduleUnit)|Layouts->(moduleMaturity)|SIMD->(moduleMaturity)|Labeled_tuples->(moduleUnit)|Small_numbers->(moduleMaturity)|Instances->(moduleUnit)|Let_mutable->(moduleUnit)|Layout_poly->(moduleMaturity)|Runtime_metaprogramming->(moduleUnit)(* We'll do this in a more principled way later. *)(* CR layouts: Note that layouts is only "mostly" erasable, because of annoying
interactions with the pre-layouts [@@immediate] attribute like:
type ('a : immediate) t = 'a [@@immediate]
But we've decided to punt on this issue in the short term.
*)letis_erasable:typea.at->bool=function|Mode|Unique|Overwriting|Layouts|Layout_poly->true|Comprehensions|Include_functor|Polymorphic_parameters|Immutable_arrays|Module_strengthening|SIMD|Labeled_tuples|Small_numbers|Instances|Let_mutable|Runtime_metaprogramming->falseletmaturity_of_unique_for_drf=Stableletmaturity_of_unique_for_destruction=AlphamoduleExist_pair=structtypet=Pair:'alanguage_extension*'a->tletmaturity:t->Maturity.t=function|Pair(Comprehensions,())->Beta|Pair(Mode,m)->m|Pair(Unique,m)->m|Pair(Overwriting,())->Alpha|Pair(Include_functor,())->Stable|Pair(Polymorphic_parameters,())->Stable|Pair(Immutable_arrays,())->Stable|Pair(Module_strengthening,())->Stable|Pair(Layouts,m)->m|Pair(SIMD,m)->m|Pair(Labeled_tuples,())->Stable|Pair(Small_numbers,m)->m|Pair(Instances,())->Stable|Pair(Let_mutable,())->Stable|Pair(Layout_poly,m)->m|Pair(Runtime_metaprogramming,())->Alphaletis_erasable:t->bool=functionPair(ext,_)->is_erasableextletto_string=function|Pair(Layouts,m)->to_stringLayouts^"_"^maturity_to_stringm|Pair(Mode,m)->to_stringMode^"_"^maturity_to_stringm|Pair(Unique,m)->to_stringUnique^"_"^maturity_to_stringm|Pair(Small_numbers,m)->to_stringSmall_numbers^"_"^maturity_to_stringm|Pair(SIMD,m)->to_stringSIMD^"_"^maturity_to_stringm|Pair(Layout_poly,m)->to_stringLayout_poly^"_"^maturity_to_stringm|Pair(((Comprehensions|Include_functor|Polymorphic_parameters|Immutable_arrays|Module_strengthening|Labeled_tuples|Instances|Overwriting|Let_mutable|Runtime_metaprogramming)asext),_)->to_stringext(* converts full extension names, like "layouts_alpha" to a pair of
an extension and its maturity. For extensions that don't take an
argument, the conversion is just [Language_extension_kernel.of_string].
*)letof_stringextn_name:toption=matchString.lowercase_asciiextn_namewith|"comprehensions"->Some(Pair(Comprehensions,()))|"mode"->Some(Pair(Mode,Stable))|"mode_beta"->Some(Pair(Mode,Beta))|"mode_alpha"->Some(Pair(Mode,Alpha))|"unique"->Some(Pair(Unique,Stable))|"unique_beta"->Some(Pair(Unique,Beta))|"unique_alpha"->Some(Pair(Unique,Alpha))|"overwriting"->Some(Pair(Overwriting,()))|"include_functor"->Some(Pair(Include_functor,()))|"polymorphic_parameters"->Some(Pair(Polymorphic_parameters,()))|"immutable_arrays"->Some(Pair(Immutable_arrays,()))|"module_strengthening"->Some(Pair(Module_strengthening,()))|"layouts"->Some(Pair(Layouts,Stable))|"layouts_alpha"->Some(Pair(Layouts,Alpha))|"layouts_beta"->Some(Pair(Layouts,Beta))|"simd"->Some(Pair(SIMD,Stable))|"simd_beta"->Some(Pair(SIMD,Beta))|"simd_alpha"->Some(Pair(SIMD,Alpha))|"labeled_tuples"->Some(Pair(Labeled_tuples,()))|"small_numbers"->Some(Pair(Small_numbers,Stable))|"small_numbers_beta"->Some(Pair(Small_numbers,Beta))|"instances"->Some(Pair(Instances,()))|"let_mutable"->Some(Pair(Let_mutable,()))|"layout_poly"->Some(Pair(Layout_poly,Stable))|"layout_poly_alpha"->Some(Pair(Layout_poly,Alpha))|"layout_poly_beta"->Some(Pair(Layout_poly,Beta))|"runtime_metaprogramming"->Some(Pair(Runtime_metaprogramming,()))|_->Noneendtypeextn_pair=Exist_pair.t=Pair:'at*'a->extn_pairtypeexist=Pack:_t->existletall_extensions=[PackComprehensions;PackMode;PackUnique;PackOverwriting;PackInclude_functor;PackPolymorphic_parameters;PackImmutable_arrays;PackModule_strengthening;PackLayouts;PackSIMD;PackLabeled_tuples;PackSmall_numbers;PackInstances;PackLet_mutable;PackLayout_poly;PackRuntime_metaprogramming](**********************************)(* string conversions *)letto_command_line_string:typea.at->a->string=funextnlevel->let(moduleOps)=get_level_opsextninto_stringextn^Ops.to_command_line_suffixlevelletpair_of_string_exnextn_name=matchExist_pair.of_stringextn_namewith|Somepair->pair|None->raise(Arg.Bad(Printf.sprintf"Extension %s is not known"extn_name))letof_stringextn_name:existoption=matchExist_pair.of_stringextn_namewith|Some(Pair(ext,_))->Some(Packext)|None->None(************************************)(* equality *)letequal_t(typeab)(a:at)(b:bt):(a,b)Misc_stdlib.eqoption=matcha,bwith|Comprehensions,Comprehensions->SomeRefl|Mode,Mode->SomeRefl|Unique,Unique->SomeRefl|Overwriting,Overwriting->SomeRefl|Include_functor,Include_functor->SomeRefl|Polymorphic_parameters,Polymorphic_parameters->SomeRefl|Immutable_arrays,Immutable_arrays->SomeRefl|Module_strengthening,Module_strengthening->SomeRefl|Layouts,Layouts->SomeRefl|SIMD,SIMD->SomeRefl|Labeled_tuples,Labeled_tuples->SomeRefl|Small_numbers,Small_numbers->SomeRefl|Instances,Instances->SomeRefl|Let_mutable,Let_mutable->SomeRefl|Layout_poly,Layout_poly->SomeRefl|Runtime_metaprogramming,Runtime_metaprogramming->SomeRefl|((Comprehensions|Mode|Unique|Overwriting|Include_functor|Polymorphic_parameters|Immutable_arrays|Module_strengthening|Layouts|SIMD|Labeled_tuples|Small_numbers|Instances|Let_mutable|Layout_poly|Runtime_metaprogramming),_)->Noneletequalab=Option.is_some(equal_tab)(*****************************)(* extension universes *)moduleUniverse:sigtypet=|No_extensions|Upstream_compatible|Stable|Beta|Alphavalall:tlistvalmaximal:tvalto_string:t->stringvalof_string:string->toptionvalget:unit->tvalset:t->unitvalis:t->boolvalcheck:extn_pair->unit(* Allowed extensions, each with the greatest allowed level. *)valallowed_extensions_in:t->extn_pairlistend=struct(** Which extensions can be enabled? *)typet=|No_extensions|Upstream_compatible|Stable|Beta|Alpha(* If you add a constructor, you should also add it to [all]. *)letall=[No_extensions;Upstream_compatible;Stable;Beta;Alpha]letmaximal=Alphaletto_string=function|No_extensions->"no_extensions"|Upstream_compatible->"upstream_compatible"|Stable->"stable"|Beta->"beta"|Alpha->"alpha"letof_string=function|"no_extensions"->SomeNo_extensions|"upstream_compatible"->SomeUpstream_compatible|"stable"->SomeStable|"beta"->SomeBeta|"alpha"->SomeAlpha|_->Noneletcomparet1t2=letrank=function|No_extensions->0|Upstream_compatible->1|Stable->2|Beta->3|Alpha->4incompare(rankt1)(rankt2)(* For now, the default universe is set to [Alpha] but only a limited set of
extensions is enabled. After the migration to extension universes, the
default will be [No_extensions]. *)letuniverse=refAlphaletget()=!universeletsetnew_universe=universe:=new_universeletisu=compareu!universe=0letcompiler_options=function|No_extensions->"flag -extension-universe no_extensions"|Upstream_compatible->"flag -extension-universe upstream_compatible"|Stable->"flag -extension-universe stable"|Beta->"flag -extension-universe beta"|Alpha->"flag -extension-universe alpha (default CLI option)"letis_allowed_intextn_pair=matchtwith|No_extensions->false|Upstream_compatible->Exist_pair.is_erasableextn_pair&&Maturity.compare(Exist_pair.maturityextn_pair)Stable<=0|Stable->Maturity.compare(Exist_pair.maturityextn_pair)Stable<=0|Beta->Maturity.compare(Exist_pair.maturityextn_pair)Beta<=0|Alpha->trueletis_allowedextn_pair=is_allowed_in!universeextn_pair(* The terminating [()] argument helps protect against ignored arguments. See
the documentation for [Base.failwithf]. *)letfailfmt=Format.ksprintf(funstr()->raise(Arg.Badstr))fmtletcheckextn_pair=ifnot(is_allowedextn_pair)thenfail"Cannot enable extension %s: incompatible with %s"(Exist_pair.to_stringextn_pair)(compiler_options!universe)()letallowed_extensions_int=letmaximal_in_universe(Packextn)=let(moduleOps)=get_level_opsextninletallowed_levels=Ops.all|>List.filter(funlvl->is_allowed_int(Pair(extn,lvl)))inmatchallowed_levelswith|[]->None|lvl::lvls->letmax_allowed_lvl=List.fold_leftOps.maxlvllvlsinSome(Pair(extn,max_allowed_lvl))inList.filter_mapmaximal_in_universeall_extensionsend(*****************************************)(* enabling / disabling *)(* Mutable state. Invariants:
(1) [!extensions] contains at most one copy of each extension.
(2) Every member of [!extensions] satisfies [Universe.is_allowed]. (For
instance, [!universe = No_extensions] implies [!extensions = []]). *)(* After the migration to extension universes, this will be an empty list. *)letlegacy_default_extensions:extn_pairlist=Universe.allowed_extensions_inStableletextensions:extn_pairlistref=reflegacy_default_extensionsletset_worker(typea)(extn:at)=function|Somevalue->Universe.check(Pair(extn,value));let(moduleOps)=get_level_opsextninletrecupdate_extensionsalready_seen:extn_pairlist->extn_pairlist=function|[]->Pair(extn,value)::already_seen|(Pair(extn',v)ase)::es->(matchequal_textnextn'with|None->update_extensions(e::already_seen)es|SomeRefl->Pair(extn,Ops.maxvvalue)::List.rev_appendalready_seenes)inextensions:=update_extensions[]!extensions|None->extensions:=List.filter(fun(Pair(extn',_):extn_pair)->not(equalextnextn'))!extensionsletsetextn~enabled=set_workerextn(ifenabledthenSome()elseNone)letenableextnvalue=set_workerextn(Somevalue)letdisableextn=set_workerextnNone(* This is similar to [Misc.protect_refs], but we don't have values to set
[extensions] to. *)letwith_temporary_extensionsf=letcurrent_extensions=!extensionsinFun.protect~finally:(fun()->extensions:=current_extensions)f(* It might make sense to ban [set], [enable], [disable],
[only_erasable_extensions], and [disallow_extensions] inside [f], but it's
not clear that it's worth the hassle *)letwith_set_workerextnvaluef=with_temporary_extensions(fun()->set_workerextnvalue;f())letwith_setextn~enabled=with_set_workerextn(ifenabledthenSome()elseNone)letwith_enabledextnvalue=with_set_workerextn(Somevalue)letwith_disabledextn=with_set_workerextnNoneletenable_of_string_exnextn_name=matchpair_of_string_exnextn_namewith|Pair(extn,setting)->enableextnsettingletdisable_of_string_exnextn_name=matchpair_of_string_exnextn_namewithPair(extn,_)->disableextnletdisable_all()=extensions:=[]letunconditionally_enable_maximal_without_checks()=letmaximal_pair(Packextn)=let(moduleOps)=get_level_opsextninPair(extn,Ops.max_value)inextensions:=List.mapmaximal_pairall_extensionsleterasable_extensions_only()=Universe.isNo_extensions||Universe.isUpstream_compatibleletset_universe_and_enable_allu=Universe.setu;extensions:=Universe.allowed_extensions_in(Universe.get())letset_universe_and_enable_all_of_string_exnuniv_name=matchUniverse.of_stringuniv_namewith|Someu->set_universe_and_enable_allu|None->raise(Arg.Bad(Printf.sprintf"Universe %s is not known"univ_name))(********************************************)(* checking an extension *)letis_at_least(typea)(extn:at)(value:a)=letreccheck:extn_pairlist->bool=function|[]->false|Pair(e,v)::es->(let(moduleOps)=get_level_opseinmatchequal_teextnwith|SomeRefl->Ops.comparevvalue>=0|None->checkes)incheck!extensionsletis_enabledextn=letreccheck:extn_pairlist->bool=function|[]->false|Pair(e,_)::_whenequaleextn->true|_::es->checkesincheck!extensionsletget_command_line_string_if_enabledextn=letrecfind=function|[]->None|Pair(e,v)::_whenequaleextn->Some(to_command_line_stringev)|_::es->findesinfind!extensions(********************************************)(* existentially packed extension *)moduleExist=structtypet=exist=Pack:_language_extension->tletall=all_extensionsletto_command_line_strings(Packextn)=let(moduleOps)=get_level_opsextninList.map(to_command_line_stringextn)Ops.allletto_string:t->string=functionPackextn->to_stringextnletis_enabled:t->bool=functionPackextn->is_enabledextnletis_erasable:t->bool=functionPackextn->is_erasableextnendmoduleError=structtypeerror=|Disabled_extension:{ext:_t;maturity:maturityoption}->errorletreport_error~loc=function|Disabled_extension{ext;maturity}->((* CR layouts: The [maturity] special case is a bit ad-hoc, but the
layouts error message would be much worse without it. It also would be
nice to mention the language construct in the error message. *)matchmaturitywith|None->Location.errorf~loc"The extension \"%s\" is disabled and cannot be used"(to_stringext)|Somematurity->Location.errorf~loc"This construct requires the %s version of the extension \"%s\", \
which is disabled and cannot be used"(maturity_to_stringmaturity)(to_stringext))exceptionErrorofLocation.t*errorlet()=Location.register_error_of_exn(function|Error(loc,err)->Some(report_error~locerr)|_->None)endletassert_enabled(typea)~loc(t:at)(setting:a)=ifnot(is_at_leasttsetting)thenletmaturity:maturityoption=matchtwithLayouts->Some(setting:maturity)|_->Noneinraise(Error.Error(loc,Disabled_extension{ext=t;maturity}))(********************************************)(* Special functionality for [Pprintast] *)moduleFor_pprintast=structtypeprinter_exporter={print_with_maximal_extensions:'a.(Format.formatter->'a->unit)->Format.formatter->'a->unit}letcan_still_define_printers=reftrueletmake_printer_exporter()=if!can_still_define_printersthen(can_still_define_printers:=false;{print_with_maximal_extensions=(funppfmtitem->with_temporary_extensions(fun()->(* It's safe to call this here without validating that the
extensions are enabled, because the [Pprintast] printers
should always print Jane syntax. *)unconditionally_enable_maximal_without_checks();ppfmtitem))})elseMisc.fatal_error"Only Pprintast may use [Language_extension.For_pprintast]"end(* merlin-jst: Enable all the ocaml-jst language extensions. We do it this way
rather than updating [default_extensions] to avoid merge conflicts. *)let_=assertUniverse.(ismaximal);(* It's safe to call this here because we've confirmed that we can. *)unconditionally_enable_maximal_without_checks();(* For now, we override the mode and layouts extensions to be in Beta instead of Alpha.
This is to prevent printing unnecessary annotations. *)letlower_mode_extension=function|Pair(Mode,Alpha)->Pair(Mode,Beta)|Pair(Layouts,Alpha)->Pair(Layouts,Beta)|_aspair->pairinextensions:=List.maplower_mode_extension!extensions;;