From 887ff4a8e7e50ddab269a3b8ac9fab1f041a970a Mon Sep 17 00:00:00 2001 From: sabiwara Date: Sat, 20 Dec 2025 14:59:48 +0900 Subject: [PATCH 1/2] Formatter respects comments in tuple keyword syntax --- lib/elixir/lib/code/formatter.ex | 12 ++++++ .../elixir/code_formatter/comments_test.exs | 42 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/lib/elixir/lib/code/formatter.ex b/lib/elixir/lib/code/formatter.ex index 70ea70ae0e8..79ca50b69b1 100644 --- a/lib/elixir/lib/code/formatter.ex +++ b/lib/elixir/lib/code/formatter.ex @@ -1648,6 +1648,7 @@ defmodule Code.Formatter do defp tuple_to_algebra(meta, args, join, state) do join = if eol?(meta, state), do: :line, else: join fun = "ed_to_algebra(&1, :parens_arg, &2) + args = flatten_last_keyword_arg(args) {args_doc, join, state} = args_to_algebra_with_comments(args, meta, false, :none, join, state, fun) @@ -2474,6 +2475,17 @@ defmodule Code.Formatter do defp keyword_key?(_), do: false + # for {foo, bar: baz} tuples which are {foo, [bar: baz]}, returns [foo, bar: baz] + defp flatten_last_keyword_arg([last]) do + if keyword?(last), do: last, else: [last] + end + + defp flatten_last_keyword_arg([]), do: [] + + defp flatten_last_keyword_arg([h | t]) do + [h | flatten_last_keyword_arg(t)] + end + defp eol?(_meta, %{skip_eol: true}), do: false defp eol?(meta, _state), do: Keyword.get(meta, :newlines, 0) > 0 diff --git a/lib/elixir/test/elixir/code_formatter/comments_test.exs b/lib/elixir/test/elixir/code_formatter/comments_test.exs index c5f8c8e8e2c..72a145d8878 100644 --- a/lib/elixir/test/elixir/code_formatter/comments_test.exs +++ b/lib/elixir/test/elixir/code_formatter/comments_test.exs @@ -1215,6 +1215,48 @@ defmodule Code.Formatter.CommentsTest do assert_format bad, good end + test "with comments inside tuple keywords before and after" do + bad = ~S""" + { + :tuple, + + # before 1 + one: 1, # after 1 + + # before 2 + two: 2, # after 2 + + # before 3 + three: 3 # after 3 + + # final + } + """ + + good = ~S""" + + { + :tuple, + + # before 1 + # after 1 + one: 1, + + # before 2 + # after 2 + two: 2, + + # before 3 + # after 3 + three: 3 + + # final + } + """ + + assert_format bad, good + end + test "with comments inside bitstrings before and after" do bad = ~S""" << From 8dc2d5a6fbca16cea490a1e5b6ef9c2bf1648287 Mon Sep 17 00:00:00 2001 From: sabiwara Date: Sat, 20 Dec 2025 15:07:01 +0900 Subject: [PATCH 2/2] make format --- lib/elixir/lib/enum.ex | 9 +---- lib/elixir/lib/inspect/algebra.ex | 13 +----- lib/elixir/lib/module/types/apply.ex | 5 +-- lib/elixir/lib/module/types/descr.ex | 4 +- lib/elixir/lib/string.ex | 5 +-- .../test/elixir/task/supervisor_test.exs | 4 +- lib/mix/test/mix/rebar_test.exs | 3 +- lib/mix/test/mix/release_test.exs | 40 +++++-------------- 8 files changed, 23 insertions(+), 60 deletions(-) diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index 2a9af55ac17..94721b15d4d 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -4271,13 +4271,8 @@ defmodule Enum do ## Helpers - @compile {:inline, - entry_to_string: 1, - reduce: 3, - reduce_by: 3, - reduce_enumerable: 3, - reduce_range: 5, - map_range: 4} + @compile {:inline, entry_to_string: 1, reduce: 3, reduce_by: 3, reduce_enumerable: 3, + reduce_range: 5, map_range: 4} defp entry_to_string(entry) when is_binary(entry), do: entry defp entry_to_string(entry), do: String.Chars.to_string(entry) diff --git a/lib/elixir/lib/inspect/algebra.ex b/lib/elixir/lib/inspect/algebra.ex index 99b8d5cce55..32d8591a0ba 100644 --- a/lib/elixir/lib/inspect/algebra.ex +++ b/lib/elixir/lib/inspect/algebra.ex @@ -677,17 +677,8 @@ defmodule Inspect.Algebra do # Algebra API - @compile {:inline, - empty: 0, - concat: 2, - break: 0, - break: 1, - glue: 2, - glue: 3, - flex_break: 0, - flex_break: 1, - flex_glue: 2, - flex_glue: 3} + @compile {:inline, empty: 0, concat: 2, break: 0, break: 1, glue: 2, glue: 3, flex_break: 0, + flex_break: 1, flex_glue: 2, flex_glue: 3} @doc """ Returns a document entity used to represent nothingness. diff --git a/lib/elixir/lib/module/types/apply.ex b/lib/elixir/lib/module/types/apply.ex index cde9e3f0d07..b738a878648 100644 --- a/lib/elixir/lib/module/types/apply.ex +++ b/lib/elixir/lib/module/types/apply.ex @@ -65,10 +65,7 @@ defmodule Module.Types.Apply do {:behaviour_info, callbacks: fas, optional_callbacks: fas}, {:module_info, module_info}, # TODO: Move this to a type signature declared by `defprotocol` (or perhaps part of the behaviour) - {:__protocol__, - module: atom(), - functions: fas, - consolidated?: boolean(), + {:__protocol__, module: atom(), functions: fas, consolidated?: boolean(), impls: union(atom([:not_consolidated]), tuple([atom([:consolidated]), list(atom())]))} ] diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 0a83401b280..6ef08b38fa1 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -280,8 +280,8 @@ defmodule Module.Types.Descr do defp term_or_optional(), do: @term_or_optional - @compile {:inline, - keep_optional: 1, remove_optional: 1, remove_optional_static: 1, optional_to_term: 1} + @compile {:inline, keep_optional: 1, remove_optional: 1, remove_optional_static: 1, + optional_to_term: 1} defp keep_optional(descr) do case descr do %{dynamic: %{optional: 1}} -> %{dynamic: %{optional: 1}} diff --git a/lib/elixir/lib/string.ex b/lib/elixir/lib/string.ex index 44aaffe088c..7ae56dde737 100644 --- a/lib/elixir/lib/string.ex +++ b/lib/elixir/lib/string.ex @@ -3200,10 +3200,7 @@ defmodule String do ## Helpers - @compile {:inline, - codepoint_byte_size: 1, - grapheme_byte_size: 1, - grapheme_to_binary: 1, + @compile {:inline, codepoint_byte_size: 1, grapheme_byte_size: 1, grapheme_to_binary: 1, reverse_characters_to_binary: 1} defp byte_size_unicode(binary) when is_binary(binary), do: byte_size(binary) diff --git a/lib/elixir/test/elixir/task/supervisor_test.exs b/lib/elixir/test/elixir/task/supervisor_test.exs index a16f1486b3e..1c944094d0b 100644 --- a/lib/elixir/test/elixir/task/supervisor_test.exs +++ b/lib/elixir/test/elixir/task/supervisor_test.exs @@ -42,8 +42,8 @@ defmodule Task.SupervisorTest do children = [ {Task.Supervisor, strategy: :one_for_one, name: :simple_name}, {Task.Supervisor, strategy: :one_for_one, name: {:global, :global_name}}, - {Task.Supervisor, - strategy: :one_for_one, name: {:via, Registry, {TaskSup.Registry, "via_name"}}} + {Task.Supervisor, strategy: :one_for_one, + name: {:via, Registry, {TaskSup.Registry, "via_name"}}} ] assert {:ok, supsup} = Supervisor.start_link(children, strategy: :one_for_one) diff --git a/lib/mix/test/mix/rebar_test.exs b/lib/mix/test/mix/rebar_test.exs index 0d468cd72ae..c07e19156a6 100644 --- a/lib/mix/test/mix/rebar_test.exs +++ b/lib/mix/test/mix/rebar_test.exs @@ -47,7 +47,8 @@ defmodule Mix.RebarTest do deps: [ { :rebar_override, - path: MixTest.Case.tmp_path("rebar_override"), app: false + path: MixTest.Case.tmp_path("rebar_override"), + app: false } ] ] diff --git a/lib/mix/test/mix/release_test.exs b/lib/mix/test/mix/release_test.exs index 39835dc351d..ad4884c956a 100644 --- a/lib/mix/test/mix/release_test.exs +++ b/lib/mix/test/mix/release_test.exs @@ -350,9 +350,7 @@ defmodule Mix.ReleaseTest do "my_sample_mode/ebin/my_sample_mode.app", {:application, :my_sample_mode, applications: [:kernel, :stdlib, :elixir, :runtime_tools, :compiler], - description: ~c"my_sample_mode", - modules: [], - vsn: ~c"1.0.0"} + description: ~c"my_sample_mode", modules: [], vsn: ~c"1.0.0"} ) apps = [my_sample_mode: :temporary] @@ -799,11 +797,8 @@ defmodule Mix.ReleaseTest do in_tmp(context.test, fn -> write_app!( "my_sample1/ebin/my_sample1.app", - {:application, :my_sample1, - applications: [:kernel, :stdlib, :elixir], - description: ~c"my_sample1", - modules: [], - vsn: ~c"1.0.0", + {:application, :my_sample1, applications: [:kernel, :stdlib, :elixir], + description: ~c"my_sample1", modules: [], vsn: ~c"1.0.0", included_applications: [:runtime_tools]} ) @@ -819,11 +814,8 @@ defmodule Mix.ReleaseTest do in_tmp(context.test, fn -> write_app!( "my_sample2/ebin/my_sample2.app", - {:application, :my_sample2, - applications: [:kernel, :stdlib, :elixir, :runtime_tools], - description: ~c"my_sample", - modules: [], - vsn: ~c"1.0.0", + {:application, :my_sample2, applications: [:kernel, :stdlib, :elixir, :runtime_tools], + description: ~c"my_sample", modules: [], vsn: ~c"1.0.0", included_applications: [:runtime_tools]} ) @@ -839,11 +831,8 @@ defmodule Mix.ReleaseTest do in_tmp(context.test, fn -> write_app!( "my_sample3/ebin/my_sample3.app", - {:application, :my_sample3, - applications: [:kernel, :stdlib, :elixir, :unknown], - optional_applications: [:unknown], - description: ~c"my_sample3", - modules: [], + {:application, :my_sample3, applications: [:kernel, :stdlib, :elixir, :unknown], + optional_applications: [:unknown], description: ~c"my_sample3", modules: [], vsn: ~c"1.0.0"} ) @@ -856,11 +845,8 @@ defmodule Mix.ReleaseTest do in_tmp(context.test, fn -> write_app!( "has_optional/ebin/has_optional.app", - {:application, :has_optional, - applications: [:kernel, :stdlib, :elixir, :unknown], - optional_applications: [:unknown], - description: ~c"has_optional", - modules: [], + {:application, :has_optional, applications: [:kernel, :stdlib, :elixir, :unknown], + optional_applications: [:unknown], description: ~c"has_optional", modules: [], vsn: ~c"1.0.0"} ) @@ -868,9 +854,7 @@ defmodule Mix.ReleaseTest do "points_as_permanent/ebin/points_as_permanent.app", {:application, :points_as_permanent, applications: [:kernel, :stdlib, :elixir, :has_optional], - optional_applications: [:unknown], - description: ~c"points_as_permanent", - modules: [], + optional_applications: [:unknown], description: ~c"points_as_permanent", modules: [], vsn: ~c"1.0.0"} ) @@ -878,9 +862,7 @@ defmodule Mix.ReleaseTest do "points_as_temporary/ebin/points_as_temporary.app", {:application, :points_as_temporary, applications: [:kernel, :stdlib, :elixir, :has_optional], - optional_applications: [:unknown], - description: ~c"points_as_temporary", - modules: [], + optional_applications: [:unknown], description: ~c"points_as_temporary", modules: [], vsn: ~c"1.0.0"} )