Skip to content

Instantly share code, notes, and snippets.

@BjRo
Last active April 22, 2016 08:45
Show Gist options
  • Save BjRo/eca4de6020dc41616ebeb4ed88a85fc6 to your computer and use it in GitHub Desktop.
Save BjRo/eca4de6020dc41616ebeb4ed88a85fc6 to your computer and use it in GitHub Desktop.
Dialyzer, who knows what's going on?
defmodule Messages.Time do
use Timex
@spec timestamp() :: Timex.DateTime.t
def timestamp, do: Timex.DateTime.now(:utc)
@type ts :: Timex.Convertable.t | none
@spec timestamp_iso8601(ts) :: binary
def timestamp_iso8601(ts \\ __MODULE__.timestamp) do
{:ok, iso8601} = Timex.format(ts, "{ISO:Extended}")
String.replace(iso8601, "+00:00", "Z")
end
end
# lib/messages/time.ex:13: Function timestamp_iso8601/0 has no local return
# lib/messages/time.ex:13: The call 'Elixir.Messages.Time':timestamp_iso8601(#{}) will never return since it differs in the 1st argument from the success typing arguments: ('Elixir.Timex.Convertable')
@BjRo
Copy link
Author

BjRo commented Apr 22, 2016

So Timex.Convertable.t is just a term https://hexdocs.pm/timex/Timex.Convertable.html#t:t/0, while Timex.DateTime.t is a struct https://hexdocs.pm/timex/Timex.DateTime.html#t:t/0

From what I see, this should be compatible. Even if I change the spec to timestamp_iso8601(Timex.DateTime.t), I get the same error messages.

I wonder why and how he infers the empty map #{} as a valid parameter

@sasa1977
Copy link

Ah, looking a bit more, I think this is actually an error in Timex. See typespec of format. It says that the first argument is Timex.Convertable, not Timex.Convertable.t, which means the first argument needs to be that very atom. In fact, if you look at the second error, this is what dialyzer says. The success (inferred) typing was 'Elixir.Timex.Convertable', so it can't match a map to it.

@BjRo
Copy link
Author

BjRo commented Apr 22, 2016

Ah, I see. How would you deal normally with such situations in your code? Can I tweak Dialyzer to ignore this and use my spec?

@sasa1977
Copy link

I'd use @dialyzer to suppress this warning. I'd also add a comment in the code about the reason, and then make a PR to timex.

You can see the list of possible options here, and a little bit about it here (search for @dialyzer).

In your case, it would be something like:

@dialyzer {:nowarn_function, timestamp_iso8601: 1}

Or maybe even this might work:

@dialyzer {[:no_match], timestamp_iso8601: 1}

I didn't try them out (since I have no full code), but something along those lines should suppress the warning.

@sasa1977
Copy link

Btw, if making a PR, you can try to fix timex locally to verify that your fix is correct. Basically, you edit the code in deps/timex, run mix compile timex, and then verify that dialyzer passes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment