Skip to content

Commit d256cd7

Browse files
committed
fix unescaping in global expressions
This fixes some issues around macro hygiene in `global` expressions. Apparently we always treat l-values in global expressions as being escaped, but we still need to be careful to handle type annotations and destructuring correctly.
1 parent 60668c5 commit d256cd7

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

src/macroexpand.scm

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@
183183
(cadr e)
184184
e))
185185

186+
(define (unescape-global-lhs e env m parent-scope inarg)
187+
(cond ((not (pair? e)) e)
188+
((eq? (car e) 'escape) (cadr e))
189+
((memq (car e) '(parameters tuple))
190+
(list* (car e) (map (lambda (e)
191+
(unescape-global-lhs e env m parent-scope inarg))
192+
(cdr e))))
193+
((and (memq (car e) '(|::| kw)) (length= e 3))
194+
(list (car e) (unescape-global-lhs (cadr e) env m parent-scope inarg)
195+
(resolve-expansion-vars-with-new-env (caddr e) env m parent-scope inarg)))
196+
(else
197+
(resolve-expansion-vars-with-new-env e env m parent-scope inarg))))
198+
186199
(define (typedef-expr-name e)
187200
(cond ((atom? e) e)
188201
((or (eq? (car e) 'curly) (eq? (car e) '<:)) (typedef-expr-name (cadr e)))
@@ -344,14 +357,14 @@
344357
(m (cadr scope))
345358
(parent-scope (cdr parent-scope)))
346359
(resolve-expansion-vars-with-new-env (cadr e) env m parent-scope inarg))))
347-
((global) (let ((arg (cadr e)))
348-
(cond ((symbol? arg) e)
349-
((assignment? arg)
350-
`(global
351-
(= ,(unescape (cadr arg))
352-
,(resolve-expansion-vars-with-new-env (caddr arg) env m parent-scope inarg))))
353-
(else
354-
`(global ,(resolve-expansion-vars-with-new-env arg env m parent-scope inarg))))))
360+
((global)
361+
`(global
362+
,@(map (lambda (arg)
363+
(if (assignment? arg)
364+
`(= ,(unescape-global-lhs (cadr arg) env m parent-scope inarg)
365+
,(resolve-expansion-vars-with-new-env (caddr arg) env m parent-scope inarg))
366+
(unescape-global-lhs arg env m parent-scope inarg)))
367+
(cdr e))))
355368
((using import export meta line inbounds boundscheck loopinfo inline noinline) (map unescape e))
356369
((macrocall) e) ; invalid syntax anyways, so just act like it's quoted.
357370
((symboliclabel) e)

test/syntax.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3429,3 +3429,26 @@ end
34293429
elseif false || (()->true)()
34303430
42
34313431
end)) == 42
3432+
3433+
macro _macroexpand(x, m=__module__)
3434+
:($__source__; macroexpand($m, Expr(:var"hygienic-scope", $(esc(Expr(:quote, x))), $m)))
3435+
end
3436+
3437+
@testset "unescaping in :global expressions" begin
3438+
m = @__MODULE__
3439+
@test @_macroexpand(global x::T) == :(global x::$(GlobalRef(m, :T)))
3440+
@test @_macroexpand(global (x, $(esc(:y)))) == :(global (x, y))
3441+
@test @_macroexpand(global (x::S, $(esc(:y))::$(esc(:T)))) ==
3442+
:(global (x::$(GlobalRef(m, :S)), y::T))
3443+
@test @_macroexpand(global (; x, $(esc(:y)))) == :(global (; x, y))
3444+
@test @_macroexpand(global (; x::S, $(esc(:y))::$(esc(:T)))) ==
3445+
:(global (; x::$(GlobalRef(m, :S)), y::T))
3446+
3447+
@test @_macroexpand(global x::T = a) == :(global x::$(GlobalRef(m, :T)) = $(GlobalRef(m, :a)))
3448+
@test @_macroexpand(global (x, $(esc(:y))) = a) == :(global (x, y) = $(GlobalRef(m, :a)))
3449+
@test @_macroexpand(global (x::S, $(esc(:y))::$(esc(:T))) = a) ==
3450+
:(global (x::$(GlobalRef(m, :S)), y::T) = $(GlobalRef(m, :a)))
3451+
@test @_macroexpand(global (; x, $(esc(:y))) = a) == :(global (; x, y) = $(GlobalRef(m, :a)))
3452+
@test @_macroexpand(global (; x::S, $(esc(:y))::$(esc(:T))) = a) ==
3453+
:(global (; x::$(GlobalRef(m, :S)), y::T) = $(GlobalRef(m, :a)))
3454+
end

0 commit comments

Comments
 (0)