Skip to content

Commit 8f31a4b

Browse files
committed
Warn when equality is always disjoint
1 parent 23982cb commit 8f31a4b

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

lib/elixir/lib/module/types/of.ex

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,21 @@ defmodule Module.Types.Of do
364364
end
365365
end
366366

367+
def apply(:erlang, name, [left, right], expr, stack, context)
368+
when name in [:==, :"/=", :"=:=", :"=/="] do
369+
cond do
370+
name in [:==, :"/="] and number_type?(left) and number_type?(right) ->
371+
{boolean(), context}
372+
373+
disjoint?(left, right) ->
374+
warning = {:mismatched_comparison, expr, context}
375+
{boolean(), warn(__MODULE__, warning, elem(expr, 1), stack, context)}
376+
377+
true ->
378+
{boolean(), context}
379+
end
380+
end
381+
367382
def apply(mod, name, args, expr, stack, context) do
368383
case :elixir_rewrite.inline(mod, name, length(args)) do
369384
{mod, name} -> apply(mod, name, args, expr, stack, context)

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ defmodule Module.Types.ExprTest do
511511
test "works across numbers" do
512512
assert typecheck!([x = 123, y = 456.0], min(x, y)) == dynamic(union(integer(), float()))
513513
assert typecheck!([x = 123, y = 456.0], x < y) == boolean()
514+
assert typecheck!([x = 123, y = 456.0], x == y) == boolean()
514515
end
515516

516517
test "warns when comparison is constant" do
@@ -536,6 +537,29 @@ defmodule Module.Types.ExprTest do
536537
While Elixir can compare across all types, you are comparing across types \
537538
which are always distinct, and the result is either always true or always false
538539
"""}
540+
541+
assert typewarn!([x = 123, y = 456.0], x === y) ==
542+
{boolean(),
543+
~l"""
544+
comparison between incompatible types found:
545+
546+
x === y
547+
548+
where "x" was given the type:
549+
550+
# type: integer()
551+
# from: types_test.ex:LINE-2
552+
x = 123
553+
554+
where "y" was given the type:
555+
556+
# type: float()
557+
# from: types_test.ex:LINE-2
558+
y = 456.0
559+
560+
While Elixir can compare across all types, you are comparing across types \
561+
which are always distinct, and the result is either always true or always false
562+
"""}
539563
end
540564

541565
test "warns on comparison with struct across dynamic call" do

0 commit comments

Comments
 (0)