no function clause matching in Gradient.ElixirExpr.pp_guards/1
Hello,
I've been really enjoying using gradient, thank you for the work! I've encountered this error today when running mix gradient
(FunctionClauseError) no function clause matching in Gradient.ElixirExpr.pp_guards/1
The following arguments were given to Gradient.ElixirExpr.pp_guards/1:
# 1
[[{:call, [generated: true, location: 486], {:remote, [generated: true, location: 486], {:atom, [generated: true, location: 486], :erlang}, {:atom, [generated: true, location: 486], :is_atom}}, [{:var, [generated: true, location: 486], :_@2}]}, {:op, [generated: true, location: 486], :"=/=", {:var, [generated: true, location: 486], :_@2}, {:atom, [generated: true, location: 486], nil}}, {:op, [generated: true, location: 486], :"=/=", {:var, [generated: true, location: 486], :_@2}, {:atom, [generated: true, location: 486], true}}, {:op, [generated: true, location: 486], :"=/=", {:var, [generated: true, location: 486], :_@2}, {:atom, [generated: true, location: 486], false}}]]
Attempted function clauses (showing 2 out of 2):
def pp_guards([])
def pp_guards([[guard]])
Gradient.ElixirExpr.pp_guards/1
lib/gradient/elixir_expr.ex:310: Gradient.ElixirExpr.pp_case_clause/1
(elixir 1.14.2) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.14.2) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
lib/gradient/elixir_expr.ex:248: Gradient.ElixirExpr.pp_clauses/2
lib/gradient/elixir_expr.ex:207: Gradient.ElixirExpr.pp_expr/1
lib/gradient/elixir_expr.ex:154: Gradient.ElixirExpr.pp_expr/1
(elixir 1.14.2) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
[[Command exited with 1]]
The error occurs three times within the same module and nowhere else. I believe that the issue stems from my custom guard which is used in three different functions.
Here is the guard definition
@max_integer 32_767
defguard pos_int(integer) when integer < @max_integer and integer > 0
And here is an example of it in use
@doc false
@spec kills(Match.t(), puuid) :: res(non_neg_integer)
def kills(match, puuid) do
case Fetch.player(match, puuid) do
{:ok, %Player{stats: %PlayerStats{kills: kills}}} when pos_int(kills) ->
{:ok, kills}
{:ok, %Player{}} ->
{:ok, 0}
{:error, error} ->
{:error, error}
end
end
Thanks for the report!
From a quick look it seems we're missing a clause for used-defined guards. We'll take a look at this.
https://github.com/esl/gradient/issues/145#issuecomment-1322441536 seems to be related.
I manage to get a small reproducible case that might be related to this
@spec indirection(number(), number(), non_neg_integer()) ::
list({atom(), list(), binary()})
def indirection(storage, key, order) do
[:hi, [<<2>>], <<4>>]
end
@spec crash() :: number()
def crash() do
order = 2
key = 5
with {:atomic, [{_, [^order, ^key | 0], value}]} <- indirection(order, key, order) do
2 + 5
end
end
calling mix gradiant gives me
lib/project/storage.ex: The atom on line 289 is expected to have type {atom(), list(), binary()} but it has type :hi
287 list({atom(), list(), binary()})
288 def indirection(storage, key, order) do
289 [:hi, [<<2>>], <<4>>]
290 end
291
lib/project/storage.ex: ** (FunctionClauseError) no function clause matching in Gradient.ElixirExpr.pp_cons/1
The following arguments were given to Gradient.ElixirExpr.pp_cons/1:
# 1
{:integer, 299, 0}
Attempted function clauses (showing 3 out of 3):
defp pp_cons({:cons, _, h, {nil, _}})
defp pp_cons({:cons, _, h, {:var, _, _} = v})
defp pp_cons({:cons, _, h, t})
(gradient 0.1.0) Gradient.ElixirExpr.pp_cons/1
(gradient 0.1.0) lib/gradient/elixir_expr.ex:491: Gradient.ElixirExpr.pp_cons/1
(gradient 0.1.0) lib/gradient/elixir_expr.ex:68: Gradient.ElixirExpr.pp_expr/1
(elixir 1.15.5) lib/enum.ex:1693: Enum."-map/2-lists^map/1-1-"/2
(elixir 1.15.5) lib/enum.ex:1693: Enum."-map/2-lists^map/1-1-"/2
(gradient 0.1.0) lib/gradient/elixir_expr.ex:158: Gradient.ElixirExpr.pp_expr/1
(gradient 0.1.0) lib/gradient/elixir_expr.ex:68: Gradient.ElixirExpr.pp_expr/1
(elixir 1.15.5) lib/enum.ex:1693: Enum."-map/2-lists^map/1-1-"/2
I've noticed that I can fix the crash by changing the code to the following
@spec crash() :: number()
def crash() do
order = 2
key = 5
zero = 0
with {:atomic, [{_, [^order, ^key | ^zero], value}]} <- indirection(order, key, order) do
2 + 5
end
end
the | 0 for some reason is causing issues