Skip to content

Commit e4f7ee4

Browse files
authored
Perform type inference using reverse arrows on all non-branching constructs (#14145)
1 parent c592252 commit e4f7ee4

25 files changed

+1661
-886
lines changed

lib/elixir/lib/module/parallel_checker.ex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ defmodule Module.ParallelChecker do
208208
or if the function does not exist return `{:error, :function}`.
209209
"""
210210
@spec fetch_export(cache(), module(), atom(), arity()) ::
211-
{:ok, mode(), binary() | nil, {:infer, [term()]} | :none}
211+
{:ok, mode(), binary() | nil, {:infer, [term()] | nil, [term()]} | :none}
212212
| :badmodule
213213
| {:badfunction, mode()}
214214
def fetch_export({checker, table}, module, fun, arity) do
@@ -451,10 +451,15 @@ defmodule Module.ParallelChecker do
451451

452452
defp cache_chunk(table, module, exports) do
453453
Enum.each(exports, fn {{fun, arity}, info} ->
454-
# TODO: Match on signature directly in Elixir v1.22+
454+
sig =
455+
case info do
456+
%{sig: {key, _, _} = sig} when key in [:infer, :strong] -> sig
457+
_ -> :none
458+
end
459+
455460
:ets.insert(
456461
table,
457-
{{module, {fun, arity}}, Map.get(info, :deprecated), Map.get(info, :sig, :none)}
462+
{{module, {fun, arity}}, Map.get(info, :deprecated), sig}
458463
)
459464
end)
460465

lib/elixir/lib/module/types.ex

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,18 @@ defmodule Module.Types do
281281
context = fresh_context(context)
282282

283283
try do
284-
{args_types, context} =
284+
{trees, context} =
285285
Pattern.of_head(args, guards, expected, {:infer, expected}, meta, stack, context)
286286

287287
{return_type, context} =
288-
Expr.of_expr(body, stack, context)
288+
Expr.of_expr(body, Descr.term(), body, stack, context)
289+
290+
args_types =
291+
if stack.mode == :traversal do
292+
expected
293+
else
294+
Pattern.of_domain(trees, expected, context)
295+
end
289296

290297
{type_index, inferred} =
291298
add_inferred(inferred, args_types, return_type, total - 1, [])
@@ -301,8 +308,19 @@ defmodule Module.Types do
301308
end
302309
end)
303310

304-
inferred = {:infer, Enum.reverse(clauses_types)}
305-
{inferred, mapping, restore_context(context, clauses_context)}
311+
domain =
312+
case clauses_types do
313+
[_] ->
314+
nil
315+
316+
_ ->
317+
clauses_types
318+
|> Enum.map(fn {args, _} -> args end)
319+
|> Enum.zip_with(fn types -> Enum.reduce(types, &Descr.union/2) end)
320+
end
321+
322+
inferred = {:infer, domain, Enum.reverse(clauses_types)}
323+
{inferred, mapping, restore_context(clauses_context, context)}
306324
end
307325

308326
# We check for term equality of types as an optimization
@@ -399,7 +417,7 @@ defmodule Module.Types do
399417
%{context | vars: %{}, failed: false}
400418
end
401419

402-
defp restore_context(%{vars: vars, failed: failed}, later_context) do
420+
defp restore_context(later_context, %{vars: vars, failed: failed}) do
403421
%{later_context | vars: vars, failed: failed}
404422
end
405423

0 commit comments

Comments
 (0)