Skip to content

Commit 992ac67

Browse files
author
José Valim
committed
Improve coverage for location: :keep
1 parent 9ff3280 commit 992ac67

File tree

3 files changed

+53
-26
lines changed

3 files changed

+53
-26
lines changed

lib/elixir/include/elixir.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
}).
3636

3737
-record(elixir_quote, {
38-
line=0,
38+
line=nil,
3939
context=nil,
4040
vars_hygiene=true,
4141
aliases_hygiene=true,

lib/elixir/lib/kernel/special_forms.ex

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ defmodule Kernel.SpecialForms do
503503
* `:unquote` - When false, disables unquoting. Useful when you have a quote
504504
inside another quote and want to control what quote is
505505
able to unquote;
506-
* `:location` - When set to `:keep`, keeps the current line and file on quotes.
506+
* `:location` - When set to `:keep`, keeps the current line and file from quote.
507507
Read the Stacktrace information section below for more information;
508508
* `:hygiene` - Allows a developer to disable hygiene selectively;
509509
* `:context` - Sets the resolution context;
@@ -721,35 +721,35 @@ defmodule Kernel.SpecialForms do
721721
722722
## Stacktrace information
723723
724-
One of Elixir's goals is to provide a proper stacktrace whenever there is an
725-
exception. In order to work properly with macros, the default behavior
726-
in quote is to not set a line. When a macro is invoked and the quoted
727-
expressions is expanded, the call site line is inserted.
724+
When defining functions via macros, developers have the option of
725+
choosing if runtime errors will be reported from the caller or from
726+
inside the quote. Let's see an example:
728727
729-
This is a good behavior for the majority of the cases, except if the macro
730-
is defining new functions. Consider this example:
731-
732-
defmodule MyServer do
733-
use GenServer.Behaviour
728+
# adder.ex
729+
defmodule Adder do
730+
@doc "Defines a function that adds two numbers"
731+
defmacro defadd do
732+
quote location: :keep do
733+
def add(a, b), do: a + b
734+
end
735+
end
734736
end
735737
736-
`GenServer.Behaviour` defines new functions in our `MyServer` module.
737-
However, if there is an exception in any of these functions, we want
738-
the stacktrace to point to the `GenServer.Behaviour` and not the line
739-
that calls `use GenServer.Behaviour`. For this reason, there is an
740-
option called `:location` that when set to `:keep` keeps the original
741-
line and file lines instead of setting them to 0:
742-
743-
quote location: :keep do
744-
def handle_call(request, _from, state) do
745-
{ :reply, :undef, state }
746-
end
738+
# sample.ex
739+
defmodule Sample do
740+
import Adder
741+
defadd
747742
end
748743
749-
It is important to warn though that `location: :keep` evaluates the
750-
code as if it was defined inside `GenServer.Behaviour` file, in
751-
particular, the macro `__FILE__` and exceptions happening inside
752-
the quote will always point to `GenServer.Behaviour` file.
744+
When using `location: :keep` and invalid arguments are given to
745+
`Sample.add/2`, the stacktrace information will point to the file
746+
and line inside the quote. Without `location: :keep`, the error is
747+
reported to where `defadd` was invoked.
748+
749+
Note that `location: :keep` evaluates the code as if it was defined
750+
inside the `Adder` file, in particular, the macro `__FILE__` and
751+
exceptions happening inside the quote will always point to the file
752+
where `Added` was defined.
753753
754754
## Binding and unquote fragments
755755

lib/elixir/test/elixir/kernel/quote_test.exs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ defmodule Kernel.QuoteTest do
173173
end
174174
end
175175

176+
## DO NOT MOVE THIS LINE
177+
defmodule Kernel.QuoteTest.Errors do
178+
defmacro defadd do
179+
quote location: :keep do
180+
def add(a, b), do: a + b
181+
end
182+
end
183+
end
184+
185+
defmodule Kernel.QuoteTest.ErrorsTest do
186+
use ExUnit.Case, async: true
187+
import Kernel.QuoteTest.Errors
188+
189+
# Defines the add function
190+
defadd
191+
192+
test :inside_function_error do
193+
assert_raise ArithmeticError, fn ->
194+
add(:a, :b)
195+
end
196+
197+
mod = Kernel.QuoteTest.ErrorsTest
198+
file = String.to_char_list!(__FILE__)
199+
assert [{ ^mod, :add, 2, [file: ^file, line: 180] }|_] = System.stacktrace
200+
end
201+
end
202+
176203
defmodule Kernel.QuoteTest.VarHygiene do
177204
defmacro no_interference do
178205
quote do: a = 1

0 commit comments

Comments
 (0)