Skip to content

Commit 8142feb

Browse files
xal-0mlechu
andauthored
New Core.declare_global and Core.declare_const lowering (#87)
* Support `const foo() = ...` * Add support for destructuring `const` * Generate Core.declare_const; make constdecl a lowering-only kind * Generate Core.declare_global; remove globaldecl kind, desugar global Corresponds to #58279 (also take unused_only) * Refresh IR test cases * Update README * Fix toplevel_pure * Random typo fix * Use Core.declare_const instead of jl_set_const * Don't test on 1.12 in CI * Update test/decls.jl Co-authored-by: Em Chu <[email protected]> * Expand global/local function def body properly * Add a handful more IR tests for declarations * Add tests for JuliaLang/julia#59755 --------- Co-authored-by: Em Chu <[email protected]>
1 parent f8e84e1 commit 8142feb

File tree

18 files changed

+404
-184
lines changed

18 files changed

+404
-184
lines changed

.github/workflows/CI.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
version:
22-
- '~1.12.0-rc1'
2322
- 'nightly'
2423
os:
2524
- ubuntu-latest

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,6 @@ In the current Julia runtime,
898898
* `:import`
899899
* `:public`
900900
* `:export`
901-
* `:global`
902-
* `:const`
903901
* `:toplevel`
904902
* `:error`
905903
* `:incomplete`

src/closure_conversion.jl

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ struct ClosureConversionCtx{GraphType} <: AbstractLoweringContext
1818
# True if we're in a section of code which preserves top-level sequencing
1919
# such that closure types can be emitted inline with other code.
2020
is_toplevel_seq_point::Bool
21+
# True if this expression should not have toplevel effects, namely, it
22+
# should not declare the globals it references. This allows generated
23+
# functions to refer to globals that have already been declared, without
24+
# triggering the "function body AST not pure" error.
25+
toplevel_pure::Bool
2126
toplevel_stmts::SyntaxList{GraphType}
2227
closure_infos::Dict{IdTag,ClosureInfo{GraphType}}
2328
end
@@ -27,7 +32,8 @@ function ClosureConversionCtx(graph::GraphType, bindings::Bindings,
2732
lambda_bindings::LambdaBindings) where {GraphType}
2833
ClosureConversionCtx{GraphType}(
2934
graph, bindings, mod, closure_bindings, nothing,
30-
lambda_bindings, false, SyntaxList(graph), Dict{IdTag,ClosureInfo{GraphType}}())
35+
lambda_bindings, false, true, SyntaxList(graph),
36+
Dict{IdTag,ClosureInfo{GraphType}}())
3137
end
3238

3339
function current_lambda_bindings(ctx::ClosureConversionCtx)
@@ -117,10 +123,39 @@ function convert_for_type_decl(ctx, srcref, ex, type, do_typeassert)
117123
]
118124
end
119125

