From 874975e5b580e0ce511b215ff520b7292757e0b8 Mon Sep 17 00:00:00 2001 From: sabiwara Date: Fri, 5 Sep 2025 08:04:55 +0900 Subject: [PATCH 1/3] Fix Enum.take(empty_date_range, -1) --- lib/elixir/lib/calendar/date_range.ex | 4 ++-- lib/elixir/test/elixir/calendar/date_range_test.exs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/elixir/lib/calendar/date_range.ex b/lib/elixir/lib/calendar/date_range.ex index a92b9d124f5..2b1c923c35d 100644 --- a/lib/elixir/lib/calendar/date_range.ex +++ b/lib/elixir/lib/calendar/date_range.ex @@ -91,8 +91,8 @@ defmodule Date.Range do slice(Map.put(date_range, :step, step)) end - defp slice(current, _step, 1, calendar) do - [date_from_iso_days(current, calendar)] + defp slice(_current, _step, 0, _calendar) do + [] end defp slice(current, step, remaining, calendar) do diff --git a/lib/elixir/test/elixir/calendar/date_range_test.exs b/lib/elixir/test/elixir/calendar/date_range_test.exs index 39465421ca4..fe6cab37e59 100644 --- a/lib/elixir/test/elixir/calendar/date_range_test.exs +++ b/lib/elixir/test/elixir/calendar/date_range_test.exs @@ -101,6 +101,10 @@ defmodule Date.RangeTest do end end + test "Enum.take/1 for empty range with negative step" do + assert Enum.take(@empty_range, -1) == [] + end + test "works with date-like structs" do range = Date.range(~N[2000-01-01 09:00:00], ~U[2000-01-02 09:00:00Z]) assert range.first == ~D[2000-01-01] From d53ea1a85887f36d24f58db6bd6afd833f01ba80 Mon Sep 17 00:00:00 2001 From: sabiwara Date: Fri, 5 Sep 2025 08:09:11 +0900 Subject: [PATCH 2/3] Do not even call fun on empty enumerable --- lib/elixir/lib/enum.ex | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index 33866871e1e..d318d7925a1 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -3674,9 +3674,14 @@ defmodule Enum do end def take(enumerable, amount) when is_integer(amount) and amount < 0 do - {count, fun} = slice_count_and_fun(enumerable, 1) - first = Kernel.max(amount + count, 0) - fun.(first, count - first, 1) + case slice_count_and_fun(enumerable, 1) do + {0, _fun} -> + [] + + {count, fun} -> + first = Kernel.max(amount + count, 0) + fun.(first, count - first, 1) + end end @doc """ From aef73cb0934523006ab00443f53e5314a6243c2b Mon Sep 17 00:00:00 2001 From: sabiwara Date: Fri, 5 Sep 2025 21:14:12 +0900 Subject: [PATCH 3/3] Follow same approach for Range + Date.Range and add a guard --- lib/elixir/lib/calendar/date_range.ex | 6 +++--- lib/elixir/lib/enum.ex | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/elixir/lib/calendar/date_range.ex b/lib/elixir/lib/calendar/date_range.ex index 2b1c923c35d..5e8c652b781 100644 --- a/lib/elixir/lib/calendar/date_range.ex +++ b/lib/elixir/lib/calendar/date_range.ex @@ -91,11 +91,11 @@ defmodule Date.Range do slice(Map.put(date_range, :step, step)) end - defp slice(_current, _step, 0, _calendar) do - [] + defp slice(current, _step, 1, calendar) do + [date_from_iso_days(current, calendar)] end - defp slice(current, step, remaining, calendar) do + defp slice(current, step, remaining, calendar) when remaining > 1 do [ date_from_iso_days(current, calendar) | slice(current + step, step, remaining - 1, calendar) diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index d318d7925a1..0bdff3f47f1 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -5186,6 +5186,9 @@ defimpl Enumerable, for: Range do slice(Map.put(range, :step, step)) end - defp slice(_current, _step, 0), do: [] - defp slice(current, step, remaining), do: [current | slice(current + step, step, remaining - 1)] + defp slice(current, _step, 1), do: [current] + + defp slice(current, step, remaining) when remaining > 1 do + [current | slice(current + step, step, remaining - 1)] + end end