Skip to content

Commit ed2829d

Browse files
committed
Keep warnings when traversing clauses
1 parent 081f99c commit ed2829d

File tree

3 files changed

+60
-51
lines changed

3 files changed

+60
-51
lines changed

lib/elixir/lib/module/types/expr.ex

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ defmodule Module.Types.Expr do
203203
stack = push_expr_stack(expr, stack)
204204

205205
with {:ok, _expr_type, context} <- of_expr(case_expr, stack, context),
206-
:ok <- of_clauses(clauses, stack, context),
206+
{:ok, context} <- of_clauses(clauses, stack, context),
207207
do: {:ok, :dynamic, context}
208208
end
209209

@@ -212,7 +212,7 @@ defmodule Module.Types.Expr do
212212
stack = push_expr_stack(expr, stack)
213213

214214
case of_clauses(clauses, stack, context) do
215-
:ok -> {:ok, :dynamic, context}
215+
{:ok, context} -> {:ok, :dynamic, context}
216216
{:error, reason} -> {:error, reason}
217217
end
218218
end
@@ -224,23 +224,31 @@ defmodule Module.Types.Expr do
224224
def of_expr({:try, _meta, [blocks]} = expr, stack, context) do
225225
stack = push_expr_stack(expr, stack)
226226

227-
result =
228-
each_ok(blocks, fn
229-
{:rescue, clauses} ->
230-
each_ok(clauses, fn
231-
{:->, _, [[{:in, _, [var, _exceptions]}], body]} ->
227+
{result, context} =
228+
reduce_ok(blocks, context, fn
229+
{:rescue, clauses}, context ->
230+
reduce_ok(clauses, context, fn
231+
{:->, _, [[{:in, _, [var, _exceptions]}], body]}, context = acc ->
232232
{_type, context} = new_pattern_var(var, context)
233-
of_expr_ok(body, stack, context)
234233

235-
{:->, _, [[var], body]} ->
234+
with {:ok, context} <- of_expr_context(body, stack, context) do
235+
{:ok, keep_warnings(acc, context)}
236+
end
237+
238+
{:->, _, [[var], body]}, context = acc ->
236239
{_type, context} = new_pattern_var(var, context)
237-
of_expr_ok(body, stack, context)
240+
241+
with {:ok, context} <- of_expr_context(body, stack, context) do
242+
{:ok, keep_warnings(acc, context)}
243+
end
238244
end)
239245

240-
{block, body} when block in @try_blocks ->
241-
of_expr_ok(body, stack, context)
246+
{block, body}, context = acc when block in @try_blocks ->
247+
with {:ok, context} <- of_expr_context(body, stack, context) do
248+
{:ok, keep_warnings(acc, context)}
249+
end
242250

243-
{block, clauses} when block in @try_clause_blocks ->
251+
{block, clauses}, context when block in @try_clause_blocks ->
244252
of_clauses(clauses, stack, context)
245253
end)
246254

@@ -254,18 +262,18 @@ defmodule Module.Types.Expr do
254262
def of_expr({:receive, _meta, [blocks]} = expr, stack, context) do
255263
stack = push_expr_stack(expr, stack)
256264

257-
result =
258-
each_ok(blocks, fn
259-
{:do, {:__block__, _, []}} ->
260-
:ok
265+
{result, context} =
266+
reduce_ok(blocks, context, fn
267+
{:do, {:__block__, _, []}}, context ->
268+
{:ok, context}
261269

262-
{:do, clauses} ->
270+
{:do, clauses}, context ->
263271
of_clauses(clauses, stack, context)
264272

265-
{:after, [{:->, _meta, [head, body]}]} ->
273+
{:after, [{:->, _meta, [head, body]}]}, context = acc ->
266274
with {:ok, _type, context} <- of_expr(head, stack, context),
267-
{:ok, _type, _context} <- of_expr(body, stack, context),
268-
do: :ok
275+
{:ok, _type, context} <- of_expr(body, stack, context),
276+
do: {:ok, keep_warnings(acc, context)}
269277
end)
270278

271279
case result do
@@ -282,7 +290,7 @@ defmodule Module.Types.Expr do
282290
with {:ok, context} <- reduce_ok(clauses, context, &for_clause(&1, stack, &2)),
283291
{:ok, context} <- reduce_ok(opts, context, &for_option(&1, stack, &2)) do
284292
if opts[:reduce] do
285-
with :ok <- of_clauses(block, stack, context) do
293+
with {:ok, context} <- of_clauses(block, stack, context) do
286294
{:ok, :dynamic, context}
287295
end
288296
else
@@ -437,22 +445,23 @@ defmodule Module.Types.Expr do
437445
end
438446

439447
defp with_option({:else, clauses}, stack, context) do
440-
case of_clauses(clauses, stack, context) do
441-
:ok -> {:ok, context}
442-
{:error, reason} -> {:error, reason}
443-
end
448+
of_clauses(clauses, stack, context)
444449
end
445450

446451
defp of_clauses(clauses, stack, context) do
447-
each_ok(clauses, fn {:->, _meta, [head, body]} ->
452+
reduce_ok(clauses, context, fn {:->, _meta, [head, body]}, context = acc ->
448453
{patterns, guards} = extract_head(head)
449454

450455
with {:ok, _, context} <- Pattern.of_head(patterns, guards, stack, context),
451-
{:ok, _expr_type, _context} <- of_expr(body, stack, context),
452-
do: :ok
456+
{:ok, _expr_type, context} <- of_expr(body, stack, context),
457+
do: {:ok, keep_warnings(acc, context)}
453458
end)
454459
end
455460

461+
defp keep_warnings(context, %{warnings: warnings}) do
462+
%{context | warnings: warnings}
463+
end
464+
456465
defp extract_head([{:when, _meta, args}]) do
457466
case Enum.split(args, -1) do
458467
{patterns, [guards]} -> {patterns, flatten_when(guards)}
@@ -479,13 +488,6 @@ defmodule Module.Types.Expr do
479488
end
480489
end
481490

482-
defp of_expr_ok(expr, stack, context) do
483-
case of_expr(expr, stack, context) do
484-
{:ok, _type, _context} -> :ok
485-
{:error, reason} -> {:error, reason}
486-
end
487-
end
488-
489491
defp new_pattern_var({:_, _meta, var_context}, context) when is_atom(var_context) do
490492
{:dynamic, context}
491493
end

lib/elixir/lib/module/types/helpers.ex

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,6 @@ defmodule Module.Types.Helpers do
8181

8282
defp do_map_ok([], acc, _fun), do: {:ok, Enum.reverse(acc)}
8383

84-
@doc """
85-
Like `Enum.each/2` but only continues while `fun` returns `:ok`
86-
and stops on `{:error, reason}`.
87-
"""
88-
def each_ok([head | tail], fun) do
89-
case fun.(head) do
90-
:ok -> each_ok(tail, fun)
91-
{:error, reason} -> {:error, reason}
92-
end
93-
end
94-
95-
def each_ok([], _fun), do: :ok
96-
9784
@doc """
9885
Like `Enum.map_reduce/3` but only continues while `fun` returns `{:ok, elem, acc}`
9986
and stops on `{:error, reason}`.

lib/elixir/test/elixir/module/types/types_test.exs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ defmodule Module.Types.TypesTest do
2323
with {:ok, _types, context} <-
2424
Pattern.of_head(patterns, guards, TypeHelper.new_stack(), TypeHelper.new_context()),
2525
{:ok, type, context} <- Expr.of_expr(body, TypeHelper.new_stack(), context) do
26-
flunk("expexted error, got: #{inspect(Types.lift_type(type, context))}")
26+
case context.warnings do
27+
[warning] -> {:warning, warning}
28+
_ -> flunk("expexted error, got: #{inspect(Types.lift_type(type, context))}")
29+
end
2730
else
2831
{:error, {type, reason, context}} ->
2932
{:error, {type, reason, context}}
@@ -48,12 +51,18 @@ defmodule Module.Types.TypesTest do
4851
min
4952
end
5053

54+
defp to_warning({:warning, {module, warning, _location}}) do
55+
warning
56+
|> module.format_warning()
57+
|> IO.iodata_to_binary()
58+
end
59+
5160
defp to_warning({:error, {type, reason, context}}) do
5261
{Module.Types, error, _location} = Module.Types.error_to_warning(type, reason, context)
5362

5463
error
5564
|> Module.Types.format_warning()
56-
|> List.to_string()
65+
|> IO.iodata_to_binary()
5766
|> String.trim_trailing("\nConflict found at")
5867
end
5968

@@ -69,6 +78,17 @@ defmodule Module.Types.TypesTest do
6978
assert Types.expr_to_string(quote(do: :erlang.element(:erlang.+(a, 1), b))) == "elem(b, a)"
7079
end
7180

81+
test "undefined function warnings" do
82+
assert warning([], URI.unknown("foo")) ==
83+
"URI.unknown/1 is undefined or private"
84+
85+
assert warning([], if(true, do: URI.unknown("foo"))) ==
86+
"URI.unknown/1 is undefined or private"
87+
88+
assert warning([], try(do: :ok, after: URI.unknown("foo"))) ==
89+
"URI.unknown/1 is undefined or private"
90+
end
91+
7292
describe "function head warnings" do
7393
test "warns on literals" do
7494
string = warning([var = 123, var = "abc"], var)

0 commit comments

Comments
 (0)