Skip to content

Commit

Permalink
lowering: Disallow splatting in non-final default value
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Keno committed Jul 15, 2023
1 parent d215d91 commit b5bb8f3
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
7 changes: 5 additions & 2 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,10 @@
(vals (list-tail dfl n))
(absent (list-tail opt n)) ;; absent arguments
(body
(if (any (lambda (defaultv)
(if (any (lambda (val) (and (pair? val) (eq? (car val) '...))) (butlast vals))
;; Forbid splat in all but the final default value
(error "Splatting in non-final positional default")
(if (any (lambda (defaultv)
;; does any default val expression...
(contains (lambda (e)
;; contain "e" such that...
Expand All @@ -681,7 +684,7 @@
;; otherwise add all
`(block
,@prologue
(call ,(arg-name (car req)) ,@(map arg-name (cdr passed)) ,@vals)))))
(call ,(arg-name (car req)) ,@(map arg-name (cdr passed)) ,@vals))))))
(method-def-expr- name sp passed body)))
(iota (length opt)))
,(method-def-expr- name sparams overall-argl body rett))))
Expand Down
20 changes: 20 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3507,3 +3507,23 @@ let x = 1 => 2
@test_throws ErrorException @eval a => b = 2
@test_throws "function Base.=> must be explicitly imported to be extended" @eval a => b = 2
end

# Splatting in non-final default value (Ref #50518)
for expr in (quote
function g1(a=(1,2)..., b...=3)
b
end
end,quote
function g2(a=(1,2)..., b=3, c=4)
(b, c)
end
end,quote
function g3(a=(1,2)..., b=3, c...=4)
(b, c)
end
end)
let exc = try eval(expr); catch exc; exc end
@test isa(exc, ErrorException)
@test startswith(exc.msg, "syntax: Splatting in non-final positional default")
end
end

0 comments on commit b5bb8f3

Please sign in to comment.