From 3622d0ee4bd581bddcaa5969df83d00e082f1739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 24 Feb 2022 19:19:22 +0100 Subject: [PATCH] Provide better stacktraces on recent Elixir+OTP versions (#1028) --- lib/livebook/runtime/evaluator.ex | 45 ++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/livebook/runtime/evaluator.ex b/lib/livebook/runtime/evaluator.ex index 1928951cb..549045107 100644 --- a/lib/livebook/runtime/evaluator.ex +++ b/lib/livebook/runtime/evaluator.ex @@ -428,25 +428,34 @@ defmodule Livebook.Runtime.Evaluator do defp code_error?(_error), do: false # Adapted from https://github.com/elixir-lang/elixir/blob/1c1654c88adfdbef38ff07fc30f6fbd34a542c07/lib/iex/lib/iex/evaluator.ex#L355-L372 + # TODO: Remove else branch once we depend on the versions below + if System.otp_release() >= "25" and Version.match?(System.version(), "~> 1.14-dev") do + defp prune_stacktrace(stack) do + stack + |> Enum.reverse() + |> Enum.drop_while(&(elem(&1, 0) != :elixir_eval)) + |> Enum.reverse() + end + else + @elixir_internals [:elixir, :elixir_expand, :elixir_compiler, :elixir_module] ++ + [:elixir_clauses, :elixir_lexical, :elixir_def, :elixir_map] ++ + [:elixir_erl, :elixir_erl_clauses, :elixir_erl_pass] - @elixir_internals [:elixir, :elixir_expand, :elixir_compiler, :elixir_module] ++ - [:elixir_clauses, :elixir_lexical, :elixir_def, :elixir_map] ++ - [:elixir_erl, :elixir_erl_clauses, :elixir_erl_pass] - - defp prune_stacktrace(stacktrace) do - # The order in which each drop_while is listed is important. - # For example, the user may call Code.eval_string/2 in their - # code and if there is an error we should not remove erl_eval - # and eval_bits information from the user stacktrace. - stacktrace - |> Enum.reverse() - |> Enum.drop_while(&(elem(&1, 0) == :proc_lib)) - |> Enum.drop_while(&(elem(&1, 0) == :gen_server)) - |> Enum.drop_while(&(elem(&1, 0) == __MODULE__)) - |> Enum.drop_while(&(elem(&1, 0) == :elixir)) - |> Enum.drop_while(&(elem(&1, 0) in [:erl_eval, :eval_bits])) - |> Enum.reverse() - |> Enum.reject(&(elem(&1, 0) in @elixir_internals)) + defp prune_stacktrace(stacktrace) do + # The order in which each drop_while is listed is important. + # For example, the user may call Code.eval_string/2 in their + # code and if there is an error we should not remove erl_eval + # and eval_bits information from the user stacktrace. + stacktrace + |> Enum.reverse() + |> Enum.drop_while(&(elem(&1, 0) == :proc_lib)) + |> Enum.drop_while(&(elem(&1, 0) == :gen_server)) + |> Enum.drop_while(&(elem(&1, 0) == __MODULE__)) + |> Enum.drop_while(&(elem(&1, 0) == :elixir)) + |> Enum.drop_while(&(elem(&1, 0) in [:erl_eval, :eval_bits])) + |> Enum.reverse() + |> Enum.reject(&(elem(&1, 0) in @elixir_internals)) + end end defp random_id() do