From c73900193a7b9cce8cefcb6f3331453d8ec10eac Mon Sep 17 00:00:00 2001 From: pnezis Date: Tue, 14 Jul 2026 11:31:12 +0300 Subject: [PATCH] Delete duplicate keys on `:pop` in `Keyword.get_and_update/3` and `get_and_update!/3` Both functions document updating "in one pass, deleting duplicate keys", but the `:pop` branch left any later duplicates in place: Keyword.get_and_update([a: 1, a: 2], :a, fn _ -> :pop end) #=> {1, [a: 2]}, expected {1, []} --- lib/elixir/lib/keyword.ex | 4 ++-- lib/elixir/test/elixir/keyword_test.exs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/elixir/lib/keyword.ex b/lib/elixir/lib/keyword.ex index 12a4aafbe0c..4db6019b178 100644 --- a/lib/elixir/lib/keyword.ex +++ b/lib/elixir/lib/keyword.ex @@ -517,7 +517,7 @@ defmodule Keyword do {get, :lists.reverse(acc, [{key, value} | delete(t, key)])} :pop -> - {current, :lists.reverse(acc, t)} + {current, :lists.reverse(acc, delete(t, key))} other -> raise "the given function must return a two-element tuple or :pop, got: #{inspect(other)}" @@ -583,7 +583,7 @@ defmodule Keyword do {get, :lists.reverse(acc, [{key, value} | delete(t, key)])} :pop -> - {value, :lists.reverse(acc, t)} + {value, :lists.reverse(acc, delete(t, key))} other -> raise "the given function must return a two-element tuple or :pop, got: #{inspect(other)}" diff --git a/lib/elixir/test/elixir/keyword_test.exs b/lib/elixir/test/elixir/keyword_test.exs index 8117e9053f5..3f802288f9f 100644 --- a/lib/elixir/test/elixir/keyword_test.exs +++ b/lib/elixir/test/elixir/keyword_test.exs @@ -31,6 +31,8 @@ defmodule KeywordTest do test "get_and_update/3 removes duplicates from the input keyword list" do assert Keyword.get_and_update([a: 1, b: 2, a: 3], :a, fn value -> {value, value + 10} end) == {1, [a: 11, b: 2]} + + assert Keyword.get_and_update([a: 1, b: 2, a: 3], :a, fn _ -> :pop end) == {1, [b: 2]} end test "get_and_update/3 raises on bad return value from the argument function" do @@ -50,6 +52,8 @@ defmodule KeywordTest do test "get_and_update!/3 removes duplicates from the input keyword list" do assert Keyword.get_and_update!([a: 1, b: 2, a: 3], :a, fn value -> {value, value + 10} end) == {1, [a: 11, b: 2]} + + assert Keyword.get_and_update!([a: 1, b: 2, a: 3], :a, fn _ -> :pop end) == {1, [b: 2]} end test "get_and_update!/3 raises on bad return value from the argument function" do