Skip to content

Commit 870d28f

Browse files
committed
Fix regression where we inferred the wrong type in a case branch that raises
1 parent 2d6e61c commit 870d28f

2 files changed

Lines changed: 54 additions & 19 deletions

File tree

lib/elixir/lib/module/types/expr.ex

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -369,38 +369,34 @@ defmodule Module.Types.Expr do
369369
of_expr(body, expected, body, stack, reset_warnings(refined_context, context))
370370
end
371371

372-
{{head_type, body_type}, _, context} =
373-
cache_arrows(meta, stack, fn cache? ->
374-
acc = {none(), none(), []}
372+
{{none?, body_type}, clauses_acc, context} =
373+
cache_arrows(meta, stack, fn _cache? ->
374+
acc = {false, none(), []}
375375

376376
{{head_acc, body_acc, clauses_acc}, context} =
377377
of_clauses_fun(clauses, [case_type], info, stack, context, of_body, acc, fn
378-
trees, precise?, body_type, context, {head_acc, body_acc, clauses_acc} ->
379-
cond do
380-
precise? and empty?(body_type) ->
381-
[arg_type] = Pattern.of_domain(trees, stack, context)
382-
{union(negation(arg_type), head_acc), body_acc, clauses_acc}
383-
384-
cache? ->
385-
[arg_type] = Pattern.of_domain(trees, stack, context)
386-
{head_acc, union(body_type, body_acc), [{arg_type, body_type} | clauses_acc]}
387-
388-
true ->
389-
{head_acc, union(body_type, body_acc), clauses_acc}
378+
trees, precise?, body_type, context, {none?, body_acc, clauses_acc} ->
379+
if precise? and empty?(body_type) do
380+
{true, body_acc, clauses_acc}
381+
else
382+
[arg_type] = Pattern.of_domain(trees, stack, context)
383+
{none?, union(body_type, body_acc), [{arg_type, body_type} | clauses_acc]}
390384
end
391385
end)
392386

393387
{{head_acc, body_acc}, clauses_acc, context}
394388
end)
395389

396390
context =
397-
if head_type == none() do
398-
context
399-
else
391+
if none? do
392+
head_type = Enum.reduce(clauses_acc, none(), &union(elem(&1, 0), &2))
393+
400394
{_, refined_context} =
401395
of_expr(case_expr, head_type, case_expr, %{stack | reverse_arrow: :use}, context)
402396

403397
reset_warnings(refined_context, context)
398+
else
399+
context
404400
end
405401

406402
dynamic_unless_static({body_type, context}, stack)

lib/elixir/test/elixir/module/types/expr_test.exs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1812,7 +1812,7 @@ defmodule Module.Types.ExprTest do
18121812
atom([:non_empty_map, :maybe_empty_map])
18131813
end
18141814

1815-
test "computes types from dead branches" do
1815+
test "computes types from dead branches (conditional)" do
18161816
assert typecheck!(
18171817
[x],
18181818
(
@@ -1848,6 +1848,45 @@ defmodule Module.Types.ExprTest do
18481848
) == dynamic()
18491849
end
18501850

1851+
test "computes types from dead branches (case)" do
1852+
assert typecheck!(
1853+
[x, key],
1854+
(
1855+
case x do
1856+
%{^key => value} -> {:ok, value}
1857+
%{} -> raise "bad"
1858+
end
1859+
1860+
x
1861+
)
1862+
) == dynamic(open_map())
1863+
1864+
assert typecheck!(
1865+
[x],
1866+
(
1867+
case x do
1868+
%{foo: _} -> :ok
1869+
%{} -> raise "bad"
1870+
end
1871+
1872+
x
1873+
)
1874+
) == dynamic(open_map(foo: term()))
1875+
1876+
assert typecheck!(
1877+
[x, key],
1878+
(
1879+
case x do
1880+
%{foo: _} -> :ok
1881+
%{^key => value} -> {:value, value}
1882+
%{} -> raise "bad"
1883+
end
1884+
1885+
x
1886+
)
1887+
) == dynamic(open_map())
1888+
end
1889+
18511890
test "warns on redundant clauses" do
18521891
assert typewarn!(
18531892
[x],

0 commit comments

Comments
 (0)