Skip to content

Commit e079ad6

Browse files
mlechuc42f
andauthored
Random lowering bugfixes (#24)
* Random lowering bugfixes - `init` not provided for possibly-empty `sum()`s in desugaring causing failures for empty ctors, empty tuple destruct - linearize: break_block type error - missing desugaring when if-condition is a block - undef var `ex` in expand_arrow_arglist Co-authored-by: Claire Foster <[email protected]>
1 parent fedc5c5 commit e079ad6

File tree

7 files changed

+120
-12
lines changed

7 files changed

+120
-12
lines changed

src/desugaring.jl

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ function expand_tuple_destruct(ctx, ex)
414414
end
415415

416416
if kind(rhs) == K"tuple"
417-
num_splat = sum(kind(rh) == K"..." for rh in children(rhs))
417+
num_splat = sum(kind(rh) == K"..." for rh in children(rhs); init=0)
418418
if num_splat == 0 && (numchildren(lhs) - num_slurp) > numchildren(rhs)
419419
throw(LoweringError(ex, "More variables on left hand side than right hand in tuple assignment"))
420420
end
@@ -1402,7 +1402,7 @@ function expand_condition(ctx, ex)
14021402
if isblock
14031403
# Special handling so that the rules for `&&` and `||` can be applied
14041404
# to the last statement of a block
1405-
@ast ctx ex [K"block" ex[1:end-1]... test]
1405+
@ast ctx ex [K"block" map(e->expand_forms_2(ctx,e), ex[1:end-1])... test]
14061406
else
14071407
test
14081408
end
@@ -2112,7 +2112,7 @@ end
21122112

21132113
# Separate decls and assignments (which require re-expansion)
21142114
# local x, (y=2), z ==> local x; local z; y = 2
2115-
function expand_decls(ctx, ex, is_const=false)
2115+
function expand_decls(ctx, ex)
21162116
declkind = kind(ex)
21172117
@assert declkind in KSet"local global"
21182118
declmeta = get(ex, :meta, nothing)
@@ -2124,7 +2124,7 @@ function expand_decls(ctx, ex, is_const=false)
21242124
@chk numchildren(binding) == 2
21252125
lhs = strip_decls!(ctx, stmts, declkind, declmeta, binding[1])
21262126
push!(stmts, expand_assignment(ctx, @ast ctx binding [kb lhs binding[2]]))
2127-
elseif is_sym_decl(binding) && !is_const
2127+
elseif is_sym_decl(binding)
21282128
strip_decls!(ctx, stmts, declkind, declmeta, binding)
21292129
else
21302130
throw(LoweringError(ex, "invalid syntax in variable declaration"))
@@ -3085,7 +3085,7 @@ function expand_arrow_arglist(ctx, arglist, arrowname)
30853085
if k == K"where"
30863086
@ast ctx arglist [K"where"
30873087
expand_arrow_arglist(ctx, arglist[1], arrowname)
3088-
argslist[2]
3088+
arglist[2]
30893089
]
30903090
else
30913091
# The arglist can sometimes be parsed as a block, or something else, and
@@ -3094,13 +3094,12 @@ function expand_arrow_arglist(ctx, arglist, arrowname)
30943094
if k == K"block"
30953095
@chk numchildren(arglist) == 2
30963096
arglist = @ast ctx arglist [K"tuple"
3097-
ex[1]
3098-
[K"parameters" ex[2]]
3097+
arglist[1]
3098+
[K"parameters" arglist[2]]
30993099
]
31003100
elseif k != K"tuple"
3101-
# `x::Int -> body`
31023101
arglist = @ast ctx arglist [K"tuple"
3103-
ex[1]
3102+
arglist[1]
31043103
]
31053104
end
31063105
@ast ctx arglist [K"call"
@@ -3665,7 +3664,7 @@ function _rewrite_ctor_new_calls(ctx, ex, struct_name, global_struct_name, ctor_
36653664
full_struct_type = if kind(ex[1]) == K"curly"
36663665
# new{A,B}(...)
36673666
new_type_params = ex[1][2:end]
3668-
n_type_splat = sum(kind(t) == K"..." for t in new_type_params)
3667+
n_type_splat = sum(kind(t) == K"..." for t in new_type_params; init=0)
36693668
n_type_nonsplat = length(new_type_params) - n_type_splat
36703669
if n_type_splat == 0 && n_type_nonsplat < length(struct_typevars)
36713670
throw(LoweringError(ex[1], "too few type parameters specified in `new{...}`"))
@@ -3685,7 +3684,7 @@ function _rewrite_ctor_new_calls(ctx, ex, struct_name, global_struct_name, ctor_
36853684
end
36863685
end
36873686
new_args = ex[2:end]
3688-
n_splat = sum(kind(t) == K"..." for t in new_args)
3687+
n_splat = sum(kind(t) == K"..." for t in new_args; init=0)
36893688
n_nonsplat = length(new_args) - n_splat
36903689
n_fields = length(field_types)
36913690
function throw_n_fields_error(desc)

src/linear_ir.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
703703
if isnothing(outer_target)
704704
delete!(ctx.break_targets, name)
705705
else
706-
ctx.break_targets = outer_target
706+
ctx.break_targets[name] = outer_target
707707
end
708708
emit(ctx, end_label)
709709
if needs_value

test/branching.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,15 @@ end
221221
""") === 3
222222

223223
end
224+
#-------------------------------------------------------------------------------
225+
# Block condition
226+
@test JuliaLowering.include_string(test_mod, """
227+
let a = true
228+
if begin; x = 2; a; end
229+
x
230+
end
231+
end
232+
""") === 2
224233

225234
#-------------------------------------------------------------------------------
226235
@testset "`&&` and `||` chains" begin

test/destructuring_ir.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,22 @@ end
280280
8 (call core.tuple %%%₃)
281281
9 (return %₈)
282282

283+
########################################
284+
# Error: Destructuring with tuple elimination and too few RHS elements
285+
(x,) = ()
286+
#---------------------
287+
LoweringError:
288+
(x,) = ()
289+
└───────┘ ── More variables on left hand side than right hand in tuple assignment
290+
291+
########################################
292+
# Error: Destructuring with tuple elimination, slurping, and too few RHS elements
293+
(x,y,ys...) = (1,)
294+
#---------------------
295+
LoweringError:
296+
(x,y,ys...) = (1,)
297+
└────────────────┘ ── More variables on left hand side than right hand in tuple assignment
298+
283299
########################################
284300
# Destructuring with tuple elimination but not in value position never creates
285301
# the tuple

test/functions.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,31 @@ end
5656
2^4
5757
""") == 16
5858

59+
#-------------------------------------------------------------------------------
60+
# Arrow syntax
61+
@test JuliaLowering.include_string(test_mod, """
62+
let
63+
f = ((x::T, y::T) where T) -> x + y
64+
f(1, 2)
65+
end
66+
""") === 3
67+
68+
@test JuliaLowering.include_string(test_mod, """
69+
let
70+
f = ((x::T; y=2) where T) -> x + y
71+
f(1)
72+
end
73+
""") === 3
74+
75+
# Passes desugaring, but T is detected as unused and throws an error.
76+
# Is it clear whether this should be `f(x::T) where T` or `f(x::T where T)`?
77+
@test_broken JuliaLowering.include_string(test_mod, """
78+
let
79+
f = ((x::T) where T) -> x
80+
f(1)
81+
end
82+
""") === 1
83+
5984
#-------------------------------------------------------------------------------
6085
# Function definitions
6186
@test JuliaLowering.include_string(test_mod, """

test/loops.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ let
9595
a
9696
end
9797
""") == [1, 2]
98+
# Break from inner nested loop
99+
@test JuliaLowering.include_string(test_mod, """
100+
let
101+
a = []
102+
for i in 1:2
103+
for j in 3:4
104+
push!(a, (i, j))
105+
j == 6 && break
106+
end
107+
end
108+
a
109+
end
110+
""") == [(1, 3), (1, 4), (2, 3), (2, 4)]
98111

99112
# continue
100113
@test JuliaLowering.include_string(test_mod, """

test/typedefs_ir.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,52 @@ end
409409
34 latestworld
410410
35 (return core.nothing)
411411

412+
########################################
413+
# Empty struct with empty ctor
414+
struct X
415+
X() = new()
416+
end
417+
#---------------------
418+
1 (global TestMod.X)
419+
2 latestworld
420+
3 (call core.svec)
421+
4 (call core.svec)
422+
5 (call core.svec)
423+
6 (call core._structtype TestMod :X %%%false 0)
424+
7 (= slot₁/X %₆)
425+
8 (call core._setsuper! %₆ core.Any)
426+
9 (call core.isdefinedglobal TestMod :X false)
427+
10 (gotoifnot %₉ label₁₄)
428+
11 TestMod.X
429+
12 (= slot₂/if_val (call core._equiv_typedef %₁₁ %₆))
430+
13 (goto label₁₅)
431+
14 (= slot₂/if_val false)
432+
15 slot₂/if_val
433+
16 (gotoifnot %₁₅ label₂₀)
434+
17 TestMod.X
435+
18 (= slot₃/if_val %₁₇)
436+
19 (goto label₂₁)
437+
20 (= slot₃/if_val false)
438+
21 slot₃/if_val
439+
22 (gotoifnot %₁₅ label₂₃)
440+
23 (call core.svec)
441+
24 (call core._typebody! %₂₁ %%₂₃)
442+
25 (constdecl TestMod.X %₂₄)
443+
26 latestworld
444+
27 TestMod.X
445+
28 (call core.apply_type core.Type %₂₇)
446+
29 (call core.svec %₂₈)
447+
30 (call core.svec)
448+
31 SourceLocation::2:5
449+
32 (call core.svec %₂₉ %₃₀ %₃₁)
450+
33 --- method core.nothing %₃₂
451+
slots: [slot₁/#ctor-self#]
452+
1 slot₁/#ctor-self#
453+
2 (new %₁)
454+
3 (return %₂)
455+
34 latestworld
456+
35 (return core.nothing)
457+
412458
########################################
413459
# Basic struct
414460
struct X

0 commit comments

Comments
 (0)