diff --git a/src/gf.c b/src/gf.c index e679969ac5376..a6d6d58e9ca32 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1012,7 +1012,7 @@ int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), jl_ } else if (jl_is_mtable(v)) { jl_methtable_t *mt = (jl_methtable_t*)v; - if (mt && mt != jl_method_table) { + if (mt && mt != jl_method_table && mt->module == current_m && mt->name == name) { if (!visit(mt, env)) { result = 0; goto cleanup; diff --git a/test/core.jl b/test/core.jl index 8d75a9e30870b..12424ec3e8bfd 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8559,6 +8559,45 @@ let load_path = mktempdir() end end +# Deduplication of method tables in jl_foreach_reachable_mtable: +# when a method table is imported, it should not be visited multiple times. +let load_path = mktempdir() + depot_path = mkdepottempdir() + try + pushfirst!(LOAD_PATH, load_path) + pushfirst!(DEPOT_PATH, depot_path) + + write(joinpath(load_path, "MtDef.jl"), + """ + module MtDef + Base.Experimental.@MethodTable(mt) + end + """) + + MtDef = Base.require(Main, :MtDef) + @test length(MtDef.mt) == 0 + + write(joinpath(load_path, "MtUser.jl"), + """ + module MtUser + using MtDef: mt + Base.Experimental.@overlay mt sin(x::Int) = 42 + end + """) + + # MtUser imports mt from MtDef, making it reachable from both modules' + # bindings during precompilation. Without deduplication in + # jl_foreach_reachable_mtable, the overlay method would be serialized + # twice, causing an assertion failure when activating methods on load. + MtUser = Base.require(Main, :MtUser) + @test length(MtDef.mt) == 1 + finally + filter!((≠)(load_path), LOAD_PATH) + filter!((≠)(depot_path), DEPOT_PATH) + rm(load_path, recursive=true, force=true) + end +end + # merging va tuple unions @test Tuple === Union{Tuple{},Tuple{Any,Vararg}} @test Tuple{Any,Vararg} === Union{Tuple{Any},Tuple{Any,Any,Vararg}}