Skip to content

Commit e8df031

Browse files
committed
Ensure defimpl add export definition on protocols
1 parent cb8b735 commit e8df031

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

lib/elixir/lib/protocol.ex

+14-3
Original file line numberDiff line numberDiff line change
@@ -1042,8 +1042,9 @@ defmodule Protocol do
10421042
raise ArgumentError, "defimpl/3 expects a :for option when declared outside a module"
10431043
end)
10441044

1045-
for =
1046-
Macro.expand_literals(for, %{env | module: env.module || Elixir, function: {:__impl__, 1}})
1045+
expansion_env = %{env | module: env.module || Elixir, function: {:__impl__, 1}}
1046+
protocol = Macro.expand_literals(protocol, expansion_env)
1047+
for = Macro.expand_literals(for, expansion_env)
10471048

10481049
case opts do
10491050
[] -> raise ArgumentError, "defimpl expects a do-end block"
@@ -1069,6 +1070,16 @@ defmodule Protocol do
10691070
def __impl__(:protocol), do: unquote(protocol)
10701071
end
10711072

1073+
# If the protocol is an atom, we will add an export dependency,
1074+
# since it was expanded before-hand. Otherwise it is a dynamic
1075+
# expression (and therefore most likely a compile-time one).
1076+
behaviour =
1077+
if is_atom(protocol) do
1078+
quote(do: require(unquote(protocol)))
1079+
else
1080+
quote(do: protocol)
1081+
end
1082+
10721083
quote do
10731084
protocol = unquote(protocol)
10741085
for = unquote(for)
@@ -1079,7 +1090,7 @@ defmodule Protocol do
10791090

10801091
defmodule name do
10811092
@moduledoc false
1082-
@behaviour protocol
1093+
@behaviour unquote(behaviour)
10831094
@protocol protocol
10841095
@for for
10851096

lib/elixir/test/elixir/kernel/lexical_tracker_test.exs

+4-1
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ defmodule Kernel.LexicalTrackerTest do
523523
refute URI in runtime
524524
end
525525

526-
test "defimpl does not add dependencies" do
526+
test "defimpl does not add dependencies on for only on impl" do
527527
{{compile, exports, runtime, _}, _binding} =
528528
Code.eval_string("""
529529
defimpl String.Chars, for: Kernel.LexicalTrackerTest do
@@ -532,6 +532,9 @@ defmodule Kernel.LexicalTrackerTest do
532532
end |> elem(3)
533533
""")
534534

535+
refute String.Chars in compile
536+
assert String.Chars in exports
537+
535538
refute Kernel.LexicalTrackerTest in compile
536539
refute Kernel.LexicalTrackerTest in exports
537540
refute Kernel.LexicalTrackerTest in runtime

0 commit comments

Comments
 (0)