Skip to content

Commit b52ddb3

Browse files
committed
Move Checker into ParallelChecker
1 parent d659949 commit b52ddb3

File tree

6 files changed

+132
-142
lines changed

6 files changed

+132
-142
lines changed

lib/elixir/lib/module/checker.ex

Lines changed: 0 additions & 117 deletions
This file was deleted.

lib/elixir/lib/module/parallel_checker.ex

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,116 @@ defmodule Module.ParallelChecker do
9696
|> Enum.sort()
9797
end
9898

99+
## Module checking
100+
101+
defp check_module(module, cache) do
102+
case extract_definitions(module) do
103+
{:ok, module, file, definitions, no_warn_undefined} ->
104+
Module.Types.warnings(module, file, definitions, no_warn_undefined, cache)
105+
|> group_warnings()
106+
|> emit_warnings()
107+
108+
:error ->
109+
[]
110+
end
111+
end
112+
113+
defp extract_definitions({module, module_map}) when is_map(module_map) do
114+
no_warn_undefined =
115+
module_map.compile_opts
116+
|> extract_no_warn_undefined()
117+
|> merge_compiler_no_warn_undefined()
118+
119+
{:ok, module, module_map.file, module_map.definitions, no_warn_undefined}
120+
end
121+
122+
defp extract_definitions({module, binary}) when is_binary(binary) do
123+
with {:ok, {_, [debug_info: chunk]}} <- :beam_lib.chunks(binary, [:debug_info]),
124+
{:debug_info_v1, backend, data} <- chunk,
125+
{:ok, module_map} <- backend.debug_info(:elixir_v1, module, data, []) do
126+
extract_definitions({module, module_map})
127+
else
128+
_ -> :error
129+
end
130+
end
131+
132+
defp extract_no_warn_undefined(compile_opts) do
133+
for(
134+
{:no_warn_undefined, values} <- compile_opts,
135+
value <- List.wrap(values),
136+
do: value
137+
)
138+
end
139+
140+
defp merge_compiler_no_warn_undefined(no_warn_undefined) do
141+
case Code.get_compiler_option(:no_warn_undefined) do
142+
:all ->
143+
:all
144+
145+
list when is_list(list) ->
146+
no_warn_undefined ++ list
147+
end
148+
end
149+
150+
## Warning helpers
151+
152+
def group_warnings(warnings) do
153+
warnings
154+
|> Enum.reduce(%{}, fn {module, warning, location}, acc ->
155+
locations = MapSet.new([location])
156+
Map.update(acc, {module, warning}, locations, &MapSet.put(&1, location))
157+
end)
158+
|> Enum.map(fn {{module, warning}, locations} -> {module, warning, Enum.sort(locations)} end)
159+
|> Enum.sort()
160+
end
161+
162+
def emit_warnings(warnings) do
163+
Enum.flat_map(warnings, fn {module, warning, locations} ->
164+
message = module.format_warning(warning)
165+
print_warning([message, ?\n, format_locations(locations)])
166+
167+
Enum.map(locations, fn {file, line, _mfa} ->
168+
{file, line, message}
169+
end)
170+
end)
171+
end
172+
173+
defp format_locations([location]) do
174+
format_location(location)
175+
end
176+
177+
defp format_locations(locations) do
178+
[
179+
"Found at #{length(locations)} locations:\n",
180+
Enum.map(locations, &format_location/1)
181+
]
182+
end
183+
184+
defp format_location({file, line, {module, fun, arity}}) do
185+
mfa = Exception.format_mfa(module, fun, arity)
186+
[format_file_line(file, line), ": ", mfa, ?\n]
187+
end
188+
189+
defp format_location({file, line, nil}) do
190+
[format_file_line(file, line), ?\n]
191+
end
192+
193+
defp format_location({file, line, module}) do
194+
[format_file_line(file, line), ": ", inspect(module), ?\n]
195+
end
196+
197+
defp format_file_line(file, line) do
198+
file = Path.relative_to_cwd(file)
199+
line = if line > 0, do: [?: | Integer.to_string(line)], else: []
200+
[" ", file, line]
201+
end
202+
203+
defp print_warning(message) do
204+
IO.puts(:stderr, [:elixir_errors.warning_prefix(), message])
205+
end
206+
207+
## Server callbacks
208+
99209
def init([modules, send_results, schedulers]) do
100210
ets = :ets.new(:checker_cache, [:set, :public, {:read_concurrency, true}])
101211

@@ -187,7 +297,7 @@ defmodule Module.ParallelChecker do
187297
send_results_pid = state.send_results
188298

