Skip to content

Commit b3f766c

Browse files
KenoJeffBezanson
andauthored
lowering: Disallow splatting in non-final default value (#50563)
Pop quiz: Do you know what the following will do? ``` julia> function g1(a=(1,2)..., b...=3) b end julia> g1() julia> function g2(a=(1,2)..., b=3, c=4) (b, c) end julia> g2() julia> function g3(a=(1,2)..., b=3, c...=4) (b, c) end julia> g3() julia> g3(1) ``` I don't either and I don't think it's particularly well defined. Splatting a default argument makes sense on the last argument, which can be a vararg, and it is desirable to be able to specify the default for the whole varargs tuple at once (although arguably that should just be the non-`...` behavior, but that'd be too breaking a change). Ref #50518. However, for other arguments, there isn't really a sensible semantic meaning. This PR disallows this in lowering. This is technically a minor change, but I doubt anybody is using this. Splatting in default values wasn't really ever supposed to work anyway, it just happened to fall out of our lowering. --------- Co-authored-by: Jeff Bezanson <[email protected]>
1 parent d270a71 commit b3f766c

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

src/julia-syntax.scm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,10 @@
663663
(vals (list-tail dfl n))
664664
(absent (list-tail opt n)) ;; absent arguments
665665
(body
666-
(if (any (lambda (defaultv)
666+
(if (any vararg? (butlast vals))
667+
;; Forbid splat in all but the final default value
668+
(error "invalid \"...\" in non-final positional argument default value")
669+
(if (any (lambda (defaultv)
667670
;; does any default val expression...
668671
(contains (lambda (e)
669672
;; contain "e" such that...
@@ -682,7 +685,7 @@
682685
;; otherwise add all
683686
`(block
684687
,@prologue
685-
(call ,(arg-name (car req)) ,@(map arg-name (cdr passed)) ,@vals)))))
688+
(call ,(arg-name (car req)) ,@(map arg-name (cdr passed)) ,@vals))))))
686689
(method-def-expr- name sp passed body)))
687690
(iota (length opt)))
688691
,(method-def-expr- name sparams overall-argl body rett))))

test/syntax.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3508,6 +3508,26 @@ let x = 1 => 2
35083508
@test_throws "function Base.=> must be explicitly imported to be extended" @eval a => b = 2
35093509
end
35103510

3511+
# Splatting in non-final default value (Ref #50518)
3512+
for expr in (quote
3513+
function g1(a=(1,2)..., b...=3)
3514+
b
3515+
end
3516+
end,quote
3517+
function g2(a=(1,2)..., b=3, c=4)
3518+
(b, c)
3519+
end
3520+
end,quote
3521+
function g3(a=(1,2)..., b=3, c...=4)
3522+
(b, c)
3523+
end
3524+
end)
3525+
let exc = try eval(expr); catch exc; exc end
3526+
@test isa(exc, ErrorException)
3527+
@test startswith(exc.msg, "syntax: invalid \"...\" in non-final positional argument default value")
3528+
end
3529+
end
3530+
35113531
# Test that bad lowering does not segfault (ref #50518)
35123532
@test_throws ErrorException("syntax: Attempted to use slot marked unused") @eval function funused50518(::Float64)
35133533
$(Symbol("#unused#"))

0 commit comments

Comments
 (0)