-
Notifications
You must be signed in to change notification settings - Fork 34
Description
Issue demonstration
In preparing to revise #160 a bit, I was trying to understand the logic a bit more. I created a fresh package depot with these "package" definitions:
A.jl:
module A
foo(x) = 1
end # moduleB.jl:
module B
import A
struct Foo end
A.foo(::Foo) = 2
end # moduleEach has its own Project.toml file and the standard package directory structure, with B's project file listing A in its [deps] section. Then if I cache symbols, I get this:
julia> env[:A][:foo].methods
1-element Array{SymbolServer.MethodStore,1}:
SymbolServer.MethodStore(:foo, :A, "/tmp/pkgs/dev/A/src/A.jl", 3, Pair{Any,Any}[:x => SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :Core), :Any), Any[])], Symbol[], SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :Core), :Any), Any[]))You'll notice there is only one method listed in the MethodStore, despite the fact that
julia> methods(A.foo)
# 2 methods for generic function "foo":
[1] foo(::B.Foo) in B at /tmp/pkgs/dev/B/src/B.jl:6
[2] foo(x) in A at /tmp/pkgs/dev/A/src/A.jl:3Is it stored in B? To make sure I don't miss it (in case there's name-mangling to encode A.foo), let's look for "foo" anywhere in the name:
julia> ks = String.(keys(env[:B].vals));
julia> filter(s->occursin("foo", s), ks)
0-element Array{String,1}Doesn't seem to be there.
If I change the definition of B.jl to
module B
import A: foo
struct Foo end
foo(::Foo) = 2
end # moduleand start a fresh session and build the cache again, I get
julia> env[:A][:foo].methods
1-element Array{SymbolServer.MethodStore,1}:
SymbolServer.MethodStore(:foo, :A, "/tmp/pkgs/dev/A/src/A.jl", 3, Pair{Any,Any}[:x => SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :Core), :Any), Any[])], Symbol[], SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :Core), :Any), Any[]))
julia> env[:B][:foo].methods
1-element Array{SymbolServer.MethodStore,1}:
SymbolServer.MethodStore(:foo, :B, "/tmp/pkgs/dev/B/src/B.jl", 6, Pair{Any,Any}[Symbol("#unused#") => SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :B), :Foo), Any[])], Symbol[], SymbolServer.FakeTypeName(SymbolServer.VarRef(SymbolServer.VarRef(nothing, :Core), :Any), Any[]))That's better---it got both methods---but if you see a foo(3) in B then
julia> B.foo(3)
1which demonstrates that it called the method defined in A, not the one defined in B. Meaning that all methods are available from any module that can access it. Might this cause a problem? To find out, I added
function bar()
return foo(convert(Int, 3.0))
endto B. Then I positioned my cursor somewhere in foo and hit F12, which takes me to foo(::Foo) rather than foo(::Any), and it doesn't give me a choice in a popup dialog. In contrast, positioning my cursor inside convert and hitting F12 takes me to a definition (the wrong one, but that's a separate issue) but gives me a dialog allowing me to manually choose other methods.
Proposed fix
Fixing this seems to require a bit of an architecture change. To me it seems that the most consistent representation would be to lump all methods for A.foo together in a single FunctionStore placed in A, rather than parcel them out to the modules in which they are defined. This is consistent with how Julia does it:
julia> B.foo === A.foo
true
julia> ft = typeof(A.foo)
typeof(A.foo)
julia> ftn = ft.name
typeof(A.foo)
julia> ftn.module # A "owns" foo...
A
julia> m = methods(A.foo).ms[1]
foo(::B.Foo) in B at /tmp/pkgs/dev/B/src/B.jl:6
julia> m.module # ...even though there are methods for it in B
BWhen foo requires module-scoping for use in B (my first definition of B.jl), then I'd propose that foo should not be a recorded symbol in env[:B]. (Ideally, hitting F12 in a call A.foo(x) would grok the explicit module-scoping and find it in A.) In the second definition of B.jl, where B imported A.foo, I'd propose that env[:B][:foo] should return just VarRef(VarRef(A), :foo), and that all methods of A.foo be looked up in env[:A].