Skip to content

Commit

Permalink
Do not warn when comparing literals
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Dec 24, 2024
1 parent 546a0db commit 4911916
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 19 deletions.
8 changes: 4 additions & 4 deletions lib/elixir/lib/kernel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1972,7 +1972,7 @@ defmodule Kernel do

defp build_boolean_check(operator, check, true_clause, false_clause) do
annotate_case(
[optimize_boolean: true, type_check: :expr],
[optimize_boolean: true],
quote do
case unquote(check) do
false -> unquote(false_clause)
Expand Down Expand Up @@ -2006,7 +2006,7 @@ defmodule Kernel do
assert_no_match_or_guard_scope(__CALLER__.context, "!")

annotate_case(
[optimize_boolean: true, type_check: :expr],
[optimize_boolean: true],
quote do
case unquote(value) do
x when :"Elixir.Kernel".in(x, [false, nil]) -> false
Expand All @@ -2020,7 +2020,7 @@ defmodule Kernel do
assert_no_match_or_guard_scope(__CALLER__.context, "!")

annotate_case(
[optimize_boolean: true, type_check: :expr],
[optimize_boolean: true],
quote do
case unquote(value) do
x when :"Elixir.Kernel".in(x, [false, nil]) -> true
Expand Down Expand Up @@ -3910,7 +3910,7 @@ defmodule Kernel do

defp build_if(condition, do: do_clause, else: else_clause) do
annotate_case(
[optimize_boolean: true, type_check: :expr],
[optimize_boolean: true],
quote do
case unquote(condition) do
x when :"Elixir.Kernel".in(x, [false, nil]) -> unquote(else_clause)
Expand Down
12 changes: 10 additions & 2 deletions lib/elixir/lib/module/types/apply.ex
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,19 @@ defmodule Module.Types.Apply do
end
end

def remote(:erlang, name, [left, right] = args_types, expr, stack, context)
def remote(
:erlang,
name,
[left, right] = args_types,
{_, _, args} = expr,
stack,
context
)
when name in [:==, :"/=", :"=:=", :"=/="] do
context =
cond do
stack.mode == :infer ->
# We ignore quoted literals as they most likely come from generated code.
stack.mode == :infer or Macro.quoted_literal?(args) ->
context

name in [:==, :"/="] and number_type?(left) and number_type?(right) ->
Expand Down
5 changes: 3 additions & 2 deletions lib/elixir/lib/module/types/expr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,9 @@ defmodule Module.Types.Expr do
{case_type, context} = of_expr(case_expr, stack, context)

# If we are only type checking the expression and the expression is a literal,
# let's mark it as generated, as it is most likely a macro code.
if is_atom(case_expr) and {:type_check, :expr} in meta do
# let's mark it as generated, as it is most likely a macro code. However, if
# no clause is matched, we should still check for that.
if Macro.quoted_literal?(case_expr) do
for {:->, meta, args} <- clauses, do: {:->, [generated: true] ++ meta, args}
else
clauses
Expand Down
27 changes: 16 additions & 11 deletions lib/elixir/test/elixir/module/types/expr_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,11 @@ defmodule Module.Types.ExprTest do
test "in dynamic mode" do
assert typedyn!([x = 123, y = 456.0], x < y) == dynamic(boolean())
assert typedyn!([x = 123, y = 456.0], x == y) == dynamic(boolean())
assert typedyn!(123 == 456) == boolean()
assert typedyn!([x = 123, y = 456], x == y) == dynamic(boolean())
end

test "using literals" do
assert typecheck!(:foo == :bar) == boolean()
end

test "min/max" do
Expand Down Expand Up @@ -1060,6 +1064,15 @@ defmodule Module.Types.ExprTest do
end

describe "case" do
test "does not type check literals" do
assert typecheck!(
case :dev do
:dev -> :ok
:prod -> :error
end
) == atom([:ok, :error])
end

test "returns unions of all clauses" do
assert typecheck!(
[x],
Expand Down Expand Up @@ -1115,25 +1128,17 @@ defmodule Module.Types.ExprTest do
end

describe "conditionals" do
test "if does not report on literal atoms" do
test "if does not report on literals" do
assert typecheck!(
if true do
:ok
end
) == atom([:ok, nil])
end

test "and does not report on literal atoms" do
test "and does not report on literals" do
assert typecheck!(false and true) == boolean()
end

test "and reports on non-atom literals" do
assert typeerror!(1 and true) == ~l"""
the following conditional expression will always evaluate to integer():
1
"""
end
end

describe "receive" do
Expand Down

0 comments on commit 4911916

Please sign in to comment.