Skip to content

Commit bac6ef9

Browse files
committed
Implement redundant clauses for reduce and convert them to warnings
1 parent 7b0ae43 commit bac6ef9

3 files changed

Lines changed: 49 additions & 19 deletions

File tree

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ defmodule Module.Types.Expr do
426426
{reduce_type, context} = of_expr(reduce, expected, expr, stack, context)
427427
# TODO: We need to type check against dynamic() instead of using reduce_type
428428
# because this is recursive. We need to infer the block type first.
429-
of_clauses(block, [dynamic()], expected, expr, :for_reduce, stack, context, reduce_type)
429+
args = [dynamic()]
430+
of_redundant_clauses(block, args, expected, :for_reduce, stack, context, reduce_type)
430431
else
431432
# TODO: Use the collectable protocol for the output
432433
into = Keyword.get(opts, :into, [])
@@ -779,8 +780,7 @@ defmodule Module.Types.Expr do
779780
cond do
780781
stack.mode != :infer and previous != [] and
781782
Pattern.args_subtype?(clause_type, previous) ->
782-
stack = %{stack | meta: meta}
783-
{previous, Pattern.badpattern_error(clause, nil, info, stack, context)}
783+
{previous, Pattern.badpattern_warn(clause, info, stack, context)}
784784

785785
precise? ->
786786
{[clause_type | previous], context}

lib/elixir/lib/module/types/pattern.ex

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,15 @@ defmodule Module.Types.Pattern do
366366
error(__MODULE__, error, meta, stack, context)
367367
end
368368

369+
@doc """
370+
Marks a badpattern warnings.
371+
"""
372+
def badpattern_warn(expr, tag, stack, context) do
373+
meta = error_meta(expr, stack)
374+
error = {:badpattern, meta, expr, nil, tag, context}
375+
warn(__MODULE__, error, meta, stack, context)
376+
end
377+
369378
defp error_meta(expr, stack) do
370379
if meta = get_meta(expr) do
371380
meta ++ Keyword.take(stack.meta, [:generated, :line, :type_check])
@@ -1366,15 +1375,12 @@ defmodule Module.Types.Pattern do
13661375
# $ type tag = head_pattern() or match_pattern()
13671376
#
13681377
# $ typep head_pattern =
1369-
# :for_reduce or :with_else or :fn or :default or
1378+
# :with_else or :fn or :default or
13701379
# {{:case | :try_else, meta, expr, type}, [arg], [previous]} or
1371-
# {:receive | :try_catch, [arg], [previous]}
1380+
# {:for_reduce | :receive | :try_catch, [arg], [previous]}
13721381
#
13731382
# $ typep match_pattern =
13741383
# :with or :for or {:match, type}
1375-
#
1376-
# The match pattern ones have the whole expression instead
1377-
# of a single pattern.
13781384
def format_diagnostic({:badpattern, meta, pattern_or_expr, index, tag, context}) do
13791385
# TODO: stop passing pattern_or_expr as argument
13801386
{to_trace, message} = badpattern(tag, pattern_or_expr, index)
@@ -1509,7 +1515,7 @@ defmodule Module.Types.Pattern do
15091515
end
15101516
end
15111517

1512-
defp badpattern({op, args, previous}, _, _) when op in [:receive, :try_catch] do
1518+
defp badpattern({op, args, previous}, _, _) when op in [:receive, :try_catch, :for_reduce] do
15131519
{args,
15141520
"""
15151521
the following clause is redundant:

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

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,13 +1804,14 @@ defmodule Module.Types.ExprTest do
18041804
dynamic(nil or binary())
18051805
"""
18061806

1807-
assert typeerror!(
1807+
assert typewarn!(
18081808
[x],
18091809
case String.to_atom(x) do
18101810
:ok -> 1
18111811
:ok -> 2
18121812
end
1813-
) == ~l"""
1813+
)
1814+
|> elem(1) == ~l"""
18141815
the following clause is redundant:
18151816
18161817
:ok ->
@@ -1820,13 +1821,14 @@ defmodule Module.Types.ExprTest do
18201821
:ok
18211822
"""
18221823

1823-
assert typeerror!(
1824+
assert typewarn!(
18241825
[a, b],
18251826
case {a, b} do
18261827
{x, y} when is_integer(x) and is_integer(y) -> 1
18271828
{x, y} when is_integer(x) and is_integer(y) -> 2
18281829
end
1829-
) =~ ~l"""
1830+
)
1831+
|> elem(1) =~ ~l"""
18301832
the following clause is redundant:
18311833
18321834
{x, y} when is_integer(x) and is_integer(y) ->
@@ -2043,12 +2045,13 @@ defmodule Module.Types.ExprTest do
20432045
end
20442046

20452047
test "errors on redundant clauses" do
2046-
assert typeerror!(
2048+
assert typewarn!(
20472049
receive do
20482050
x when is_binary(x) -> x
20492051
"foo" -> "bar"
20502052
end
2051-
) == """
2053+
)
2054+
|> elem(1) == """
20522055
the following clause is redundant:
20532056
20542057
"foo" ->
@@ -2159,14 +2162,15 @@ defmodule Module.Types.ExprTest do
21592162
end
21602163

21612164
test "catch: errors on redundant clauses" do
2162-
assert typeerror!(
2165+
assert typewarn!(
21632166
try do
21642167
flunk("whatever")
21652168
catch
21662169
x when is_binary(x) -> x
21672170
"foo" -> "bar"
21682171
end
2169-
) == """
2172+
)
2173+
|> elem(1) == """
21702174
the following clause is redundant:
21712175
21722176
:throw, "foo" ->
@@ -2192,7 +2196,7 @@ defmodule Module.Types.ExprTest do
21922196
end
21932197

21942198
test "else: errors on redundant clauses" do
2195-
assert typeerror!(
2199+
assert typewarn!(
21962200
try do
21972201
Process.get(:x)
21982202
rescue
@@ -2201,7 +2205,8 @@ defmodule Module.Types.ExprTest do
22012205
x when is_binary(x) -> x
22022206
"foo" -> "bar"
22032207
end
2204-
) == """
2208+
)
2209+
|> elem(1) == """
22052210
the following clause is redundant:
22062211
22072212
"foo" ->
@@ -2577,6 +2582,25 @@ defmodule Module.Types.ExprTest do
25772582
)
25782583
) == dynamic(integer())
25792584
end
2585+
2586+
test ":reduce errors on redundant clauses" do
2587+
assert typewarn!(
2588+
[list, x],
2589+
for _ <- list, reduce: x do
2590+
x when is_binary(x) -> x
2591+
"foo" -> "bar"
2592+
end
2593+
)
2594+
|> elem(1) == """
2595+
the following clause is redundant:
2596+
2597+
"foo" ->
2598+
2599+
previous clauses have already matched on the following types:
2600+
2601+
binary()
2602+
"""
2603+
end
25802604
end
25812605

25822606
describe "info" do

0 commit comments

Comments
 (0)