Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in Gradient.ElixirExpr.pp_guards #145

Open
lukaszsamson opened this issue Nov 14, 2022 · 3 comments
Open

Crash in Gradient.ElixirExpr.pp_guards #145

lukaszsamson opened this issue Nov 14, 2022 · 3 comments
Labels
bug Something isn't working

Comments

@lukaszsamson
Copy link

some_module.ex: ** (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: 21], {:remote, [generated: true, location: 21], {:atom, [generated: true, location: 21], :erlang}, {:atom, [generated: true, location: 21], :is_atom}}, [{:var, [generated: true, location: 21], :_@1}]}, {:op, [generated: true, location: 21], :"=/=", {:var, [generated: true, location: 21], :_@1}, {:atom, [generated: true, location: 21], nil}}, {:op, [generated: true, location: 21], :"=/=", {:var, [generated: true, location: 21], :_@1}, {:atom, [generated: true, location: 21], true}}, {:op, [generated: true, location: 21], :"=/=", {:var, [generated: true, location: 21], :_@1}, {:atom, [generated: true, location: 21], false}}]]
    
    Attempted function clauses (showing 2 out of 2):
    
        def pp_guards([])
        def pp_guards([[guard]])
    
    (gradient 0.1.0) Gradient.ElixirExpr.pp_guards/1
    (gradient 0.1.0) 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
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:248: Gradient.ElixirExpr.pp_clauses/2
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:207: Gradient.ElixirExpr.pp_expr/1
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:490: Gradient.ElixirExpr.pp_cons/1
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:68: Gradient.ElixirExpr.pp_expr/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
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:115: Gradient.ElixirExpr.pp_expr/1
    (gradient 0.1.0) lib/gradient/elixir_expr.ex:17: Gradient.ElixirExpr.pp_expr_format/2
    (gradient 0.1.0) lib/gradient/elixir_fmt.ex:265: anonymous fn/4 in Gradient.ElixirFmt.pp_expr_fun/1
    (gradient 0.1.0) lib/gradient/elixir_fmt.ex:233: Gradient.ElixirFmt.format_expr_type_error/4
    (gradient 0.1.0) lib/gradient/elixir_fmt.ex:58: Gradient.ElixirFmt.print_error/2
    (gradient 0.1.0) lib/gradient/elixir_fmt.ex:44: anonymous fn/3 in Gradient.ElixirFmt.print_errors/2
    (elixir 1.14.2) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (gradient 0.1.0) lib/gradient/elixir_fmt.ex:42: Gradient.ElixirFmt.print_errors/2
    (gradient 0.1.0) lib/gradient.ex:88: Gradient.handle_elixir_ast/2
    (elixir 1.14.2) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
@erszcz
Copy link
Member

erszcz commented Nov 15, 2022

Hey, @lukaszsamson!

Thanks for creating the ticket. It would help a lot if you could also attach the code the crash happens on.

@erszcz erszcz added the bug Something isn't working label Nov 15, 2022
@lukaszsamson
Copy link
Author

I cannot share the repo but I'll try to isolate it

@erszcz
Copy link
Member

erszcz commented Nov 21, 2022

I've been trying to reproduce this error, but after trying a number of different combinations I still don't know what generates the guards we see in the error message. These guards check for an argument being an atom, but neither nil, nor true, nor false:

[
  [
    {:call, [generated: true, location: 21],
     {:remote, [generated: true, location: 21],
      {:atom, [generated: true, location: 21], :erlang},
      {:atom, [generated: true, location: 21], :is_atom}},
     [{:var, [generated: true, location: 21], :_@1}]},
    {:op, [generated: true, location: 21], :"=/=",
     {:var, [generated: true, location: 21], :_@1},
     {:atom, [generated: true, location: 21], nil}},
    {:op, [generated: true, location: 21], :"=/=",
     {:var, [generated: true, location: 21], :_@1},
     {:atom, [generated: true, location: 21], true}},
    {:op, [generated: true, location: 21], :"=/=",
     {:var, [generated: true, location: 21], :_@1},
     {:atom, [generated: true, location: 21], false}}
  ]
]

In general, when defining guards in Elixir we have to use the and / or conjunctives. These are equivalent to andalso / orelse in Erlang, and these in turn always lead to the following form of guards in the abstract syntax tree:

iex(1)> :merl.quote('fun (X) when X > 1 andalso X < 5 -> ok end')
{:fun, 1,
 {:clauses,
  [
    {:clause, 1, [{:var, 1, :X}],
     [
       [
         {:op, 1, :andalso, {:op, 1, :>, {:var, 1, :X}, {:integer, 1, 1}},
          {:op, 1, :<, {:var, 1, :X}, {:integer, 1, 5}}}
       ]
     ], [{:atom, 1, :ok}]}
  ]}}

We can see there's a single op expression within a nested list, not a list of consecutive guard expressions as in the original error message:

       [
         {:op, 1, :andalso, {:op, 1, :>, {:var, 1, :X}, {:integer, 1, 1}},
          {:op, 1, :<, {:var, 1, :X}, {:integer, 1, 5}}}
       ]

In Erlang it's possible to generate a list of guards by using the , or ; conjunctives, too:

iex(2)> :merl.quote('fun (X) when X > 1, X < 5 -> ok end')
{:fun, 1,
 {:clauses,
  [
    {:clause, 1, [{:var, 1, :X}],
     [
       [
         {:op, 1, :>, {:var, 1, :X}, {:integer, 1, 1}},
         {:op, 1, :<, {:var, 1, :X}, {:integer, 1, 5}}
       ]
     ], [{:atom, 1, :ok}]}
  ]}}

This, in fact, generates a list of guards:

       [
         {:op, 1, :>, {:var, 1, :X}, {:integer, 1, 1}},
         {:op, 1, :<, {:var, 1, :X}, {:integer, 1, 5}}
       ]

However, as far as I know, Elixir doesn't have an equivalent of , / ; conjunctives for use in guard expressions. Moreover, [generated: true, location: 21] tells us that these guards were generated by the Elixir compiler, likely by some special form, on line 21 of some unknown file.

Without a hint about what code leads to this error it's going to be quite hard to debug further :|

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants