Skip to content

Commit

Permalink
lowering: Recognize argument destructuring inside macro hygiene
Browse files Browse the repository at this point in the history
Fixes #54701
  • Loading branch information
Keno committed Jun 8, 2024
1 parent 30542e0 commit 742eb13
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
22 changes: 9 additions & 13 deletions src/macroexpand.scm
Original file line number Diff line number Diff line change
Expand Up @@ -229,30 +229,26 @@
lst)))

;; get the name from a function formal argument expression, allowing `(escape x)`
(define (try-arg-name v)
(cond ((symbol? v) (list v))
(define (try-arg-name v (escaped #f))
(cond ((symbol? v) (if escaped '() (list v)))
((atom? v) '())
(else
(case (car v)
((|::|) (if (length= v 2) '() (try-arg-name (cadr v))))
((... kw =) (try-arg-name (cadr v)))
((escape) (list v))
((hygienic-scope) (try-arg-name (cadr v)))
((|::|) (if (length= v 2) '() (try-arg-name (cadr v) escaped)))
((... kw =) (try-arg-name (cadr v) escaped))
((escape) (if escaped (list (cadr v)) '()))
((hygienic-scope) (try-arg-name (cadr v) escaped))
((tuple) (apply nconc (map (lambda (e) (try-arg-name e escaped)) (cdr v))))
((meta) ;; allow certain per-argument annotations
(if (nospecialize-meta? v #t)
(try-arg-name (caddr v))
(try-arg-name (caddr v) escaped)
'()))
(else '())))))

;; get names from a formal argument list, specifying whether to include escaped ones
(define (safe-arg-names lst (escaped #f))
(apply nconc
(map (lambda (v)
(let ((vv (try-arg-name v)))
(if (eq? escaped (and (pair? vv) (pair? (car vv)) (eq? (caar vv) 'escape)))
(if escaped (list (cadar vv)) vv)
'())))
lst)))
(map (lambda (v) (try-arg-name v escaped)) lst)))

;; arg names, looking only at positional args
(define (safe-llist-positional-args lst (escaped #f))
Expand Down
16 changes: 16 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3683,3 +3683,19 @@ end
# Issue #53729 - Lowering recursion into Expr(:toplevel)
@test eval(Expr(:let, Expr(:block), Expr(:block, Expr(:toplevel, :(f53729(x) = x)), :(x=1)))) == 1
@test f53729(2) == 2

# Issue #54701 - Macro hygiene of argument destructuring
macro makef54701()
quote
call(f) = f((1, 2))
function $(esc(:f54701))()
call() do (a54701, b54701)
return a54701+b54701
end
end
end
end
@makef54701
@test f54701() == 3
@test !@isdefined(a54701)
@test !@isdefined(b54701)

0 comments on commit 742eb13

Please sign in to comment.