dashbitco/nimble_parsec

Warning emitted by integer combinator

lukaszsamson opened this issue · 3 comments

This code

defmodule ParserRepro do
  import NimbleParsec

  defparsec(:foo_parsec, integer(min: 1))
end

emits a warning

warning: this clause cannot match because of different types/sizes

debug:

defp foo_parsec__0(rest, acc, stack, context, line, offset) do
  foo_parsec__1(rest, [], [acc | stack], context, line, offset)
end

defp foo_parsec__1(<<x0, rest::binary>>, acc, stack, context, comb__line, comb__offset) when x0 >= 48 and x0 <= 57 do
  foo_parsec__2(rest, [x0 - 48] ++ acc, stack, context, comb__line, comb__offset + 1)
end

defp foo_parsec__1(rest, _acc, _stack, context, line, offset) do
  {:error, "expected ASCII character in the range '0' to '9'", rest, context, line, offset}
end

defp foo_parsec__2(rest, acc, stack, context, line, offset) do
  case {:cont, context} do
    {:cont, context} -> foo_parsec__4(rest, acc, stack, context, line, offset)
    {:halt, context} -> foo_parsec__3(rest, acc, stack, context, line, offset)
  end
end

defp foo_parsec__4(<<x0, rest::binary>>, acc, stack, context, comb__line, comb__offset) when x0 >= 48 and x0 <= 57 do
  foo_parsec__5(rest, [x0] ++ acc, stack, context, comb__line, comb__offset + 1)
end

defp foo_parsec__4(rest, acc, stack, context, line, offset) do
  foo_parsec__3(rest, acc, stack, context, line, offset)
end

defp foo_parsec__5(rest, acc, stack, context, line, offset) do
  foo_parsec__2(rest, acc, stack, context, line, offset)
end

defp foo_parsec__3(rest, user_acc, [acc | stack], context, line, offset) do
  _ = user_acc

foo_parsec__6(
  rest,
  (
    [head | tail] = :lists.reverse(user_acc)
    [:lists.foldl(fn x, acc -> x - 48 + acc * 10 end, head, tail)]
  ) ++ acc,
  stack,
  context,
  line,
  offset
)
end

defp foo_parsec__6(rest, acc, _stack, context, line, offset) do
  {:ok, acc, rest, context, line, offset}
end

the warning comes from foo_parsec__2.
Interestingly, the warning is not emitted when compiling the project with mix. It is only emitted in elixir-ls.

You can mark the relevant bit as generated: true in the compiler. Does that work?

I tried setting generated: true on the quote using output of NimbleParsec.Compiler.compile but it didn't help.

dvic commented

I have the same problem. With the example, I found that there is a difference between the generated code when elixir ls compiles it and when mix compiles it:

image

(left is elixir ls and right is mix)

Not sure why elixir ls is compiling the version with the strange pattern match, which is the reason for the compiler warning (case {:cont, context} with a pattern {:halt, context}).