Skip to content

Commit

Permalink
Track GlobalRef consistently (#822)
Browse files Browse the repository at this point in the history
Companion PR to JuliaDebug/LoweredCodeUtils.jl#107. With both of
these and JuliaDebug/JuliaInterpreter.jl#634, basic Revise functionality
is working for me again on Julia master. However, tests are still failing, so there will be more
work needed for full functionality.

Co-authored-by: Tim Holy <[email protected]>
  • Loading branch information
Keno and timholy authored Jul 24, 2024
1 parent 54ee94a commit 4ad68c2
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 20 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- '1.6' # LTS
- '1.9' # parsing errors branch on 1.10, so test the last pre-1.10 version
- '1' # current stable
- 'pre' # next release, if available
os:
- ubuntu-latest
- macOS-latest
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Revise"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.5.15"
version = "3.5.16"

[deps]
CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
Expand All @@ -19,7 +19,7 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
[compat]
CodeTracking = "1.2"
JuliaInterpreter = "0.9"
LoweredCodeUtils = "2.3"
LoweredCodeUtils = "3"
OrderedCollections = "1"
# Exclude Requires-1.1.0 - see https://github.com/JuliaPackaging/Requires.jl/issues/94
Requires = "~1.0, ^1.1.1"
Expand Down
39 changes: 24 additions & 15 deletions src/lowered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ Since the contents of such expression are difficult to analyze, it is generally
safest to execute all such evals.
"""
function minimal_evaluation!(@nospecialize(predicate), methodinfo, mod::Module, src::Core.CodeInfo, mode::Symbol)
edges = CodeEdges(src)
edges = CodeEdges(mod, src)
# LoweredCodeUtils.print_with_code(stdout, src, edges)
isrequired = fill(false, length(src.code))
namedconstassigned = Dict{Symbol,Bool}()
namedconstassigned = Dict{GlobalRef,Bool}()
evalassign = false
for (i, stmt) in enumerate(src.code)
if !isrequired[i]
Expand All @@ -99,18 +99,24 @@ function minimal_evaluation!(@nospecialize(predicate), methodinfo, mod::Module,
end
end
if isexpr(stmt, :const)
name = stmt.args[1]::Symbol
namedconstassigned[name] = false
elseif isexpr(stmt, :(=))
name = stmt.args[1]
if isa(name, Symbol)
name = GlobalRef(mod, name)
end
namedconstassigned[name::GlobalRef] = false
elseif LoweredCodeUtils.is_assignment_like(stmt)
lhs = (stmt::Expr).args[1]
if isa(lhs, Symbol)
lhs = GlobalRef(mod, lhs)
end
if isa(lhs, GlobalRef)
if haskey(namedconstassigned, lhs)
namedconstassigned[lhs] = true
end
end
if mode === :evalassign
evalassign = isrequired[i] = true
if isa(lhs, Symbol)
if isa(lhs, GlobalRef)
isrequired[edges.byname[lhs].succs] .= true # mark any `const` statements or other "uses" in this block
end
end
Expand All @@ -119,7 +125,7 @@ function minimal_evaluation!(@nospecialize(predicate), methodinfo, mod::Module,
if mode === :sigs
for (name, isassigned) in namedconstassigned
isassigned || continue
if isdefined(mod, name)
if isdefined(name.mod, name.name)
empty!(edges.byname[name].succs) # avoid redefining `consts` in `:sigs` mode (fixes #789)
end
end
Expand Down Expand Up @@ -225,7 +231,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
Core.eval(mod, ex)
catch err
(always_rethrow || isa(err, InterruptException)) && rethrow(err)
loc = location_string(whereis(frame)...)
loc = location_string(whereis(frame))
bt = trim_toplevel!(catch_backtrace())
throw(ReviseEvalException(loc, err, Any[(sf, 1) for sf in stacktrace(bt)]))
end
Expand All @@ -248,7 +254,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
methods_by_execution!(recurse, methodinfo, docexprs, frame, isrequired; mode=mode, kwargs...)
catch err
(always_rethrow || isa(err, InterruptException)) && (disablebp && foreach(enable, active_bp_refs); rethrow(err))
loc = location_string(whereis(frame)...)
loc = location_string(whereis(frame))
sfs = [] # crafted for interaction with Base.show_backtrace
frame = JuliaInterpreter.leaf(frame)
while frame !== nothing
Expand Down Expand Up @@ -277,7 +283,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
while true
JuliaInterpreter.is_leaf(frame) || (@warn("not a leaf"); break)
stmt = pc_expr(frame, pc)
if !isrequired[pc] && mode !== :eval && !(mode === :evalassign && isexpr(stmt, :(=)))
if !isrequired[pc] && mode !== :eval && !(mode === :evalassign && LoweredCodeUtils.is_assignment_like(stmt))
pc = next_or_nothing!(frame)
pc === nothing && break
continue
Expand Down Expand Up @@ -309,10 +315,13 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
# However, it might have been followed by a thunk that defined a
# method (issue #435), so we still need to check for additions.
if !isempty(signatures)
file, line = whereis(frame.framecode, pc)
lnn = LineNumberNode(Int(line), Symbol(file))
for sig in signatures
add_signature!(methodinfo, sig, lnn)
loc = whereis(frame.framecode, pc)
if loc !== nothing
file, line = loc
lnn = LineNumberNode(Int(line), Symbol(file))
for sig in signatures
add_signature!(methodinfo, sig, lnn)
end
end
end
pc = next_or_nothing!(frame)
Expand Down Expand Up @@ -400,7 +409,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
end
end
end
elseif head === :(=)
elseif LoweredCodeUtils.is_assignment_like(stmt)
# If we're here, either isrequired[pc] is true, or the mode forces us to eval assignments
pc = step_expr!(recurse, frame, stmt, true)
elseif head === :call
Expand Down
2 changes: 1 addition & 1 deletion src/parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function process_source!(mod_exprs_sigs::ModuleExprsSigs, ex, filename, mod::Mod
catch err
bt = trim_toplevel!(catch_backtrace())
lnn = firstline(ex)
loc = location_string(lnn.file, lnn.line)
loc = location_string((lnn.file, lnn.line))
throw(ReviseEvalException(loc, err, Any[(sf, 1) for sf in stacktrace(bt)]))
end
end
Expand Down
5 changes: 3 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ firstline(rex::RelocatableExpr) = firstline(rex.ex)

newloc(methloc::LineNumberNode, ln, lno) = fixpath(ln)

location_string(file::AbstractString, line) = abspath(file)*':'*string(line)
location_string(file::Symbol, line) = location_string(string(file), line)
location_string((file, line)::Tuple{AbstractString, Any},) = abspath(file)*':'*string(line)
location_string((file, line)::Tuple{Symbol, Any},) = location_string((string(file), line))
location_string(::Nothing) = "unknown location"

function linediff(la::LineNumberNode, lb::LineNumberNode)
(isa(la.file, Symbol) && isa(lb.file, Symbol) && (la.file::Symbol === lb.file::Symbol)) || return typemax(Int)
Expand Down

2 comments on commit 4ad68c2

@timholy
Copy link
Owner

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/111656

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v3.5.16 -m "<description of version>" 4ad68c211b9f31db739e451e5f67d842a0f0592e
git push origin v3.5.16

Please sign in to comment.