189299
spawn_link(fn ->
190-
warnings = Module.Checker.verify(verify, {parent, ets})
300+
warnings = check_module(verify, {parent, ets})
191301
send(send_results_pid, {__MODULE__, module, warnings})
192302
send(parent, {__MODULE__, :done})
193303
end)

lib/elixir/lib/module/types.ex

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ defmodule Module.Types do
44
import Module.Types.Helpers
55
alias Module.Types.{Expr, Pattern}
66

7-
@doc """
8-
Infer function definitions' types.
9-
"""
10-
def infer_definitions(file, module, defs, no_warn_undefined, cache) do
7+
@doc false
8+
def warnings(module, file, defs, no_warn_undefined, cache) do
119
stack = stack()
1210

1311
Enum.flat_map(defs, fn {{fun, _arity} = function, kind, meta, clauses} ->
1412
context = context(with_file_meta(meta, file), module, function, no_warn_undefined, cache)
1513

1614
Enum.flat_map(clauses, fn {_meta, args, guards, body} ->
1715
def_expr = {kind, meta, [guards_to_expr(guards, {fun, [], args})]}
18-
infer_definition(args, guards, body, def_expr, stack, context)
16+
warnings_from_clause(args, guards, body, def_expr, stack, context)
1917
end)
2018
end)
2119
end
@@ -27,7 +25,15 @@ defmodule Module.Types do
2725
end
2826
end
2927

30-
defp infer_definition(args, guards, body, def_expr, stack, context) do
28+
defp guards_to_expr([], left) do
29+
left
30+
end
31+
32+
defp guards_to_expr([guard | guards], left) do
33+
guards_to_expr(guards, {:when, [], [left, guard]})
34+
end
35+
36+
defp warnings_from_clause(args, guards, body, def_expr, stack, context) do
3137
head_stack = push_expr_stack(def_expr, stack)
3238

3339
with {:ok, _types, context} <- Pattern.of_head(args, guards, head_stack, context),
@@ -95,6 +101,8 @@ defmodule Module.Types do
95101
}
96102
end
97103

104+
## VARIABLE LIFTING
105+
98106
@doc """
99107
Lifts type variables to their infered types from the context.
100108
"""
@@ -109,7 +117,9 @@ defmodule Module.Types do
109117
types
110118
end
111119

112-
@doc false
120+
@doc """
121+
Lifts a single type to its infered type from the context.
122+
"""
113123
def lift_type(type, context) do
114124
context = %{
115125
types: context.types,
@@ -121,18 +131,6 @@ defmodule Module.Types do
121131
type
122132
end
123133

124-
## GUARDS
125-
126-
defp guards_to_expr([], left) do
127-
left
128-
end
129-
130-
defp guards_to_expr([guard | guards], left) do
131-
guards_to_expr(guards, {:when, [], [left, guard]})
132-
end
133-
134-
## VARIABLE LIFTING
135-
136134
# Lift type variable to its infered (hopefully concrete) types from the context
137135
defp do_lift_type({:var, var}, context) do
138136
case Map.fetch(context.lifted_types, var) do
@@ -249,7 +247,7 @@ defmodule Module.Types do
249247
end)
250248
end
251249

252-
## ERROR FORMATTING
250+
## FORMAT WARNINGS
253251

254252
def format_warning({:unable_unify, left, right, {location, expr, traces}}) do
255253
cond do

lib/elixir/src/elixir_compiler.erl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ bootstrap_files() ->
163163
],
164164
[
165165
<<"lib/elixir/lib/list/chars.ex">>,
166-
<<"lib/elixir/lib/module/checker.ex">>,
167166
<<"lib/elixir/lib/module/locals_tracker.ex">>,
168167
<<"lib/elixir/lib/module/parallel_checker.ex">>,
169168
<<"lib/elixir/lib/module/types/remote.ex">>,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Code.require_file("../../test_helper.exs", __DIR__)
22

3-
defmodule Module.Checker.IntegrationTest do
3+
defmodule Module.Types.IntegrationTest do
44
use ExUnit.Case
55

66
import ExUnit.CaptureIO

lib/mix/lib/mix/compilers/application_tracer.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ defmodule Mix.Compilers.ApplicationTracer do
7878
)
7979

8080
warnings
81-
|> Module.Checker.group_warnings()
82-
|> Module.Checker.emit_warnings()
81+
|> Module.ParallelChecker.group_warnings()
82+
|> Module.ParallelChecker.emit_warnings()
8383
end
8484

8585
# ../elixir/ebin/elixir.beam -> elixir

0 commit comments

Comments
 (0)