Skip to content

Commit e2abd35

Browse files
author
José Valim
committed
Ensure missing protocol dependencies are discarded, closes #4842
Signed-off-by: José Valim <[email protected]>
1 parent cc35c8f commit e2abd35

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

lib/mix/lib/mix/tasks/compile.protocols.ex

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,24 @@ defmodule Mix.Tasks.Compile.Protocols do
122122
defp consolidate(protocol, paths, output, opts) do
123123
impls = Protocol.extract_impls(protocol, paths)
124124
reload(protocol)
125-
{:ok, binary} = Protocol.consolidate(protocol, impls)
126-
File.write!(Path.join(output, "#{protocol}.beam"), binary)
127-
if opts[:verbose] do
128-
Mix.shell.info "Consolidated #{inspect protocol}"
125+
case Protocol.consolidate(protocol, impls) do
126+
{:ok, binary} ->
127+
File.write!(Path.join(output, "#{protocol}.beam"), binary)
128+
if opts[:verbose] do
129+
Mix.shell.info "Consolidated #{inspect protocol}"
130+
end
131+
132+
# If we remove a dependency and we have implemented one of its
133+
# protocols locally, we will mark the protocol as needing to be
134+
# reconsolidated when the implementation is removed even though
135+
# the protocol no longer exists. Although most times removing a
136+
# dependency will trigger a full recompilation, such won't happen
137+
# in umbrella apps with shared build.
138+
{:error, :no_beam_info} ->
139+
remove_consolidated(protocol, output)
140+
if opts[:verbose] do
141+
Mix.shell.info "Unavailable #{inspect protocol}"
142+
end
129143
end
130144
end
131145

lib/mix/test/mix/umbrella_test.exs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ defmodule Mix.UmbrellaTest do
364364
end)
365365
end
366366

367-
test "reconsolidates using umbrella information even on shared _build" do
367+
test "reconsolidates using umbrella parent information on shared _build" do
368368
in_fixture("umbrella_dep/deps/umbrella", fn ->
369369
File.write!("apps/bar/lib/bar.ex", """
370370
defprotocol Bar do
@@ -388,6 +388,29 @@ defmodule Mix.UmbrellaTest do
388388
end)
389389
end
390390

391+
test "reconsolidates using umbrella child information on shared _build" do
392+
in_fixture("umbrella_dep/deps/umbrella", fn ->
393+
File.write!("apps/bar/lib/bar.ex", """
394+
defprotocol Bar do
395+
def foo(arg)
396+
end
397+
defimpl Bar, for: List do
398+
def foo(list), do: list
399+
end
400+
""")
401+
402+
Mix.Project.in_project(:umbrella, ".", fn _ ->
403+
Mix.Task.run("compile.protocols")
404+
end)
405+
406+
# Emulate the dependency being removed
407+
Mix.Project.in_project(:foo, "apps/foo", [build_path: "../../_build", deps: []], fn _ ->
408+
File.rm_rf "../../_build/dev/lib/bar"
409+
Mix.Task.run("compile.protocols")
410+
end)
411+
end)
412+
end
413+
391414
defmodule Selective do
392415
def project do
393416
[apps_path: "apps",

0 commit comments

Comments
 (0)