diff --git a/Project.toml b/Project.toml index 1208605..f14fff2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "LoweredCodeUtils" uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" -version = "3.10.1" +version = "3.10.2" authors = ["Tim Holy ", "Shuhei Kadowaki ", "and contributors"] [workspace] diff --git a/src/codeedges.jl b/src/codeedges.jl index 1f6bde3..f13f609 100644 --- a/src/codeedges.jl +++ b/src/codeedges.jl @@ -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) + 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 @@ -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 diff --git a/src/signatures.jl b/src/signatures.jl index a9dd045..56aaa1a 100644 --- a/src/signatures.jl +++ b/src/signatures.jl @@ -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 + 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 @@ -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 @@ -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) @@ -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 @@ -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 diff --git a/src/utils.jl b/src/utils.jl index 0526918..20c4edd 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -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 @@ -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