diff --git a/base/reflection.jl b/base/reflection.jl index 6dfaf34bc0047..1a6f4c7b9da54 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -207,6 +207,23 @@ function _fieldnames(@nospecialize t) return t.name.names end +const BINDING_KIND_GLOBAL = 0x0 +const BINDING_KIND_CONST = 0x1 +const BINDING_KIND_CONST_IMPORT = 0x2 +const BINDING_KIND_IMPLICIT = 0x3 +const BINDING_KIND_EXPLICIT = 0x4 +const BINDING_KIND_IMPORTED = 0x5 +const BINDING_KIND_FAILED = 0x6 +const BINDING_KIND_DECLARED = 0x7 +const BINDING_KIND_GUARD = 0x8 + +function lookup_binding_partition(world::UInt, b::Union{GlobalRef, Core.Binding}) + ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world) +end + +binding_kind(bpart::Core.BindingPartition) = bpart.flags & 0xf +binding_kind(m::Module, s::Symbol) = binding_kind(lookup_binding_partition(get_world_counter(), GlobalRef(m, s))) + """ fieldname(x::DataType, i::Integer) diff --git a/src/julia_internal.h b/src/julia_internal.h index 5ab918db9bf59..092d266656728 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -855,7 +855,9 @@ STATIC_INLINE int jl_bpart_is_some_guard(jl_binding_partition_t *b) JL_NOTSAFEPO return b->kind == BINDING_KIND_FAILED || b->kind == BINDING_KIND_GUARD || b->kind == BINDING_KIND_DECLARED; } -STATIC_INLINE jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) JL_NOTSAFEPOINT { +JL_DLLEXPORT inline jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) JL_NOTSAFEPOINT { + if (b && jl_is_globalref(b)) + b = ((jl_globalref_t*)b)->binding; if (!b) return NULL; assert(jl_is_binding(b)); diff --git a/src/module.c b/src/module.c index 52513a3be79b4..7cb1869bccf05 100644 --- a/src/module.c +++ b/src/module.c @@ -12,6 +12,9 @@ extern "C" { #endif +// In this translation unit and this translation unit only emit this symbol `extern` for use by julia +extern JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) JL_NOTSAFEPOINT; + JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_names) { jl_task_t *ct = jl_current_task; @@ -175,6 +178,7 @@ static jl_binding_partition_t *new_binding_partition(void) jl_atomic_store_relaxed(&bpart->max_world, (size_t)-1); jl_atomic_store_relaxed(&bpart->next, NULL); bpart->kind = BINDING_KIND_GUARD; + bpart->padding = 0; return bpart; } @@ -1080,7 +1084,7 @@ void append_module_names(jl_array_t* a, jl_module_t *m, int all, int imported, i jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (((b->publicp) || (imported && (bpart->kind == BINDING_KIND_CONST_IMPORT || bpart->kind == BINDING_KIND_IMPORTED)) || - (usings && bpart->kind == BINDING_KIND_IMPLICIT) || + (usings && bpart->kind == BINDING_KIND_EXPLICIT) || ((bpart->kind == BINDING_KIND_GLOBAL || bpart->kind == BINDING_KIND_CONST) && (all || main_public))) && (all || (!b->deprecated && !hidden))) _append_symbol_to_bindings_array(a, asname); diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index c4b87deb4c854..8000d382fd624 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -33,35 +33,19 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) if isdefined(ex, :scope) scope = ex.scope if scope isa Module - bnd = ccall(:jl_get_module_binding, Any, (Any, Any, Cint), scope, var, true)::Core.Binding - if isdefined(bnd, :owner) - owner = bnd.owner - if owner === bnd - print(io, "\nSuggestion: add an appropriate import or assignment. This global was declared but not assigned.") - end + bpart = Base.lookup_binding_partition(Base.get_world_counter(), GlobalRef(scope, var)) + kind = Base.binding_kind(bpart) + if kind === Base.BINDING_KIND_GLOBAL || kind === Base.BINDING_KIND_CONST || kind == Base.BINDING_KIND_DECLARED + print(io, "\nSuggestion: add an appropriate import or assignment. This global was declared but not assigned.") + elseif kind === Base.BINDING_KIND_FAILED + print(io, "\nHint: It looks like two or more modules export different ", + "bindings with this name, resulting in ambiguity. Try explicitly ", + "importing it from a particular module, or qualifying the name ", + "with the module it should come from.") + elseif kind === Base.BINDING_KIND_GUARD + print(io, "\nSuggestion: check for spelling errors or missing imports.") else - owner = ccall(:jl_binding_owner, Ptr{Cvoid}, (Any, Any), scope, var) - if C_NULL == owner - # No global of this name exists in this module. - # This is the common case, so do not print that information. - # It could be the binding was exported by two modules, which we can detect - # by the `usingfailed` flag in the binding: - if false # TODO: #isdefined(bnd, :flags) && Bool(bnd.flags >> 4 & 1) # magic location of the `usingfailed` flag - print(io, "\nHint: It looks like two or more modules export different ", - "bindings with this name, resulting in ambiguity. Try explicitly ", - "importing it from a particular module, or qualifying the name ", - "with the module it should come from.") - else - print(io, "\nSuggestion: check for spelling errors or missing imports.") - end - owner = bnd - else - owner = unsafe_pointer_to_objref(owner)::Core.Binding - end - end - if owner !== bnd - # this could use jl_binding_dbgmodule for the exported location in the message too - print(io, "\nSuggestion: this global was defined as `$(owner.globalref)` but not assigned a value.") + print(io, "\nSuggestion: this global was defined as `$(bpart.restriction.globalref)` but not assigned a value.") end elseif scope === :static_parameter print(io, "\nSuggestion: run Test.detect_unbound_args to detect method arguments that do not fully constrain a type parameter.")