dialyxir
dialyxir copied to clipboard
Unknown error occurred in format_long
Unknown error occurred: %FunctionClauseError{args: nil, arity: 1, clauses: nil, function: :format_long, kind: nil, module: Dialyxir.Warnings.OpaqueTypeTest}
Legacy warning: ets.ex:15: The type test is_reference('undefined' | ets:tid()) breaks the opacity of the term 'undefined' | ets:tid()
Source code: @spec alive?() :: boolean def alive?, do: is_reference(whereis())
Precheck
- Take a look at the open issues and be sure that your issue is not already covered.
- Be sure your versions of Dialyxir and Erlex are up to date.
Environment
- Elixir & Erlang/OTP versions (elixir --version): Erlang/OTP 21 [erts-10.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Elixir 1.7.4 (compiled with Erlang/OTP 20)
- Which version of Dialyxir are you using? (cat mix.lock | grep dialyxir): I upgraded from 1.0.0 to 1.1.0 and still have the issue. erlex 0.2.6
Current behavior
- Describe current behavior. Include errors, stack traces, and any additional information that might be important here.
Expected behavior
- A short description of the expected behavior. No error messages from the tool telling me to report an issue against the tool.
Hi, is there any chance you can share a code-sample that reproduces this problem?
sample.ex:
defmodule Sample do
def hello do
if alive?(), do: :world,
else: :goodbye
end
@spec alive?() :: boolean
def alive?, do: is_reference(whereis())
@spec whereis() :: reference | :undefined
def whereis, do: :ets.whereis(:sample)
end
dialyxir output: lib/sample.ex:2:no_return Function hello/0 has no local return.
lib/sample.ex:8:no_return Function alive?/0 has no local return.
Please file a bug in https://github.com/jeremyjh/dialyxir/issues with this message.
Unknown error occurred: %FunctionClauseError{args: nil, arity: 1, clauses: nil, function: :format_long, kind: nil, module: Dialyxir.Warnings.OpaqueTypeTest}
Legacy warning: lib/sample.ex:8: The type test is_reference('undefined' | ets:tid()) breaks the opacity of the term 'undefined' | ets:tid()
done (warnings were emitted) Halting VM with exit status 2
I just had a look at the code in OpaqueTypeTest. I'm quite intrigued by the fact that current source code, reputedly 2 years old, uses the term opaqueness
, where my error message says opacity
, and I have dialyxir .1.1.0 which is supposed to be current. Why are the words different? Are you building from a branch these days?
Thank you for the sample. We are not using a branch. The word "opacity" in the legacy comment is simply part of the text message that Erlang dialyzer would write to the console. We do not use that message when we format the message in Dialyxir, we use structured information from the term to build the message.
The issue I'm reporting is going to let you eliminate the FunctionClauseError in the Dialyxir code. Is there a good reference that will help me understand how I should fix the actual opacity error? I'm really new to the tool.
I do not really know of a good reference. The only reference I recall reading at first was the dialyzer paper linked in the readme and "Learn You Some Erlang" but that was at a time when there was not a single book written on Elixir, so you had to learn Erlang. There probably are books now that explain it in Elixir terms. You can also ask questions on elixirforums.com. It helps to know Haskell, Scala or OCaml (I've done quite a bit of Haskell) but you really have to develop your own understanding and intuitions as success typing is very different from a whole static type system.
In this specific case the issue might simply be that the spec for :ets.whereis
has it returning :ets.tid() | :undefined
; I think tid()
is an opaque term and you are trying to peel back the cover and look inside by typing it as :reference
.
I appreciate that input. That could make sense. Now I have an idea what opaque means. I'll do some digging. Maybe the return :undefined is equivalent to is_reference returning false. That is, that if :ets.whereis returns a tid() then the process is up and :undefined means that it is not. That would make alive?
just need to be whereis() != :undefined
.
Yes probably so, you can't call is_reference on a tid(). You should also change the @spec
for Sample.whereis
to match the return spec for :ets.whereis
, e.g. @spec whereis() :: :ets.tid() | :undefined