Skip to content

Commit 802ecdd

Browse files
authored
Add local_for_callback option to Macro.Env.expand_import (#14620)
1 parent 36eb9da commit 802ecdd

File tree

2 files changed

+27
-7
lines changed

2 files changed

+27
-7
lines changed

lib/elixir/lib/macro/env.ex

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ defmodule Macro.Env do
9696
]
9797

9898
@type expand_import_opts :: [
99-
allow_locals: boolean(),
99+
allow_locals:
100+
boolean() | (Macro.metadata(), atom(), arity(), t() -> function() | false),
100101
check_deprecations: boolean(),
101102
trace: boolean()
102103
]
@@ -555,8 +556,15 @@ defmodule Macro.Env do
555556
556557
## Options
557558
558-
* `:allow_locals` - when set to `false`, it does not attempt to capture
559-
local macros defined in the current module in `env`
559+
* `:allow_locals` - controls how local macros are resolved.
560+
Defaults to `true`.
561+
562+
- When `false`, does not attempt to capture local macros defined in the
563+
current module in `env`
564+
- When `true`, uses a default resolver that looks for public macros in
565+
the current module
566+
- When a function, uses the function as a custom local resolver. The function
567+
must have the signature: `(meta, name, arity, env) -> function() | false`
560568
561569
* `:check_deprecations` - when set to `false`, does not check for deprecations
562570
when expanding macros
@@ -580,10 +588,16 @@ defmodule Macro.Env do
580588
trace = Keyword.get(opts, :trace, true)
581589
module = env.module
582590

591+
# When allow_locals is a callback, we don't need to pass module macros as extra
592+
# because the callback will handle local macro resolution
583593
extra =
584-
case allow_locals and function_exported?(module, :__info__, 1) do
585-
true -> [{module, module.__info__(:macros)}]
586-
false -> []
594+
if is_function(allow_locals, 4) do
595+
[]
596+
else
597+
case allow_locals and function_exported?(module, :__info__, 1) do
598+
true -> [{module, module.__info__(:macros)}]
599+
false -> []
600+
end
587601
end
588602

589603
case :elixir_dispatch.expand_import(meta, name, arity, env, extra, allow_locals, trace) do

lib/elixir/src/elixir_dispatch.erl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,13 @@ expand_import(Meta, Name, Arity, E, Extra, AllowLocals, Trace) ->
172172
do_expand_import(Dispatch, Meta, Name, Arity, Module, E, Trace);
173173

174174
_ ->
175-
Local = AllowLocals andalso elixir_def:local_for(Meta, Name, Arity, [defmacro, defmacrop], E),
175+
Local = case AllowLocals of
176+
false -> false;
177+
true -> elixir_def:local_for(Meta, Name, Arity, [defmacro, defmacrop], E);
178+
Fun when is_function(Fun, 4) ->
179+
%% If we have a custom local resolver, use it.
180+
Fun(Meta, Name, Arity, E)
181+
end,
176182

177183
case Dispatch of
178184
%% There is a local and an import. This is a conflict unless

0 commit comments

Comments
 (0)