Skip to content

Commit 77bdfd4

Browse files
committed
Simplify inference entry point
1 parent 9a9e052 commit 77bdfd4

8 files changed

Lines changed: 67 additions & 84 deletions

File tree

lib/elixir/lib/code.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,10 +1741,10 @@ defmodule Code do
17411741
module. Type checking will be executed regardless of the value of this option.
17421742
Defaults to `true`, which is equivalent to setting it to `[:elixir]` only.
17431743
1744-
When setting this option, we recommend running `mix clean` so the current module
1745-
may be compiled from scratch. `mix test` automatically disables this option via
1746-
the `:test_elixirc_options` project configuration, as there is typically no need
1747-
to infer signatures for test files.
1744+
When setting this option, we recommend running `mix clean` so the modules can be
1745+
recompiled with the new behaviour. `mix test` automatically disables this option
1746+
via the `:test_elixirc_options` project configuration, as there is typically no
1747+
need to infer signatures for test files.
17481748
17491749
* `:relative_paths` - when `true`, uses relative paths in quoted nodes,
17501750
warnings, and errors generated by the compiler. Note disabling this option

lib/elixir/lib/module/parallel_checker.ex

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,6 @@ defmodule Module.ParallelChecker do
220220
end
221221
end
222222

223-
@doc """
224-
Test cache.
225-
"""
226-
def test_cache do
227-
{:ok, cache} = start_link()
228-
cache
229-
end
230-
231223
@doc """
232224
Returns the export kind and deprecation reason for the given MFA from
233225
the cache. If the module does not exist return `:badmodule`,

lib/elixir/lib/module/types.ex

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ defmodule Module.Types do
3434
@no_infer [behaviour_info: 1]
3535

3636
@doc false
37-
def infer(module, file, attrs, defs, private, used_private, env, {_, cache}) do
37+
def infer(module, file, attrs, defs, used_private, env, {_, cache}) do
3838
# We don't care about inferring signatures for protocols,
3939
# those will be replaced anyway. There is also nothing to
4040
# infer if there is no cache system, we only do traversals.
@@ -72,11 +72,10 @@ defmodule Module.Types do
7272

7373
stack = stack(:infer, file, module, {:__info__, 1}, env, cache, handler)
7474

75-
{types, %{local_sigs: reachable_sigs} = context} =
75+
{types, private, %{local_sigs: reachable_sigs} = context} =
7676
for {fun_arity, kind, meta, _clauses} = def <- defs,
77-
kind in [:def, :defmacro],
78-
reduce: {[], context()} do
79-
{types, context} ->
77+
reduce: {[], [], context()} do
78+
{types, private, context} when kind in [:def, :defmacro] ->
8079
# Optimized version of finder, since we already have the definition
8180
finder = fn _ ->
8281
default_domain(infer_mode(kind, infer_signatures?), def, fun_arity, impl)
@@ -85,10 +84,13 @@ defmodule Module.Types do
8584
{_kind, inferred, context} = local_handler(meta, fun_arity, stack, context, finder)
8685

8786
if infer_signatures? and kind == :def and fun_arity not in @no_infer do
88-
{[{fun_arity, inferred} | types], context}
87+
{[{fun_arity, inferred} | types], private, context}
8988
else
90-
{types, context}
89+
{types, private, context}
9190
end
91+
92+
{types, private, context} ->
93+
{types, [def | private], context}
9294
end
9395

9496
# Now traverse all used privates to find any other private that have been used by them.
@@ -102,8 +104,8 @@ defmodule Module.Types do
102104

103105
{unreachable, _context} =
104106
Enum.reduce(private, {[], context}, fn
105-
{fun_arity, kind, _meta, _defaults} = info, {unreachable, context} ->
106-
warn_unused_def(info, used_sigs, env)
107+
{fun_arity, kind, meta, _clauses}, {unreachable, context} ->
108+
warn_unused_def(fun_arity, kind, meta, used_sigs, env)
107109

108110
# Find anything undefined within unused functions
109111
{_kind, _inferred, context} = local_handler([], fun_arity, stack, context, finder)
@@ -170,29 +172,30 @@ defmodule Module.Types do
170172
:elixir_errors.module_error(Helpers.with_span(meta, fun), env, __MODULE__, tuple)
171173
end
172174

173-
defp warn_unused_def({_fun_arity, _kind, false, _}, _used, _env) do
174-
:ok
175-
end
175+
defp warn_unused_def(fun_arity, kind, meta, used, env) do
176+
default = Keyword.get(meta, :defaults, 0)
176177

177-
defp warn_unused_def({fun_arity, kind, meta, 0}, used, env) do
178-
case is_map_key(used, fun_arity) do
179-
true -> :ok
180-
false -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, fun_arity, kind})
181-
end
178+
cond do
179+
Keyword.get(meta, :context) != nil ->
180+
:ok
182181

183-
:ok
184-
end
182+
default == 0 ->
183+
case is_map_key(used, fun_arity) do
184+
true -> :ok
185+
false -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, fun_arity, kind})
186+
end
185187

186-
defp warn_unused_def({tuple, kind, meta, default}, used, env) when default > 0 do
187-
{name, arity} = tuple
188-
min = arity - default
189-
max = arity
188+
default > 0 ->
189+
{name, arity} = fun_arity
190+
min = arity - default
191+
max = arity
190192

191-
case min_reachable_default(max, min, :none, name, used) do
192-
:none -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, tuple, kind})
193-
^min -> :ok
194-
^max -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, tuple})
195-
diff -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, tuple, diff})
193+
case min_reachable_default(max, min, :none, name, used) do
194+
:none -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_def, fun_arity, kind})
195+
^min -> :ok
196+
^max -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, fun_arity})
197+
diff -> :elixir_errors.file_warn(meta, env, __MODULE__, {:unused_args, fun_arity, diff})
198+
end
196199
end
197200

198201
:ok

lib/elixir/src/elixir_def.erl

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -97,43 +97,27 @@ fetch_definitions(Module, E) ->
9797
error:badarg -> []
9898
end,
9999

100-
fetch_definition(Entries, E, Module, Set, Bag, [], []).
100+
fetch_definition(Entries, E, Module, Set, Bag, []).
101101

102-
fetch_definition([Tuple | T], E, Module, Set, Bag, All, Private) ->
103-
[{_, Kind, Meta, _, Check, {MaxDefaults, _, Defaults}}] = ets:lookup(Set, {def, Tuple}),
102+
fetch_definition([Tuple | T], E, Module, Set, Bag, All) ->
103+
[{_, Kind, Meta, _, _, {MaxDefaults, _, _}}] = ets:lookup(Set, {def, Tuple}),
104104

105105
try ets:lookup_element(Bag, {clauses, Tuple}, 2) of
106106
Clauses ->
107-
NewAll =
108-
[{Tuple, Kind, add_defaults_to_meta(MaxDefaults, Meta), Clauses} | All],
109-
NewPrivate =
110-
case (Kind == defp) orelse (Kind == defmacrop) of
111-
true ->
112-
Metas = head_and_definition_meta(Check, Meta, MaxDefaults - Defaults, All),
113-
[{Tuple, Kind, Metas, MaxDefaults} | Private];
114-
false ->
115-
Private
116-
end,
117-
fetch_definition(T, E, Module, Set, Bag, NewAll, NewPrivate)
107+
NewAll = [{Tuple, Kind, add_defaults_to_meta(MaxDefaults, Meta), Clauses} | All],
108+
fetch_definition(T, E, Module, Set, Bag, NewAll)
118109
catch
119110
error:badarg ->
120111
elixir_errors:module_error(Meta, E, ?MODULE, {function_head, Kind, Tuple}),
121-
fetch_definition(T, E, Module, Set, Bag, All, Private)
112+
fetch_definition(T, E, Module, Set, Bag, All)
122113
end;
123114

124-
fetch_definition([], _E, _Module, _Set, _Bag, All, Private) ->
125-
{All, Private}.
115+
fetch_definition([], _E, _Module, _Set, _Bag, All) ->
116+
All.
126117

127118
add_defaults_to_meta(0, Meta) -> Meta;
128119
add_defaults_to_meta(Defaults, Meta) -> [{defaults, Defaults} | Meta].
129120

130-
head_and_definition_meta(none, _Meta, _HeadDefaults, _All) ->
131-
false;
132-
head_and_definition_meta(_, Meta, 0, _All) ->
133-
Meta;
134-
head_and_definition_meta(_, _Meta, _HeadDefaults, [{_, _, HeadMeta, _} | _]) ->
135-
HeadMeta.
136-
137121
%% Section for storing definitions
138122

139123
store_definition(Kind, {Call, Body}, Pos) ->
@@ -168,11 +152,7 @@ store_definition(Kind, HasNoUnquote, Call, Body, #{line := Line} = E) ->
168152
_ -> Column
169153
end,
170154

171-
CheckClauses = if
172-
Context /= [] -> none;
173-
HasNoUnquote -> all;
174-
true -> unused_only
175-
end,
155+
CheckClauses = (Context == []) andalso HasNoUnquote,
176156

177157
%% Check if there is a file information in the definition.
178158
%% If so, we assume this come from another source and
@@ -223,7 +203,7 @@ store_definition(Meta, Kind, CheckClauses, Name, Arity, DefaultsArgs, Guards, Bo
223203

224204
store_definition(CheckClauses, Kind, Meta, Name, Arity, File,
225205
Module, DefaultsLength, Clauses),
226-
[store_definition(none, Kind, Meta, Name, length(DefaultArgs), File,
206+
[store_definition(false, Kind, [{context, ?MODULE} | Meta], Name, length(DefaultArgs), File,
227207
Module, 0, [Default]) || {_, DefaultArgs, _, _} = Default <- Defaults],
228208

229209
run_on_definition_callbacks(Meta, Kind, Module, Name, DefaultsArgs, Guards, Body, E),
@@ -281,11 +261,10 @@ run_on_definition_callbacks(Meta, Kind, Module, Name, Args, Guards, Body, E) ->
281261
ok.
282262

283263
store_definition(CheckClauses, Kind, Meta, Name, Arity, File, Module, Defaults, Clauses)
284-
when CheckClauses == all; CheckClauses == none; CheckClauses == unused_only ->
264+
when is_boolean(CheckClauses) ->
285265
{Set, Bag} = elixir_module:data_tables(Module),
286266
Tuple = {Name, Arity},
287267
HasBody = Clauses =/= [],
288-
CheckAll = CheckClauses == all,
289268

290269
if
291270
Defaults > 0 ->
@@ -299,7 +278,7 @@ store_definition(CheckClauses, Kind, Meta, Name, Arity, File, Module, Defaults,
299278
[{_, StoredKind, StoredMeta, StoredFile, StoredCheck, {StoredDefaults, LastHasBody, LastDefaults}}] ->
300279
check_valid_kind(Meta, File, Name, Arity, Kind, StoredKind, StoredFile, StoredMeta),
301280
check_valid_defaults(Meta, File, Name, Arity, Kind, Defaults, StoredMeta, StoredDefaults, LastDefaults, HasBody, LastHasBody),
302-
(CheckAll and (StoredCheck == all)) andalso
281+
(CheckClauses and StoredCheck) andalso
303282
check_valid_clause(Meta, File, Name, Arity, Kind, Set, StoredMeta, StoredFile, Clauses),
304283

305284
{max(Defaults, StoredDefaults), StoredMeta};
@@ -308,7 +287,7 @@ store_definition(CheckClauses, Kind, Meta, Name, Arity, File, Module, Defaults,
308287
{Defaults, Meta}
309288
end,
310289

311-
CheckAll andalso ets:insert(Set, {?last_def, Tuple}),
290+
CheckClauses andalso ets:insert(Set, {?last_def, Tuple}),
312291
ets:insert(Bag, [{{clauses, Tuple}, Clause} || Clause <- Clauses]),
313292
ets:insert(Set, {{def, Tuple}, Kind, FirstMeta, File, CheckClauses, {MaxDefaults, HasBody, Defaults}}).
314293

lib/elixir/src/elixir_erl.erl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
-module(elixir_erl).
88
-export([elixir_to_erl/1, elixir_to_erl/2, definition_to_anonymous/5, compile/2, consolidate/4,
9-
get_ann/1, debug_info/4, scope/2, checker_version/0, format_error/1]).
9+
get_ann/1, debug_info/4, scope/2, checker_chunk/2, checker_version/0, format_error/1]).
1010
-include("elixir.hrl").
1111
-define(typespecs, 'Elixir.Kernel.Typespec').
1212

@@ -140,6 +140,13 @@ consolidate(Map, Checker, TypeSpecs, DocsChunk) ->
140140
CheckerChunk = checker_chunk(Checker, chunk_opts(Map)),
141141
load_form(Map, Prefix, Forms, TypeSpecs, DocsChunk ++ CheckerChunk).
142142

143+
%% Used for updating type checking chunks in Elixir
144+
145+
checker_chunk(nil, _ChunkOpts) ->
146+
[];
147+
checker_chunk(Contents, ChunkOpts) ->
148+
[{<<"ExCk">>, term_to_binary({checker_version(), Contents}, ChunkOpts)}].
149+
143150
%% Dynamic compilation hook, used in regular compiler
144151

145152
compile(#{module := Module, anno := Anno} = BaseMap, Signatures) ->
@@ -642,11 +649,6 @@ signature_to_binary(_, Name, Signature) ->
642649
Doc = 'Elixir.Inspect.Algebra':format('Elixir.Code':quoted_to_algebra(Quoted), infinity),
643650
'Elixir.IO':iodata_to_binary(Doc).
644651

645-
checker_chunk(nil, _ChunkOpts) ->
646-
[];
647-
checker_chunk(Contents, ChunkOpts) ->
648-
[{<<"ExCk">>, term_to_binary({checker_version(), Contents}, ChunkOpts)}].
649-
650652
checker_chunk(Map, Def, Signatures, ChunkOpts) ->
651653
#{deprecated := Deprecated, defines_behaviour := DefinesBehaviour, attributes := Attributes} = Map,
652654
DeprecatedMap = maps:from_list(Deprecated),

lib/elixir/src/elixir_module.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ compile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, E) ->
168168
elixir_erl_compiler:spawn(fun() ->
169169
PersistedAttributes = ets:lookup_element(DataBag, persisted_attributes, 2),
170170
Attributes = attributes(DataSet, DataBag, PersistedAttributes),
171-
{AllDefinitions, Private} = elixir_def:fetch_definitions(Module, E),
171+
AllDefinitions = elixir_def:fetch_definitions(Module, E),
172172

173173
OnLoadAttribute = lists:keyfind(on_load, 1, Attributes),
174174
validate_on_load_attribute(OnLoadAttribute, AllDefinitions, DataBag, Line, E),
@@ -196,7 +196,7 @@ compile(Meta, Module, ModuleAsCharlist, Block, Vars, Prune, E) ->
196196
true -> {#{}, []};
197197
false ->
198198
UsedPrivate = bag_lookup_element(DataBag, used_private, 2),
199-
'Elixir.Module.Types':infer(Module, File, Attributes, AllDefinitions, Private, UsedPrivate, E, CheckerInfo)
199+
'Elixir.Module.Types':infer(Module, File, Attributes, AllDefinitions, UsedPrivate, E, CheckerInfo)
200200
end,
201201

202202
RawCompileOpts = bag_lookup_element(DataBag, {accumulate, compile}, 2),

lib/elixir/src/elixir_overridable.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ store(Set, Module, Tuple, {_, Count, Def, Overridden}, Hidden) ->
9696
case Overridden of
9797
false ->
9898
ets:update_element(Set, {overridable, Tuple}, {?overridden_pos, true}),
99-
elixir_def:store_definition(none, FinalKind, Meta, FinalName, FinalArity,
99+
elixir_def:store_definition(false, FinalKind, Meta, FinalName, FinalArity,
100100
File, Module, Defaults, FinalClauses);
101101
true ->
102102
ok

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,14 @@ defmodule TypeHelper do
141141
end
142142

143143
defp new_stack(mode) do
144-
cache = if mode == :infer, do: :none, else: Module.ParallelChecker.test_cache()
144+
cache =
145+
if mode == :infer do
146+
:none
147+
else
148+
{:ok, cache} = Module.ParallelChecker.start_link()
149+
cache
150+
end
151+
145152
handler = fn _, fun_arity, _, _ -> raise "no local lookup for: #{inspect(fun_arity)}" end
146153
Types.stack(mode, "types_test.ex", TypesTest, {:test, 0}, [], cache, handler)
147154
end

0 commit comments

Comments
 (0)