Skip to content

Commit f1b0b01

Browse files
authored
Fix scope of hoisted signature-local variables (#56712)
When we declare inner methods, e.g. the `f` in ``` function fs() f(lhs::Integer) = 1 f(lhs::Integer, rhs::(local x=Integer; x)) = 2 return f end ``` we must hoist the definition of the (appropriately mangled) generic function `f` to top-level, including all variables that were used in the signature definition of `f`. This situation is a bit unique in the language because it uses inner function scope, but gets executed in toplevel scope. For example, you're not allowed to use a local of the inner function in the signature definition: ``` julia> function fs() local x=Integer f(lhs::Integer, rhs::x) = 2 return f end ERROR: syntax: local variable x cannot be used in closure declaration Stacktrace: [1] top-level scope @ REPL[3]:1 ``` In particular, the restriction is signature-local: ``` julia> function fs() f(rhs::(local x=Integer; x)) = 1 f(lhs::Integer, rhs::x) = 2 return f end ERROR: syntax: local variable x cannot be used in closure declaration Stacktrace: [1] top-level scope @ REPL[4]:1 ``` There's a special intermediate form `moved-local` that gets generated for this definition. In c6c3d72, this form stopped getting generated for certain inner methods. I suspect this happened because of the incorrect assumption that the set of moved locals is being computed over all signatures, rather than being a per-signature property. The result of all of this was that this is one of the few places where lowering still generated a symbol as the lhs of an assignment for a global (instead of globalref), because the code that generates the assignment assumes it's a local, but the later pass doesn't know this. Because we still retain the code for this from before we started using globalref consistently, this wasn't generally causing a problems, except possibly leaking a global (or potentially assigning to a global when this wasn't intended). However, in follow on work, I want to make use of knowing whether the LHS is a global or local in lowering, so this was causing me trouble. Fix all of this by putting back the `moved-local` where it was dropped. Fixes #56711
1 parent 8ce7d0f commit f1b0b01

File tree

2 files changed

+9
-0
lines changed

2 files changed

+9
-0
lines changed

src/julia-syntax.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4279,6 +4279,7 @@ f(x) = yt(x)
42794279
(if (or exists (and short (pair? alldefs)))
42804280
`(toplevel-butfirst
42814281
(null)
4282+
,@(map (lambda (v) `(moved-local ,v)) moved-vars)
42824283
,@sp-inits
42834284
,@mk-method
42844285
(latestworld))

test/syntax.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,3 +4033,11 @@ end
40334033
@test isa(create_inner_f_no_methods(), Function)
40344034
@test length(methods(create_inner_f_no_methods())) == 0
40354035
@test Base.invoke_in_world(first(methods(create_inner_f_one_method)).primary_world, create_inner_f_one_method()) == 1
4036+
4037+
# Issue 56711 - Scope of signature hoisting
4038+
function fs56711()
4039+
f(lhs::Integer) = 1
4040+
f(lhs::Integer, rhs::(local x_should_not_be_defined=Integer; x_should_not_be_defined)) = 2
4041+
return f
4042+
end
4043+
@test !@isdefined(x_should_not_be_defined)

0 commit comments

Comments
 (0)