hannesveit
Question about elixirc's static code analysis
Hi all,
I’m trying to get up to speed with elixir and have just stumbled across a compiler warning that I find a bit puzzling. I was wondering if someone here could explain to me why the compiler behaves like this. Consider the following code:
defmodule Foo do
def f(), do: :foo
end
defmodule Bar do
def f(), do: :bar
end
defmodule Test do
def return_module_tuple_directly(name) do
case name do
"foo" -> {:ok, Foo}
"bar" -> {:ok, Bar}
_ -> {:error, :unknown_module}
end
end
def return_module_tuple_with_module_variable(name) do
module = case name do
"foo" -> Foo
"bar" -> Bar
_ -> nil
end
if module != nil, do: {:ok, module}, else: {:error, :unknown_module}
end
def this_works_fine(name) do
{:ok, module} = return_module_tuple_directly(name)
module.f()
end
def this_fails(name) do
{:ok, module} = return_module_tuple_with_module_variable(name)
module.f()
end
def this_also_fails(name) do
case return_module_tuple_with_module_variable(name) do
{:ok, module} -> module.f()
_ -> :error
end
end
def but_this_works(name) do
with {:ok, module} <- return_module_tuple_with_module_variable(name) do
module.f()
end
end
end
If I compile that, I’m getting the following warnings:
warning: nil.f/0 is undefined (module nil is not available or is yet to be defined)
│
34 │ module.f()
│ ~
│
└─ modules.ex:34:12: Test.this_fails/1
└─ modules.ex:39:31: Test.this_also_fails/1
What I don’t understand is:
-
In
this_fails/1, why does the compiler think the module could be nil? We’re explicitly testingif module != nil. So it should know that the module can never benilif the first tuple element is:ok. I’m assuming it’s smart enough to “see” that the value could benilfrom thecasestatement but then it’s not smart enough to also introspect the condition ofif(module != nil)? -
Why does wrapping the matching of
{:ok, module}in a with statement prevent this warning, but the similar variant with thecasestatement does not? This is what confuses me the most.
I’d really appreciate an explanation! Thanks!
Most Liked
LostKobrakai
This looks like a bug in the typesystem, though it’s a bit surprising that using with would make things work.








