Skip to content

Commit

Permalink
Eval thunks that create methods (#794)
Browse files Browse the repository at this point in the history
Fixes #792
  • Loading branch information
timholy authored Jan 6, 2024
1 parent 1ea6980 commit 9272cba
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
19 changes: 17 additions & 2 deletions src/lowered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,25 @@ function categorize_stmt(@nospecialize(stmt))
ismeth, haseval, isinclude, isnamespace, istoplevel = false, false, false, false, false
if isa(stmt, Expr)
haseval = matches_eval(stmt)
ismeth = stmt.head === :method
ismeth = stmt.head === :method || (stmt.head === :thunk && defines_function(only(stmt.args)))
istoplevel = stmt.head === :toplevel
isnamespace = stmt.head === :export || stmt.head === :import || stmt.head === :using
isinclude = stmt.head === :call && stmt.args[1] === :include
end
return ismeth, haseval, isinclude, isnamespace, istoplevel
end
# Check for thunks that define functions (fixes #792)
function defines_function(ci)
isa(ci, CodeInfo) || return false
if length(ci.code) == 1
stmt = ci.code[1]
if isa(stmt, Core.ReturnNode)
val = stmt.val
isexpr(val, :method) && return true
end
end
return false
end

"""
isrequired, evalassign = minimal_evaluation!([predicate,] methodinfo, src::Core.CodeInfo, mode::Symbol)
Expand Down Expand Up @@ -280,6 +292,9 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
end
isassign(frame, pc) && assign_this!(frame, value)
pc = next_or_nothing!(frame)
elseif head === :thunk && defines_function(only(stmt.args))
mode !== :sigs && Core.eval(mod, stmt)
pc = next_or_nothing!(frame)
# elseif head === :thunk && isanonymous_typedef(stmt.args[1])
# # Anonymous functions should just be defined anew, since there does not seem to be a practical
# # way to find them within the already-defined module.
Expand All @@ -300,7 +315,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
add_signature!(methodinfo, sig, lnn)
end
end
pc += 1
pc = next_or_nothing!(frame)
else
pc, pc3 = ret
# Get the line number from the body
Expand Down
2 changes: 1 addition & 1 deletion test/backedges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ do_test("Backedges") && @testset "Backedges" begin
src2 = src.code[idtype].args[1]
methodinfo = Revise.MethodInfo()
isrequired = Revise.minimal_evaluation!(methodinfo, frame, :sigs)[1]
@test sum(isrequired) == length(src.code)-2 # skips the `return` at the end
@test sum(isrequired) == length(src.code)-1 # skips the `return` at the end

src = """
# issue #249
Expand Down
22 changes: 21 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using Base.CoreLogging: Debug,Info
using Revise.CodeTracking: line_is_decl

# In addition to using this for the "More arg-modifying macros" test below,
# this package is used on Travis to test what happens when you have multiple
# this package is used on CI to test what happens when you have multiple
# *.ji files for the package.
using EponymTuples

Expand All @@ -41,6 +41,12 @@ macro addint(ex)
:($(esc(ex))::$(esc(Int)))
end

macro empty_function(name)
return esc(quote
function $name end
end)
end

# The following two submodules are for testing #199
module A
f(x::Int) = 1
Expand Down Expand Up @@ -1409,6 +1415,20 @@ const issue639report = []
@test MacroLineNos568.my_fun() == 30
rm_precompile("MacroLineNos568")

# Macros that create empty functions (another macro *execution* bug, issue #792)
file = tempname()
write(file, "@empty_function issue792f1\n")
sleep(mtimedelay)
includet(ReviseTestPrivate, file)
sleep(mtimedelay)
@test isempty(methods(ReviseTestPrivate.issue792f1))
open(file, "a") do f
println(f, "@empty_function issue792f2")
end
yry()
@test isempty(methods(ReviseTestPrivate.issue792f2))
rm(file)

pop!(LOAD_PATH)
end

Expand Down

0 comments on commit 9272cba

Please sign in to comment.