@@ -206,13 +206,42 @@ function prepare_macro_args(ctx, mctx, raw_args)
206206 return macro_args
207207end
208208
209+ """
210+ Insert a hygienic-scope around each arg of K"toplevel" returned from a macro.
211+
212+ It isn't correct for macro expansion to recurse into a K"toplevel" expression
213+ since one child may define a macro and the next may use it. However, not
214+ recursing now means we lose some important context: the module of the macro we
215+ just expanded, which is necessary for resolving the identifiers in the
216+ K"toplevel" AST. The solution implemented in JuliaLang/julia#53515 was to save
217+ our place and expand later using `Expr(:hygienic-scope toplevel_child mod)`.
218+
219+ Of course, these hygienic-scopes are also necessary because existing user code
220+ contains the corresponding escaping, which would otherwise cause errors. We
221+ already consumed the hygienic-scope that comes with every expansion, but won't
222+ be looking for escapes under :toplevel, so push hygienic-scope under toplevel
223+ """
224+ function fix_toplevel_expansion (ctx, ex:: SyntaxTree , mod:: Module , lnn:: LineNumberNode )
225+ if kind (ex) === K " toplevel"
226+ mapchildren (ctx, ex) do e
227+ @ast ctx ex [K " hygienic_scope" e mod:: K"Value" lnn:: K"Value" ]
228+ end
229+ else
230+ mapchildren (e-> fix_toplevel_expansion (ctx, e, mod, lnn), ctx, ex)
231+ end
232+ end
233+
209234function expand_macro (ctx, ex)
210235 @assert kind (ex) == K " macrocall"
211236
212237 macname = ex[1 ]
213238 mctx = MacroContext (ctx. graph, ex, current_layer (ctx))
214239 macfunc = eval_macro_name (ctx, mctx, macname)
215240 raw_args = ex[2 : end ]
241+ macro_loc = let loc = source_location (LineNumberNode, ex)
242+ # Some macros, e.g. @cmd, don't play nicely with file == nothing
243+ isnothing (loc. file) ? LineNumberNode (loc. line, :none ) : loc
244+ end
216245 # We use a specific well defined world age for the next checks and macro
217246 # expansion invocations. This avoids inconsistencies if the latest world
218247 # age changes concurrently.
@@ -242,10 +271,6 @@ function expand_macro(ctx, ex)
242271 else
243272 # Compat: attempt to invoke an old-style macro if there's no applicable
244273 # method for new-style macro arguments.
245- macro_loc = let loc = source_location (LineNumberNode, ex)
246- # Some macros, e.g. @cmd, don't play nicely with file == nothing
247- isnothing (loc. file) ? LineNumberNode (loc. line, :none ) : loc
248- end
249274 macro_args = Any[macro_loc, current_layer (ctx). mod]
250275 for arg in raw_args
251276 # For hygiene in old-style macros, we omit any additional scope
@@ -281,6 +306,7 @@ function expand_macro(ctx, ex)
281306 # method was defined (may be different from `parentmodule(macfunc)`)
282307 mod_for_ast = lookup_method_instance (macfunc, macro_args,
283308 ctx. macro_world). def. module
309+ expanded = fix_toplevel_expansion (ctx, expanded, mod_for_ast, macro_loc)
284310 new_layer = ScopeLayer (length (ctx. scope_layers)+ 1 , mod_for_ast,
285311 current_layer_id (ctx), true )
286312 push! (ctx. scope_layers, new_layer)
0 commit comments