Skip to content

Commit 0f902bf

Browse files
ericphansonvtjnashararslan
authored
Provide better error hint when UndefVarError results from name clashes (JuliaLang#53469)
We can detect this since we set the `usingfailed` bit when the clash occurs (to avoid printing the `WARNING` multiple times). In this case, typos or missing imports (the current message) isn't quite as clear as it could be, because in fact the name is probably spelled totally right, it's just that there is a missing explicit import or the name should be qualified. This code will stop working if we change the flags in `Core.Binding`, but the test I added should catch that. However if REPL is supposed to be independent of Base and not depend on internals there, there could be an issue. In that case we should probably add an API to Base to inspect this `usingfailed` bit so we can use it in the REPL. --------- Co-authored-by: Jameson Nash <[email protected]> Co-authored-by: Alex Arslan <[email protected]>
1 parent e7734ea commit 0f902bf

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

stdlib/REPL/src/REPL.jl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,16 @@ function UndefVarError_hint(io::IO, ex::UndefVarError)
4444
if C_NULL == owner
4545
# No global of this name exists in this module.
4646
# This is the common case, so do not print that information.
47-
print(io, "\nSuggestion: check for spelling errors or missing imports.")
47+
# It could be the binding was exported by two modules, which we can detect
48+
# by the `usingfailed` flag in the binding:
49+
if isdefined(bnd, :flags) && Bool(bnd.flags >> 4 & 1) # magic location of the `usingfailed` flag
50+
print(io, "\nHint: It looks like two or more modules export different ",
51+
"bindings with this name, resulting in ambiguity. Try explicitly ",
52+
"importing it from a particular module, or qualifying the name ",
53+
"with the module it should come from.")
54+
else
55+
print(io, "\nSuggestion: check for spelling errors or missing imports.")
56+
end
4857
owner = bnd
4958
else
5059
owner = unsafe_pointer_to_objref(owner)::Core.Binding

stdlib/REPL/test/repl.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,35 @@ finally
16961696
empty!(Base.Experimental._hint_handlers)
16971697
end
16981698

1699+
try # test the functionality of `UndefVarError_hint` against import clashes
1700+
@assert isempty(Base.Experimental._hint_handlers)
1701+
Base.Experimental.register_error_hint(REPL.UndefVarError_hint, UndefVarError)
1702+
1703+
@eval module X
1704+
1705+
module A
1706+
export x
1707+
x = 1
1708+
end # A
1709+
1710+
module B
1711+
export x
1712+
x = 2
1713+
end # B
1714+
1715+
using .A, .B
1716+
1717+
end # X
1718+
1719+
expected_message = string("\nHint: It looks like two or more modules export different ",
1720+
"bindings with this name, resulting in ambiguity. Try explicitly ",
1721+
"importing it from a particular module, or qualifying the name ",
1722+
"with the module it should come from.")
1723+
@test_throws expected_message X.x
1724+
finally
1725+
empty!(Base.Experimental._hint_handlers)
1726+
end
1727+
16991728
# Hints for tab completes
17001729

17011730
fake_repl() do stdin_write, stdout_read, repl

0 commit comments

Comments
 (0)