Skip to content

Commit 0b02f6f

Browse files
committed
fix macroexpansion scope miscalculation
previously, we were treating hygienic-scope as also introducing a new scope-block that was wrong (and inconsistent with previous behavior) also, we were failing to set the outermost flag when entering a hygienic-scope block, further compounding the above error fix #23239
1 parent 131807c commit 0b02f6f

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

src/macroexpand.scm

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@
377377
(let ((parent-scope (cons (list env m) parent-scope))
378378
(body (cadr e))
379379
(m (caddr e)))
380-
(resolve-expansion-vars-with-new-env body env m parent-scope inarg)))
380+
(resolve-expansion-vars-with-new-env body env m parent-scope inarg #t)))
381381

382382
;; todo: trycatch
383383
(else
@@ -407,10 +407,30 @@
407407
(and (eq? (car e) '=) (length= e 3)
408408
(eventually-call? (cadr e))))))
409409

410+
;; count hygienic / escape pairs
411+
;; and fold together a list resulting from applying the function to
412+
;; and block at the same hygienic scope
413+
(define (resume-on-escape lam e nblocks)
414+
(if (or (not (pair? e)) (quoted? e))
415+
'()
416+
(cond ((memq (car e) '(lambda module toplevel))
417+
'())
418+
((eq? (car e) 'hygienic-scope)
419+
(resume-on-escape lam (cadr e) (+ nblocks 1)))
420+
((eq? (car e) 'escape)
421+
(if (= nblocks 0)
422+
(lam (cadr e))
423+
(resume-on-escape lam (cadr e) (- nblocks 1))))
424+
(else
425+
(foldl (lambda (a l) (append! l (resume-on-escape lam a nblocks)))
426+
'()
427+
(cdr e))))))
428+
410429
(define (find-declared-vars-in-expansion e decl (outer #t))
411430
(cond ((or (not (pair? e)) (quoted? e)) '())
412431
((eq? (car e) 'escape) '())
413-
((eq? (car e) 'hygienic-scope) '())
432+
((eq? (car e) 'hygienic-scope)
433+
(resume-on-escape (lambda (e) (find-declared-vars-in-expansion e decl outer)) (cadr e) 0))
414434
((eq? (car e) decl) (map decl-var* (cdr e)))
415435
((and (not outer) (function-def? e)) '())
416436
(else
@@ -421,7 +441,8 @@
421441
(define (find-assigned-vars-in-expansion e (outer #t))
422442
(cond ((or (not (pair? e)) (quoted? e)) '())
423443
((eq? (car e) 'escape) '())
424-
((eq? (car e) 'hygienic-scope) '())
444+
((eq? (car e) 'hygienic-scope)
445+
(resume-on-escape (lambda (e) (find-assigned-vars-in-expansion e outer)) (cadr e) 0))
425446
((and (not outer) (function-def? e))
426447
;; pick up only function name
427448
(let ((fname (cond ((eq? (car e) '=) (decl-var* (cadr e)))
@@ -501,11 +522,12 @@
501522
(error (string "macro \"" (cadr e) "\" not defined")))
502523
(if (and (pair? form) (eq? (car form) 'error))
503524
(error (cadr form)))
504-
(let ((form (car form)) ;; form is the expression returned from expand-macros
505-
(modu (cdr form))) ;; modu is the macro's def module
506-
`(hygienic-scope
507-
,(julia-expand-macros- (cons modu m) (rename-symbolic-labels form) (- max-depth 1))
508-
,modu))))
525+
(let* ((modu (cdr form)) ;; modu is the macro's def module
526+
(form (car form)) ;; form is the expression returned from expand-macros
527+
(form (julia-expand-macros- (cons modu m) form (- max-depth 1))))
528+
(if (and (pair? form) (eq? (car form) 'escape))
529+
(cadr form) ; immediately fold away (hygienic-scope (escape ...))
530+
`(hygienic-scope ,form ,modu)))))
509531
((eq? (car e) 'module) e)
510532
((eq? (car e) 'escape)
511533
(let ((m (if (null? m) m (cdr m))))

test/core.jl

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4999,7 +4999,7 @@ let a_foo = Foo22256(Bar22256{true}(2))
49994999
@test a_foo.bar.inner == 3
50005000
end
50015001

5002-
# macro hygiene scope (#22307)
5002+
# macro hygiene scope (#22307, #23239)
50035003
macro a22307()
50045004
return esc(:a22307)
50055005
end
@@ -5013,6 +5013,36 @@ end
50135013
a22307 = 2
50145014
@test c22307() == 2
50155015

5016+
macro identity23239b(x)
5017+
return esc(x)
5018+
end
5019+
macro identity23239c(x)
5020+
return quote
5021+
$(esc(x))
5022+
end
5023+
end
5024+
macro assign23239d(x, v)
5025+
return esc(:($x = $v))
5026+
end
5027+
macro assign23239e(x, v)
5028+
return quote
5029+
$(esc(:($x = $v)))
5030+
end
5031+
end
5032+
macro aa23239()
5033+
return quote
5034+
a = 1
5035+
@identity23239b b = 2
5036+
@identity23239c c = 3
5037+
@assign23239d d 4
5038+
@assign23239e e 5
5039+
(a, b, c, d, e)
5040+
end
5041+
end
5042+
f23239() = @aa23239()
5043+
@test @inferred(f23239()) === (1, 2, 3, 4, 5)
5044+
5045+
50165046
# issue #22026
50175047
module M22026
50185048

0 commit comments

Comments
 (0)