From 47ca7004b60f29255eb3a11fbb09854b80647b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 25 Oct 2017 00:32:52 +0200 Subject: [PATCH] Avoid conflicts with erl_anno in meta We avoid using :file publicly as well as :location privately. We do still use :file privately but that's supposed to mirror the `-file` annotation in Erlang before function definitions. --- lib/elixir/lib/kernel/special_forms.ex | 2 + lib/elixir/lib/module.ex | 4 -- lib/elixir/src/elixir_def.erl | 14 +++---- lib/elixir/src/elixir_erl.erl | 8 ++-- lib/elixir/src/elixir_errors.erl | 2 +- lib/elixir/src/elixir_quote.erl | 42 +++++++++----------- lib/elixir/src/elixir_utils.erl | 23 ++++------- lib/elixir/test/elixir/kernel/quote_test.exs | 2 +- 8 files changed, 42 insertions(+), 55 deletions(-) diff --git a/lib/elixir/lib/kernel/special_forms.ex b/lib/elixir/lib/kernel/special_forms.ex index 16335200a1..fcc9cabd7f 100644 --- a/lib/elixir/lib/kernel/special_forms.ex +++ b/lib/elixir/lib/kernel/special_forms.ex @@ -767,6 +767,8 @@ defmodule Kernel.SpecialForms do quote. Read the Stacktrace information section below for more information. + * `:line` - sets the quoted expressions to have the given line. + * `:generated` - marks the given chunk as generated so it does not emit warnings. Currently it only works on special forms (for example, you can annotate a `case` but not an `if`). diff --git a/lib/elixir/lib/module.ex b/lib/elixir/lib/module.ex index d80c9897d9..08a2febf44 100644 --- a/lib/elixir/lib/module.ex +++ b/lib/elixir/lib/module.ex @@ -1630,10 +1630,6 @@ defmodule Module do end end - defp preprocess_attribute(:file, file) when is_binary(file) do - file - end - defp preprocess_attribute(:before_compile, atom) when is_atom(atom), do: {atom, :__before_compile__} diff --git a/lib/elixir/src/elixir_def.erl b/lib/elixir/src/elixir_def.erl index b2f2fdea68..c14a76d85b 100644 --- a/lib/elixir/src/elixir_def.erl +++ b/lib/elixir/src/elixir_def.erl @@ -105,8 +105,8 @@ store_definition(Kind, CheckClauses, Call, Body, Pos) -> %% will always point to the quoted one and __ENV__.file will %% always point to the one at @file or the quoted one. {Location, Key} = - case elixir_utils:meta_location(Meta) of - {_, _} = Keep -> {Keep, keep}; + case elixir_utils:meta_keep(Meta) of + {_, _} = MetaFile -> {MetaFile, keep}; nil -> {nil, line} end, @@ -116,18 +116,18 @@ store_definition(Kind, CheckClauses, Call, Body, Pos) -> LinifyBody = elixir_quote:linify(Line, Key, Body), Generated = case DoCheckClauses of true -> []; false -> ?generated([]) end, - {File, MetaLocation} = + {File, DefMeta} = case retrieve_location(Location, ?key(E, module)) of {F, L} -> - {F, [{line, Line}, {location, {F, L}} | Generated]}; + {F, [{line, Line}, {file, {F, L}} | Generated]}; nil -> {nil, [{line, Line} | Generated]} end, run_with_location_change(File, E, fun(EL) -> - assert_no_aliases_name(MetaLocation, Name, Args, EL), - assert_valid_name(MetaLocation, Kind, Name, Args, EL), - store_definition(MetaLocation, Kind, DoCheckClauses, Name, Arity, + assert_no_aliases_name(DefMeta, Name, Args, EL), + assert_valid_name(DefMeta, Kind, Name, Args, EL), + store_definition(DefMeta, Kind, DoCheckClauses, Name, Arity, LinifyArgs, LinifyGuards, LinifyBody, ?key(E, file), EL) end). diff --git a/lib/elixir/src/elixir_erl.erl b/lib/elixir/src/elixir_erl.erl index ae012fc931..16e19ee8c8 100644 --- a/lib/elixir/src/elixir_erl.erl +++ b/lib/elixir/src/elixir_erl.erl @@ -140,8 +140,8 @@ definition_scope(Meta, File) -> %% warnings are raised in elixir_erl_pass. Once we remove %% all warnings from the Erlang pass, we can remove the %% file field from #elixir_erl and clean up the code. - case lists:keyfind(location, 1, Meta) of - {location, {F, _}} -> #elixir_erl{file=F}; + case lists:keyfind(file, 1, Meta) of + {file, {F, _}} -> #elixir_erl{file=F}; false -> #elixir_erl{file=File} end. @@ -210,8 +210,8 @@ split_definition(Tuple, defmacrop, Meta, Clauses, T, File, Unreachable, add_definition(Meta, Entry, Functions)). add_definition(Meta, Body, {Head, Tail}) -> - case lists:keyfind(location, 1, Meta) of - {location, {F, L}} -> + case lists:keyfind(file, 1, Meta) of + {file, {F, L}} -> %% Erlang's epp attempts to perform offsetting when generated is set to true %% and that causes cover to fail when processing modules. Therefore we never %% pass the generated annotation forward for file attributes. The function diff --git a/lib/elixir/src/elixir_errors.erl b/lib/elixir/src/elixir_errors.erl index d70ce56284..81596baccd 100644 --- a/lib/elixir/src/elixir_errors.erl +++ b/lib/elixir/src/elixir_errors.erl @@ -141,7 +141,7 @@ file_format(Line, File) -> io_lib:format("~ts:~w", [elixir_utils:relative_to_cwd(File), Line]). meta_location(Meta, File) -> - case elixir_utils:meta_location(Meta) of + case elixir_utils:meta_keep(Meta) of {F, L} -> {F, L}; nil -> {File, ?line(Meta)} end. diff --git a/lib/elixir/src/elixir_quote.erl b/lib/elixir/src/elixir_quote.erl index 5263b9bdd5..83ab725706 100644 --- a/lib/elixir/src/elixir_quote.erl +++ b/lib/elixir/src/elixir_quote.erl @@ -5,7 +5,7 @@ -include("elixir.hrl"). -define(defs(Kind), Kind == def; Kind == defp; Kind == defmacro; Kind == defmacrop; Kind == '@'). -define(lexical(Kind), Kind == import; Kind == alias; Kind == require). --compile({inline, [keyfind/2, keystore/3, keydelete/2, keyreplace/3, keynew/3]}). +-compile({inline, [keyfind/2, keystore/3, keydelete/2, keynew/3]}). %% Apply the line from site call on quoted contents. %% Receives a Key to look for the default line as argument. @@ -46,18 +46,13 @@ do_tuple_linify(Line, Key, Var, Meta, Left, Right) -> do_linify_meta(0, line, Meta) -> Meta; do_linify_meta(Line, line, Meta) -> - case keyfind(line, Meta) of - {line, Int} when is_integer(Int), Int /= 0 -> - Meta; - _ -> - keystore(line, Meta, Line) - end; + keynew(line, Meta, Line); do_linify_meta(Line, keep, Meta) -> - case keyfind(keep, Meta) of - {keep, Int} when is_integer(Int), Int /= 0 -> - keyreplace(keep, keydelete(line, Meta), {line, Int}); + case lists:keytake(keep, 1, Meta) of + {value, {keep, {_, Int}}, MetaNoFile} -> + [{line, Int} | keydelete(line, MetaNoFile)]; _ -> - do_linify_meta(Line, line, Meta) + keynew(line, Meta, Line) end. %% Some expressions cannot be unquoted at compilation time. @@ -342,21 +337,26 @@ do_quote_tuple(Left, Meta, Right, Q, E) -> {{'{}', [], [TLeft, meta(Meta, Q), TRight]}, RQ}. meta(Meta, Q) -> - generated(file(line(Meta, Q), Q), Q). + generated(keep(Meta, Q), Q). generated(Meta, #elixir_quote{generated=true}) -> [{generated, true} | Meta]; generated(Meta, #elixir_quote{generated=false}) -> Meta. -file(Meta, #elixir_quote{file=nil}) -> Meta; -file(Meta, #elixir_quote{file=File}) -> [{file, File} | Meta]. +keep(Meta, #elixir_quote{file=nil, line=Line}) -> + line(Meta, Line); +keep(Meta, #elixir_quote{file=File}) -> + case lists:keytake(line, 1, Meta) of + {value, {line, Line}, MetaNoLine} -> + [{keep, {File, Line}} | MetaNoLine]; + false -> + [{keep, {File, 0}} | Meta] + end. -line(Meta, #elixir_quote{file=File}) when File /= nil -> - [case KV of {line, V} -> {keep, V}; _ -> KV end || KV <- Meta]; -line(Meta, #elixir_quote{line=true}) -> +line(Meta, true) -> Meta; -line(Meta, #elixir_quote{line=false}) -> +line(Meta, false) -> keydelete(line, Meta); -line(Meta, #elixir_quote{line=Line}) -> +line(Meta, Line) -> keystore(line, Meta, Line). reverse_improper(L) -> reverse_improper(L, []). @@ -376,10 +376,6 @@ keystore(_Key, Meta, nil) -> Meta; keystore(Key, Meta, Value) -> lists:keystore(Key, 1, Meta, {Key, Value}). -keyreplace(Key, Meta, {Key, _V}) -> - Meta; -keyreplace(Key, Meta, Tuple) -> - lists:keyreplace(Key, 1, Meta, Tuple). keynew(Key, Meta, Value) -> case keyfind(Key, Meta) of {Key, _} -> Meta; diff --git a/lib/elixir/src/elixir_utils.erl b/lib/elixir/src/elixir_utils.erl index 86085da4db..0b92c5ef5d 100644 --- a/lib/elixir/src/elixir_utils.erl +++ b/lib/elixir/src/elixir_utils.erl @@ -3,7 +3,7 @@ -module(elixir_utils). -export([get_line/1, split_last/1, noop/0, characters_to_list/1, characters_to_binary/1, relative_to_cwd/1, - macro_name/1, returns_boolean/1, caller/4, meta_location/1, + macro_name/1, returns_boolean/1, caller/4, meta_keep/1, read_file_type/1, read_link_type/1, read_mtime_and_size/1, change_universal_time/2, guard_op/2, match_op/2, extract_splat_guards/1, extract_guards/1]). -include("elixir.hrl"). @@ -129,22 +129,15 @@ get_line(Opts) when is_list(Opts) -> %% Meta location. %% -%% Macros add a file+keep pair on location keep -%% which we should take into account for error -%% reporting. +%% Macros add a file pair on location keep which we +%% should take into account for error reporting. %% -%% Returns {binary, integer} on location keep or -%% nil. +%% Returns {binary, integer} on location keep or nil. -meta_location(Meta) -> - case lists:keyfind(file, 1, Meta) of - {file, MetaFile} when is_binary(MetaFile) -> - MetaLine = - case lists:keyfind(keep, 1, Meta) of - {keep, Keep} when is_integer(Keep) -> Keep; - _ -> 0 - end, - {MetaFile, MetaLine}; +meta_keep(Meta) -> + case lists:keyfind(keep, 1, Meta) of + {keep, {File, Line} = Pair} when is_binary(File), is_integer(Line) -> + Pair; _ -> nil end. diff --git a/lib/elixir/test/elixir/kernel/quote_test.exs b/lib/elixir/test/elixir/kernel/quote_test.exs index e386354b1b..cf95472532 100644 --- a/lib/elixir/test/elixir/kernel/quote_test.exs +++ b/lib/elixir/test/elixir/kernel/quote_test.exs @@ -14,7 +14,7 @@ defmodule Kernel.QuoteTest do test "keep line" do # DO NOT MOVE THIS LINE assert quote(location: :keep, do: bar(1, 2, 3)) == - {:bar, [file: Path.relative_to_cwd(__ENV__.file), keep: 16], [1, 2, 3]} + {:bar, [keep: {Path.relative_to_cwd(__ENV__.file), 16}], [1, 2, 3]} end test "fixed line" do