From 91746828de019efb053bcb2b2c285d9ca720a99f Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Tue, 7 Oct 2025 16:38:01 -0700 Subject: [PATCH] Make `=` and `const` toplevel-preserving syntax Previously, `map-cl-convert` would keep the toplevel flag only when the containing expression was toplevel and each element of the list passed to it satisfied `toplevel-preserving?`. Instead, make it so `toplevel-preserving?` expressions are those where the toplevel flag should be propagated to the children during closure conversion. Fixes #59755. --- src/julia-syntax.scm | 8 +++----- test/syntax.jl | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 6bfb3ff5a7a7e..f3a57c6699c08 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4063,14 +4063,12 @@ f(x) = yt(x) (and vi (vinfo:nospecialize vi)))) (define (toplevel-preserving? e) - (and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally trycatchelse)))) + (and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally trycatchelse = const)))) (define (map-cl-convert exprs fname lam namemap defined toplevel interp opaq toplevel-pure parsed-method-stack (globals (table)) (locals (table))) (if toplevel (map (lambda (x) - (let ((tl (lift-toplevel (cl-convert x fname lam namemap defined - (and toplevel (toplevel-preserving? x)) - interp opaq toplevel-pure parsed-method-stack globals locals)))) + (let ((tl (lift-toplevel (cl-convert x fname lam namemap defined toplevel interp opaq toplevel-pure parsed-method-stack globals locals)))) (if (null? (cdr tl)) (car tl) `(block ,@(cdr tl) ,(car tl))))) @@ -4473,7 +4471,7 @@ f(x) = yt(x) (cl-convert (cadr e) fname lam namemap defined toplevel interp opaq toplevel-pure parsed-method-stack globals locals)) (else (cons (car e) - (map-cl-convert (cdr e) fname lam namemap defined toplevel interp opaq toplevel-pure parsed-method-stack globals locals)))))))) + (map-cl-convert (cdr e) fname lam namemap defined (and toplevel (toplevel-preserving? e)) interp opaq toplevel-pure parsed-method-stack globals locals)))))))) ;; wrapper for `cl-convert-` (define (cl-convert e fname lam namemap defined toplevel interp opaq toplevel-pure (parsed-method-stack '()) (globals (table)) (locals (table))) diff --git a/test/syntax.jl b/test/syntax.jl index af5d7ce5e50e8..cec389be057ad 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4617,3 +4617,47 @@ end @test_throws UndefVarError macroexpand(@__MODULE__, :(@undefined_macro(x))) @test_throws UndefVarError macroexpand!(@__MODULE__, :(@undefined_macro(x))) end + +# #59755 - Don't hoist global declarations out of toplevel-preserving syntax +module M59755 end +@testset "toplevel-preserving syntax" begin + Core.eval(M59755, :(if true + global v1::Bool + else + const v1 = 1 + end)) + @test !isdefined(M59755, :v1) + @test Base.binding_kind(M59755, :v1) == Base.PARTITION_KIND_GLOBAL + @test Core.get_binding_type(M59755, :v1) == Bool + + Core.eval(M59755, :(if false + global v2::Bool + else + const v2 = 2 + end)) + @test M59755.v2 === 2 + @test Base.binding_kind(M59755, :v2) == Base.PARTITION_KIND_CONST + + Core.eval(M59755, :(v3 = if true + global v4::Bool + 4 + else + const v4 = 5 + 6 + end)) + @test M59755.v3 == 4 + @test !isdefined(M59755, :v4) + @test Base.binding_kind(M59755, :v4) == Base.PARTITION_KIND_GLOBAL + @test Core.get_binding_type(M59755, :v4) == Bool + + Core.eval(M59755, :(v5 = if false + global v6::Bool + 4 + else + const v6 = 5 + 6 + end)) + @test M59755.v5 === 6 + @test M59755.v6 === 5 + @test Base.binding_kind(M59755, :v6) == Base.PARTITION_KIND_CONST +end