Skip to content

Commit 6e2a2c4

Browse files
mlechuc42f
andcommitted
Changes from code review: const/global lowering
Ping me if you'd like this squashed into the original const/global commit! Co-authored-by: Claire Foster <[email protected]>
1 parent a3d647d commit 6e2a2c4

File tree

7 files changed

+117
-128
lines changed

7 files changed

+117
-128
lines changed

src/closure_conversion.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,13 @@ function _convert_closures(ctx::ClosureConversionCtx, ex)
352352
@assert kind(ex[1]) == K"BindingId"
353353
binfo = lookup_binding(ctx, ex[1])
354354
if binfo.kind == :global
355-
@ast ctx ex [
356-
K"globaldecl"
357-
ex[1]
358-
_convert_closures(ctx, ex[2])
359-
]
355+
@ast ctx ex [K"block"
356+
# flisp has this, but our K"assert" handling is in a previous pass
357+
# [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex]]
358+
[K"globaldecl"
359+
ex[1]
360+
_convert_closures(ctx, ex[2])]
361+
"nothing"::K"core"]
360362
else
361363
makeleaf(ctx, ex, K"TOMBSTONE")
362364
end

src/desugaring.jl

Lines changed: 49 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,7 @@ function expand_generator(ctx, ex)
814814
outervars_by_key = Dict{NameKey,typeof(ex)}()
815815
for iterspecs in ex[2:end-1]
816816
for iterspec in children(iterspecs)
817-
lhs = iterspec[1]
818-
foreach_lhs_var(lhs) do var
817+
foreach_lhs_name(iterspec[1]) do var
819818
@assert kind(var) == K"Identifier" # Todo: K"BindingId"?
820819
outervars_by_key[NameKey(var)] = var
821820
end
@@ -1170,15 +1169,13 @@ function expand_unionall_def(ctx, srcref, lhs, rhs, is_const=true)
11701169
throw(LoweringError(lhs, "empty type parameter list in type alias"))
11711170
end
11721171
name = lhs[1]
1173-
rr = ssavar(ctx, srcref)
11741172
expand_forms_2(
11751173
ctx,
1176-
@ast ctx srcref [
1177-
K"block"
1178-
[K"=" rr [K"where" rhs lhs[2:end]...]]
1179-
[is_const ? K"constdecl" : K"assign_const_if_global" name rr]
1174+
@ast ctx srcref [K"block"
1175+
rr := [K"where" rhs lhs[2:end]...]
1176+
[is_const ? K"constdecl" : K"assign_or_constdecl_if_global" name rr]
11801177
[K"latestworld_if_toplevel"]
1181-
rr
1178+
[K"removable" rr]
11821179
]
11831180
)
11841181
end
@@ -1229,10 +1226,8 @@ function expand_assignment(ctx, ex, is_const=false)
12291226
)
12301227
elseif is_identifier_like(lhs)
12311228
if is_const
1232-
rr = ssavar(ctx, rhs)
1233-
@ast ctx ex [
1234-
K"block"
1235-
sink_assignment(ctx, ex, rr, expand_forms_2(ctx, rhs))
1229+
@ast ctx ex [K"block"
1230+
rr := expand_forms_2(ctx, rhs)
12361231
[K"constdecl" lhs rr]
12371232
[K"latestworld"]
12381233
[K"removable" rr]
@@ -1276,11 +1271,10 @@ function expand_assignment(ctx, ex, is_const=false)
12761271
x = lhs[1]
12771272
T = lhs[2]
12781273
res = if is_const
1279-
expand_forms_2(ctx, @ast ctx ex [
1280-
K"const"
1274+
expand_forms_2(ctx, @ast ctx ex [K"const"
12811275
[K"="
1282-
lhs[1]
1283-
convert_for_type_decl(ctx, ex, rhs, T, true)
1276+
lhs[1]
1277+
convert_for_type_decl(ctx, ex, rhs, T, true)
12841278
]])
12851279
elseif is_identifier_like(x)
12861280
# Identifer in lhs[1] is a variable type declaration, eg
@@ -1467,7 +1461,7 @@ function expand_let(ctx, ex)
14671461
]
14681462
elseif kind(lhs) == K"tuple"
14691463
lhs_locals = SyntaxList(ctx)
1470-
foreach_lhs_var(lhs) do var
1464+
foreach_lhs_name(lhs) do var
14711465
push!(lhs_locals, @ast ctx var [K"local" var])
14721466
push!(lhs_locals, @ast ctx var [K"always_defined" var])
14731467
end
@@ -1904,23 +1898,6 @@ end
19041898
#-------------------------------------------------------------------------------
19051899
# Expand for loops
19061900

1907-
# Extract the variable names assigned to from a "fancy assignment left hand
1908-
# side" such as nested tuple destructuring.
1909-
function foreach_lhs_var(f::Function, ex)
1910-
k = kind(ex)
1911-
if k == K"Identifier" || k == K"BindingId"
1912-
f(ex)
1913-
elseif k == K"::" && numchildren(ex) == 2
1914-
foreach_lhs_var(f, ex[1])
1915-
elseif k == K"tuple" || k == K"parameters"
1916-
for e in children(ex)
1917-
foreach_lhs_var(f, e)
1918-
end
1919-
end
1920-
# k == K"Placeholder" ignored, along with everything else - we assume
1921-
# validation is done elsewhere.
1922-
end
1923-
19241901
function expand_for(ctx, ex)
19251902
iterspecs = ex[1]
19261903

@@ -1936,7 +1913,7 @@ function expand_for(ctx, ex)
19361913
@chk kind(iterspec) == K"in"
19371914
lhs = iterspec[1]
19381915
if kind(lhs) != K"outer"
1939-
foreach_lhs_var(lhs) do var
1916+
foreach_lhs_name(lhs) do var
19401917
push!(copied_vars, @ast ctx var [K"=" var var])
19411918
end
19421919
end
@@ -1953,7 +1930,7 @@ function expand_for(ctx, ex)
19531930
if outer
19541931
lhs = lhs[1]
19551932
end
1956-
foreach_lhs_var(lhs) do var
1933+
foreach_lhs_name(lhs) do var
19571934
if outer
19581935
push!(lhs_outer_defs, @ast ctx var var)
19591936
else
@@ -2108,17 +2085,14 @@ end
21082085
# (x::T, (y::U, z))
21092086
# strip out stmts = (local x) (decl x T) (local x) (decl y U) (local z)
21102087
# and return (x, (y, z))
2111-
function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex)
2088+
function strip_decls!(ctx, stmts, declkind, declmeta, ex)
21122089
k = kind(ex)
21132090
if k == K"Identifier"
21142091
if !isnothing(declmeta)
21152092
push!(stmts, makenode(ctx, ex, declkind, ex; meta=declmeta))
21162093
else
21172094
push!(stmts, makenode(ctx, ex, declkind, ex))
21182095
end
2119-
if !isnothing(declkind2)
2120-
push!(stmts, makenode(ctx, ex, declkind2, ex))
2121-
end
21222096
ex
21232097
elseif k == K"Placeholder"
21242098
ex
@@ -2127,90 +2101,75 @@ function strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex)
21272101
name = ex[1]
21282102
@chk kind(name) == K"Identifier"
21292103
push!(stmts, makenode(ctx, ex, K"decl", name, ex[2]))
2130-
strip_decls!(ctx, stmts, declkind, declkind2, declmeta, ex[1])
2104+
strip_decls!(ctx, stmts, declkind, declmeta, ex[1])
21312105
elseif k == K"tuple" || k == K"parameters"
21322106
cs = SyntaxList(ctx)
21332107
for e in children(ex)
2134-
push!(cs, strip_decls!(ctx, stmts, declkind, declkind2, declmeta, e))
2108+
push!(cs, strip_decls!(ctx, stmts, declkind, declmeta, e))
21352109
end
21362110
makenode(ctx, ex, k, cs)
2111+
else
2112+
throw(LoweringError(ex, "invalid kind $k in $declkind declaration"))
21372113
end
21382114
end
21392115

2116+
# Separate decls and assignments (which require re-expansion)
21402117
# local x, (y=2), z ==> local x; local z; y = 2
2141-
# Note there are differences from lisp (evaluation order?)
2142-
function expand_decls(ctx, ex)
2118+
function expand_decls(ctx, ex, is_const=false)
21432119
declkind = kind(ex)
2120+
@assert declkind in KSet"local global"
21442121
declmeta = get(ex, :meta, nothing)
2145-
if numchildren(ex) == 1 && kind(ex[1]) KSet"const global local"
2146-
declkind2 = kind(ex[1])
2147-
bindings = children(ex[1])
2148-
else
2149-
declkind2 = nothing
2150-
bindings = children(ex)
2151-
end
2122+
bindings = children(ex)
21522123
stmts = SyntaxList(ctx)
21532124
for binding in bindings
21542125
kb = kind(binding)
21552126
if is_prec_assignment(kb)
21562127
@chk numchildren(binding) == 2
2157-
lhs = strip_decls!(ctx, stmts, declkind, declkind2, declmeta, binding[1])
2158-
push!(stmts, @ast ctx binding [kb lhs binding[2]])
2159-
elseif is_sym_decl(binding)
2160-
if declkind == K"const" || declkind2 == K"const"
2161-
throw(LoweringError(ex, "expected assignment after `const`"))
2162-
end
2163-
strip_decls!(ctx, stmts, declkind, declkind2, declmeta, binding)
2128+
lhs = strip_decls!(ctx, stmts, declkind, declmeta, binding[1])
2129+
push!(stmts, expand_assignment(ctx, @ast ctx binding [kb lhs binding[2]]))
2130+
elseif is_sym_decl(binding) && !is_const
2131+
strip_decls!(ctx, stmts, declkind, declmeta, binding)
21642132
else
21652133
throw(LoweringError(ex, "invalid syntax in variable declaration"))
21662134
end
21672135
end
21682136
makenode(ctx, ex, K"block", stmts)
21692137
end
21702138

2171-
# Return all the names that will be bound by the assignment LHS, including
2172-
# curlies and calls.
2173-
function lhs_bound_names(ex)
2139+
# Iterate over the variable names assigned to from a "fancy assignment left hand
2140+
# side" such as nested tuple destructuring, curlies, and calls.
2141+
function foreach_lhs_name(f::Function, ex)
21742142
k = kind(ex)
21752143
if k == K"Placeholder"
2176-
[]
2144+
# Ignored
21772145
elseif is_identifier_like(ex)
2178-
[ex]
2179-
elseif k in KSet"call curly where ::"
2180-
lhs_bound_names(ex[1])
2146+
f(ex)
2147+
elseif (k === K"::" && numchildren(ex) === 2) || k in KSet"call curly where"
2148+
foreach_lhs_name(f, ex[1])
21812149
elseif k in KSet"tuple parameters"
2182-
vcat(map(lhs_bound_names, children(ex))...)
2183-
else
2184-
[]
2150+
for c in children(ex)
2151+
foreach_lhs_name(f, c)
2152+
end
21852153
end
2154+
return nothing
21862155
end
21872156

21882157
function expand_const_decl(ctx, ex)
2189-
function check_assignment(asgn)
2190-
@chk (kind(asgn) == K"=") (ex, "expected assignment after `const`")
2191-
end
2192-
21932158
k = kind(ex[1])
2194-
if numchildren(ex) == 2
2195-
@ast ctx ex [
2196-
K"constdecl"
2197-
ex[1]
2198-
expand_forms_2(ctx, ex[2])
2199-
]
2200-
elseif k == K"global"
2159+
if k == K"global"
22012160
asgn = ex[1][1]
2202-
check_assignment(asgn)
2203-
globals = map(lhs_bound_names(asgn[1])) do x
2204-
@ast ctx ex [K"global" x]
2161+
@chk (kind(asgn) == K"=") (ex, "expected assignment after `const`")
2162+
globals = SyntaxList(ctx)
2163+
foreach_lhs_name(asgn[1]) do x
2164+
push!(globals, @ast ctx ex [K"global" x])
22052165
end
2206-
@ast ctx ex [
2207-
K"block"
2166+
@ast ctx ex [K"block"
22082167
globals...
2209-
expand_assignment(ctx, ex[1], true)
2168+
expand_assignment(ctx, asgn, true)
22102169
]
22112170
elseif k == K"="
22122171
if numchildren(ex[1]) >= 1 && kind(ex[1][1]) == K"tuple"
2213-
throw(LoweringError(ex[1][1], "unsupported `const` tuple"))
2172+
TODO(ex[1][1], "`const` tuple assignment desugaring")
22142173
end
22152174
expand_assignment(ctx, ex[1], true)
22162175
elseif k == K"local"
@@ -4403,8 +4362,11 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing)
44034362
if numchildren(ex) == 1 && kind(ex[1]) == K"Identifier"
44044363
# Don't recurse when already simplified - `local x`, etc
44054364
ex
4365+
elseif k == K"global" && kind(ex[1]) == K"const"
4366+
# Normalize `global const` to `const global`
4367+
expand_const_decl(ctx, @ast ctx ex [K"const" [K"global" ex[1][1]]])
44064368
else
4407-
expand_forms_2(ctx, expand_decls(ctx, ex))
4369+
expand_decls(ctx, ex)
44084370
end
44094371
elseif k == K"where"
44104372
expand_forms_2(ctx, expand_wheres(ctx, ex))

src/kinds.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ function _register_kinds()
9696
"_opaque_closure"
9797
# The enclosed statements must be executed at top level
9898
"toplevel_butfirst"
99-
"assign_const_if_global"
99+
"assign_or_constdecl_if_global"
100100
"moved_local"
101101
"label"
102102
"trycatchelse"

src/linear_ir.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -325,14 +325,14 @@ function emit_break(ctx, ex)
325325
emit_jump(ctx, ex, target)
326326
end
327327

328-
# `op` may also be K"constdecl"
329-
function emit_assignment_or_setglobal(ctx, srcref, lhs, rhs, op=K"=")
330-
# (const (globalref _ _) _) does not use setglobal!
328+
# `op` may be either K"=" (where global assignments are converted to setglobal!)
329+
# or K"constdecl". flisp: emit-assignment-or-setglobal
330+
function emit_simple_assignment(ctx, srcref, lhs, rhs, op=K"=")
331331
binfo = lookup_binding(ctx, lhs.var_id)
332332
if binfo.kind == :global && op == K"="
333333
emit(ctx, @ast ctx srcref [
334334
K"call"
335-
"setglobal!"::K"top"
335+
"setglobal!"::K"core"
336336
binfo.mod::K"Value"
337337
binfo.name::K"Symbol"
338338
rhs
@@ -345,15 +345,15 @@ end
345345
function emit_assignment(ctx, srcref, lhs, rhs, op=K"=")
346346
if !isnothing(rhs)
347347
if is_valid_ir_rvalue(ctx, lhs, rhs)
348-
emit_assignment_or_setglobal(ctx, srcref, lhs, rhs, op)
348+
emit_simple_assignment(ctx, srcref, lhs, rhs, op)
349349
else
350350
r = emit_assign_tmp(ctx, rhs)
351-
emit_assignment_or_setglobal(ctx, srcref, lhs, r, op)
351+
emit_simple_assignment(ctx, srcref, lhs, r, op)
352352
end
353353
else
354354
# in unreachable code (such as after return); still emit the assignment
355355
# so that the structure of those uses is preserved
356-
emit_assignment_or_setglobal(ctx, srcref, lhs, @ast ctx srcref "nothing"::K"core", op)
356+
emit_simple_assignment(ctx, srcref, lhs, @ast ctx srcref "nothing"::K"core", op)
357357
nothing
358358
end
359359
end
@@ -657,10 +657,11 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
657657
# TODO look up arg-map for renaming if lhs was reassigned
658658
if needs_value && !isnothing(rhs)
659659
r = emit_assign_tmp(ctx, rhs)
660-
emit_assignment_or_setglobal(ctx, ex, lhs, r, k)
660+
emit_simple_assignment(ctx, ex, lhs, r, k)
661661
if in_tail_pos
662662
emit_return(ctx, ex, r)
663663
else
664+
@assert false "If this code is reachable, add a test case"
664665
r
665666
end
666667
else
@@ -825,9 +826,9 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
825826
end
826827
emit(ctx, ex)
827828
nothing
828-
elseif k == K"global"
829+
elseif k == K"global"
829830
if needs_value
830-
throw(LoweringError(ex, "misplaced kind $k in value position"))
831+
throw(LoweringError(ex, "misplaced global declaration in value position"))
831832
end
832833
emit(ctx, ex)
833834
ctx.is_toplevel_thunk && emit(ctx, makenode(ctx, ex, K"latestworld"))
@@ -884,8 +885,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
884885
if numchildren(ex) == 1 || is_identifier_like(ex[2])
885886
emit(ctx, ex)
886887
else
887-
rr = ssavar(ctx, ex[2])
888-
emit(ctx, @ast ctx ex [K"=" rr ex[2]])
888+
rr = emit_assign_tmp(ctx, ex[2])
889889
emit(ctx, @ast ctx ex [K"globaldecl" ex[1] rr])
890890
end
891891
ctx.is_toplevel_thunk && emit(ctx, makenode(ctx, ex, K"latestworld"))

src/scope_analysis.jl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function _find_scope_vars!(ctx, assignments, locals, destructured_args, globals,
4444
end
4545
elseif k == K"global"
4646
_insert_if_not_present!(globals, NameKey(ex[1]), ex)
47-
elseif k == K"assign_const_if_global"
47+
elseif k == K"assign_or_constdecl_if_global"
4848
# like v = val, except that if `v` turns out global(either implicitly or
4949
# by explicit `global`), it gains an implicit `const`
5050
_insert_if_not_present!(assignments, NameKey(ex[1]), ex)
@@ -565,16 +565,12 @@ function _resolve_scopes(ctx, ex::SyntaxTree)
565565
end
566566
end
567567
resolved
568-
elseif k == K"assign_const_if_global"
568+
elseif k == K"assign_or_constdecl_if_global"
569569
id = _resolve_scopes(ctx, ex[1])
570570
bk = lookup_binding(ctx, id).kind
571-
if bk == :local && numchildren(ex) != 1
572-
@ast ctx ex _resolve_scopes(ctx, [K"=" children(ex)...])
573-
elseif bk != :local # TODO: should this be == :global?
574-
@ast ctx ex _resolve_scopes(ctx, [K"constdecl" children(ex)...])
575-
else
576-
makeleaf(ctx, ex, K"TOMBSTONE")
577-
end
571+
@assert numchildren(ex) === 2
572+
assignment_kind = bk == :global ? K"constdecl" : K"="
573+
@ast ctx ex _resolve_scopes(ctx, [assignment_kind ex[1] ex[2]])
578574
else
579575
mapchildren(e->_resolve_scopes(ctx, e), ctx, ex)
580576
end

0 commit comments

Comments
 (0)