From 10f2ef2305146e1ec40429b9e1c07c06ea3ae41b Mon Sep 17 00:00:00 2001 From: sabiwara Date: Fri, 20 Dec 2024 09:53:39 +0900 Subject: [PATCH 1/2] Remove no_parens when using capture with arity Close #14089 --- lib/elixir/src/elixir_fn.erl | 9 +++++++++ lib/elixir/test/elixir/kernel/expansion_test.exs | 5 +++++ lib/elixir/test/elixir/kernel/fn_test.exs | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/lib/elixir/src/elixir_fn.erl b/lib/elixir/src/elixir_fn.erl index 668b201909d..89688ccae99 100644 --- a/lib/elixir/src/elixir_fn.erl +++ b/lib/elixir/src/elixir_fn.erl @@ -112,6 +112,10 @@ capture_expr(Meta, Expr, S, E, Escaped, Sequential) -> case escape(Expr, E, Escaped) of {_, []} when not Sequential -> invalid_capture(Meta, Expr, E); + {EExpr, []} -> + Meta2 = lists:keydelete(no_parens, 1, Meta), + Fn = {fn, Meta2, [{'->', Meta2, [[], remove_no_parens(EExpr)]}]}, + {expand, Fn, S, E}; {EExpr, EDict} -> EVars = validate(Meta, EDict, 1, E), Fn = {fn, Meta, [{'->', Meta, [EVars, EExpr]}]}, @@ -121,6 +125,11 @@ capture_expr(Meta, Expr, S, E, Escaped, Sequential) -> invalid_capture(Meta, Arg, E) -> file_error(Meta, E, ?MODULE, {invalid_args_for_capture, Arg}). +remove_no_parens({{'.', _, [_, _]} = Dot, Meta, Args}) when is_list(Args) -> + Meta2 = lists:keydelete(no_parens, 1, Meta), + {Dot, Meta2, Args}; +remove_no_parens(Other) -> Other. + validate(Meta, [{Pos, Var} | T], Pos, E) -> [Var | validate(Meta, T, Pos + 1, E)]; validate(Meta, [{Pos, _} | _], Expected, E) -> diff --git a/lib/elixir/test/elixir/kernel/expansion_test.exs b/lib/elixir/test/elixir/kernel/expansion_test.exs index 81b0a65a70b..4e08384a5b0 100644 --- a/lib/elixir/test/elixir/kernel/expansion_test.exs +++ b/lib/elixir/test/elixir/kernel/expansion_test.exs @@ -1203,6 +1203,11 @@ defmodule Kernel.ExpansionTest do [{:->, [{:line, 1}], [[{:capture, [line: 1], nil}], {:capture, [line: 1], nil}]}]} end + test "removes no_parens when expanding 0-arity capture to fn" do + assert expand(quote(do: &foo().bar/0)) == + quote(do: fn -> foo().bar() end) + end + test "expands remotes" do assert expand(quote(do: &List.flatten/2)) == quote(do: &:"Elixir.List".flatten/2) diff --git a/lib/elixir/test/elixir/kernel/fn_test.exs b/lib/elixir/test/elixir/kernel/fn_test.exs index 1304d753577..0d0e8471994 100644 --- a/lib/elixir/test/elixir/kernel/fn_test.exs +++ b/lib/elixir/test/elixir/kernel/fn_test.exs @@ -95,6 +95,12 @@ defmodule Kernel.FnTest do assert (&mod.flatten/1) == (&List.flatten/1) end + test "capture with module from local call" do + assert (&math_mod().pi/0).() == :math.pi() + end + + defp math_mod, do: :math + test "local partial application" do assert (&atb(&1, :utf8)).(:a) == "a" assert (&atb(List.to_atom(&1), :utf8)).(~c"a") == "a" From 129b5880c324ca77ae834e50865e872871591ee9 Mon Sep 17 00:00:00 2001 From: sabiwara Date: Fri, 20 Dec 2024 10:43:42 +0900 Subject: [PATCH 2/2] More concise implementation --- lib/elixir/src/elixir_fn.erl | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/elixir/src/elixir_fn.erl b/lib/elixir/src/elixir_fn.erl index 89688ccae99..fafdbd8207a 100644 --- a/lib/elixir/src/elixir_fn.erl +++ b/lib/elixir/src/elixir_fn.erl @@ -112,9 +112,9 @@ capture_expr(Meta, Expr, S, E, Escaped, Sequential) -> case escape(Expr, E, Escaped) of {_, []} when not Sequential -> invalid_capture(Meta, Expr, E); - {EExpr, []} -> + {{{'.', _, [_, _]} = Dot, _, Args}, []} -> Meta2 = lists:keydelete(no_parens, 1, Meta), - Fn = {fn, Meta2, [{'->', Meta2, [[], remove_no_parens(EExpr)]}]}, + Fn = {fn, Meta2, [{'->', Meta2, [[], {Dot, Meta2, Args}]}]}, {expand, Fn, S, E}; {EExpr, EDict} -> EVars = validate(Meta, EDict, 1, E), @@ -125,11 +125,6 @@ capture_expr(Meta, Expr, S, E, Escaped, Sequential) -> invalid_capture(Meta, Arg, E) -> file_error(Meta, E, ?MODULE, {invalid_args_for_capture, Arg}). -remove_no_parens({{'.', _, [_, _]} = Dot, Meta, Args}) when is_list(Args) -> - Meta2 = lists:keydelete(no_parens, 1, Meta), - {Dot, Meta2, Args}; -remove_no_parens(Other) -> Other. - validate(Meta, [{Pos, Var} | T], Pos, E) -> [Var | validate(Meta, T, Pos + 1, E)]; validate(Meta, [{Pos, _} | _], Expected, E) ->