Skip to content

Commit 89e5788

Browse files
michallepickijosevalim
authored andcommitted
Tweak type unification to fix infinite loop with recursive vars (#11664)
1 parent 67cf14c commit 89e5788

File tree

3 files changed

+62
-30
lines changed

3 files changed

+62
-30
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ defmodule Module.Types.Unify do
4343
{:ok, same, context}
4444
end
4545

46-
def unify(type, {:var, var}, stack, context) do
47-
unify_var(var, type, stack, context, _var_source = false)
48-
end
49-
5046
def unify({:var, var}, type, stack, context) do
5147
unify_var(var, type, stack, context, _var_source = true)
5248
end
5349

50+
def unify(type, {:var, var}, stack, context) do
51+
unify_var(var, type, stack, context, _var_source = false)
52+
end
53+
5454
def unify({:tuple, n, sources}, {:tuple, n, targets}, stack, context) do
5555
result =
5656
map_reduce_ok(Enum.zip(sources, targets), context, fn {source, target}, context ->

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

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,20 @@ defmodule Module.Types.TypesTest do
200200
# types_test.ex:1
201201
is_binary(y)
202202
203-
where "y" was given the same type as "x" in:
203+
where "x" was given the same type as "y" in:
204204
205205
# types_test.ex:1
206206
x = y
207207
208-
where "y" was given the type binary() in:
208+
where "y" was given the type integer() in:
209209
210210
# types_test.ex:1
211-
is_binary(y)
211+
is_integer(x)
212212
213-
where "x" was given the type integer() in:
213+
where "y" was given the type binary() in:
214214
215215
# types_test.ex:1
216-
is_integer(x)
216+
is_binary(y)
217217
"""
218218
end
219219

@@ -256,20 +256,20 @@ defmodule Module.Types.TypesTest do
256256
# types_test.ex:1
257257
is_binary(y)
258258
259-
where "y" was given the same type as "x" in:
259+
where "x" was given the same type as "y" in:
260260
261261
# types_test.ex:1
262262
x = y
263263
264-
where "y" was given the type binary() in:
264+
where "y" was given the type integer() in:
265265
266266
# types_test.ex:1
267-
is_binary(y)
267+
is_integer(x)
268268
269-
where "x" was given the type integer() in:
269+
where "y" was given the type binary() in:
270270
271271
# types_test.ex:1
272-
is_integer(x)
272+
is_binary(y)
273273
"""
274274
end
275275

@@ -443,7 +443,17 @@ defmodule Module.Types.TypesTest do
443443
# types_test.ex:5
444444
%{"id" => user_id} = user
445445
446-
where "user" was given the same type as "amount" in:
446+
where "amount" was given the type binary() in:
447+
448+
# types_test.ex:3
449+
%{"amount" => amount} = event
450+
451+
where "amount" was given the same type as "user" in:
452+
453+
# types_test.ex:4
454+
%{"user" => user} = event
455+
456+
where "user" was given the type binary() in:
447457
448458
# types_test.ex:4
449459
%{"user" => user} = event
@@ -452,11 +462,6 @@ defmodule Module.Types.TypesTest do
452462
453463
# types_test.ex:5
454464
%{"id" => user_id} = user
455-
456-
where "amount" was given the type binary() in:
457-
458-
# types_test.ex:3
459-
%{"amount" => amount} = event
460465
"""
461466
end
462467

@@ -700,5 +705,32 @@ defmodule Module.Types.TypesTest do
700705
)
701706
) == :none
702707
end
708+
709+
test "other recursive" do
710+
assert warning(
711+
[x, y],
712+
(
713+
key_var = y
714+
%{^key_var => _value} = x
715+
key_var2 = y
716+
%{^key_var2 => _value2} = x
717+
y.z
718+
)
719+
) == :none
720+
end
721+
722+
test "other recursive2" do
723+
assert warning(
724+
[x, y],
725+
(
726+
key_var = y
727+
%{^key_var => _value} = x
728+
key_var2 = y
729+
%{^key_var2 => _value2} = x
730+
key_var3 = y
731+
%{^key_var3 => _value3} = x
732+
)
733+
) == :none
734+
end
703735
end
704736
end

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -502,25 +502,25 @@ defmodule Module.Types.UnifyTest do
502502
assert {:ok, {:var, _}, context} = unify({:var, 0}, :tuple, var_context)
503503
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 0}, context)
504504
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, context)
505-
assert context.types[0] == {:var, 1}
506-
assert context.types[1] == :tuple
505+
assert context.types[0] == :tuple
506+
assert context.types[1] == {:var, 0}
507507

508508
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, var_context)
509509
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 2}, context)
510510
assert {:ok, {:var, _}, _context} = unify({:var, 2}, {:var, 0}, context)
511-
assert context.types[0] == :unbound
512-
assert context.types[1] == {:var, 0}
513-
assert context.types[2] == {:var, 1}
511+
assert context.types[0] == {:var, 1}
512+
assert context.types[1] == {:var, 2}
513+
assert context.types[2] == :unbound
514514

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

517-
assert {:error, {:unable_unify, {{:var, 0}, {:tuple, 1, [{:var, 0}]}, _}}} =
517+
assert {:error, {:unable_unify, {{:var, 1}, {:tuple, 1, [{:var, 0}]}, _}}} =
518518
unify_lift({:var, 1}, {:tuple, 1, [{:var, 0}]}, context)
519519

520520
assert {:ok, {:var, _}, context} = unify({:var, 0}, {:var, 1}, var_context)
521521
assert {:ok, {:var, _}, context} = unify({:var, 1}, {:var, 2}, context)
522522

523-
assert {:error, {:unable_unify, {{:var, 0}, {:tuple, 1, [{:var, 0}]}, _}}} =
523+
assert {:error, {:unable_unify, {{:var, 2}, {:tuple, 1, [{:var, 0}]}, _}}} =
524524
unify_lift({:var, 2}, {:tuple, 1, [{:var, 0}]}, context)
525525
end
526526

@@ -707,9 +707,9 @@ defmodule Module.Types.UnifyTest do
707707

708708
{{:var, 0}, var_context} = new_var({:foo, [version: 0], nil}, new_context())
709709
{{:var, 1}, var_context} = new_var({:bar, [version: 1], nil}, var_context)
710-
{:ok, {:var, 1}, var_context} = unify({:var, 0}, {:var, 1}, var_context)
711-
assert flatten_union({:var, 0}, var_context) == [{:var, 0}]
712-
assert flatten_union({:var, 1}, var_context) == [{:var, 0}]
710+
{:ok, {:var, 0}, var_context} = unify({:var, 0}, {:var, 1}, var_context)
711+
assert flatten_union({:var, 0}, var_context) == [{:var, 1}]
712+
assert flatten_union({:var, 1}, var_context) == [{:var, 1}]
713713
end
714714

715715
test "format_type/1" do

0 commit comments

Comments
 (0)