Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eval thunks that create methods #794

Merged
merged 1 commit into from
Jan 6, 2024
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
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
Loading