Skip to content

Commit f044def

Browse files
committed
Handle recursive vars in map values (#10498)
1 parent 05c9cca commit f044def

File tree

3 files changed

+40
-12
lines changed

3 files changed

+40
-12
lines changed

lib/elixir/lib/module/types/unify.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,11 @@ defmodule Module.Types.Unify do
166166
end
167167

168168
case unify_result do
169-
{:ok, var_type, context} ->
170-
context = refine_var(var, var_type, stack, context)
169+
{:ok, {:var, ^var}, context} ->
170+
{:ok, {:var, var}, context}
171+
172+
{:ok, res_type, context} ->
173+
context = refine_var(var, res_type, stack, context)
171174
{:ok, {:var, var}, context}
172175

173176
{:error, reason} ->

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,21 @@ defmodule Module.Types.TypesTest do
1313
expr = TypeHelper.expand_expr(patterns, guards, body, __CALLER__)
1414

1515
quote do
16-
unquote(Macro.escape(expr))
17-
|> Module.Types.TypesTest.__expr__()
18-
|> to_warning()
16+
Module.Types.TypesTest.__expr__(unquote(Macro.escape(expr)))
1917
end
2018
end
2119

2220
def __expr__({patterns, guards, body}) do
2321
with {:ok, _types, context} <-
2422
Pattern.of_head(patterns, guards, TypeHelper.new_stack(), TypeHelper.new_context()),
25-
{:ok, type, context} <- Expr.of_expr(body, TypeHelper.new_stack(), context) do
23+
{:ok, _type, context} <- Expr.of_expr(body, TypeHelper.new_stack(), context) do
2624
case context.warnings do
27-
[warning] -> {:warning, warning}
28-
_ -> flunk("expexted error, got: #{inspect(Types.lift_type(type, context))}")
25+
[warning] -> to_message(:warning, warning)
26+
_ -> :none
2927
end
3028
else
3129
{:error, {type, reason, context}} ->
32-
{:error, {type, reason, context}}
30+
to_message(:error, {type, reason, context})
3331
end
3432
end
3533

@@ -51,13 +49,13 @@ defmodule Module.Types.TypesTest do
5149
min
5250
end
5351

54-
defp to_warning({:warning, {module, warning, _location}}) do
52+
defp to_message(:warning, {module, warning, _location}) do
5553
warning
5654
|> module.format_warning()
5755
|> IO.iodata_to_binary()
5856
end
5957

60-
defp to_warning({:error, {type, reason, context}}) do
58+
defp to_message(:error, {type, reason, context}) do
6159
{Module.Types, error, _location} = Module.Types.error_to_warning(type, reason, context)
6260

6361
error
@@ -472,4 +470,20 @@ defmodule Module.Types.TypesTest do
472470
"""
473471
end
474472
end
473+
474+
describe "regressions" do
475+
test "recursive map fields" do
476+
assert warning(
477+
[queried],
478+
with(
479+
true <- is_nil(queried.foo.bar),
480+
_ = queried.foo
481+
) do
482+
%{foo: %{other_id: _other_id} = foo} = queried
483+
%{other_id: id} = foo
484+
%{id: id}
485+
end
486+
) == :none
487+
end
488+
end
475489
end

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,22 @@ defmodule Module.Types.UnifyTest do
350350
assert {{:var, 2}, var_context} = new_var({:baz, [version: 2], nil}, var_context)
351351

352352
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, var_context)
353-
assert {:ok, {:var, _}, _context} = unify({:var, 1}, {:var, 0}, context)
353+
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 0}, context)
354+
assert context.types[0] == {:var, 1}
355+
assert context.types[1] == {:var, 0}
356+
357+
assert {:ok, {:var, _}, context} = unify({:var, 0}, :tuple, var_context)
358+
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 0}, context)
359+
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, context)
360+
assert context.types[0] == {:var, 1}
361+
assert context.types[1] == :tuple
354362

355363
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, var_context)
356364
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 2}, context)
357365
assert {:ok, {:var, _}, _context} = unify({:var, 2}, {:var, 0}, context)
366+
assert context.types[0] == :unbound
367+
assert context.types[1] == {:var, 0}
368+
assert context.types[2] == {:var, 1}
358369

359370
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, var_context)
360371

0 commit comments

Comments
 (0)