Skip to content

Commit 62ceff2

Browse files
committed
More 1.12/GlobalRef fixes
1 parent 1f62f0a commit 62ceff2

File tree

5 files changed

+62
-42
lines changed

5 files changed

+62
-42
lines changed

src/codeedges.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function postprint_linelinks(io::IO, idx::Int, src::CodeInfo, cl::CodeLinks, bbc
157157
printstyled(io, " # ", color=:yellow)
158158
stmt = src.code[idx]
159159
if is_assignment_like(stmt)
160-
lhs = stmt.args[1]
160+
lhs = normalize_defsig(stmt.args[1], cl.thismod)
161161
if @issslotnum(lhs)
162162
# id = lhs.id
163163
# preds, succs = cl.slotpreds[id], cl.slotsuccs[id]

src/signatures.jl

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ MethodInfo(start) = MethodInfo(start, -1, Int[])
121121
struct SelfCall
122122
linetop::Int
123123
linebody::Int
124-
callee::Symbol
125-
caller::Union{Symbol,Bool,Nothing}
124+
callee::GlobalRef
125+
caller::Union{GlobalRef,Bool,Nothing}
126126
end
127127

128128
"""
@@ -140,14 +140,17 @@ which will correspond to a 3-argument `:method` expression containing a `CodeInf
140140
`callee` is the Symbol of the called method.
141141
"""
142142
function identify_framemethod_calls(frame)
143-
refs = Pair{Symbol,Int}[]
144-
methodinfos = Dict{Symbol,MethodInfo}()
143+
refs = Pair{GlobalRef,Int}[]
144+
methodinfos = Dict{GlobalRef,MethodInfo}()
145145
selfcalls = SelfCall[]
146146
for (i, stmt) in enumerate(frame.framecode.src.code)
147147
isa(stmt, Expr) || continue
148148
if stmt.head === :global && length(stmt.args) == 1
149149
key = stmt.args[1]
150150
if isa(key, Symbol)
151+
key = GlobalRef(moduleof(frame), key)
152+
end
153+
if isa(key, GlobalRef)
151154
# We don't know for sure if this is a reference to a method, but let's
152155
# tentatively cue it
153156
push!(refs, key=>i)
@@ -159,7 +162,10 @@ function identify_framemethod_calls(frame)
159162
if is_return(tstmt)
160163
tex = tstmt.val
161164
if isa(tex, Expr)
162-
if tex.head === :method && (methname = tex.args[1]; isa(methname, Symbol))
165+
if tex.head === :method && (methname = tex.args[1]; isa(methname, Union{Symbol, GlobalRef}))
166+
if isa(methname, Symbol)
167+
methname = GlobalRef(moduleof(frame), methname)
168+
end
163169
push!(refs, methname=>i)
164170
end
165171
end
@@ -168,7 +174,7 @@ function identify_framemethod_calls(frame)
168174
elseif ismethod1(stmt)
169175
key = stmt.args[1]
170176
key = normalize_defsig(key, frame)
171-
key = key::Symbol
177+
key = key::GlobalRef
172178
mi = get(methodinfos, key, nothing)
173179
if mi === nothing
174180
methodinfos[key] = MethodInfo(i)
@@ -178,7 +184,7 @@ function identify_framemethod_calls(frame)
178184
elseif ismethod3(stmt)
179185
key = stmt.args[1]
180186
key = normalize_defsig(key, frame)
181-
if key isa Symbol
187+
if key isa GlobalRef
182188
# XXX A temporary hack to fix https://github.com/JuliaDebug/LoweredCodeUtils.jl/issues/80
183189
# We should revisit it.
184190
mi = get(methodinfos, key, MethodInfo(1))
@@ -188,20 +194,23 @@ function identify_framemethod_calls(frame)
188194
end
189195
msrc = stmt.args[3]
190196
if msrc isa CodeInfo
191-
key = key::Union{Symbol,Bool,Nothing}
197+
key = key::Union{GlobalRef,Bool,Nothing}
192198
for (j, mstmt) in enumerate(msrc.code)
193199
isa(mstmt, Expr) || continue
194200
jj = j
195201
if mstmt.head === :call
196-
mkey = mstmt.args[1]
202+
mkey = normalize_defsig(mstmt.args[1], frame)
197203
if isa(mkey, SSAValue) || isa(mkey, Core.SSAValue)
198204
refstmt = msrc.code[mkey.id]
199-
if isa(refstmt, Symbol)
205+
if isa(refstmt, Union{Symbol, GlobalRef})
200206
jj = mkey.id
201207
mkey = refstmt
202208
end
203209
end
204210
if isa(mkey, Symbol)
211+
mkey = GlobalRef(moduleof(frame), mkey)
212+
end
213+
if isa(mkey, GlobalRef)
205214
# Could be a GlobalRef but then it's outside frame
206215
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
207216
elseif is_global_ref(mkey, Core, isdefined(Core, :_apply_iterate) ? :_apply_iterate : :_apply)
@@ -212,14 +221,20 @@ function identify_framemethod_calls(frame)
212221
end
213222
mkey = mstmt.args[end-2]
214223
if isa(mkey, Symbol)
224+
mkey = GlobalRef(moduleof(frame), mkey)
225+
end
226+
if isa(mkey, GlobalRef)
215227
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
216228
end
217229
end
218230
elseif mstmt.head === :meta && mstmt.args[1] === :generated
219231
newex = mstmt.args[2]
220232
if isa(newex, Expr)
221233
if newex.head === :new && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
222-
mkey = newex.args[2]::Symbol
234+
mkey = newex.args[2]
235+
if isa(mkey, Symbol)
236+
mkey = GlobalRef(moduleof(frame), mkey)
237+
end
223238
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
224239
end
225240
end
@@ -235,20 +250,22 @@ function identify_framemethod_calls(frame)
235250
return methodinfos, selfcalls
236251
end
237252

238-
# try to normalize `def` to `Symbol` representation
239-
function normalize_defsig(@nospecialize(def), frame::Frame)
253+
# try to normalize `def` to `GlobalRef` representation
254+
function normalize_defsig(@nospecialize(def), mod::Module)
240255
if def isa QuoteNode
241256
def = nameof(def.value)
242-
elseif def isa GlobalRef
243-
def = def.name
257+
end
258+
if def isa Symbol
259+
def = GlobalRef(mod, def)
244260
end
245261
return def
246262
end
263+
normalize_defsig(@nospecialize(def), frame::Frame) = normalize_defsig(def, moduleof(frame))
247264

248265
function callchain(selfcalls)
249-
calledby = Dict{Symbol,Union{Symbol,Bool,Nothing}}()
266+
calledby = Dict{GlobalRef,Union{GlobalRef,Bool,Nothing}}()
250267
for sc in selfcalls
251-
startswith(String(sc.callee), '#') || continue
268+
startswith(String(sc.callee.name), '#') || continue
252269
caller = get(calledby, sc.callee, nothing)
253270
if caller === nothing
254271
calledby[sc.callee] = sc.caller
@@ -261,7 +278,7 @@ function callchain(selfcalls)
261278
end
262279

263280
function set_to_running_name!(@nospecialize(recurse), replacements, frame, methodinfos, selfcall, calledby, callee, caller)
264-
if isa(caller, Symbol) && startswith(String(caller), '#')
281+
if isa(caller, GlobalRef) && startswith(String(caller.name), '#')
265282
rep = get(replacements, caller, nothing)
266283
if rep === nothing
267284
parentcaller = get(calledby, caller, nothing)
@@ -313,9 +330,9 @@ the same name in the `start:stop` range.
313330
"""
314331
function rename_framemethods!(@nospecialize(recurse), frame::Frame, methodinfos, selfcalls, calledby)
315332
src = frame.framecode.src
316-
replacements = Dict{Symbol,Symbol}()
333+
replacements = Dict{GlobalRef,GlobalRef}()
317334
for (callee, caller) in calledby
318-
(!startswith(String(callee), '#') || haskey(replacements, callee)) && continue
335+
(!startswith(String(callee.name), '#') || haskey(replacements, callee)) && continue
319336
idx = findfirst(sc->sc.callee === callee && sc.caller === caller, selfcalls)
320337
idx === nothing && continue
321338
try
@@ -364,7 +381,7 @@ function find_name_caller_sig(@nospecialize(recurse), frame, pc, name, parentnam
364381
stmt = pc_expr(frame, pc)
365382
end
366383
body = stmt.args[3]
367-
if stmt.args[1] !== name && isa(body, CodeInfo)
384+
if normalize_defsig(stmt.args[1], frame) !== name && isa(body, CodeInfo)
368385
# This might be the GeneratedFunctionStub for a @generated method
369386
for (i, bodystmt) in enumerate(body.code)
370387
if isexpr(bodystmt, :meta) && (bodystmt::Expr).args[1] === :generated
@@ -374,7 +391,7 @@ function find_name_caller_sig(@nospecialize(recurse), frame, pc, name, parentnam
374391
end
375392
if length(body.code) > 1
376393
bodystmt = body.code[end-1] # the line before the final return
377-
iscallto(bodystmt, name, body) && return signature_top(frame, stmt, pc), false
394+
iscallto(bodystmt, moduleof(frame), name, body) && return signature_top(frame, stmt, pc), false
378395
end
379396
end
380397
pc = next_or_nothing(frame, pc)
@@ -412,6 +429,8 @@ function replacename!(args::AbstractVector, pr)
412429
replacename!(a.val::Expr, pr)
413430
elseif a === oldname
414431
args[i] = newname
432+
elseif isa(a, Symbol) && a == oldname.name
433+
args[i] = newname.name
415434
end
416435
end
417436
return args
@@ -438,7 +457,7 @@ function get_running_name(@nospecialize(recurse), frame, pc, name, parentname)
438457
methparent = whichtt(sigtparent)
439458
methparent === nothing && return name, pc, lastpcparent # caller isn't defined, no correction is needed
440459
if isgen
441-
cname = nameof(methparent.generator.gen)
460+
cname = GlobalRef(moduleof(frame), nameof(methparent.generator.gen))
442461
else
443462
bodyparent = Base.uncompressed_ast(methparent)
444463
bodystmt = bodyparent.code[end-1]
@@ -450,7 +469,7 @@ function get_running_name(@nospecialize(recurse), frame, pc, name, parentname)
450469
isa(ref, GlobalRef) || @show ref typeof(ref)
451470
@assert isa(ref, GlobalRef)
452471
@assert ref.mod == moduleof(frame)
453-
cname = ref.name
472+
cname = ref
454473
end
455474
return cname, pc, lastpcparent
456475
end
@@ -519,21 +538,20 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
519538
return pc, pc3
520539
end
521540
ismethod1(stmt) || Base.invokelatest(error, "expected method opening, got ", stmt)
522-
name = stmt.args[1]
523-
name = normalize_defsig(name, frame)
541+
name = normalize_defsig(stmt.args[1], frame)
524542
if isa(name, Bool)
525543
error("not valid for anonymous methods")
526544
elseif name === missing
527545
Base.invokelatest(error, "given invalid definition: ", stmt)
528546
end
529-
name = name::Symbol
547+
name = name::GlobalRef
530548
# Is there any 3-arg method definition with the same name? If not, avoid risk of executing code that
531549
# we shouldn't (fixes https://github.com/timholy/Revise.jl/issues/758)
532550
found = false
533551
for i = pc+1:length(framecode.src.code)
534552
newstmt = framecode.src.code[i]
535553
if ismethod3(newstmt)
536-
if ismethod_with_name(framecode.src, newstmt, string(name))
554+
if ismethod_with_name(framecode.src, newstmt, string(name.name))
537555
found = true
538556
break
539557
end
@@ -550,7 +568,7 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
550568
end
551569
pc3 = pc
552570
stmt = stmt::Expr
553-
name3 = stmt.args[1]
571+
name3 = normalize_defsig(stmt.args[1], frame)
554572
sigt === nothing && (error("expected a signature"); return next_or_nothing(frame, pc)), pc3
555573
# Methods like f(x::Ref{<:Real}) that use gensymmed typevars will not have the *exact*
556574
# signature of the active method. So let's get the active signature.

src/utils.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ end
1818
1919
Returns `true` is `stmt` is a call expression to `name`.
2020
"""
21-
function iscallto(@nospecialize(stmt), name, src)
21+
function iscallto(@nospecialize(stmt), mod::Module, name::GlobalRef, src)
2222
if isa(stmt, Expr)
2323
if stmt.head === :call
2424
a = stmt.args[1]
2525
if isa(a, SSAValue) || isa(a, Core.SSAValue)
2626
a = src.code[a.id]
2727
end
28-
a === name && return true
29-
is_global_ref(a, Core, :_apply) && stmt.args[2] === name && return true
30-
is_global_ref(a, Core, :_apply_iterate) && stmt.args[3] === name && return true
28+
normalize_defsig(a, mod) === name && return true
29+
is_global_ref(a, Core, :_apply) && normalize_defsig(stmt.args[2], mod) === name && return true
30+
is_global_ref(a, Core, :_apply_iterate) && normalize_defsig(stmt.args[3], mod) === name && return true
3131
end
3232
end
3333
return false
@@ -103,7 +103,7 @@ function ismethod_with_name(src, stmt, target::AbstractString; reentrant::Bool=f
103103
end
104104
# On Julia 1.6 we have to add escaping (CBinding makes function names like "(S)")
105105
target = escape_string(target, "()")
106-
return match(Regex("(^|#)$target(\$|#)"), string(name)) !== nothing
106+
return match(Regex("(^|#)$target(\$|#)"), isa(name, GlobalRef) ? string(name.name) : string(name)) !== nothing
107107
end
108108

109109
# anonymous function types are defined in a :thunk expr with a characteristic CodeInfo

test/codeedges.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ module ModSelective end
392392
str = String(take!(io))
393393
if isdefined(Base.IRShow, :show_ir_stmt)
394394
@test occursin(r"slot 1:\n preds: ssas: \[\d+, \d+\], slots: ∅, names: ∅;\n succs: ssas: \[\d+, \d+, \d+\], slots: ∅, names: ∅;\n assign @: \[\d+, \d+\]", str)
395-
@test occursin("# see name s", str)
395+
@test occursin("# see name Main.s", str)
396396
@test occursin("# see slot 1", str)
397397
if Base.VERSION < v"1.8" # changed by global var inference
398398
@test occursin(r"# preds: ssas: \[\d+\], slots: ∅, names: \[\:\(Main\.s\)\]; succs: ssas: ∅, slots: ∅, names: \[\:\(Main\.s\)\];", str)

test/signatures.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ bodymethtest5(x, y=Dict(1=>2)) = 5
103103
modeval, modinclude = getfield(Lowering, :eval), getfield(Lowering, :include)
104104
failed = []
105105
for fsym in nms
106+
isdefined(Lowering, fsym) || continue
106107
f = getfield(Lowering, fsym)
107108
isa(f, Base.Callable) || continue
108109
(f === modeval || f === modinclude) && continue
@@ -348,10 +349,11 @@ bodymethtest5(x, y=Dict(1=>2)) = 5
348349
Core.eval(Lowering, ex)
349350
frame = Frame(Lowering, ex)
350351
dct = rename_framemethods!(frame)
351-
ks = collect(filter(k->startswith(String(k), "#Items#"), keys(dct)))
352+
ks = collect(filter(k->startswith(String(k.name), "#Items#"), keys(dct)))
352353
@test length(ks) == 2
353354
@test dct[ks[1]] == dct[ks[2]]
354-
@test isdefined(Lowering, ks[1]) || isdefined(Lowering, ks[2])
355+
@test ks[1].mod === ks[2].mod === Lowering
356+
@test isdefined(Lowering, ks[1].name) || isdefined(Lowering, ks[2].name)
355357
if !isdefined(Core, :kwcall)
356358
nms = filter(sym->occursin(r"#Items#\d+#\d+", String(sym)), names(Lowering; all=true))
357359
@test length(nms) == 1
@@ -455,7 +457,7 @@ let
455457
@show foogr(1,2,3)
456458
end
457459
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
458-
@test haskey(methranges, :foogr)
460+
@test haskey(methranges, GlobalRef(@__MODULE__, :foogr))
459461
end
460462

461463
function fooqn end
@@ -469,7 +471,7 @@ let
469471
@show fooqn(1,2,3)
470472
end
471473
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
472-
@test haskey(methranges, :fooqn)
474+
@test haskey(methranges, GlobalRef(@__MODULE__, :fooqn))
473475
end
474476

475477
# define methods in other module
@@ -486,7 +488,7 @@ let
486488
@show sandboxgr.foogr_sandbox(1,2,3)
487489
end
488490
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
489-
@test haskey(methranges, :foogr_sandbox)
491+
@test haskey(methranges, GlobalRef(sandboxgr, :foogr_sandbox))
490492
end
491493

492494
module sandboxqn; function fooqn_sandbox end; end
@@ -500,7 +502,7 @@ let
500502
@show sandboxqn.fooqn_sandbox(1,2,3)
501503
end
502504
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
503-
@test haskey(methranges, :fooqn_sandbox)
505+
@test haskey(methranges, GlobalRef(sandboxqn, :fooqn_sandbox))
504506
end
505507

506508
end

0 commit comments

Comments
 (0)