Skip to content

Commit f111efe

Browse files
authored
More 1.12/GlobalRef fixes (#113)
1 parent 1f62f0a commit f111efe

File tree

5 files changed

+58
-52
lines changed

5 files changed

+58
-52
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: 44 additions & 39 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,14 @@ 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
149-
key = stmt.args[1]
150-
if isa(key, Symbol)
149+
key = normalize_defsig(stmt.args[1], frame)
150+
if isa(key, GlobalRef)
151151
# We don't know for sure if this is a reference to a method, but let's
152152
# tentatively cue it
153153
push!(refs, key=>i)
@@ -159,16 +159,16 @@ function identify_framemethod_calls(frame)
159159
if is_return(tstmt)
160160
tex = tstmt.val
161161
if isa(tex, Expr)
162-
if tex.head === :method && (methname = tex.args[1]; isa(methname, Symbol))
163-
push!(refs, methname=>i)
162+
if tex.head === :method && (methname = tex.args[1]; isa(methname, Union{Symbol, GlobalRef}))
163+
push!(refs, normalize_defsig(methname, frame)=>i)
164164
end
165165
end
166166
end
167167
end
168168
elseif ismethod1(stmt)
169169
key = stmt.args[1]
170170
key = normalize_defsig(key, frame)
171-
key = key::Symbol
171+
key = key::GlobalRef
172172
mi = get(methodinfos, key, nothing)
173173
if mi === nothing
174174
methodinfos[key] = MethodInfo(i)
@@ -178,7 +178,7 @@ function identify_framemethod_calls(frame)
178178
elseif ismethod3(stmt)
179179
key = stmt.args[1]
180180
key = normalize_defsig(key, frame)
181-
if key isa Symbol
181+
if key isa GlobalRef
182182
# XXX A temporary hack to fix https://github.com/JuliaDebug/LoweredCodeUtils.jl/issues/80
183183
# We should revisit it.
184184
mi = get(methodinfos, key, MethodInfo(1))
@@ -188,38 +188,40 @@ function identify_framemethod_calls(frame)
188188
end
189189
msrc = stmt.args[3]
190190
if msrc isa CodeInfo
191-
key = key::Union{Symbol,Bool,Nothing}
191+
key = key::Union{GlobalRef,Bool,Nothing}
192192
for (j, mstmt) in enumerate(msrc.code)
193193
isa(mstmt, Expr) || continue
194194
jj = j
195195
if mstmt.head === :call
196-
mkey = mstmt.args[1]
196+
mkey = normalize_defsig(mstmt.args[1], frame)
197197
if isa(mkey, SSAValue) || isa(mkey, Core.SSAValue)
198198
refstmt = msrc.code[mkey.id]
199-
if isa(refstmt, Symbol)
199+
if isa(refstmt, Union{Symbol, GlobalRef})
200200
jj = mkey.id
201-
mkey = refstmt
201+
mkey = normalize_defsig(refstmt, frame)
202202
end
203203
end
204-
if isa(mkey, Symbol)
205-
# Could be a GlobalRef but then it's outside frame
206-
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
207-
elseif is_global_ref(mkey, Core, isdefined(Core, :_apply_iterate) ? :_apply_iterate : :_apply)
204+
if is_global_ref(mkey, Core, isdefined(Core, :_apply_iterate) ? :_apply_iterate : :_apply)
208205
ssaref = mstmt.args[end-1]
209206
if isa(ssaref, JuliaInterpreter.SSAValue)
210207
id = ssaref.id
211208
has_self_call(msrc, msrc.code[id]) || continue
212209
end
213-
mkey = mstmt.args[end-2]
214-
if isa(mkey, Symbol)
210+
mkey = normalize_defsig(mstmt.args[end-2], frame)
211+
if isa(mkey, GlobalRef)
215212
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
216213
end
214+
elseif isa(mkey, GlobalRef)
215+
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
217216
end
218217
elseif mstmt.head === :meta && mstmt.args[1] === :generated
219218
newex = mstmt.args[2]
220219
if isa(newex, Expr)
221220
if newex.head === :new && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
222-
mkey = newex.args[2]::Symbol
221+
mkey = newex.args[2]
222+
if isa(mkey, Symbol)
223+
mkey = GlobalRef(moduleof(frame), mkey)
224+
end
223225
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
224226
end
225227
end
@@ -235,20 +237,22 @@ function identify_framemethod_calls(frame)
235237
return methodinfos, selfcalls
236238
end
237239

238-
# try to normalize `def` to `Symbol` representation
239-
function normalize_defsig(@nospecialize(def), frame::Frame)
240+
# try to normalize `def` to `GlobalRef` representation
241+
function normalize_defsig(@nospecialize(def), mod::Module)
240242
if def isa QuoteNode
241243
def = nameof(def.value)
242-
elseif def isa GlobalRef
243-
def = def.name
244+
end
245+
if def isa Symbol
246+
def = GlobalRef(mod, def)
244247
end
245248
return def
246249
end
250+
normalize_defsig(@nospecialize(def), frame::Frame) = normalize_defsig(def, moduleof(frame))
247251

248252
function callchain(selfcalls)
249-
calledby = Dict{Symbol,Union{Symbol,Bool,Nothing}}()
253+
calledby = Dict{GlobalRef,Union{GlobalRef,Bool,Nothing}}()
250254
for sc in selfcalls
251-
startswith(String(sc.callee), '#') || continue
255+
startswith(String(sc.callee.name), '#') || continue
252256
caller = get(calledby, sc.callee, nothing)
253257
if caller === nothing
254258
calledby[sc.callee] = sc.caller
@@ -261,7 +265,7 @@ function callchain(selfcalls)
261265
end
262266

263267
function set_to_running_name!(@nospecialize(recurse), replacements, frame, methodinfos, selfcall, calledby, callee, caller)
264-
if isa(caller, Symbol) && startswith(String(caller), '#')
268+
if isa(caller, GlobalRef) && startswith(String(caller.name), '#')
265269
rep = get(replacements, caller, nothing)
266270
if rep === nothing
267271
parentcaller = get(calledby, caller, nothing)
@@ -313,9 +317,9 @@ the same name in the `start:stop` range.
313317
"""
314318
function rename_framemethods!(@nospecialize(recurse), frame::Frame, methodinfos, selfcalls, calledby)
315319
src = frame.framecode.src
316-
replacements = Dict{Symbol,Symbol}()
320+
replacements = Dict{GlobalRef,GlobalRef}()
317321
for (callee, caller) in calledby
318-
(!startswith(String(callee), '#') || haskey(replacements, callee)) && continue
322+
(!startswith(String(callee.name), '#') || haskey(replacements, callee)) && continue
319323
idx = findfirst(sc->sc.callee === callee && sc.caller === caller, selfcalls)
320324
idx === nothing && continue
321325
try
@@ -364,7 +368,7 @@ function find_name_caller_sig(@nospecialize(recurse), frame, pc, name, parentnam
364368
stmt = pc_expr(frame, pc)
365369
end
366370
body = stmt.args[3]
367-
if stmt.args[1] !== name && isa(body, CodeInfo)
371+
if normalize_defsig(stmt.args[1], frame) !== name && isa(body, CodeInfo)
368372
# This might be the GeneratedFunctionStub for a @generated method
369373
for (i, bodystmt) in enumerate(body.code)
370374
if isexpr(bodystmt, :meta) && (bodystmt::Expr).args[1] === :generated
@@ -374,7 +378,7 @@ function find_name_caller_sig(@nospecialize(recurse), frame, pc, name, parentnam
374378
end
375379
if length(body.code) > 1
376380
bodystmt = body.code[end-1] # the line before the final return
377-
iscallto(bodystmt, name, body) && return signature_top(frame, stmt, pc), false
381+
iscallto(bodystmt, moduleof(frame), name, body) && return signature_top(frame, stmt, pc), false
378382
end
379383
end
380384
pc = next_or_nothing(frame, pc)
@@ -412,6 +416,8 @@ function replacename!(args::AbstractVector, pr)
412416
replacename!(a.val::Expr, pr)
413417
elseif a === oldname
414418
args[i] = newname
419+
elseif isa(a, Symbol) && a == oldname.name
420+
args[i] = newname.name
415421
end
416422
end
417423
return args
@@ -438,7 +444,7 @@ function get_running_name(@nospecialize(recurse), frame, pc, name, parentname)
438444
methparent = whichtt(sigtparent)
439445
methparent === nothing && return name, pc, lastpcparent # caller isn't defined, no correction is needed
440446
if isgen
441-
cname = nameof(methparent.generator.gen)
447+
cname = GlobalRef(moduleof(frame), nameof(methparent.generator.gen))
442448
else
443449
bodyparent = Base.uncompressed_ast(methparent)
444450
bodystmt = bodyparent.code[end-1]
@@ -450,7 +456,7 @@ function get_running_name(@nospecialize(recurse), frame, pc, name, parentname)
450456
isa(ref, GlobalRef) || @show ref typeof(ref)
451457
@assert isa(ref, GlobalRef)
452458
@assert ref.mod == moduleof(frame)
453-
cname = ref.name
459+
cname = ref
454460
end
455461
return cname, pc, lastpcparent
456462
end
@@ -519,21 +525,20 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
519525
return pc, pc3
520526
end
521527
ismethod1(stmt) || Base.invokelatest(error, "expected method opening, got ", stmt)
522-
name = stmt.args[1]
523-
name = normalize_defsig(name, frame)
528+
name = normalize_defsig(stmt.args[1], frame)
524529
if isa(name, Bool)
525530
error("not valid for anonymous methods")
526531
elseif name === missing
527532
Base.invokelatest(error, "given invalid definition: ", stmt)
528533
end
529-
name = name::Symbol
534+
name = name::GlobalRef
530535
# Is there any 3-arg method definition with the same name? If not, avoid risk of executing code that
531536
# we shouldn't (fixes https://github.com/timholy/Revise.jl/issues/758)
532537
found = false
533538
for i = pc+1:length(framecode.src.code)
534539
newstmt = framecode.src.code[i]
535540
if ismethod3(newstmt)
536-
if ismethod_with_name(framecode.src, newstmt, string(name))
541+
if ismethod_with_name(framecode.src, newstmt, string(name.name))
537542
found = true
538543
break
539544
end
@@ -550,7 +555,7 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
550555
end
551556
pc3 = pc
552557
stmt = stmt::Expr
553-
name3 = stmt.args[1]
558+
name3 = normalize_defsig(stmt.args[1], frame)
554559
sigt === nothing && (error("expected a signature"); return next_or_nothing(frame, pc)), pc3
555560
# Methods like f(x::Ref{<:Real}) that use gensymmed typevars will not have the *exact*
556561
# 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: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,11 @@ bodymethtest5(x, y=Dict(1=>2)) = 5
348348
Core.eval(Lowering, ex)
349349
frame = Frame(Lowering, ex)
350350
dct = rename_framemethods!(frame)
351-
ks = collect(filter(k->startswith(String(k), "#Items#"), keys(dct)))
351+
ks = collect(filter(k->startswith(String(k.name), "#Items#"), keys(dct)))
352352
@test length(ks) == 2
353353
@test dct[ks[1]] == dct[ks[2]]
354-
@test isdefined(Lowering, ks[1]) || isdefined(Lowering, ks[2])
354+
@test ks[1].mod === ks[2].mod === Lowering
355+
@test isdefined(Lowering, ks[1].name) || isdefined(Lowering, ks[2].name)
355356
if !isdefined(Core, :kwcall)
356357
nms = filter(sym->occursin(r"#Items#\d+#\d+", String(sym)), names(Lowering; all=true))
357358
@test length(nms) == 1
@@ -455,7 +456,7 @@ let
455456
@show foogr(1,2,3)
456457
end
457458
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
458-
@test haskey(methranges, :foogr)
459+
@test haskey(methranges, GlobalRef(@__MODULE__, :foogr))
459460
end
460461

461462
function fooqn end
@@ -469,7 +470,7 @@ let
469470
@show fooqn(1,2,3)
470471
end
471472
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
472-
@test haskey(methranges, :fooqn)
473+
@test haskey(methranges, GlobalRef(@__MODULE__, :fooqn))
473474
end
474475

475476
# define methods in other module
@@ -486,7 +487,7 @@ let
486487
@show sandboxgr.foogr_sandbox(1,2,3)
487488
end
488489
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
489-
@test haskey(methranges, :foogr_sandbox)
490+
@test haskey(methranges, GlobalRef(sandboxgr, :foogr_sandbox))
490491
end
491492

492493
module sandboxqn; function fooqn_sandbox end; end
@@ -500,7 +501,7 @@ let
500501
@show sandboxqn.fooqn_sandbox(1,2,3)
501502
end
502503
methranges = rename_framemethods!(Frame(@__MODULE__, ex))
503-
@test haskey(methranges, :fooqn_sandbox)
504+
@test haskey(methranges, GlobalRef(sandboxqn, :fooqn_sandbox))
504505
end
505506

506507
end

0 commit comments

Comments
 (0)