Following this and I’m wondering the deets about it.
I made a simple recreation:
def hello(map) do
map
|> Map.to_list()
|> Enum.reduce_while(%{}, fn {key, value}, acc ->
if value == 2 do
{:halt, :error}
else
{:cont, Map.put(acc, key, value)}
end
end)
|> then(fn
%{a: a} = data when a == 3 ->
%{data | b: a}
data ->
data
end)
|> case do
:error -> "It's error"
data -> "It's okay #{data.a}"
end
end
This produces the warning:
warning: the following clause will never match:
:error
because it attempts to match on the result of:
(fn
%{a: a} = data when a == 3 -> %{data | b: a}
data -> data
end).(
Enum.reduce_while(Map.to_list(map), %{}, fn {key, value}, acc ->
if value == 2 do
{:halt, :error}
else
{:cont, Map.put(acc, key, value)}
end
end)
)
which has type:
dynamic(%{..., a: term(), b: term()})
typing violation found at:
│
33 │ :error -> "It's error"
│ ~~~~~~~~~~~~~~~~~~~~~~
│
└─ lib/then_case.ex:33: ThenCase.hello/1
It’s like putting the first clause in then makes the compiler think the data variable is always dynamic(%{..., a: term(), b: term()})
.
Removing that clause or moving it inside case (inside then or removing then and just case) resolves the warning.
It seems the compiler does not like cases made with then.
I’m just curious, is this the expected behavior and what’s the reason behind it?