From fa01b95d7f451d3d1125a3ddb9dc3b64840e3f0f Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 25 Jul 2024 22:30:45 +0000 Subject: [PATCH] More 1.12 compat With this and the LCU fixes, Revise should pass tests again on 1.12. --- src/loading.jl | 30 +++++++++++++++++++++--------- src/lowered.jl | 21 +++++++++++++++++++-- src/packagedef.jl | 10 ++++++---- src/pkgs.jl | 2 +- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/loading.jl b/src/loading.jl index f7f57660..f4b31d45 100644 --- a/src/loading.jl +++ b/src/loading.jl @@ -1,23 +1,31 @@ +const badfile = (nothing, nothing, nothing, UInt128(0)) function pkg_fileinfo(id::PkgId) origin = get(Base.pkgorigins, id, nothing) - origin === nothing && return nothing, nothing, nothing + origin === nothing && return badfile cachepath = origin.cachepath - cachepath === nothing && return nothing, nothing, nothing + cachepath === nothing && return badfile + local checksum provides, includes_requires, required_modules = try - @static if VERSION ≥ v"1.11.0-DEV.683" # https://github.com/JuliaLang/julia/pull/49866 + ret = @static if VERSION ≥ v"1.11.0-DEV.683" # https://github.com/JuliaLang/julia/pull/49866 + io = open(cachepath, "r") + checksum = Base.isvalid_cache_header(io) + iszero(checksum) && (close(io); return badfile) provides, (_, includes_srcfiles_only, requires), required_modules, _... = - Base.parse_cache_header(cachepath) + Base.parse_cache_header(io, cachepath) + close(io) provides, (includes_srcfiles_only, requires), required_modules else + checksum = UInt64(0) # Buildid prior to v"1.12.0-DEV.764", and the `srcfiles_only` API does not take `io` Base.parse_cache_header(cachepath, srcfiles_only = true) end - catch - return nothing, nothing, nothing + ret + catch err + return badfile end includes, _ = includes_requires for (pkgid, buildid) in provides if pkgid.uuid === id.uuid && pkgid.name == id.name - return cachepath, includes, first.(required_modules) + return cachepath, includes, first.(required_modules), (UInt128(checksum) << 64 | buildid) end end end @@ -29,13 +37,17 @@ function parse_pkg_files(id::PkgId) end modsym = Symbol(id.name) if use_compiled_modules() - cachefile, includes, reqs = pkg_fileinfo(id) + cachefile, includes, reqs, buildid = pkg_fileinfo(id) if cachefile !== nothing @assert includes !== nothing @assert reqs !== nothing pkgdata.requirements = reqs for chi in includes - mod = Base.root_module(id) + if VERSION >= v"1.12.0-DEV.764" && haskey(Base.loaded_precompiles, id => buildid) + mod = Base.loaded_precompiles[id => buildid] + else + mod = Base.root_module(id) + end for mpath in chi.modpath mod = getfield(mod, Symbol(mpath))::Module end diff --git a/src/lowered.jl b/src/lowered.jl index 97546915..1533213c 100644 --- a/src/lowered.jl +++ b/src/lowered.jl @@ -23,6 +23,23 @@ pop_expr!(methodinfo::MethodInfo) = methodinfo add_dependencies!(methodinfo::MethodInfo, be::CodeEdges, src, isrequired) = methodinfo add_includes!(methodinfo::MethodInfo, mod::Module, filename) = methodinfo +function is_some_include(@nospecialize(f)) + if isa(f, GlobalRef) + return f.name === :include + elseif isa(f, Symbol) + return f === :include + else + if isa(f, QuoteNode) + f = f.value + end + if isa(f, Function) + mod = Base.typename(typeof(f)).module + return isdefined(mod, :include) && f === (@isdefined(getglobal) ? getglobal(mod, :include) : getfield(mod, :include)) + end + end + return false +end + # This is not generally used, see `is_method_or_eval` instead function hastrackedexpr(stmt; heads=LoweredCodeUtils.trackedheads) haseval = false @@ -32,7 +49,7 @@ function hastrackedexpr(stmt; heads=LoweredCodeUtils.trackedheads) f = stmt.args[1] callee_matches(f, Core, :_typebody!) && return true, haseval callee_matches(f, Core, :_setsuper!) && return true, haseval - f === :include && return true, haseval + is_some_include(f) && return true, haseval elseif stmt.head === :thunk any(s->any(hastrackedexpr(s; heads=heads)), (stmt.args[1]::Core.CodeInfo).code) && return true, haseval elseif stmt.head ∈ heads @@ -57,7 +74,7 @@ function categorize_stmt(@nospecialize(stmt)) 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 + isinclude = stmt.head === :call && is_some_include(stmt.args[1]) end return ismeth, haseval, isinclude, isnamespace, istoplevel end diff --git a/src/packagedef.jl b/src/packagedef.jl index 78c031b3..df8ac42a 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -862,7 +862,7 @@ function revise(mod::Module) for def in keys(exsigs) ex = def.ex exuw = unwrap(ex) - isexpr(exuw, :call) && exuw.args[1] === :include && continue + isexpr(exuw, :call) && is_some_include(exuw.args[1]) && continue try Core.eval(mod, ex) catch err @@ -1264,6 +1264,8 @@ function init_worker(p) end) end +active_repl_backend_available() = isdefined(Base, :active_repl_backend) && Base.active_repl_backend !== nothing + function __init__() ccall(:jl_generating_output, Cint, ()) == 1 && return nothing run_on_worker = get(ENV, "JULIA_REVISE_WORKER_ONLY", "0") @@ -1330,18 +1332,18 @@ function __init__() else pushfirst!(REPL.repl_ast_transforms, revise_first) # #664: once a REPL is started, it no longer interacts with REPL.repl_ast_transforms - if isdefined(Base, :active_repl_backend) + if active_repl_backend_available() push!(Base.active_repl_backend.ast_transforms, revise_first) else # wait for active_repl_backend to exist # #719: do this async in case Revise is being loaded from startup.jl t = @async begin iter = 0 - while !isdefined(Base, :active_repl_backend) && iter < 20 + while !active_repl_backend_available() && iter < 20 sleep(0.05) iter += 1 end - if isdefined(Base, :active_repl_backend) + if active_repl_backend_available() push!(Base.active_repl_backend.ast_transforms, revise_first) end end diff --git a/src/pkgs.jl b/src/pkgs.jl index 6935b9a6..7b03694f 100644 --- a/src/pkgs.jl +++ b/src/pkgs.jl @@ -241,7 +241,7 @@ end function deferrable_require!(includes, expr::Expr) if expr.head === :call callee = expr.args[1] - if callee === :include + if is_some_include(callee) if isa(expr.args[2], AbstractString) push!(includes, expr.args[2]) else