Skip to content

Commit 43b6781

Browse files
committed
Fix placeholders in parameters and decls, work around hasmethod, and temporarily rm our @atomic`
1 parent f22ea72 commit 43b6781

File tree

9 files changed

+186
-38
lines changed

9 files changed

+186
-38
lines changed

src/desugaring.jl

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,8 +1357,8 @@ function expand_assignment(ctx, ex, is_const=false)
13571357
# Identifer in lhs[1] is a variable type declaration, eg
13581358
# x::T = rhs
13591359
@ast ctx ex [K"block"
1360-
[K"decl" lhs[1] lhs[2]]
1361-
is_const ? [K"const" [K"=" lhs[1] rhs]] : [K"=" lhs[1] rhs]
1360+
kind(x) === K"Placeholder" ? nothing : [K"decl" x T]
1361+
is_const ? [K"const" [K"=" x rhs]] : [K"=" x rhs]
13621362
]
13631363
else
13641364
# Otherwise just a type assertion, eg
@@ -2171,8 +2171,14 @@ function make_lhs_decls(ctx, stmts, declkind, declmeta, ex, type_decls=true)
21712171
if type_decls
21722172
@chk numchildren(ex) == 2
21732173
name = ex[1]
2174-
@chk kind(name) == K"Identifier"
2175-
push!(stmts, makenode(ctx, ex, K"decl", name, ex[2]))
2174+
if kind(name) == K"Identifier"
2175+
push!(stmts, makenode(ctx, ex, K"decl", name, ex[2]))
2176+
else
2177+
# Setting the global type of underscores is likely undesired.
2178+
# Locals are debatable, though that isn't known here.
2179+
@chk kind(name) == K"Placeholder"
2180+
return
2181+
end
21762182
end
21772183
make_lhs_decls(ctx, stmts, declkind, declmeta, ex[1], type_decls)
21782184
elseif k == K"tuple" || k == K"parameters"
@@ -2198,7 +2204,7 @@ function expand_decls(ctx, ex)
21982204
# expand_assignment will create the type decls
21992205
make_lhs_decls(ctx, stmts, declkind, declmeta, binding[1], false)
22002206
push!(stmts, expand_assignment(ctx, binding))
2201-
elseif is_sym_decl(binding) || kind(binding) == K"Value"
2207+
elseif is_sym_decl(binding) || kind(binding) in (K"Value", K"Placeholder")
22022208
make_lhs_decls(ctx, stmts, declkind, declmeta, binding, true)
22032209
elseif kind(binding) == K"function"
22042210
make_lhs_decls(ctx, stmts, declkind, declmeta, binding[1], false)
@@ -2260,7 +2266,7 @@ end
22602266
#-------------------------------------------------------------------------------
22612267
# Expansion of function definitions
22622268

2263-
function expand_function_arg(ctx, body_stmts, arg, is_last_arg, is_kw)
2269+
function expand_function_arg(ctx, body_stmts, arg, is_last_arg, is_kw, arg_id)
22642270
ex = arg
22652271

22662272
if kind(ex) == K"="
@@ -2311,7 +2317,13 @@ function expand_function_arg(ctx, body_stmts, arg, is_last_arg, is_kw)
23112317
K"local"(meta=CompileHints(:is_destructured_arg, true))
23122318
[K"=" ex name]
23132319
])
2314-
elseif k == K"Identifier" || k == K"Placeholder"
2320+
elseif k == K"Placeholder"
2321+
# The user shouldn't be able to access this name, but lowering should be
2322+
# able to use it as an rvalue internally, e.g. for kw method dispatch.
2323+
# Duplicate positional placeholder names should be allowed.
2324+
name_str = is_kw ? "#kw$(ex.name_val)#" : "#arg$(string(arg_id))#"
2325+
name = @ast ctx ex name_str::K"Identifier"
2326+
elseif k == K"Identifier"
23152327
name = ex
23162328
else
23172329
throw(LoweringError(ex, is_kw ? "Invalid keyword name" : "Invalid function argument"))
@@ -2649,7 +2661,7 @@ function keyword_function_defs(ctx, srcref, callex_srcref, name_str, typevar_nam
26492661
kwtmp = new_local_binding(ctx, keywords, "kwtmp")
26502662
for (i,arg) in enumerate(children(keywords))
26512663
(aname, atype, default, is_slurp) =
2652-
expand_function_arg(ctx, nothing, arg, i == numchildren(keywords), true)
2664+
expand_function_arg(ctx, nothing, arg, i == numchildren(keywords), true, i)
26532665
push!(kw_names, aname)
26542666
name_sym = @ast ctx aname aname=>K"Symbol"
26552667
push!(body_arg_names, aname)
@@ -3026,8 +3038,8 @@ function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body=
30263038
first_default = 0 # index into arg_names/arg_types
30273039
arg_defaults = SyntaxList(ctx)
30283040
for (i,arg) in enumerate(args)
3029-
(aname, atype, default, is_slurp) = expand_function_arg(ctx, body_stmts, arg,
3030-
i == length(args), false)
3041+
(aname, atype, default, is_slurp) =
3042+
expand_function_arg(ctx, body_stmts, arg, i == length(args), false, i)
30313043
has_slurp |= is_slurp
30323044
push!(arg_names, aname)
30333045

@@ -3248,8 +3260,8 @@ function expand_opaque_closure(ctx, ex)
32483260
body_stmts = SyntaxList(ctx)
32493261
is_va = false
32503262
for (i, arg) in enumerate(children(args))
3251-
(aname, atype, default, is_slurp) = expand_function_arg(ctx, body_stmts, arg,
3252-
i == numchildren(args), false)
3263+
(aname, atype, default, is_slurp) =
3264+
expand_function_arg(ctx, body_stmts, arg, i == numchildren(args), false, i)
32533265
is_va |= is_slurp
32543266
push!(arg_names, aname)
32553267
push!(arg_types, atype)

src/macro_expansion.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,13 @@ function expand_macro(ctx, ex)
290290
# age changes concurrently.
291291
#
292292
# TODO: Allow this to be passed in
293-
if hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}; world=ctx.macro_world)
293+
# TODO: hasmethod always returns false for our `typemax(UInt)` meaning
294+
# "latest world," which we shouldn't be using.
295+
has_new_macro = ctx.macro_world === typemax(UInt) ?
296+
hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}) :
297+
hasmethod(macfunc, Tuple{typeof(mctx), typeof.(raw_args)...}; world=ctx.macro_world)
298+
299+
if has_new_macro
294300
macro_args = prepare_macro_args(ctx, mctx, raw_args)
295301
expanded = try
296302
Base.invoke_in_world(ctx.macro_world, macfunc, macro_args...)

src/syntax_macros.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ function Base.var"@nospecialize"(__context__::MacroContext, ex, exs...)
3434
_apply_nospecialize(__context__, ex)
3535
end
3636

37-
function Base.var"@atomic"(__context__::MacroContext, ex)
38-
@chk kind(ex) == K"Identifier" || kind(ex) == K"::" (ex, "Expected identifier or declaration")
39-
@ast __context__ __context__.macrocall [K"atomic" ex]
40-
end
37+
# TODO: support all forms that the original supports
38+
# function Base.var"@atomic"(__context__::MacroContext, ex)
39+
# @chk kind(ex) == K"Identifier" || kind(ex) == K"::" (ex, "Expected identifier or declaration")
40+
# @ast __context__ __context__.macrocall [K"atomic" ex]
41+
# end
4142

4243
function Base.var"@label"(__context__::MacroContext, ex)
4344
@chk kind(ex) == K"Identifier"

test/closures_ir.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ end
237237
21 SourceLocation::1:10
238238
22 (call core.svec %₁₈ %₂₀ %₂₁)
239239
23 --- method core.nothing %₂₂
240-
slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/g]
240+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/g]
241241
1 TestMod.#f#g##2
242242
2 static_parameter₁
243243
3 (new %%₂)

test/decls.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,17 @@ end
9292

9393
# Tuple/destructuring assignments
9494
@test JuliaLowering.include_string(test_mod, "(a0, a1, a2) = [1,2,3]") == [1,2,3]
95-
9695
@test JuliaLowering.include_string(test_mod, "const a,b,c = 1,2,3") === (1, 2, 3)
9796

97+
@testset "Placeholder decls" begin
98+
@test JuliaLowering.include_string(test_mod, "global _ = 1") === 1
99+
@test JuliaLowering.include_string(test_mod, "global _::Int = 1") === 1
100+
@test JuliaLowering.include_string(test_mod, "let; local _; _ = 1; end") === 1
101+
@test JuliaLowering.include_string(test_mod, "let; local _::Int = 1; end") === 1
102+
@test JuliaLowering.include_string(test_mod, "let; local (a0, _, a2) = [1,2,3]; end") == [1,2,3]
103+
@test JuliaLowering.include_string(test_mod, "let; local (a0, _::Int, a2) = [1,2,3]; end") == [1,2,3]
104+
end
105+
98106
test_mod_2 = Module()
99107
@testset "toplevel-preserving syntax" begin
100108
JuliaLowering.include_string(test_mod_2, "if true; global v1::Bool; else const v1 = 1; end")

test/functions.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,33 @@ end
471471
@test cl(x = 20) == 21
472472
end
473473

474+
@testset "Write-only placeholder function arguments" begin
475+
# positional arguments may be duplicate placeholders. keyword arguments can
476+
# contain placeholders, but they must be unique
477+
params_req = [""
478+
"_"
479+
"::Int"
480+
"_, _"]
481+
params_opt = [""
482+
"::Int=2"
483+
"_=2"]
484+
params_va = ["", "_..."]
485+
params_kw = [""
486+
"; _"
487+
"; _::Int"
488+
"; _::Int=1"
489+
"; _=1, __=2"
490+
"; _..."
491+
"; _=1, __..."]
492+
for req in params_req, opt in params_opt, va in params_va, kw in params_kw
493+
arg_str = join(filter(!isempty, (req, opt, va, kw)), ", ")
494+
f_str = "function f_placeholders($arg_str); end"
495+
@testset "$f_str" begin
496+
@test JuliaLowering.include_string(test_mod, f_str) isa Function
497+
end
498+
end
499+
end
500+
474501
@testset "Generated functions" begin
475502
@test JuliaLowering.include_string(test_mod, raw"""
476503
begin

test/functions_ir.jl

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ end
2323
7 SourceLocation::1:10
2424
8 (call core.svec %%%₇)
2525
9 --- method core.nothing %
26-
slots: [slot₁/#self#(!read) slot₂/x slot₃/_(!read) slot₄/y]
26+
slots: [slot₁/#self#(!read) slot₂/x slot₃/#arg2#(!read) slot₄/y]
2727
1 TestMod.+
2828
2 (call %₁ slot₂/x slot₄/y)
2929
3 (return %₂)
@@ -47,7 +47,7 @@ end
4747
8 SourceLocation::1:10
4848
9 (call core.svec %%%₈)
4949
10 --- method core.nothing %
50-
slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/x]
50+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/x]
5151
1 slot₃/x
5252
2 (return %₁)
5353
11 latestworld
@@ -160,7 +160,7 @@ end
160160
16 SourceLocation::1:10
161161
17 (call core.svec %₁₁ %₁₅ %₁₆)
162162
18 --- method core.nothing %₁₇
163-
slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/_(!read) slot₄/_(!read)]
163+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/#arg2#(!read) slot₄/#arg3#(!read)]
164164
1 static_parameter₃
165165
2 static_parameter₁
166166
3 static_parameter₂
@@ -192,7 +192,7 @@ end
192192
14 SourceLocation::1:10
193193
15 (call core.svec %₁₁ %₁₃ %₁₄)
194194
16 --- method core.nothing %₁₅
195-
slots: [slot₁/#self#(!read) slot₂/_(!read)]
195+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read)]
196196
1 static_parameter₁
197197
2 (return %₁)
198198
17 latestworld
@@ -220,7 +220,7 @@ end
220220
13 SourceLocation::1:10
221221
14 (call core.svec %₁₀ %₁₂ %₁₃)
222222
15 --- method core.nothing %₁₄
223-
slots: [slot₁/#self#(!read) slot₂/_(!read)]
223+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read)]
224224
1 static_parameter₁
225225
2 (return %₁)
226226
16 latestworld
@@ -513,8 +513,8 @@ end
513513
8 SourceLocation::1:10
514514
9 (call core.svec %%%₈)
515515
10 --- method core.nothing %
516-
slots: [slot₁/#self#(called) slot₂/_]
517-
1 (call slot₁/#self# slot₂/_ 1 2)
516+
slots: [slot₁/#self#(called) slot₂/#arg1#]
517+
1 (call slot₁/#self# slot₂/#arg1# 1 2)
518518
2 (return %₁)
519519
11 latestworld
520520
12 TestMod.f
@@ -525,8 +525,8 @@ end
525525
17 SourceLocation::1:10
526526
18 (call core.svec %₁₅ %₁₆ %₁₇)
527527
19 --- method core.nothing %₁₈
528-
slots: [slot₁/#self#(called) slot₂/_ slot₃/y]
529-
1 (call slot₁/#self# slot₂/_ slot₃/y 2)
528+
slots: [slot₁/#self#(called) slot₂/#arg1# slot₃/y]
529+
1 (call slot₁/#self# slot₂/#arg1# slot₃/y 2)
530530
2 (return %₁)
531531
20 latestworld
532532
21 TestMod.f
@@ -537,7 +537,7 @@ end
537537
26 SourceLocation::1:10
538538
27 (call core.svec %₂₄ %₂₅ %₂₆)
539539
28 --- method core.nothing %₂₇
540-
slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/y slot₄/z]
540+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/y slot₄/z]
541541
1 (call core.tuple slot₃/y slot₄/z)
542542
2 (return %₁)
543543
29 latestworld
@@ -560,8 +560,8 @@ end
560560
8 SourceLocation::1:10
561561
9 (call core.svec %%%₈)
562562
10 --- method core.nothing %
563-
slots: [slot₁/#self#(called) slot₂/_]
564-
1 (call slot₁/#self# slot₂/_ 1)
563+
slots: [slot₁/#self#(called) slot₂/#arg1#]
564+
1 (call slot₁/#self# slot₂/#arg1# 1)
565565
2 (return %₁)
566566
11 latestworld
567567
12 TestMod.f
@@ -572,7 +572,7 @@ end
572572
17 SourceLocation::1:10
573573
18 (call core.svec %₁₅ %₁₆ %₁₇)
574574
19 --- method core.nothing %₁₈
575-
slots: [slot₁/#self#(!read) slot₂/_(!read) slot₃/x]
575+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/x]
576576
1 slot₃/x
577577
2 (return %₁)
578578
20 latestworld
@@ -923,6 +923,25 @@ end
923923
19 TestMod.f
924924
20 (return %₁₉)
925925

926+
########################################
927+
# Duplicate positional placeholders ok
928+
function f(_, _); end
929+
#---------------------
930+
1 (method TestMod.f)
931+
2 latestworld
932+
3 TestMod.f
933+
4 (call core.Typeof %₃)
934+
5 (call core.svec %₄ core.Any core.Any)
935+
6 (call core.svec)
936+
7 SourceLocation::1:10
937+
8 (call core.svec %%%₇)
938+
9 --- method core.nothing %
939+
slots: [slot₁/#self#(!read) slot₂/#arg1#(!read) slot₃/#arg2#(!read)]
940+
1 (return core.nothing)
941+
10 latestworld
942+
11 TestMod.f
943+
12 (return %₁₁)
944+
926945
########################################
927946
# Duplicate destructured placeholders ok
928947
function f((_,), (_,))
@@ -1216,6 +1235,84 @@ end
12161235
76 TestMod.f_kw_simple
12171236
77 (return %₇₆)
12181237

1238+
########################################
1239+
# Keyword args with placeholders that need to be read
1240+
function f_kw_placeholders(_, ::Int; kw=1)
1241+
kw
1242+
end
1243+
#---------------------
1244+
1 (method TestMod.f_kw_placeholders)
1245+
2 latestworld
1246+
3 (method TestMod.#f_kw_placeholders#0)
1247+
4 latestworld
1248+
5 TestMod.#f_kw_placeholders#0
1249+
6 (call core.Typeof %₅)
1250+
7 TestMod.f_kw_placeholders
1251+
8 (call core.Typeof %₇)
1252+
9 TestMod.Int
1253+
10 (call core.svec %₆ core.Any %₈ core.Any %₉)
1254+
11 (call core.svec)
1255+
12 SourceLocation::1:10
1256+
13 (call core.svec %₁₀ %₁₁ %₁₂)
1257+
14 --- method core.nothing %₁₃
1258+
slots: [slot₁/#self#(!read) slot₂/kw slot₃/#self#(!read) slot₄/#arg1#(!read) slot₅/#arg2#(!read)]
1259+
1 (meta :nkw 1)
1260+
2 slot₂/kw
1261+
3 (return %₂)
1262+
15 latestworld
1263+
16 (call core.typeof core.kwcall)
1264+
17 TestMod.f_kw_placeholders
1265+
18 (call core.Typeof %₁₇)
1266+
19 TestMod.Int
1267+
20 (call core.svec %₁₆ core.NamedTuple %₁₈ core.Any %₁₉)
1268+
21 (call core.svec)
1269+
22 SourceLocation::1:10
1270+
23 (call core.svec %₂₀ %₂₁ %₂₂)
1271+
24 --- method core.nothing %₂₃
1272+
slots: [slot₁/#self#(!read) slot₂/kws slot₃/#self# slot₄/#arg1# slot₅/#arg2# slot₆/kwtmp slot₇/kw(!read)]
1273+
1 (newvar slot₇/kw)
1274+
2 (call core.isdefined slot₂/kws :kw)
1275+
3 (gotoifnot %₂ label₇)
1276+
4 (call core.getfield slot₂/kws :kw)
1277+
5 (= slot₆/kwtmp %₄)
1278+
6 (goto label₈)
1279+
7 (= slot₆/kwtmp 1)
1280+
8 slot₆/kwtmp
1281+
9 (call top.keys slot₂/kws)
1282+
10 (call core.tuple :kw)
1283+
11 (call top.diff_names %%₁₀)
1284+
12 (call top.isempty %₁₁)
1285+
13 (gotoifnot %₁₂ label₁₅)
1286+
14 (goto label₁₆)
1287+
15 (call top.kwerr slot₂/kws slot₃/#self# slot₄/#arg1# slot₅/#arg2#)
1288+
16 TestMod.#f_kw_placeholders#0
1289+
17 (call %₁₆ %₈ slot₃/#self# slot₄/#arg1# slot₅/#arg2#)
1290+
18 (return %₁₇)
1291+
25 latestworld
1292+
26 TestMod.f_kw_placeholders
1293+
27 (call core.Typeof %₂₆)
1294+
28 TestMod.Int
1295+
29 (call core.svec %₂₇ core.Any %₂₈)
1296+
30 (call core.svec)
1297+
31 SourceLocation::1:10
1298+
32 (call core.svec %₂₉ %₃₀ %₃₁)
1299+
33 --- method core.nothing %₃₂
1300+
slots: [slot₁/#self# slot₂/#arg1# slot₃/#arg2#]
1301+
1 TestMod.#f_kw_placeholders#0
1302+
2 (call %1 slot₁/#self# slot₂/#arg1# slot₃/#arg2#)
1303+
3 (return %₂)
1304+
34 latestworld
1305+
35 TestMod.f_kw_placeholders
1306+
36 (return %₃₅)
1307+
1308+
########################################
1309+
# Error: Duplicate keyword placeholder name
1310+
function f_kw_placeholders(; _=1, _=2); end
1311+
#---------------------
1312+
LoweringError:
1313+
function f_kw_placeholders(; _=1, _=2); end
1314+
# ╙ ── function argument name not unique
1315+
12191316
########################################
12201317
# Keyword slurping - simple forwarding of all kws
12211318
function f_kw_slurp_simple(; all_kws...)

0 commit comments

Comments
 (0)