Skip to content

Commit 5c439d7

Browse files
committed
Ensure module of macro method is used for AST scope
This change allows macros to be extended from modules other than `parentmodule(mac)` and have the scope of the AST be that of the module the extension is written in. This matches Julia's current semantics for macro extensions though it's unclear how useful this actually is when different macro methods are distinguished based only on the number of arguments.
1 parent 1d0f774 commit 5c439d7

File tree

3 files changed

+47
-4
lines changed

3 files changed

+47
-4
lines changed

src/macro_expansion.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,15 @@ function expand_macro(ctx, ex)
138138
# a macro expansion.
139139
# In either case, we need to set any unset scope layers before passing the
140140
# arguments to the macro call.
141-
macro_args = [set_scope_layer(ctx, e, ctx.current_layer.id, false)
142-
for e in children(ex)[2:end]]
143141
mctx = MacroContext(ctx.graph, ex, ctx.current_layer)
142+
macro_args = Any[mctx]
143+
for i in 2:numchildren(ex)
144+
push!(macro_args, set_scope_layer(ctx, ex[i], ctx.current_layer.id, false))
145+
end
146+
macro_invocation_world = Base.get_world_counter()
144147
expanded = try
145148
# TODO: Allow invoking old-style macros for compat
146-
invokelatest(macfunc, mctx, macro_args...)
149+
invokelatest(macfunc, macro_args...)
147150
catch exc
148151
if exc isa MacroExpansionError
149152
# Add context to the error.
@@ -162,7 +165,10 @@ function expand_macro(ctx, ex)
162165
expanded = copy_ast(ctx, expanded)
163166
end
164167
expanded = append_sourceref(ctx, expanded, ex)
165-
new_layer = ScopeLayer(length(ctx.scope_layers)+1, parentmodule(macfunc), true)
168+
# Module scope for the returned AST is the module where this particular
169+
# method was defined (may be different from `parentmodule(macfunc)`)
170+
mod_for_ast = lookup_method_instance(macfunc, macro_args, macro_invocation_world).def.module
171+
new_layer = ScopeLayer(length(ctx.scope_layers)+1, mod_for_ast, true)
166172
push!(ctx.scope_layers, new_layer)
167173
inner_ctx = MacroExpansionContext(ctx.graph, ctx.bindings, ctx.scope_layers, new_layer)
168174
expanded = expand_forms_1(inner_ctx, expanded)

src/runtime.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,11 @@ function reserve_module_binding_i(mod, basename)
418418
end
419419
end
420420

421+
function lookup_method_instance(func, args, world::Integer)
422+
allargs = Vector{Any}(undef, length(args) + 1)
423+
allargs[1] = func
424+
allargs[2:end] = args
425+
mi = @ccall jl_method_lookup(allargs::Ptr{Any}, length(allargs)::Csize_t,
426+
world::Csize_t)::Ptr{Cvoid}
427+
return mi == C_NULL ? nothing : unsafe_pointer_to_objref(mi)
428+
end

test/macros_ir.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
module MacroMethods
2+
macro some_macro()
3+
quote
4+
some_global
5+
end
6+
end
7+
8+
module ExtraMacroMethods
9+
using ..MacroMethods
10+
macro MacroMethods.some_macro(ex)
11+
quote
12+
some_global
13+
end
14+
end
15+
end
16+
end
17+
18+
#*******************************************************************************
119
########################################
220
# Simple macro
321
macro add_one(ex)
@@ -42,6 +60,17 @@ end
4260
9 TestMod.@foo
4361
10 (return %₉)
4462

63+
########################################
64+
# Scope for symbols emitted by macros is the module where the method was
65+
# defined, thus two different modules in this case, even though `@some_macro`
66+
# belongs to the MacroMethods module.
67+
(MacroMethods.@some_macro(), MacroMethods.@some_macro(unused))
68+
#---------------------
69+
1 TestMod.MacroMethods.some_global
70+
2 TestMod.MacroMethods.ExtraMacroMethods.some_global
71+
3 (call core.tuple %%₂)
72+
4 (return %₃)
73+
4574
########################################
4675
# Error: Macro with kw args
4776
macro mmm(a; b=2)

0 commit comments

Comments
 (0)