diff --git a/NEWS.md b/NEWS.md index e4b509689ec47..2a83fd67e4afe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ Julia v1.8 Release Notes New language features --------------------- +* `Module(:name, false, false)` can be used to create a `module` that does not import `Core`. ([#40110]) Language changes ---------------- diff --git a/base/boot.jl b/base/boot.jl index dcf62a0b9cab2..98b8cf2e9cf40 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -433,7 +433,7 @@ eval(Core, :(InterConditional(slot::Int, @nospecialize(vtype), @nospecialize(els eval(Core, :(MethodMatch(@nospecialize(spec_types), sparams::SimpleVector, method::Method, fully_covers::Bool) = $(Expr(:new, :MethodMatch, :spec_types, :sparams, :method, :fully_covers)))) -Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports) +Module(name::Symbol=:anonymous, std_imports::Bool=true, using_core::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool, Bool), name, std_imports, using_core) function _Task(@nospecialize(f), reserved_stack::Int, completion_future) return ccall(:jl_new_task, Ref{Task}, (Any, Any, Int), f, completion_future, reserved_stack) diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index 3e93ed7d7be02..7d3304810a428 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -303,6 +303,8 @@ include(p) = Base.include(Mod, p) end ``` +If even `Core` is not wanted, a module that imports nothing at all can be defined with `Module(:YourNameHere, false, false)` and code can be evaluated into it with [`@eval`](@ref) or [`Core.eval`](@ref). + ### Standard modules There are three important standard modules: diff --git a/src/module.c b/src/module.c index eee3bc8137ed0..4120b6cb9225d 100644 --- a/src/module.c +++ b/src/module.c @@ -11,7 +11,7 @@ extern "C" { #endif -JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) +JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, uint8_t using_core) { jl_task_t *ct = jl_current_task; const jl_uuid_t uuid_zero = {0, 0}; @@ -36,7 +36,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) htable_new(&m->bindings, 0); arraylist_new(&m->usings, 0); JL_GC_PUSH1(&m); - if (jl_core_module) { + if (jl_core_module && using_core) { jl_module_using(m, jl_core_module); } // export own name, so "using Foo" makes "Foo" itself visible @@ -46,15 +46,20 @@ JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) return m; } +JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name) +{ + return jl_new_module_(name, 1); +} + uint32_t jl_module_next_counter(jl_module_t *m) { return jl_atomic_fetch_add(&m->counter, 1); } -JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports) +JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, uint8_t using_core) { // TODO: should we prohibit this during incremental compilation? - jl_module_t *m = jl_new_module(name); + jl_module_t *m = jl_new_module_(name, using_core); JL_GC_PUSH1(&m); m->parent = jl_main_module; // TODO: this is a lie jl_gc_wb(m, m->parent); diff --git a/test/core.jl b/test/core.jl index e0be3b109cb44..c27a0008fa727 100644 --- a/test/core.jl +++ b/test/core.jl @@ -997,6 +997,8 @@ end # Module() constructor @test names(Module(:anonymous), all = true, imported = true) == [:anonymous] @test names(Module(:anonymous, false), all = true, imported = true) == [:anonymous] +@test Module(:anonymous, false, true).Core == Core +@test_throws UndefVarError Module(:anonymous, false, false).Core # exception from __init__() let didthrow =