Elixir: Improve error messages on bad arithmetic expression

Created on 24 Jun 2018  路  7Comments  路  Source: elixir-lang/elixir

Environment

  • Elixir & Erlang/OTP versions (elixir --version): Elixir 1.6.5 (compiled with OTP 19) + Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [kernel-poll:false]
  • Operating system: Linux Mint 17.3 Rosa

Current behavior

** (ArithmeticError) bad argument in arithmetic expression
    lib/mix/tasks/analyze.macro.ex:208: Mix.Tasks.Analyze.Macro.get_wave/3
    (elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
    lib/mix/tasks/analyze.macro.ex:171: Mix.Tasks.Analyze.Macro.analyze_ticker/4
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
    lib/mix/tasks/analyze.macro.ex:39: Mix.Tasks.Analyze.Macro.run/1
    (mix) lib/mix/task.ex:314: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:80: Mix.CLI.run_task/2

Expected behavior

** (ArithmeticError) bad argument in arithmetic expression: tried to divide 10 by 0
    lib/mix/tasks/analyze.macro.ex:208: Mix.Tasks.Analyze.Macro.get_wave/3
    (elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
    lib/mix/tasks/analyze.macro.ex:171: Mix.Tasks.Analyze.Macro.analyze_ticker/4
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
    (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
    lib/mix/tasks/analyze.macro.ex:39: Mix.Tasks.Analyze.Macro.run/1
    (mix) lib/mix/task.ex:314: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:80: Mix.CLI.run_task/2

Notes

Currently, in order to debug "bad argument in arithmetic expression", we have to print the arguments to console. It it possible to show them right in the error message?

Elixir Bug Starter

All 7 comments

In Erlang/OTP 21 this will be possible to do since the function call will be in the stacktrace.

Here is the Erlang/OTP commit that adds this information: https://github.com/erlang/otp/pull/1478

Here is a commit that adds improved error messages to apply/3. Something similar could be done here for the operators linked in the PR above, although we need to make sure the tests run only on OTP 21: https://github.com/elixir-lang/elixir/commit/d2799bade389ab96cc620d84e7f59cde8ca61a36

I tried to solve this issue but I couldn't. First I installed OTP 21.0 using asdf. Then I compiled the master branch successfully:

$ bin/elixir -v
Erlang/OTP 21 [erts-10.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Elixir 1.7.0-dev (094eb6a86) (compiled with Erlang/OTP 21)

I defined the function blame in lib/elixir/lib/exception.ex:

defmodule ArithmeticError do
  defexception message: "bad argument in arithmetic expression"

  @impl true
  def blame(exception, stacktrace) do
    IO.inspect(exception, label: "exception")
    IO.inspect(stacktrace, label: "stacktrace")
    {exception, stacktrace}
  end
end

And I added a test in lib/elixir/test/elixir/exception_test.exs:

    test "annotates arithmetic error" do
      assert blame_message(0, &(10/&1)) == """
      """
    end

But the output I have is this one:

exception: %ArithmeticError{message: "bad argument in arithmetic expression"}
stacktrace: [
  {ExceptionTest, :"-test blaming annotates arithmetic error/1-fun-0-", 1,
   [file: 'lib/elixir/test/elixir/exception_test.exs', line: 487]},
  {ExceptionTest, :blame_message, 2,
   [file: 'lib/elixir/test/elixir/exception_test.exs', line: 493]},
  {ExceptionTest, :"test blaming annotates arithmetic error", 1,
   [file: 'lib/elixir/test/elixir/exception_test.exs', line: 487]},
  {ExUnit.Runner, :exec_test, 1, [file: 'lib/ex_unit/runner.ex', line: 312]},
  {:timer, :tc, 1, [file: 'timer.erl', line: 166]},
  {ExUnit.Runner, :"-spawn_test/3-fun-1-", 4,
   [file: 'lib/ex_unit/runner.ex', line: 251]}
]

I don't receive in the stacktrace the division call.

What am I doing wrong?

Thank you!

I don't see a stacktrace entry for that either. Interestingly it's definitely there for div(1, 0) but not for 1 / 0. @josevalim, any idea what might be going on in here? Looking at the code you introduced in the PR, I would expect both to work.

@alexcastano good catch. It seems 1 / 0 is not being checked. However, you can try those:

  • :foo / 1 (also a badarith)
  • div(1, 0)
  • rem(1, 0)

and others in the linked PR.

@josevalim it was completely unintentionally xD I'll try to solve the other ones.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jakubpawlowicz picture jakubpawlowicz  路  32Comments

pragdave picture pragdave  路  28Comments

josevalim picture josevalim  路  41Comments

conradwt picture conradwt  路  34Comments

josevalim picture josevalim  路  33Comments