Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/elixir/src/elixir.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}).

-record(elixir_erl, {
context=nil, %% can be match, guards or nil
context=nil, %% can be match, guard or nil
extra=nil, %% extra information about the context, like pin_guard and map_key
caller=false, %% when true, it means caller was invoked
var_names=#{}, %% maps of defined variables and their alias
Expand Down
7 changes: 7 additions & 0 deletions lib/elixir/src/elixir_erl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ elixir_to_erl(Tree, Ann) when is_atom(Tree) ->
{atom, Ann, Tree};
elixir_to_erl(Tree, Ann) when is_integer(Tree) ->
{integer, Ann, Tree};
elixir_to_erl(Tree, Ann) when is_float(Tree), Tree == 0.0 ->
Op =
case <<Tree/float>> of
<<1:1,_:63>> -> '-';
_ -> '+'
end,
{op, Ann, Op, {float, Ann, 0.0}};
elixir_to_erl(Tree, Ann) when is_float(Tree) ->
{float, Ann, Tree};
elixir_to_erl(Tree, Ann) when is_binary(Tree) ->
Expand Down
14 changes: 13 additions & 1 deletion lib/elixir/src/elixir_expand.erl
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,10 @@ expand(Pid, S, E) when is_pid(Pid) ->
{Pid, E}
end;

expand(Float, S, #{context := match} = E) when is_float(Float), Float == 0.0 ->
elixir_errors:file_warn([], E, ?MODULE, invalid_match_on_zero_float),
{Float, S, E};

expand(Other, S, E) when is_number(Other); is_atom(Other); is_binary(Other) ->
{Other, S, E};

Expand Down Expand Up @@ -861,7 +865,7 @@ expand_remote(Receiver, DotMeta, Right, Meta, NoParens, Args, S, SL, #{context :

true ->
AttachedDotMeta = attach_context_module(Receiver, DotMeta, E),
{EArgs, {SA, _}, EA} = mapfold(fun expand_arg/3, {SL, S}, E, Args),
{EArgs, {SA, _}, EA} = expand_remote_args(Receiver, Right, Args, {SL, S}, E),

case rewrite(Context, Receiver, AttachedDotMeta, Right, Meta, EArgs, S) of
{ok, Rewritten} ->
Expand All @@ -876,6 +880,12 @@ expand_remote(Receiver, DotMeta, Right, Meta, _NoParens, Args, _, _, E) ->
Call = {{'.', DotMeta, [Receiver, Right]}, Meta, Args},
file_error(Meta, E, ?MODULE, {invalid_call, Call}).

%% 0.0 inside a match warns. It must be either +0.0 or -0.0.
%% Therefore we want to avoid the warning here.
expand_remote_args(erlang, '+', [Arg], PairS, E) when is_number(Arg) -> {[Arg], PairS, E};
expand_remote_args(erlang, '-', [Arg], PairS, E) when is_number(Arg) -> {[Arg], PairS, E};
expand_remote_args(_Remote, _Fun, Args, PairS, E) -> mapfold(fun expand_arg/3, PairS, E, Args).

attach_context_module(_Receiver, Meta, #{function := nil}) ->
Meta;
attach_context_module(Receiver, Meta, #{context_modules := [Ctx | _], module := Mod})
Expand Down Expand Up @@ -1160,6 +1170,8 @@ assert_no_underscore_clause_in_cond(_Other, _E) ->
guard_context(#elixir_ex{prematch={_, _, {bitsize, _}}}) -> "bitstring size specifier";
guard_context(_) -> "guards".

format_error(invalid_match_on_zero_float) ->
"pattern matching on 0.0 is equivalent to matching only on +0.0 from Erlang/OTP 27+. Instead you must match on +0.0 or -0.0";
format_error({remote_nullary_no_parens, Expr}) ->
String = 'Elixir.String':replace_suffix('Elixir.Macro':to_string(Expr), <<"()">>, <<>>),
io_lib:format("parentheses are required for function calls with no arguments, got: ~ts", [String]);
Expand Down
10 changes: 10 additions & 0 deletions lib/elixir/test/elixir/kernel/expansion_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,16 @@ defmodule Kernel.ExpansionTest do
end
end

describe "floats" do
test "cannot be 0.0 inside match" do
assert capture_io(:stderr, fn -> expand(quote(do: 0.0 = 0.0)) end) =~
"pattern matching on 0.0 is equivalent to matching only on +0.0 from Erlang/OTP 27+"

assert {:=, [], [+0.0, +0.0]} = expand(quote(do: +0.0 = 0.0))
assert {:=, [], [-0.0, +0.0]} = expand(quote(do: -0.0 = 0.0))
end
end

describe "tuples" do
test "expanded as arguments" do
assert expand(quote(do: {after_expansion = 1, a})) == quote(do: {after_expansion = 1, a()})
Expand Down
6 changes: 6 additions & 0 deletions lib/elixir/test/erlang/control_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ cond_line_test() ->
{clause, 3, _, _, _}]
} = to_erl("cond do\n 1 -> :ok\n 2 -> :ok\nend").

float_match_test() ->
{'case', _, _,
[{clause, _, [{op, _, '+', {float, _, 0.0}}], [], [{atom, _, pos}]},
{clause, _, [{op, _, '-', {float, _, 0.0}}], [], [{atom, _, neg}]}]
} = to_erl("case X do\n +0.0 -> :pos\n -0.0 -> :neg\nend").

% Optimized

optimized_if_test() ->
Expand Down