-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Incompatible type warning #10485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This is a common warning in guards because guards are expanded and the compiler is smart enough to "see inside". For example, we can't really test One possible fix for now is for you to replace |
Yeah I was suspecting something like that, but the test still looks valid to me. Is it maybe an option to not emit these warnings for (doc)tests? |
For now I don't want to allow to skip warnings because that's a tricky slippery slope. First we start skip warnings for tests then folks will start skip warnings in actual valid code. The good news though is that: every time you get a warning because of your example, the user will also get the same warning, which means they will know it will fail before they even invoke it. |
I think the warnings is incorrect. The type warning should only be emitted for expressions that will fail at runtime - this is not the case, the expression discussed here will return In other words, |
Ah, yes, good point about the conditionals. |
To be able to fix this warning we need to implement a couple of things. We would also need to extend the conditional checks we do inside guards, that make sure Since it wont be foolproof we have the choice of accepting that we will have some false positives or do something like give all type variables from the conditional the |
I just had another convo with @ericmj where it seems the issue here is a bit simpler. Let's take two functions, def v1 do
foo = %{}
if is_map_key(foo, :bar) do
foo.bar
else
:default
end
end def v2 do
v2?(%{})
end
defp v2?(map) do
if is_map_key(foo, :bar) do
foo.bar
else
:default
end
end They are equivalent, implementation-wise, but we can arguably say v1 should warn something, because at worst it has dead code, while v2 should not warn. The issue in this PR is that we are calling the code as in |
This still leaves "fixing" the warning in non-generated code. The code in v1 is entirely valid and will not fail at runtime, so a warning about an undefined field [1] is not helpful. A warning about dead code could be helpful, but it should probably be completely different. [1] For the code like in the
|
Yes, in the future it will be a warning about dead-code because we will identify only one of the clauses match and then we won't bother to analyze what is inside that clause. |
Here' s a reduced test case for a similar bug reported in Elixir Forum defmodule Warning do
defguardp is_tuple_or_nil(param) when is_nil(param) or is_tuple(param)
def hello(param) when is_atom(param) and is_tuple_or_nil(param) do
:is_atom_or_nil
end
end |
I wanted to use the new capability from Elixir 1.11 to use the When conditionals are not taken into account, how can I ever use a BTW: Shouldn't the |
I have another example that unexpectedly produces a warning: defmodule Warning do
defguard some_guard(x) when x == :foo or (is_tuple(x) and elem(x, 0) == :zzz)
def bla(foo) when not some_guard(foo) do
foo.bar
end
end Interestingly, if we remove the defmodule NoWarning do
defguard some_guard(x) when x == :foo or is_tuple(x)
def bla(foo) when not some_guard(foo) do
foo.bar
end
end |
Another one from #12505: Current behaviorCompiling this snippet raises a type warning: defmodule Foo do
def bar(token, number) when is_number(number) do
case token do
token when is_float(number) -> token
token when is_integer(number) -> token
end
end
end warning: incompatible types integer() !~ float()warning: incompatible types:
in expression:
where "number" was given the type integer() | float() in:
where "number" was given the type float() in:
Conflict found at Expected behaviornotably this code correctly doesn't warn, which is the expected behaviour for the block above as well defmodule Foo do
def bar(number) when is_number(number) do
case number do
number when is_float(number) -> :float
number when is_integer(number) -> :integer
end
end
end |
to expand on the snippet above, i played with removing the # both of these still warn
def bar(token, number) when is_number(number) do
case token do
token when is_float(number) -> token
token -> token
end
end
def bar(token, number) when is_number(number) do
case token do
token when is_integer(number) -> token
token -> token
end
end
# no warning
def bar(token, number) when is_number(number) do
integer? = is_integer(number)
case token do
token when integer? -> token
token -> token
end
end |
Closing this, as there is a new implementation coming soon, and the old implementation has been removed. |
Environment
Current behavior
We have a function for validating a certain struct, but our doctest seems to generate a warning. The warning itself is obvious, but the test is also to show it's wrong.
I think that the code and tests are valid, but the doctest generates this warning:
It will show the error for any type other than
%Foo{}
.Expected behavior
No warnings when running the doctest.
The text was updated successfully, but these errors were encountered: