Skip to content

Commit 821b7c6

Browse files
author
José Valim
committed
Ensure Enum.member? uses match (===)
1 parent 9897b89 commit 821b7c6

File tree

7 files changed

+33
-10
lines changed

7 files changed

+33
-10
lines changed

lib/elixir/lib/enum.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ defprotocol Enumerable do
3838

3939
@doc """
4040
The function is used to check if a value exists within the collection.
41+
Membership should be tested with the match (`===`) operator.
4142
"""
4243
def member?(collection, value)
4344

@@ -87,6 +88,10 @@ defmodule Enum do
8788
@doc """
8889
Checks if `value` exists within the `collection`.
8990
91+
Membership is tested with the match (`===`) operator although
92+
enumerables like ranges may include floats inside the given
93+
range.
94+
9095
## Examples
9196
9297
iex> Enum.member?(1..10, 5)
@@ -1850,8 +1855,9 @@ defimpl Enumerable, for: Function do
18501855
end
18511856

18521857
def member?(function, value) do
1853-
function.(false, fn(entry, _) ->
1854-
if entry === value, do: throw(:function_member?), else: false
1858+
function.(false, fn
1859+
^value, _ -> throw(:function_member?)
1860+
_, _ -> false
18551861
end)
18561862
catch
18571863
:function_member? -> true

lib/elixir/lib/range.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ defprotocol Range.Iterator do
1717
end
1818

1919
defimpl Enumerable, for: Range do
20-
def reduce(Range[first: first] = range, acc, fun) do
20+
def reduce(first .. _ = range, acc, fun) do
2121
Range.Iterator.reduce(first, range, acc, fun)
2222
end
2323

24-
def member?(Range[first: first, last: last], value) do
25-
value in first..last
24+
def member?(first .. last, value) do
25+
first <= value and value <= last
2626
end
2727

28-
def count(Range[first: first] = range) do
28+
def count(first .. _ = range) do
2929
Range.Iterator.count(first, range)
3030
end
3131
end

lib/elixir/src/elixir_macros.erl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,13 @@ translate_in(Meta, Left, Right, S) ->
233233
{ cons, _, _, _ } ->
234234
[H|T] = elixir_utils:cons_to_list(TRight),
235235
Expr = lists:foldr(fun(X, Acc) ->
236-
{ op, Line, 'orelse', { op, Line, '==', Var, X }, Acc }
237-
end, { op, Line, '==', Var, H }, T),
236+
{ op, Line, 'orelse', { op, Line, '=:=', Var, X }, Acc }
237+
end, { op, Line, '=:=', Var, H }, T),
238238
{ Cache, Expr };
239239
{ string, _, [H|T] } ->
240240
Expr = lists:foldl(fun(X, Acc) ->
241-
{ op, Line, 'orelse', { op, Line, '==', Var, { integer, Line, X } }, Acc }
242-
end, { op, Line, '==', Var, { integer, Line, H } }, T),
241+
{ op, Line, 'orelse', { op, Line, '=:=', Var, { integer, Line, X } }, Acc }
242+
end, { op, Line, '=:=', Var, { integer, Line, H } }, T),
243243
{ Cache, Expr };
244244
{ tuple, _, [{ atom, _, 'Elixir.Range' }, Start, End] } ->
245245
Expr = case { Start, End } of

lib/elixir/test/elixir/dict_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,13 @@ defmodule DictTest.Common do
327327
refute Dict.equal?(dict1, dict2)
328328
end
329329

330+
test :enum_member do
331+
assert Enum.member?(new_dict([{1,1}]), { 1, 1 })
332+
refute Enum.member?(new_dict([{1,1}]), { 1.0, 1 })
333+
refute Enum.member?(new_dict([{1,1}]), { 1, 1.0 })
334+
refute Enum.member?(new_dict([{1,1}]), { 1.0, 1.0 })
335+
end
336+
330337
test "unsupported dict" do
331338
assert_raise ArgumentError, "unsupported dict: :bad_dict", fn ->
332339
Dict.to_list :bad_dict

lib/elixir/test/elixir/kernel/case_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ defmodule Kernel.CaseTest do
3737
assert not y in [1, 2, 3], "not in assertion"
3838
end
3939

40+
test :in_with_match do
41+
refute 1.0 in [1, 2, 3], "not in assertion"
42+
end
43+
4044
defp get_case do
4145
case internal do
4246
:invalid ->

lib/elixir/test/elixir/range_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ defmodule RangeTest do
3939
refute Enum.empty?(1..1)
4040

4141
assert Enum.member?(1..3, 2)
42+
4243
refute Enum.member?(1..3, 0)
4344
refute Enum.member?(1..3, 4)
4445
refute Enum.member?(3..1, 0)

lib/elixir/test/elixir/set_test.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ defmodule SetTest.Common do
9898
assert Set.size(Set.union(int_set, new_set([1.0]))) == 4
9999
end
100100

101+
test :enum_member do
102+
assert Enum.member?(int_set, 1)
103+
refute Enum.member?(int_set, 1.0)
104+
end
105+
101106
test "unsupported set" do
102107
assert_raise ArgumentError, "unsupported set: :bad_set", fn ->
103108
Set.to_list :bad_set

0 commit comments

Comments
 (0)