Skip to content

Commit 2d13935

Browse files
authored
Fix cond scope and improve coverage, closes #8542 (#8544)
1 parent 5ce4b61 commit 2d13935

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

lib/elixir/src/elixir_erl_pass.erl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,16 @@ translate({fn, Meta, Clauses}, S) ->
109109
%% Cond
110110

111111
translate({'cond', CondMeta, [[{do, Clauses}]]}, S) ->
112-
[{'->', Meta, [[Condition], Body]} = H | T] = lists:reverse(Clauses),
113-
114-
Case =
115-
case Condition of
116-
X when is_atom(X) and (X /= false) and (X /= nil) ->
117-
build_cond_clauses(T, Body, Meta);
118-
_ ->
119-
Error = {{'.', Meta, [erlang, error]}, [], [cond_clause]},
120-
build_cond_clauses([H | T], Error, Meta)
112+
[{'->', Meta, [[Condition], _]} = H | T] = lists:reverse(Clauses),
113+
114+
FirstMeta =
115+
if
116+
is_atom(Condition), Condition /= false, Condition /= nil -> ?generated(Meta);
117+
true -> Meta
121118
end,
119+
120+
Error = {{'.', Meta, [erlang, error]}, [], [cond_clause]},
121+
Case = build_cond_clauses([H | T], Error, FirstMeta),
122122
translate(replace_case_meta(CondMeta, Case), S);
123123

124124
%% Case
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
defmodule Dialyzer.Cond do
2+
def one_boolean do
3+
cond do
4+
true -> :ok
5+
end
6+
end
7+
8+
def two_boolean do
9+
cond do
10+
List.flatten([]) == [] -> :ok
11+
true -> :ok
12+
end
13+
end
14+
15+
def one_otherwise do
16+
cond do
17+
:otherwise -> :ok
18+
end
19+
end
20+
21+
def two_otherwise do
22+
cond do
23+
List.flatten([]) == [] -> :ok
24+
:otherwise -> :ok
25+
end
26+
end
27+
end

lib/elixir/test/elixir/kernel/dialyzer_test.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ defmodule Kernel.DialyzerTest do
121121
assert_dialyze_no_warnings!(context)
122122
end
123123

124+
test "no warnings on cond", context do
125+
copy_beam!(context, Dialyzer.Cond)
126+
assert_dialyze_no_warnings!(context)
127+
end
128+
124129
test "no warnings on for comprehensions with bitstrings", context do
125130
copy_beam!(context, Dialyzer.ForBitstring)
126131
assert_dialyze_no_warnings!(context)

lib/elixir/test/elixir/kernel/special_forms_test.exs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,53 @@ defmodule Kernel.SpecialFormsTest do
44
use ExUnit.Case, async: true
55

66
doctest Kernel.SpecialForms
7+
8+
describe "cond" do
9+
test "does not leak variables for one clause" do
10+
x = 0
11+
12+
cond do
13+
true ->
14+
x = 1
15+
x
16+
end
17+
18+
assert x == 0
19+
end
20+
21+
test "does not leak variables for one clause with non-boolean as catch-all" do
22+
x = 0
23+
24+
cond do
25+
:otherwise ->
26+
x = 1
27+
x
28+
end
29+
30+
assert x == 0
31+
end
32+
33+
test "does not leak variables for multiple clauses" do
34+
x = 0
35+
36+
cond do
37+
List.flatten([]) == [] ->
38+
x = 1
39+
x
40+
41+
true ->
42+
x = 1
43+
x
44+
end
45+
46+
assert x == 0
47+
end
48+
49+
test "does not warn on non-boolean as catch-all" do
50+
cond do
51+
List.flatten([]) == [] -> :good
52+
:otherwise -> :also_good
53+
end
54+
end
55+
end
756
end

0 commit comments

Comments
 (0)