@@ -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}}
2328end
@@ -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}} ())
3137end
3238
3339function current_lambda_bindings (ctx:: ClosureConversionCtx )
@@ -117,10 +123,39 @@ function convert_for_type_decl(ctx, srcref, ex, type, do_typeassert)
117123 ]
118124end
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+
120153function 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)
0 commit comments