From 9022a05ab2213e0d7b1abb34ee8d67eb439f8fbd Mon Sep 17 00:00:00 2001 From: Andrea Leopardi Date: Wed, 12 Jul 2017 23:17:05 +0200 Subject: [PATCH] Force {Enum,Stream}.zip/1 to take a list of enumerabls as argument Before this commit, there wasn't a clear check on these two functions accepting only a list of enumerables as its argument. This lead to things like https://github.com/elixir-lang/elixir/pull/6321. --- lib/elixir/lib/enum.ex | 6 +++--- lib/elixir/lib/stream.ex | 9 +++++---- lib/elixir/test/elixir/enum_test.exs | 6 +++++- lib/elixir/test/elixir/stream_test.exs | 5 +++++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index c0251d74bcf..855c418135a 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -2710,10 +2710,10 @@ defmodule Enum do end @doc """ - Zips corresponding elements from a collection of enumerables + Zips corresponding elements from a list of enumerables into one list of tuples. - The zipping finishes as soon as any enumerable completes. + The zipping finishes as soon as any enumerable in the given list completes. ## Examples @@ -2728,7 +2728,7 @@ defmodule Enum do def zip([]), do: [] - def zip(enumerables) do + def zip(enumerables) when is_list(enumerables) do Stream.zip(enumerables).({:cont, []}, &{:cont, [&1 | &2]}) |> elem(1) |> :lists.reverse diff --git a/lib/elixir/lib/stream.ex b/lib/elixir/lib/stream.ex index d58a34b4d48..d9eb8322f12 100644 --- a/lib/elixir/lib/stream.ex +++ b/lib/elixir/lib/stream.ex @@ -1033,10 +1033,10 @@ defmodule Stream do def zip(left, right), do: zip([left, right]) @doc """ - Zips corresponding elements from a collection of enumerables + Zips corresponding elements from a list of enumerables into one stream of tuples. - The zipping finishes as soon as any enumerable completes. + The zipping finishes as soon as any enumerable in the given list completes. ## Examples @@ -1047,8 +1047,9 @@ defmodule Stream do """ @spec zip([Enumerable.t]) :: Enumerable.t - def zip(enumerables) do - step = &do_zip_step(&1, &2) + def zip(enumerables) when is_list(enumerables) do + step = &do_zip_step(&1, &2) + enum_funs = Enum.map(enumerables, fn enum -> {&Enumerable.reduce(enum, &1, step), :cont} end) diff --git a/lib/elixir/test/elixir/enum_test.exs b/lib/elixir/test/elixir/enum_test.exs index 1b2ded61492..c3f4ebd707d 100644 --- a/lib/elixir/test/elixir/enum_test.exs +++ b/lib/elixir/test/elixir/enum_test.exs @@ -812,7 +812,11 @@ defmodule EnumTest do assert Enum.zip([[]]) == [] assert Enum.zip([[1]]) == [{1}] - assert Enum.zip([[], [], [], []]) == [] + assert Enum.zip([[], [], [], []]) == [] + + assert_raise FunctionClauseError, fn -> + Enum.zip(%{}) + end end end diff --git a/lib/elixir/test/elixir/stream_test.exs b/lib/elixir/test/elixir/stream_test.exs index 74ca3777394..ae0f87b056a 100644 --- a/lib/elixir/test/elixir/stream_test.exs +++ b/lib/elixir/test/elixir/stream_test.exs @@ -1007,6 +1007,11 @@ test "transform/4 closes on nested errors" do cycle = Stream.cycle([:a, :b, :c]) assert Stream.zip([concat, cycle]) |> Enum.to_list == [{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}] + + assert_raise FunctionClauseError, fn -> + enum_of_enums = Stream.cycle([[1, 2], [:a, :b]]) + Stream.zip(enum_of_enums) + end end test "zip/1 does not leave streams suspended" do