126+
# TODO: Avoid producing redundant calls to declare_global
127+
function make_globaldecl(ctx, src_ex, mod, name, strong=false, type=nothing; ret_nothing=false)
128+
if !ctx.toplevel_pure
129+
decl = @ast ctx src_ex [K"block"
130+
[K"call"
131+
"declare_global"::K"core"
132+
mod::K"Value" name::K"Symbol" strong::K"Bool"
133+
if type !== nothing
134+
type
135+
end
136+
]
137+
[K"latestworld"]
138+
@ast ctx src_ex [K"removable" "nothing"::K"core"]
139+
]
140+
if ctx.is_toplevel_seq_point
141+
return decl
142+
else
143+
push!(ctx.toplevel_stmts, decl)
144+
end
145+
end
146+
if ret_nothing
147+
nothing
148+
else
149+
@ast ctx src_ex [K"removable" "nothing"::K"core"]
150+
end
151+
end
152+
120153
function convert_global_assignment(ctx, ex, var, rhs0)
121154
binfo = lookup_binding(ctx, var)
122155
@assert binfo.kind == :global
123156
stmts = SyntaxList(ctx)
157+
decl = make_globaldecl(ctx, ex, binfo.mod, binfo.name, true; ret_nothing=true)
158+
decl !== nothing && push!(stmts, decl)
124159
rhs1 = if is_simple_atom(ctx, rhs0)
125160
rhs0
126161
else
@@ -147,7 +182,6 @@ function convert_global_assignment(ctx, ex, var, rhs0)
147182
end
148183
push!(stmts, @ast ctx ex [K"=" var rhs])
149184
@ast ctx ex [K"block"
150-
[K"globaldecl" var]
151185
stmts...
152186
rhs1
153187
]
@@ -296,7 +330,7 @@ function map_cl_convert(ctx::ClosureConversionCtx, ex, toplevel_preserving)
296330
toplevel_stmts = SyntaxList(ctx)
297331
ctx2 = ClosureConversionCtx(ctx.graph, ctx.bindings, ctx.mod,
298332
ctx.closure_bindings, ctx.capture_rewriting, ctx.lambda_bindings,
299-
false, toplevel_stmts, ctx.closure_infos)
333+
false, ctx.toplevel_pure, toplevel_stmts, ctx.closure_infos)
300334
res = mapchildren(e->_convert_closures(ctx2, e), ctx2, ex)
301335
if isempty(toplevel_stmts)
302336
res
@@ -352,16 +386,24 @@ function _convert_closures(ctx::ClosureConversionCtx, ex)
352386
@assert kind(ex[1]) == K"BindingId"
353387
binfo = lookup_binding(ctx, ex[1])
354388
if binfo.kind == :global
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"]
389+
# flisp has this, but our K"assert" handling is in a previous pass
390+
# [K"assert" "toplevel_only"::K"Symbol" [K"inert" ex]]
391+
make_globaldecl(ctx, ex, binfo.mod, binfo.name, true, _convert_closures(ctx, ex[2]))
362392
else
363393
makeleaf(ctx, ex, K"TOMBSTONE")
364394
end
395+
elseif k == K"global"
396+
# Leftover `global` forms become weak globals.
397+
mod, name = if kind(ex[1]) == K"BindingId"
398+
binfo = lookup_binding(ctx, ex[1])
399+
@assert binfo.kind == :global
400+
binfo.mod, binfo.name
401+
else
402+
# See note about using eval on Expr(:global/:const, GlobalRef(...))
403+
@assert ex[1].value isa GlobalRef
404+
ex[1].value.mod, String(ex[1].value.name)
405+
end
406+
@ast ctx ex [K"unused_only" make_globaldecl(ctx, ex, mod, name, false)]
365407
elseif k == K"local"
366408
var = ex[1]
367409
binfo = lookup_binding(ctx, var)
@@ -453,7 +495,8 @@ function _convert_closures(ctx::ClosureConversionCtx, ex)
453495
cap_rewrite = is_closure ? ctx.closure_infos[name.var_id] : nothing
454496
ctx2 = ClosureConversionCtx(ctx.graph, ctx.bindings, ctx.mod,
455497
ctx.closure_bindings, cap_rewrite, ctx.lambda_bindings,
456-
ctx.is_toplevel_seq_point, ctx.toplevel_stmts, ctx.closure_infos)
498+
ctx.is_toplevel_seq_point, ctx.toplevel_pure, ctx.toplevel_stmts,
499+
ctx.closure_infos)
457500
body = map_cl_convert(ctx2, ex[2], false)
458501
if is_closure
459502
if ctx.is_toplevel_seq_point
@@ -478,7 +521,7 @@ function _convert_closures(ctx::ClosureConversionCtx, ex)
478521

479522
ctx2 = ClosureConversionCtx(ctx.graph, ctx.bindings, ctx.mod,
480523
ctx.closure_bindings, capture_rewrites, ctx.lambda_bindings,
481-
false, ctx.toplevel_stmts, ctx.closure_infos)
524+
false, ctx.toplevel_pure, ctx.toplevel_stmts, ctx.closure_infos)
482525

483526
init_closure_args = SyntaxList(ctx)
484527
for id in field_orig_bindings
@@ -521,7 +564,8 @@ function closure_convert_lambda(ctx, ex)
521564
end
522565
ctx2 = ClosureConversionCtx(ctx.graph, ctx.bindings, ctx.mod,
523566
ctx.closure_bindings, cap_rewrite, lambda_bindings,
524-
ex.is_toplevel_thunk, ctx.toplevel_stmts, ctx.closure_infos)
567+
ex.is_toplevel_thunk, ctx.toplevel_pure && ex.toplevel_pure,
568+
ctx.toplevel_stmts, ctx.closure_infos)
525569
lambda_children = SyntaxList(ctx)
526570
args = ex[1]
527571
push!(lambda_children, args)

src/compat.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function expr_to_syntaxtree(@nospecialize(e), lnn::Union{LineNumberNode, Nothing
2525
kind=Kind, syntax_flags=UInt16,
2626
source=SourceAttrType, var_id=Int, value=Any,
2727
name_val=String, is_toplevel_thunk=Bool,
28-
scope_layer=LayerId, meta=CompileHints)
28+
scope_layer=LayerId, meta=CompileHints,
29+
toplevel_pure=Bool)
2930
expr_to_syntaxtree(graph, e, lnn)
3031
end
3132

0 commit comments

Comments
 (0)