Skip to content

Commit 5e0fe08

Browse files
authored
Merge pull request #178 from peterahrens/pja/fix-splitcombinearg-1.7
Fixes 165, Fixes 177.
2 parents a80be88 + 0dea2c0 commit 5e0fe08

File tree

2 files changed

+34
-14
lines changed

2 files changed

+34
-14
lines changed

src/utils.jl

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export @esc, isexpr, isline, iscall, rmlines, unblock, block, inexpr, namify, isdef,
2-
longdef, shortdef, @expand, makeif, prettify, combinedef, splitdef, splitarg
2+
longdef, shortdef, @expand, makeif, prettify, combinedef, splitdef, splitarg, combinearg
33

44
"""
55
assoc!(d, k, v)
@@ -406,7 +406,10 @@ end
406406
`combinearg` is the inverse of [`splitarg`](@ref).
407407
"""
408408
function combinearg(arg_name, arg_type, is_splat, default)
409-
a = arg_name===nothing ? :(::$arg_type) : :($arg_name::$arg_type)
409+
@assert arg_name !== nothing || arg_type !== nothing
410+
a = arg_name===nothing ? :(::$arg_type) :
411+
arg_type==:Any && is_splat ? arg_name : # see #177 and julia#43625
412+
:($arg_name::$arg_type)
410413
a2 = is_splat ? Expr(:..., a) : a
411414
return default === nothing ? a2 : Expr(:kw, a2, default)
412415
end
@@ -430,19 +433,21 @@ julia> map(splitarg, (:(f(a=2, x::Int=nothing, y, args...))).args[2:end])
430433
See also: [`combinearg`](@ref)
431434
"""
432435
function splitarg(arg_expr)
433-
splitvar(arg) =
434-
(@match arg begin
435-
::T_ => (nothing, T)
436-
name_::T_ => (name, T)
437-
x_ => (x, :Any)
438-
end)::NTuple{2,Any} # the pattern `x_` matches any expression
439-
(is_splat = @capture(arg_expr, arg_expr2_...)) || (arg_expr2 = arg_expr)
440-
if @capture(arg_expr2, arg_ = default_)
441-
@assert default !== nothing "splitarg cannot handle `nothing` as a default. Use a quoted `nothing` if possible. (MacroTools#35)"
442-
return (splitvar(arg)..., is_splat, default)
436+
if @capture(arg_expr, arg_expr2_ = default_)
437+
# This assert will only be triggered if a `nothing` literal was somehow spliced into the Expr.
438+
# A regular `nothing` default value is a `Symbol` when it gets here. See #178
439+
@assert default !== nothing "splitarg cannot handle `nothing` as a default. Use a quoted `nothing` if possible. (MacroTools#35)"
443440
else
444-
return (splitvar(arg_expr2)..., is_splat, nothing)
441+
arg_expr2 = arg_expr
445442
end
443+
is_splat = @capture(arg_expr2, arg_expr3_...)
444+
is_splat || (arg_expr3 = arg_expr2)
445+
(arg_name, arg_type) = (@match arg_expr3 begin
446+
::T_ => (nothing, T)
447+
name_::T_ => (name, T)
448+
x_ => (x, :Any)
449+
end)::NTuple{2,Any} # the pattern `x_` matches any expression
450+
return (arg_name, arg_type, is_splat, default)
446451
end
447452

448453

test/split.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ end
66

77
macro splitcombine(fundef) # should be a no-op
88
dict = splitdef(fundef)
9+
dict[:args] = map(arg->combinearg(splitarg(arg)...), dict[:args])
10+
dict[:kwargs] = map(arg->combinearg(splitarg(arg)...), dict[:kwargs])
911
esc(MacroTools.combinedef(dict))
1012
end
1113

@@ -24,10 +26,17 @@ let
2426
@test longdef(:(f(x)::Int = 10)).head == :function
2527
@test longdef(:(f(x::T) where U where T = 2)).head == :function
2628
@test shortdef(:(function f(x)::Int 10 end)).head != :function
27-
@test map(splitarg, (:(f(a=2, x::Int=nothing, y, args...))).args[2:end]) ==
29+
@test map(splitarg, (:(f(a=2, x::Int=nothing, y::Any, args...))).args[2:end]) ==
2830
[(:a, :Any, false, 2), (:x, :Int, false, :nothing),
2931
(:y, :Any, false, nothing), (:args, :Any, true, nothing)]
3032
@test splitarg(:(::Int)) == (nothing, :Int, false, nothing)
33+
kwargs = splitdef(:(f(; a::Int = 1, b...) = 1))[:kwargs]
34+
@test map(splitarg, kwargs) ==
35+
[(:a, :Int, false, 1), (:b, :Any, true, nothing)]
36+
args = splitdef(:(f(a::Int = 1) = 1))[:args]
37+
@test map(splitarg, args) == [(:a, :Int, false, 1)]
38+
args = splitdef(:(f(a::Int ... = 1) = 1))[:args]
39+
@test map(splitarg, args) == [(:a, :Int, true, 1)] # issue 165
3140

3241
@splitcombine foo(x) = x+2
3342
@test foo(10) == 12
@@ -47,6 +56,12 @@ let
4756
@splitcombine fmacro1() = @onearg 1
4857
@test fmacro1() == 2
4958

59+
@splitcombine bar(; a::Int = 1, b...) = 2
60+
@test bar(a=3, x = 1, y = 2) == 2
61+
@splitcombine qux(a::Int... = 0) = sum(a)
62+
@test qux(1, 2, 3) == 6
63+
@test qux() == 0
64+
5065
struct Foo{A, B}
5166
a::A
5267
b::B

0 commit comments

Comments
 (0)