sztosz
Is Dialyzer fetching incorrect specs, or are they incorrect in Meeseeks?
defmodule A do
def x() do
Meeseeks.parse("<div id=main><p>Hello, Meeseeks!</p></div>")
end
end
This gives me this error:
The call:
Meeseeks.parse(<<_::336>>)
will never return since it differs in arguments with
positions 1 from the success typing arguments:
(
[
binary()
| {:comment, binary()}
| {:pi, binary()}
| {:pi | binary(), binary() | [{_, _}], binary() | [any()]}
| {:doctype, binary(), binary(), binary()}
]
| {:comment, binary()}
| {:pi, binary()}
| {:pi | binary(), binary() | [{binary(), binary()}], binary() | [any()]}
| {:doctype, binary(), binary(), binary()}
)
When the specs for Meeseeks.parse is @spec parse(Parser.source()) :: Document.t() | {:error, Error.t()} with Parser.source() being @type source :: String.t() | TupleTree.t() and then TupleTree.t() being
@type comment :: {:comment, String.t()}
@type doctype :: {:doctype, String.t(), String.t(), String.t()}
@type element :: {String.t(), [{String.t(), String.t()}], [node_t]}
@type processing_instruction ::
{:pi, String.t()}
| {:pi, String.t(), [{String.t(), String.t()}]}
| {:pi, String.t(), String.t()}
@type text :: String.t()
@type node_t :: comment | doctype | element | processing_instruction | text
@type t :: node_t | [node_t]
Dialyxir and Dialyzer helped ma lot, but I don’t understand what’s wrong with those specs, or is it bug with tools rather.
If source :: String.t() | TupleTree.t() or source :: binary() | TupleTree.t() then call Meeseeks.parse(<<_::336>>) where <<_::336>> is binary should satisfy those specs. Right?
Beside, even when dialyxir/dialyzer says [...] will never return since [...] actually when run always returns and simply works OK.
Most Liked
NobbZ
I code dived a bit. And on a first glance everything looks like passing in a string should work (and actually does).
But, this string gets passed (deep in the stack of function calls) to MeeseeksHtml5ever.Native.parse_html/1. As you can guess from its name, its a NIF.
NIFs always have two implemantations. A native one (eg.: C or Rust) and a “naive” one (BEAM-compatible). Often the naive one is simply throwing.
This throw does happen as well for this function (check https://github.com/mischov/meeseeks_html5ever/blob/master/lib/meeseeks_html5ever/native.ex).
This is the only implementation dialyzer sees. So from dialyzers view, passing a string to Meeseex.parse/1 will always resuilt in a throw, so dialyzer removes String.t silently from the spec.
This has to be fixed upstream (meeseex_html5ever).
mischov
Using :erlang.nif_error appears to resolve the error.
Thanks for bringing it to my attention- I’ll see if I can’t get releases out with the fix before too long.
jeremyjh
What I’m suggesting is just change above spec to what appears to be the success typing:
@spec parse(list(Parser.source()) | Parser.source()) :: Document.t() | {:error, Error.t()}
mischov
Hmm. Would using :erlang.nif_error in the naive function where I previously raised be the standard solution? From the description of nif_error:
Works exactly like error/1, but Dialyzer thinks that this BIF will return an arbitrary term. When used in a stub function for a NIF to generate an exception when the NIF library is not loaded, Dialyzer does not generate false warnings.
mischov
Well Meeseeks 0.9.3 was available on Github already, I just hadn’t gotten it up on Hex yet. It’s up now.








