Skip to content

Commit e94131d

Browse files
committed
Infer at once
1 parent 77bdfd4 commit e94131d

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ $(KERNEL): lib/elixir/src/* lib/elixir/lib/*.ex lib/elixir/lib/*/*.ex lib/elixir
107107
fi
108108
@ echo "==> elixir (compile)";
109109
$(Q) cd lib/elixir && ../../$(ELIXIRC_MIN_SIG) "lib/**/*.ex" -o ebin;
110+
$(Q) bin/elixir lib/elixir/scripts/infer.exs;
110111

111112
$(APP): lib/elixir/src/elixir.app.src lib/elixir/ebin VERSION $(GENERATE_APP)
112113
$(Q) $(GENERATE_APP) $(VERSION)

lib/elixir/scripts/infer.exs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
parent = self()
2+
{:ok, checker} = Module.ParallelChecker.start_link()
3+
4+
{time, modules} =
5+
:timer.tc(fn ->
6+
[_ | _] = paths = Path.wildcard(Path.join(__DIR__, "../ebin/Elixir.*.beam"))
7+
8+
paths
9+
|> Task.async_stream(
10+
fn path ->
11+
path = Path.expand(path)
12+
Module.ParallelChecker.put(parent, checker)
13+
cache = Module.ParallelChecker.get()
14+
binary = File.read!(path)
15+
16+
{:ok, {_, [{:debug_info, debug_info}, {_, checker_blob}]}} =
17+
:beam_lib.chunks(binary, [:debug_info, ~c"ExCk"])
18+
19+
{:debug_info_v1, _backend, {:elixir_v1, module_map, _specs}} = debug_info
20+
21+
%{module: module, file: file, attributes: attributes, definitions: definitions} =
22+
module_map
23+
24+
{_, checker} = :erlang.binary_to_term(checker_blob)
25+
env = :elixir_env.new()
26+
27+
# We assume that all private functions have been invoked at this point
28+
private =
29+
for {fun_arity, kind, _, _} <- definitions, kind in [:defp, :defmacrop], do: fun_arity
30+
31+
{signatures, _} =
32+
Module.Types.infer(module, file, attributes, definitions, private, env, cache)
33+
34+
checker =
35+
update_in(checker.exports, fn exports ->
36+
for {fun, info} <- exports do
37+
{fun, %{info | sig: Map.get(signatures, fun, info.sig)}}
38+
end
39+
end)
40+
41+
[{"ExCk", checker_chunk}] = :elixir_erl.checker_chunk(checker, [])
42+
{:ok, ^module, chunks} = :beam_lib.all_chunks(binary)
43+
44+
{:ok, new_binary} =
45+
chunks
46+
|> List.keyreplace(~c"ExCk", 0, {~c"ExCk", checker_chunk})
47+
|> :beam_lib.build_module()
48+
49+
File.write!(path, new_binary)
50+
{module, path}
51+
end,
52+
timeout: :infinity
53+
)
54+
|> Enum.map(fn {:ok, result} -> result end)
55+
end)
56+
57+
IO.puts(:stderr, ["Type inferred stdlib in ", Integer.to_string(div(time, 1000)), "ms"])
58+
59+
{time, _} =
60+
:timer.tc(fn ->
61+
Module.ParallelChecker.verify(checker, modules)
62+
end)
63+
64+
IO.puts(:stderr, ["Type checked stdlib in ", Integer.to_string(div(time, 1000)), "ms"])

0 commit comments

Comments
 (0)