Skip to content

Commit b3e33bf

Browse files
committed
implement #6614, destructuring in formal arguments
1 parent 109b0b4 commit b3e33bf

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

NEWS.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ New language features
77
* Local variables can be tested for being defined
88
using the new `@isdefined variable` macro ([#22281]).
99

10+
* Destructuring in function arguments: when an expression such as `(x, y)` is used as
11+
a function argument name, the argument is unpacked into local variables `x` and `y`
12+
as in the assignment `(x, y) = arg` ([#6614]).
13+
1014
Language changes
1115
----------------
1216

src/julia-syntax.scm

+29
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,32 @@
993993
(loop (cadr ex) (append! (reverse (cddr ex)) vars))
994994
`(where ,ex ,.(reverse! vars)))))
995995

996+
(define (lower-destructuring-args argl)
997+
(define (check-lhs a)
998+
(if (expr-contains-p (lambda (e) (or (decl? e) (assignment? e) (kwarg? e)))
999+
a)
1000+
(error (string "invalid argument destructuring syntax \"" (deparse a) "\""))
1001+
a))
1002+
(define (transform-arg a)
1003+
(cond ((and (pair? a) (eq? (car a) 'tuple))
1004+
(let ((a2 (gensy)))
1005+
(cons a2 `(local (= ,(check-lhs a) ,a2)))))
1006+
((or (and (decl? a) (length= a 3)) (kwarg? a))
1007+
(let ((x (transform-arg (cadr a))))
1008+
(cons `(,(car a) ,(car x) ,(caddr a)) (cdr x))))
1009+
((vararg? a)
1010+
(let ((x (transform-arg (cadr a))))
1011+
(cons `(... ,(car x)) (cdr x))))
1012+
(else (cons a #f))))
1013+
(let loop ((argl argl)
1014+
(newa '())
1015+
(stmts '()))
1016+
(if (null? argl)
1017+
(cons (reverse newa) (reverse stmts))
1018+
(let ((a (transform-arg (car argl))))
1019+
(loop (cdr argl) (cons (car a) newa)
1020+
(if (cdr a) (cons (cdr a) stmts) stmts))))))
1021+
9961022
(define (expand-function-def- e)
9971023
(let* ((name (cadr e))
9981024
(where (if (and (pair? name) (eq? (car name) 'where))
@@ -1040,6 +1066,9 @@
10401066
(farg (if (decl? name)
10411067
(adj-decl name)
10421068
`(|::| |#self#| (call (core Typeof) ,name))))
1069+
(argl-stmts (lower-destructuring-args argl))
1070+
(argl (car argl-stmts))
1071+
(body (insert-after-meta body (cdr argl-stmts)))
10431072
(argl (fix-arglist
10441073
(arglist-unshift argl farg)
10451074
(and (not (any kwarg? argl)) (not (and (pair? argl)

test/core.jl

+26
Original file line numberDiff line numberDiff line change
@@ -5497,3 +5497,29 @@ for U in unboxedunions
54975497
end
54985498

54995499
end # module UnionOptimizations
5500+
5501+
# issue #6614, argument destructuring
5502+
f6614((x, y)) = [x, y]
5503+
@test f6614((4, 3)) == [4, 3]
5504+
g6614((x, y), (z,), (a, b)) = (x,y,z,a,b)
5505+
@test g6614((1, 2), (3,), (4, 5)) === (1,2,3,4,5)
5506+
@test_throws MethodError g6614(1, 2)
5507+
@test_throws MethodError g6614((1, 2), (3,))
5508+
@test_throws BoundsError g6614((1, 2), (3,), (1,))
5509+
h6614((x, y) = (5, 6)) = (y, x)
5510+
@test h6614() == (6, 5)
5511+
@test h6614((4, 5)) == (5, 4)
5512+
ff6614((x, y)::Tuple{Int, String}) = (x, y)
5513+
@test ff6614((1, "")) == (1, "")
5514+
@test_throws MethodError ff6614((1, 1))
5515+
gg6614((x, y)::Tuple{Int, String} = (2, " ")) = (x, y)
5516+
@test gg6614() == (2, " ")
5517+
function hh6614()
5518+
x, y = 1, 2
5519+
function g((x,y))
5520+
# make sure x and y are local
5521+
end
5522+
g((4,5))
5523+
x, y
5524+
end
5525+
@test hh6614() == (1, 2)

0 commit comments

Comments
 (0)