Skip to content

Commit 7a90b59

Browse files
authored
Enable use of unquote in defguard(p) (#13716)
1 parent 797e503 commit 7a90b59

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

lib/elixir/lib/kernel.ex

+15-5
Original file line numberDiff line numberDiff line change
@@ -5765,8 +5765,11 @@ defmodule Kernel do
57655765
"only a single when clause is allowed"
57665766

57675767
{call, impls} ->
5768-
case Macro.decompose_call(call) do
5769-
{_name, args} ->
5768+
case decompose_args(call) do
5769+
:error ->
5770+
raise ArgumentError, "invalid syntax in defguard #{Macro.to_string(call)}"
5771+
5772+
args ->
57705773
validate_variable_only_args!(call, args)
57715774

57725775
macro_definition =
@@ -5788,13 +5791,20 @@ defmodule Kernel do
57885791
Elixir.Kernel.@(doc(guard: true))
57895792
unquote(macro_definition)
57905793
end
5791-
5792-
_invalid_definition ->
5793-
raise ArgumentError, "invalid syntax in defguard #{Macro.to_string(call)}"
57945794
end
57955795
end
57965796
end
57975797

5798+
defp decompose_args({name, _, args}) when is_atom(name) and is_atom(args), do: []
5799+
5800+
defp decompose_args({name, _, args}) when is_atom(name) and is_list(args), do: args
5801+
5802+
defp decompose_args({{:unquote, _, _}, _, args}) when is_atom(args), do: []
5803+
5804+
defp decompose_args({{:unquote, _, _}, _, args}) when is_list(args), do: args
5805+
5806+
defp decompose_args(_), do: :error
5807+
57985808
defp validate_variable_only_args!(call, args) do
57995809
Enum.each(args, fn
58005810
{ref, _meta, context} when is_atom(ref) and is_atom(context) ->

lib/elixir/test/elixir/kernel/guard_test.exs

+12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ defmodule Kernel.GuardTest do
6060
refute MacrosInGuards.is_foobar(:baz)
6161
end
6262

63+
defmodule UnquotedInGuardCall do
64+
@value :foo
65+
66+
defguard unquote(String.to_atom("is_#{@value}"))(x) when x == unquote(@value)
67+
end
68+
69+
test "guards names can be defined dynamically using unquote" do
70+
require UnquotedInGuardCall
71+
assert UnquotedInGuardCall.is_foo(:foo)
72+
refute UnquotedInGuardCall.is_foo(:bar)
73+
end
74+
6375
defmodule GuardsInGuards do
6476
defguard is_foo(atom) when atom == :foo
6577
defguard is_foobar(atom) when is_foo(atom) or atom == :bar

0 commit comments

Comments
 (0)