forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keywordargs.jl
402 lines (370 loc) · 11.3 KB
/
keywordargs.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# This file is a part of Julia. License is MIT: https://julialang.org/license
kwf1(ones; tens=0, hundreds=0) = ones + 10*tens + 100*hundreds
@testset "simple keyword args case" begin
@test kwf1(2) == 2
@test kwf1(2, hundreds=6) == 602
@test kwf1(2, tens=6) == 62
@test kwf1(1, hundreds=2, tens=7) == 271
@test kwf1(3, tens=7, hundreds=2) == 273
let tens = 2, hundreds = 4
@test kwf1(8; tens, hundreds) == 428
nt = (hundreds = 5,)
@test kwf1(7; nt.hundreds) == 507
end
@test_throws MethodError kwf1() # no method, too few args
@test_throws MethodError kwf1(1, z=0) # unsupported keyword
@test_throws MethodError kwf1(1, 2) # no method, too many positional args
end
kwf2(x, rest...; y=1) = (x, y, rest)
@testset "keyword args plus varargs" begin
@test isequal(kwf2(0), (0, 1, ()))
@test isequal(kwf2(0,1,2), (0, 1, (1,2)))
@test isequal(kwf2(0,1,2,y=88), (0, 88, (1,2)))
@test isequal(kwf2(0,y=88,1,2), (0, 88, (1,2)))
@test_throws MethodError kwf2(0, z=1)
@test_throws MethodError kwf2(y=1)
end
@testset "Issue #13919" begin
test13919(x::Vararg{Int}; key=100) = (x, key)
@test test13919(1, 1)[1] === (1, 1)
@test test13919(1, 1)[2] === 100
@test test13919(1, 1, key=10)[1] === (1, 1)
@test test13919(1, 1, key=10)[2] === 10
end
@testset "keyword arg with declared type" begin
kwf3(x; y::Float64 = 1.0) = x + y
@test kwf3(2) == 3.0
@test kwf3(2, y=3.0) == 5.0
@test_throws TypeError kwf3(2, y=3) # wrong type keyword
end
@testset "function with only keyword args" begin
kwf4(;a=1,b=2) = (a,b)
@test isequal(kwf4(), (1,2))
@test isequal(kwf4(b=10), (1,10))
end
@testset "in-order evaluation of keyword args" begin
kwf9(;read=true,write=!read) = (read,write)
@test kwf9() === (true,false)
@test kwf9(read=false) === (false,true)
@test kwf9(write=true) === (true,true)
end
# rest keywords
kwdelegator(ones;kw...) = kwf1(ones;kw...)
@test kwdelegator(4,hundreds=8) == 804
@testset "optional positional args" begin
opaf1(a,b=1,c=2,d=3) = (a,b,c,d)
@test isequal(opaf1(0), (0,1,2,3))
@test isequal(opaf1(0,2), (0,2,2,3))
@test isequal(opaf1(0,2,4), (0,2,4,3))
@test isequal(opaf1(0,2,4,6), (0,2,4,6))
@test_throws MethodError opaf1()
@test_throws MethodError opaf1(0,1,2,3,4)
@testset "with varargs" begin
opaf2(a=1,rest...) = (a,rest)
@test isequal(opaf2(), (1,()))
@test isequal(opaf2(2), (2,()))
@test isequal(opaf2(2,3), (2,(3,)))
end
@testset "with keyword args" begin
opkwf1(a=0,b=1;k=2) = (a,b,k)
@test isequal(opkwf1(), (0,1,2))
@test isequal(opkwf1(10), (10,1,2))
@test isequal(opkwf1(10,20), (10,20,2))
@test_throws MethodError opkwf1(10,20,30)
@test isequal(opkwf1(10,20,k=8), (10,20,8))
@test isequal(opkwf1(11;k=8), (11, 1,8))
@test isequal(opkwf1(k=8), ( 0, 1,8))
end
end
# dictionaries as keywords
@test kwf1(4; Dict(:hundreds=>9, :tens=>5)...) == 954
@testset "with inner function" begin
function kwf_maker()
f(;k=0) = 2k+1
end
kwf5 = kwf_maker()
@test kwf5() == 1
@test kwf5(k=2) == 5
@test_throws MethodError kwf5(1)
end
extravagant_args(x,y=0,rest...;color="blue",kw...) = (x,y,rest,color,kwf1(6;tens=8,kw...))
@testset "with every feature!" begin
@test isequal(extravagant_args(1), (1,0,(),"blue",86))
@test isequal(extravagant_args(1;hundreds=7), (1,0,(),"blue",786))
@test isequal(extravagant_args(1,2,3;Dict(:color=>"red", :hundreds=>3)...),
(1,2,(3,),"red",386))
# passing junk kw container
@test_throws BoundsError extravagant_args(1; Any[[]]...)
end
# passing empty kw container to function with no kwargs
@test sin(1.0) == sin(1.0; Dict()...)
f18845() = 2
@testset "issue #18845" begin
@test (@eval sin(1.0; $([]...))) == sin(1.0)
@test f18845(;) == 2
@test f18845(; []...) == 2
@test (@eval f18845(; $([]...))) == 2
end
@testset "keyword args with static parameters" begin
kwf6(x; k::T=1) where {T} = T
@test kwf6(1) === Int
@test kwf6(1;k=2.5) === Float64
kwf7(x::T; k::T=1) where {T} = T
@test kwf7(2) === Int
@test kwf7(1.5;k=2.5) === Float64
@test_throws MethodError kwf7(1.5)
@test_throws TypeError kwf7(1.5; k=2)
# issue #30792
g30792(a::C; b=R(1)) where {R <: Real, C <: Union{R, Complex{R}}} = R
@test g30792(1.0) === Float64
@test g30792(1.0im) === Float64
@test g30792(1.0im, b=1) === Float64
@test_throws MethodError g30792("")
f30792(a::C; b::R=R(1)) where {R <: Real, C <: Union{R, Complex{R}}} = R
@test f30792(2im) === Int
@test f30792(2im, b=3) === Int
@test_throws TypeError f30792(2im, b=3.0)
end
# try to confuse it with quoted symbol
kwf8(x::MIME{:T};k::T=0) where {T} = 0
@test kwf8(MIME{:T}()) === 0
macro TEST4538()
quote
function $(esc(:test4538))(x=1)
return x
end
end
end
macro TEST4538_2()
quote
function $(esc(:test4538_2))(;x=1)
return x
end
end
end
module Foo4538
macro TEST()
quote
function $(esc(:test4538_foo_2))(;x=1)
return x
end
end
end
end
f4538_3(;x=1) = x
macro TEST4538_3()
quote
x = 2
f4538_3(x=3)
end
end
@testset "issue #4538" begin
@TEST4538
@test test4538() == 1
@test test4538(2) == 2
@TEST4538_2
@test test4538_2() == 1
@test_throws MethodError test4538_2(2)
@test test4538_2(x=2) == 2
# that, but in a module
Foo4538.@TEST()
@test test4538_foo_2() == 1
@test test4538_foo_2(x=2) == 2
@test (@TEST4538_3) == 3
end
# issue #4801
mutable struct T4801{X}
T4801{X}(;k=0) where X = new()
end
@test isa(T4801{Any}(k=0), T4801{Any})
# issue #4974
function Foo4974(f; kwargs...)
(f(), kwargs)
end
function test4974(;kwargs...)
Foo4974(;kwargs...) do
2
end
end
@test test4974(a=1) == (2, pairs((a=1,)))
@testset "issue #7704, computed keywords" begin
@test kwf1(1; :tens => 2) == 21
let p = (:hundreds, 3),
q = (:tens, 1)
@test kwf1(0; p[1]=>p[2], q[1]=>q[2]) == 310
@test kwf1(0; q[1]=>q[2], hundreds=4) == 410
end
end
@testset "with anonymous functions, issue #2773" begin
f = (x;a=1,b=2)->(x, a, b)
@test f(0) === (0, 1, 2)
@test f(1,a=10,b=20) === (1,10,20)
@test f(0,b=88) === (0, 1, 88)
@test_throws MethodError f(0,z=1)
end
@test ((a=2)->10a)(3) == 30
@test ((a=2)->10a)() == 20
@test ((a=1,b=2)->(a,b))() == (1,2)
@test ((a=1,b=2)->(a,b))(5) == (5,2)
@test ((a=1,b=2)->(a,b))(5,6) == (5,6)
@testset "issue #9948" begin
f9948, getx9948 = let x
x = 3
h(;x=x) = x
getx() = x
h, getx
end
@test f9948() == 3
@test getx9948() == 3
@test f9948(x=5) == 5
@test f9948() == 3
@test getx9948() == 3
end
@testset "issue #17785 - handle all sources of kwargs left-to-right" begin
g17785(; a=1, b=2) = (a, b)
let opts = (:a=>3, :b=>4)
@test g17785(; a=5, opts...) == (3, 4)
@test g17785(; opts..., a=5) == (5, 4)
@test g17785(; opts..., a=5, b=6) == (5, 6)
@test g17785(; b=0, opts..., a=5) == (5, 4)
end
end
# pr #18396, kwargs before Base is defined
@eval Core.Compiler begin
f18396(;kwargs...) = g18396(;kwargs...)
g18396(;x=1,y=2) = x+y
end
@test Core.Compiler.f18396() == 3
@testset "issue #7045, `invoke` with keyword args" begin
f7045(x::Float64; y=true) = y ? 1 : invoke(f7045,Tuple{Real},x,y=y)
f7045(x::Real; y=true) = y ? 2 : 3
@test f7045(1) === 2
@test f7045(1.0) === 1
@test f7045(1, y=false) === 3
@test f7045(1.0, y=false) === 3
end
struct T20804{T}
y::T
end
(f::T20804)(;x=10) = f.y + x
@testset "issue #20804" begin
x = T20804(4)
@test x() == 14
@test x(x=8) == 12
end
@testset "issue #21147" begin
function f21147(f::Tuple{A}; kwargs...) where {B,A<:Tuple{B}}
return B
end
@test f21147(((1,),)) === Int
@test f21147(((1,),), k = 2) === Int
function g21147(f::Tuple{A}, k = 2) where {B,A<:Tuple{B}}
return B
end
@test g21147(((1,),)) === Int
@test g21147(((1,),), 2) === Int
end
@testset "issue #21510" begin
f21510(; @nospecialize a = 2) = a
@test f21510(a=:b) === :b
@test f21510() == 2
end
@testset "issue #34516" begin
f34516(; @nospecialize(x)) = 0
f34516(y; @nospecialize(x::Any)) = 1
@test_throws UndefKeywordError f34516()
@test_throws UndefKeywordError f34516(1)
g34516(@nospecialize(x); k=0) = 0
@test only(methods(Core.kwcall, (Any, typeof(g34516), Vararg))).nospecialize != 0
end
@testset "issue #21518" begin
a = 0
f21518(;kw=nothing) = kw
g21518() = (a+=1; f21518)
g21518()(kw=1)
@test a == 1
g21518()(; :kw=>1)
@test a == 2
end
@testset "issue #17240 - evaluate default expressions in nested scopes" begin
a = 10
f17240(;a=a-1, b=2a) = (a, b)
@test f17240() == (9, 18)
@test f17240(a=2) == (2, 4)
@test f17240(b=3) == (9, 3)
@test f17240(a=2, b=1) == (2, 1)
end
@testset "issue #9535 - evaluate all arguments left-to-right" begin
counter = 0
function get_next()
counter += 1
return counter
end
f(args...; kws...) = (args, values(kws))
@test f(get_next(), a=get_next(), get_next(),
b=get_next(), get_next(),
[get_next(), get_next()]...; c=get_next(),
(d = get_next(), f = get_next())...) ==
((1, 3, 5, 6, 7),
(a = 2, b = 4, c = 8, d = 9, f = 10))
end
@testset "required keyword arguments" begin
f(x; y, z=3) = x + 2y + 3z
@test f(1, y=2) === 14 === f(10, y=2, z=0)
@test_throws UndefKeywordError f(1)
@test_throws UndefKeywordError f(1, z=2)
g(x; y::Int, z=3) = x + 2y + 3z
@test g(1, y=2) === 14 === g(10, y=2, z=0)
@test_throws TypeError g(1, y=2.3)
@test_throws UndefKeywordError g(1)
@test_throws UndefKeywordError g(1, z=2)
end
@testset "issue #26916 - anonymous function with 1 keyword arg and 1 optional arg" begin
f = (x=1;y=2)->(x,y)
@test f() == (1,2)
@test f(10) == (10,2)
@test f(y=20) == (1,20)
@test f(20, y=30) == (20,30)
g = (x=1;)->(x,x)
@test g() == (1,1)
@test g(2) == (2,2)
end
# issue #32074
function g32074(i::Float32; args...)
hook(i; args...) = args
hook(i; args...)
end
function g32074(i::Int32; args...)
hook(i; args...) = args
hook(i; args...)
end
@test isempty(g32074(Int32(1)))
# issue #33026
using InteractiveUtils
@test (@which kwf1(1, tens=2)).line > 0
no_kw_args(x::Int) = 0
@test_throws MethodError no_kw_args(1, k=1)
@test_throws MethodError no_kw_args("", k=1)
# issue #40964
f40964(xs::Int...=1; k = 2) = (xs, k)
@test f40964() === ((1,), 2)
@test f40964(7, 8) === ((7,8), 2)
@test f40964(7, 8, k=0) === ((7,8), 0)
# issue #41416
@test f40964(; k = 1) === ((1,), 1)
f41416(a...="a"; b=true) = (b, a)
@test f41416() === (true, ("a",))
@test f41416(;b=false) === (false, ("a",))
@test f41416(33) === (true, (33,))
@test f41416(3; b=false) === (false, (3,))
Core.kwcall(i::Int) = "hi $i"
let m = first(methods(Core.kwcall, (NamedTuple,typeof(kwf1),Vararg)))
@test m.name === :kwf1
@test Core.kwcall(1) == "hi 1"
@test which(Core.kwcall, (Int,)).name === :kwcall
end
# issue #50518
function f50518(xs...=["a", "b", "c"]...; debug=false)
return xs[1]
end
@test f50518() == f50518(;debug=false) == "a"