From 6505d0de7466bf2cbc2c59eb8987fcfa2bf340a0 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Sat, 11 Jul 2026 10:05:57 +0900 Subject: [PATCH] [JuliaLowering] Restore partial Julia 1.12 compatibility Recent JuliaLowering changes unconditionally referenced runtime features that are unavailable on Julia 1.12. This prevented JuliaLowering and JuliaSyntax from loading or lowering code on that release (esp. in JETLS). Guard `Core.MacroSource`, `Core.TypeEqOf`, and `jl_lowering_world` behind availability checks, falling back to `Core.Typeof` and direct invocation where needed. The `include_string` precompile workload remains restricted to newer runtimes because its evaluation path is incompatible with Julia 1.12. Keep the preceding lowering-only workloads enabled there: they do not evaluate lowered code, still exercise the basic lowering pipeline, and remain usable on Julia 1.12. --- JuliaLowering/src/JuliaLowering.jl | 4 +- JuliaLowering/src/closure_conversion.jl | 2 +- JuliaLowering/src/macro_expansion.jl | 2 +- JuliaLowering/src/precompile.jl | 47 ++++++++++++----------- JuliaLowering/src/runtime.jl | 18 +++++---- JuliaSyntax/src/integration/expr.jl | 2 +- JuliaSyntax/src/porcelain/syntax_graph.jl | 4 +- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/JuliaLowering/src/JuliaLowering.jl b/JuliaLowering/src/JuliaLowering.jl index ec18b4d1d9fff..867ef7cb69b42 100644 --- a/JuliaLowering/src/JuliaLowering.jl +++ b/JuliaLowering/src/JuliaLowering.jl @@ -27,7 +27,9 @@ const DEBUG = true # Falls back to `Union{}` so that `loc isa MacroSource` is always false on Julia < 1.14 # where `Core.MacroSource` is not defined. -const MacroSource = isdefined(Core, :MacroSource) ? Core.MacroSource : Union{} +const MacroSource = isdefinedglobal(Core, :MacroSource) ? Core.MacroSource : Union{} + +const TypeEqOf = isdefinedglobal(Core, :TypeEqOf) ? "TypeEqOf" : "Typeof" _include("kinds.jl") _register_kinds() diff --git a/JuliaLowering/src/closure_conversion.jl b/JuliaLowering/src/closure_conversion.jl index 2f92290d44603..030a3fd97d610 100644 --- a/JuliaLowering/src/closure_conversion.jl +++ b/JuliaLowering/src/closure_conversion.jl @@ -487,7 +487,7 @@ function _convert_closures(ctx::ClosureConversionCtx, ex) (ex, "function_type of local without known closure type")) ctx.closure_infos[func_name.var_id].type_name else - @ast ctx ex [K"call" "TypeEqOf"::K"core" _convert_closures(ctx, func_name)] + @ast ctx ex [K"call" TypeEqOf::K"core" _convert_closures(ctx, func_name)] end elseif k == K"method_defs" name = ex[1] diff --git a/JuliaLowering/src/macro_expansion.jl b/JuliaLowering/src/macro_expansion.jl index 8cdb2b709daca..73229a10e4981 100644 --- a/JuliaLowering/src/macro_expansion.jl +++ b/JuliaLowering/src/macro_expansion.jl @@ -207,7 +207,7 @@ function _macrocall_expr_location(st::SyntaxTree) end elseif kind(st[2]) === K"VERSION" loc = source_location(LineNumberNode, st) - isdefined(Core, :MacroSource) ? Core.MacroSource(loc, st[2].value) : loc + @static isdefinedglobal(Core, :MacroSource) ? Core.MacroSource(loc, st[2].value) : loc else LineNumberNode(0, :none) end diff --git a/JuliaLowering/src/precompile.jl b/JuliaLowering/src/precompile.jl index 4606d0052c737..2a3fb65bd9614 100644 --- a/JuliaLowering/src/precompile.jl +++ b/JuliaLowering/src/precompile.jl @@ -1,5 +1,6 @@ -# exercise the whole lowering pipeline -if Base.get_bool_env("JULIA_LOWERING_PRECOMPILE", true) +@static if Base.get_bool_env("JULIA_LOWERING_PRECOMPILE", true) + # Exercise lowering directly so this also works on runtimes where evaluating + # JuliaLowering output through `include_string` is not yet compatible. thunks = String[ """ function foo(xxx, yyy) @@ -25,28 +26,30 @@ if Base.get_bool_env("JULIA_LOWERING_PRECOMPILE", true) @assert Meta.isexpr(lwr, :thunk) && only(lwr.args) isa Core.CodeInfo end - workload = raw""" - _precompile_kwf(x; y=1, z=2) = x + y + z + @static if VERSION >= v"1.14.0-DEV.2635" + workload = raw""" + _precompile_kwf(x; y=1, z=2) = x + y + z - function _precompile_destr(t) - (a, b) = t - a + b - end + function _precompile_destr(t) + (a, b) = t + a + b + end - macro _precompile_plus1(ex) - :($(esc(ex)) + 1) - end - _precompile_usemac(x) = @_precompile_plus1(x) + macro _precompile_plus1(ex) + :($(esc(ex)) + 1) + end + _precompile_usemac(x) = @_precompile_plus1(x) - @generated function _precompile_genf(x) - :(x + 1) - end + @generated function _precompile_genf(x) + :(x + 1) + end - # Fire everything so inference and the generator run during the build. - _precompile_kwf(1; y = 2) - _precompile_destr((1, 2)) - _precompile_usemac(3) - _precompile_genf(1.0) - """ - include_string(@__MODULE__, workload, @__FILE__; expr_compat_mode=true) + # Fire everything so inference and the generator run during the build. + _precompile_kwf(1; y = 2) + _precompile_destr((1, 2)) + _precompile_usemac(3) + _precompile_genf(1.0) + """ + include_string(@__MODULE__, workload, @__FILE__; expr_compat_mode=true) + end end diff --git a/JuliaLowering/src/runtime.jl b/JuliaLowering/src/runtime.jl index 9fc573b9a2f5b..8d6378d810a99 100644 --- a/JuliaLowering/src/runtime.jl +++ b/JuliaLowering/src/runtime.jl @@ -18,14 +18,18 @@ end # Re-dispatch `f(args...)` at the pinned lowering world (see `jl_lowering_world`) @inline function invoke_in_lowering_world(f::F, @nospecialize(args...)) where {F} - w = unsafe_load(cglobal(:jl_lowering_world, Csize_t)) - if w == 0 - # Fallback when the Base lowering hook is not set up - w = Base.tls_world_age() - # FIXME: as a side effect, enabling the Base lowering hook now affects - # JuliaLowering execution not passing through the hook + @static if VERSION >= v"1.14.0-DEV.2635" + w = unsafe_load(cglobal(:jl_lowering_world, Csize_t)) + if w == 0 + # Fallback when the Base lowering hook is not set up + w = Base.tls_world_age() + # FIXME: as a side effect, enabling the Base lowering hook now affects + # JuliaLowering execution not passing through the hook + end + return _invoke_in_world(w, f, args...) + else + f(args...) end - return _invoke_in_world(w, f, args...) end # Return the current exception. In JuliaLowering we use this rather than the diff --git a/JuliaSyntax/src/integration/expr.jl b/JuliaSyntax/src/integration/expr.jl index 39edcd10bbb09..dd3f42f8612d2 100644 --- a/JuliaSyntax/src/integration/expr.jl +++ b/JuliaSyntax/src/integration/expr.jl @@ -376,7 +376,7 @@ end # Encode the syntax version into `loc` so that the argument order # matches what ordinary macros expect. # Core.MacroSource was added in Julia 1.13+; fall back to plain loc on older versions. - if isdefined(Core, :MacroSource) + @static if isdefined(Core, :MacroSource) loc = Core.MacroSource(loc, popat!(args, 2)) else popat!(args, 2) # discard the version argument diff --git a/JuliaSyntax/src/porcelain/syntax_graph.jl b/JuliaSyntax/src/porcelain/syntax_graph.jl index c4efa7c7d4d7b..a2bb56d7ffc6d 100644 --- a/JuliaSyntax/src/porcelain/syntax_graph.jl +++ b/JuliaSyntax/src/porcelain/syntax_graph.jl @@ -1536,7 +1536,9 @@ function _green_to_est(parent::SyntaxTree, parent_i::Int, loc_st = let loc = source_location(LineNumberNode, st) if n_cs >= 2 && kind(cs[2]) === K"VERSION" v = version_to_expr(popat!(cs, 2)) - loc = Core.MacroSource(loc, v) + @static if isdefined(Core, :MacroSource) + loc = Core.MacroSource(loc, v) + end end valleaf(loc) end