Skip to content

Commit 48b838a

Browse files
gldubcjosevalim
authored andcommitted
Fix formatting of map-like types in warnings (#11351)
This came up in issue #11204: When emitting a warning for a type unification error, the compiler overly simplifies the formatting of types when these are maps or unions of maps. To address this, we recursively check for maps inside of a union type when comparing it to another map-like type.
1 parent 5aa1c9a commit 48b838a

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

lib/elixir/lib/module/types.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ defmodule Module.Types do
354354
end
355355

356356
defp simplify_type?(type, other) do
357-
map_type?(type) and not map_type?(other)
357+
map_like_type?(type) and not map_like_type?(other)
358358
end
359359

360360
## EXPRESSION FORMATTING
@@ -505,6 +505,10 @@ defmodule Module.Types do
505505
defp map_type?({:map, _}), do: true
506506
defp map_type?(_other), do: false
507507

508+
defp map_like_type?({:map, _}), do: true
509+
defp map_like_type?({:union, union}), do: Enum.any?(union, &map_like_type?/1)
510+
defp map_like_type?(_other), do: false
511+
508512
defp atom_type?(:atom), do: true
509513
defp atom_type?({:atom, _}), do: false
510514
defp atom_type?({:union, union}), do: Enum.all?(union, &atom_type?/1)

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,41 @@ defmodule Module.Types.TypesTest do
606606
%{foo: ^other_key} = event
607607
"""
608608
end
609+
610+
test "expands map when maps are nested" do
611+
string =
612+
warning(
613+
[map1, map2],
614+
(
615+
[_var1, _var2] = [map1, map2]
616+
%{} = map1
617+
%{} = map2.subkey
618+
)
619+
)
620+
621+
assert string == """
622+
incompatible types:
623+
624+
%{subkey: var1, optional(dynamic()) => dynamic()} !~ %{optional(dynamic()) => dynamic()} | %{optional(dynamic()) => dynamic()}
625+
626+
in expression:
627+
628+
# types_test.ex:5
629+
map2.subkey
630+
631+
where "map2" was given the type %{optional(dynamic()) => dynamic()} | %{optional(dynamic()) => dynamic()} in:
632+
633+
# types_test.ex:3
634+
[_var1, _var2] = [map1, map2]
635+
636+
where "map2" was given the type %{subkey: var1, optional(dynamic()) => dynamic()} (due to calling var.field) in:
637+
638+
# types_test.ex:5
639+
map2.subkey
640+
641+
HINT: "var.field" (without parentheses) implies "var" is a map() while "var.fun()" (with parentheses) implies "var" is an atom()
642+
"""
643+
end
609644
end
610645

611646
describe "regressions" do

0 commit comments

Comments
 (0)