Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "LoweredCodeUtils"
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
version = "3.10.1"
version = "3.10.2"
authors = ["Tim Holy <tim.holy@gmail.com>", "Shuhei Kadowaki <aviatesk@gmail.com>", "and contributors"]

[workspace]
Expand Down
8 changes: 6 additions & 2 deletions src/codeedges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
end
rhs = stmt
target = P(SSAValue(i), cl.ssapreds[i])
elseif isexpr(stmt, :call) && isanonymous_typedef(stmt)
push!(get!(Vector{Int}, cl.nameassigns, GlobalRef(stmt.args[2]::Module, (stmt.args[3]::QuoteNode).value::Symbol)), i)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit adversarial example-wise, but these accesses are stricter than what isanonymous_typedef checks:

using LoweredCodeUtils
eval_closure_type(x) = x
macro m() :($eval_closure_type(1)) end
CodeEdges(Main, Meta.lower(Main, :(@m)).args[1]) # TypeError

rhs = stmt
target = P(SSAValue(i), cl.ssapreds[i])
elseif (lhs_rhs = get_lhs_rhs(stmt); lhs_rhs !== nothing)
# An assignment
lhs, rhs = lhs_rhs
Expand Down Expand Up @@ -1151,9 +1155,9 @@ function add_typedefs!(
while i <= length(stmts) && !ismethod3(stmts[i])
i += 1
end
if i <= length(stmts) && method_name(stmts[i]::Expr) == false
if i <= length(stmts) && method_name(stmts[i]::Expr) in (false, nothing)
tpreds = terminal_preds(i, edges)
if minimum(tpreds) == idx && i ∉ norequire
if minimum(tpreds) == minimum(terminal_preds(idx, edges); init=idx) && i ∉ norequire
changed |= !isrequired[i]
isrequired[i] = true
end
Expand Down
20 changes: 13 additions & 7 deletions src/signatures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ function identify_framemethod_calls(frame::Frame)
elseif mstmt.head === :meta && mstmt.args[1] === :generated
newex = mstmt.args[2]
if isa(newex, Expr)
if newex.head === :new && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
mkey = newex.args[2]
if newex.head === :new && length(newex.args) >= 3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the consequences are too bad here, but boy does it feel icky to match any :new in :meta :generated and assume it's a @generated stub. Can't wait for the re-work.

mkey = is_global_ref(newex.args[1], Core, :GeneratedFunctionStub) ? newex.args[2] : newex.args[3]
if isa(mkey, Symbol)
mkey = GlobalRef(moduleof(frame), mkey)
end
Expand Down Expand Up @@ -365,10 +365,10 @@ end
rename_framemethods!(frame::Frame) = rename_framemethods!(RecursiveInterpreter(), frame)

"""
pctop, isgen = find_name_caller_sig(interp::Interpreter, frame::Frame, pc::Int, name::GlobalRef)
pctop, isgen, pcmeth = find_name_caller_sig(interp::Interpreter, frame::Frame, pc::Int, name::GlobalRef)

Scans forward from `pc` in `frame` until a method is found that calls `name`.
`pctop` points to the beginning of that method's signature.
`pctop` points to the beginning of that method's signature, and `pcmeth` to its 3-argument `:method` expression.
`isgen` is true if `name` corresponds to a generated-function stub.

Alternatively, this returns `nothing` if `pc` does not appear to point to either
Expand All @@ -387,13 +387,13 @@ function find_name_caller_sig(interp::Interpreter, frame::Frame, pc::Int, name::
# This might be the GeneratedFunctionStub for a @generated method
for (i, bodystmt) in enumerate(body.code)
if isexpr(bodystmt, :meta) && (bodystmt::Expr).args[1] === :generated
return signature_top(frame, stmt, pc), true
return signature_top(frame, stmt, pc), true, pc
end
i >= 5 && break # we should find this early
end
if length(body.code) > 1
bodystmt = body.code[end-1] # the line before the final return
iscallto(bodystmt, moduleof(frame), name, body) && return signature_top(frame, stmt, pc), false
iscallto(bodystmt, moduleof(frame), name, body) && return signature_top(frame, stmt, pc), false, pc
end
end
pc = next_or_nothing(interp, frame, pc)
Expand Down Expand Up @@ -448,7 +448,7 @@ function get_running_name(interp::Interpreter, frame::Frame, pc::Int, name::Glob
pc = next_or_nothing(interp, frame, pc)
return name, pc, nothing
end
pctop, isgen = nameinfo
pctop, isgen, pcmeth = nameinfo
# Sometimes signature_top---which follows SSAValue links backwards to find the first
# line needed to define the signature---misses out on a SlotNumber assignment.
# Fix https://github.com/timholy/Revise.jl/issues/422
Expand All @@ -458,6 +458,12 @@ function get_running_name(interp::Interpreter, frame::Frame, pc::Int, name::Glob
stmt = pc_expr(frame, pctop)
end # end fix
methinfo, lastpcparent = signature(interp, frame, pctop)
# Other methods may be defined among the statements of the caller's signature
while methinfo !== nothing && frame.pc < pcmeth
pcnext = next_or_nothing!(interp, frame)
pcnext === nothing && break
methinfo, lastpcparent = signature(interp, frame, pcnext)
end
methinfo === nothing && return name, pc, lastpcparent
mt, sigtparent = methinfo
# Resolve against the live method tables at the latest committed world, not `whichtt`'s
Expand Down
3 changes: 3 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ end
# anonymous function types are defined in a :thunk expr with a characteristic CodeInfo
function isanonymous_typedef(@nospecialize stmt)
if isa(stmt, Expr)
stmt.head === :call && return isa(stmt.args[1], Function) && nameof(stmt.args[1]) === :eval_closure_type
stmt.head === :thunk || return false
stmt = stmt.args[1]
end
Expand Down Expand Up @@ -302,6 +303,8 @@ function typedef_range(src::CodeInfo, idx)
iend, n = idx, length(src.code)
while iend <= n
s = src.code[iend]
next = iend < n ? getrhs(src.code[iend+1]) : nothing
isexpr(s, :latestworld) && isexpr(next, :call) && callee_matches(next.args[1], Core, :getfield) && (iend += 1; continue)
(isexpr(s, :latestworld) || isexpr(s, :global) || is_return(s)) && break
iend += 1
end
Expand Down
Loading