Skip to content

Commit 20162ea

Browse files
authored
Only implicitly using Base, not Core (JuliaLang#57357)
Inspired by the question in JuliaLang#57311 (comment), I want to revisit the basic setup where every module `using`s both `Core` and `Base`. In general, I think we mostly expect users to inferface with `Base`, not `Core`, so this PR changes things to only have new modules `using` Base (while re-exporting all `Core` names from `Base`). There should be little user-visible impact from these changes. The only situation I can think of where it makes a difference is if somebody were to make their own Base/toplevel module that does not re-export Core. However, we don't really support that situation in the first place, and I actually think it's a feature that such toplevel modules can more closely control the set of implicitly exposed names.
1 parent c6805e2 commit 20162ea

File tree

9 files changed

+75
-16
lines changed

9 files changed

+75
-16
lines changed

Compiler/src/typeinfer.jl

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ being used for this purpose alone.
1010
"""
1111
module Timings
1212

13+
using ..Core
1314
using ..Compiler: -, +, :, Vector, length, first, empty!, push!, pop!, @inline,
1415
@inbounds, copy, backtrace
1516

base/Base_compiler.jl

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
baremodule Base
44

5+
using Core
56
using Core.Intrinsics, Core.IR
67

78
# to start, we're going to use a very simple definition of `include`
@@ -135,14 +136,16 @@ include("coreio.jl")
135136

136137
import Core: @doc, @__doc__, WrappedException, @int128_str, @uint128_str, @big_str, @cmd
137138

139+
# Export list
140+
include("exports.jl")
141+
138142
# core docsystem
139143
include("docs/core.jl")
140144
Core.atdoc!(CoreDocs.docm)
141145

142146
eval(x) = Core.eval(Base, x)
143147
eval(m::Module, x) = Core.eval(m, x)
144148

145-
include("exports.jl")
146149
include("public.jl")
147150

148151
if false

base/boot.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ export
238238
# method reflection
239239
applicable, invoke,
240240
# constants
241-
nothing, Main
241+
nothing, Main,
242+
# backwards compatibility
243+
arrayref, arrayset, arraysize, const_arrayref
242244

243245
const getproperty = getfield # TODO: use `getglobal` for modules instead
244246
const setproperty! = setfield!
@@ -1040,7 +1042,6 @@ const_arrayref(inbounds::Bool, A::Array, i::Int...) = Main.Base.getindex(A, i...
10401042
arrayset(inbounds::Bool, A::Array{T}, x::Any, i::Int...) where {T} = Main.Base.setindex!(A, x::T, i...)
10411043
arraysize(a::Array) = a.size
10421044
arraysize(a::Array, i::Int) = sle_int(i, nfields(a.size)) ? getfield(a.size, i) : 1
1043-
export arrayref, arrayset, arraysize, const_arrayref
10441045
const check_top_bit = check_sign_bit
10451046

10461047
# For convenience

base/exports.jl

+39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,44 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3+
# Re-exports from `Core`
4+
export Core,
5+
# key types
6+
Any, DataType, Vararg, NTuple,
7+
Tuple, Type, UnionAll, TypeVar, Union, Nothing, Cvoid,
8+
AbstractArray, DenseArray, NamedTuple, Pair,
9+
# special objects
10+
Function, Method, Module, Symbol, Task, UndefInitializer, undef, WeakRef, VecElement,
11+
Array, Memory, MemoryRef, AtomicMemory, AtomicMemoryRef, GenericMemory, GenericMemoryRef,
12+
# numeric types
13+
Number, Real, Integer, Bool, Ref, Ptr,
14+
AbstractFloat, Float16, Float32, Float64,
15+
Signed, Int, Int8, Int16, Int32, Int64, Int128,
16+
Unsigned, UInt, UInt8, UInt16, UInt32, UInt64, UInt128,
17+
# string types
18+
AbstractChar, Char, AbstractString, String, IO,
19+
# errors
20+
ErrorException, BoundsError, DivideError, DomainError, Exception,
21+
InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError,
22+
OverflowError, StackOverflowError, SegmentationFault, UndefRefError, UndefVarError,
23+
TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError,
24+
UndefKeywordError, ConcurrencyViolationError, FieldError,
25+
# AST representation
26+
Expr, QuoteNode, LineNumberNode, GlobalRef,
27+
# object model functions
28+
fieldtype, getfield, setfield!, swapfield!, modifyfield!, replacefield!, setfieldonce!,
29+
nfields, throw, tuple, ===, isdefined,
30+
# access to globals
31+
getglobal, setglobal!, swapglobal!, modifyglobal!, replaceglobal!, setglobalonce!, isdefinedglobal,
32+
# ifelse, sizeof # not exported, to avoid conflicting with Base
33+
# type reflection
34+
<:, typeof, isa, typeassert,
35+
# method reflection
36+
applicable, invoke,
37+
# constants
38+
nothing, Main,
39+
# backwards compatibility
40+
arrayref, arrayset, arraysize, const_arrayref
41+
342
export
443
# Modules
544
Meta,

base/show.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ function make_typealias(@nospecialize(x::Type))
618618
Any === x && return nothing
619619
x <: Tuple && return nothing
620620
mods = modulesof!(Set{Module}(), x)
621-
Core in mods && push!(mods, Base)
621+
replace!(mods, Core=>Base)
622622
aliases = Tuple{GlobalRef,SimpleVector}[]
623623
xenv = UnionAll[]
624624
for p in uniontypes(unwrap_unionall(x))

src/julia_internal.h

+1
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ _Atomic(jl_value_t*) *jl_table_peek_bp(jl_genericmemory_t *a, jl_value_t *key) J
12381238

12391239
JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*);
12401240

1241+
JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name);
12411242
JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module);
12421243
JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache);
12431244
jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_PROPAGATES_ROOT;

src/module.c

+16-10
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b, size_t min
205205
return bpart;
206206
}
207207

208-
JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_names)
208+
JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name)
209209
{
210210
jl_task_t *ct = jl_current_task;
211211
const jl_uuid_t uuid_zero = {0, 0};
@@ -237,14 +237,20 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui
237237
jl_atomic_store_relaxed(&m->bindings, jl_emptysvec);
238238
jl_atomic_store_relaxed(&m->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any);
239239
arraylist_new(&m->usings, 0);
240-
if (jl_core_module && default_names) {
241-
JL_GC_PUSH1(&m);
242-
jl_module_using(m, jl_core_module);
243-
// export own name, so "using Foo" makes "Foo" itself visible
244-
jl_set_const(m, name, (jl_value_t*)m);
245-
jl_module_public(m, name, 1);
246-
JL_GC_POP();
240+
JL_GC_PUSH1(&m);
241+
if (jl_core_module) {
242+
// Bootstrap: Before jl_core_module is defined, we don't have enough infrastructure
243+
// for bindings, so Core itself gets special handling in jltypes.c
244+
if (default_using_core) {
245+
jl_module_using(m, jl_core_module);
246+
}
247+
if (self_name) {
248+
// export own name, so "using Foo" makes "Foo" itself visible
249+
jl_set_const(m, name, (jl_value_t*)m);
250+
jl_module_public(m, name, 1);
251+
}
247252
}
253+
JL_GC_POP();
248254
return m;
249255
}
250256

@@ -324,7 +330,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3(
324330

325331
JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent)
326332
{
327-
return jl_new_module_(name, parent, 1);
333+
return jl_new_module_(name, parent, 1, 1);
328334
}
329335

330336
uint32_t jl_module_next_counter(jl_module_t *m)
@@ -336,7 +342,7 @@ JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, ui
336342
{
337343
// TODO: should we prohibit this during incremental compilation?
338344
// TODO: the parent module is a lie
339-
jl_module_t *m = jl_new_module_(name, jl_main_module, default_names);
345+
jl_module_t *m = jl_new_module_(name, jl_main_module, default_names, default_names);
340346
JL_GC_PUSH1(&m);
341347
if (std_imports)
342348
jl_add_standard_imports(m);

src/toplevel.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex
135135
}
136136

137137
int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module);
138-
jl_module_t *newm = jl_new_module(name, is_parent__toplevel__ ? NULL : parent_module);
138+
// If we have `Base`, don't also try to import `Core` - the `Base` exports are a superset.
139+
// While we allow multiple imports of the same binding from different modules, various error printing
140+
// performs reflection on which module a binding came from and we'd prefer users see "Base" here.
141+
jl_module_t *newm = jl_new_module_(name, is_parent__toplevel__ ? NULL : parent_module, std_imports && jl_base_module != NULL ? 0 : 1, 1);
139142
jl_value_t *form = (jl_value_t*)newm;
140143
JL_GC_PUSH1(&form);
141144
JL_LOCK(&jl_modules_mutex);

test/misc.jl

+6-1
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,12 @@ end
15741574
@testset "Base docstrings" begin
15751575
undoc = Docs.undocumented_names(Base)
15761576
@test_broken isempty(undoc)
1577-
@test undoc == [:BufferStream, :CanonicalIndexError, :CapturedException, :Filesystem, :IOServer, :InvalidStateException, :Order, :PipeEndpoint, :ScopedValues, :Sort, :TTY]
1577+
@test isempty(setdiff(undoc, [:BufferStream, :CanonicalIndexError, :CapturedException, :Filesystem, :IOServer, :InvalidStateException, :Order, :PipeEndpoint, :ScopedValues, :Sort, :TTY, :AtomicMemoryRef, :Exception, :GenericMemoryRef, :GlobalRef, :IO, :LineNumberNode, :MemoryRef, :Method, :SegmentationFault, :TypeVar, :arrayref, :arrayset, :arraysize, :const_arrayref]))
1578+
end
1579+
1580+
exported_names(m) = filter(s -> Base.isexported(m, s), names(m))
1581+
@testset "Base re-exports Core" begin
1582+
@test issubset(exported_names(Core), exported_names(Base))
15781583
end
15791584

15801585
@testset "Base.Libc docstrings" begin

0 commit comments

Comments
 (0)