You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Elixir 1.21.0-dev (a4ab118) (compiled with Erlang/OTP 28)
Operating system
any
Current behavior
numberize/1 rewrites negated BDD leaves so so == guard narrowing on difference types excludes values equal at runtime
Repro:
defmoduleMdodefcheck(v,q)doother=casevdo{a}whenis_float(a)->{:float,a}# clause subtraction givesother->other# other : ... and not {float()}endw=ifq,do: {1},else: {1.5}casewdoxwhenx==other->{:matched,x}_->:nomatchendendendM.check({1},true)# => {:matched, {1}}
emits false positive warning:
warning: the following pattern will never match:
x == other
where "other" was given the type:
# type: dynamic(
({...} and not {float()}) or atom() or bitstring() or empty_list() or float() or fun() or
integer() or map() or non_empty_list(term(), term()) or pid() or port() or reference() or
{:float, float()}
)
# from: iex:3
other =
case v do
...
end
└─ iex:10: M.check/2
After numberization, not {float()} becomes not {number()}
numberize(:map, _) skips domain value types, so == on integer-keyed maps narrows to types excluding equal maps
warning: incompatible types assigned to "y":
%{integer() => integer()} !~ %{integer() => float()} and not empty_map()
where "y" was given the types:
# type: %{integer() => integer()}
# from: iex:16
y = %{1 => 1}
# type: %{integer() => float()} and not empty_map()
# from: iex:19
x == y
└─ iex:19: M.check/0
numberize should also map the domain value types inside the leaf tag
comparison between distinct types ignores coercion inside containers
NOTE: this is acknowledged in code comments but it's relatively easy to produce code triggering that
warning: comparison between distinct types found:
a == b
given types:
dynamic({integer()}) == {float()}
where "a" was given the type:
# type: dynamic({integer()})
# from: iex:24
a =
if q do
{1}
else
{2}
end
where "b" was given the type:
# type: {float()}
# from: iex:25
b = {1.0}
While Elixir can compare across all types, you are comparing across types which are always disjoint, and the result is either always true or always false
└─ iex:27: M3.check/1
Expected behavior
Issues 1 and 2 should be addressed; 3 might be an intended tradeoff
Activity