Skip to content

Commit 86d3751

Browse files
committed
Respect struct field order when printing types
1 parent 49e3209 commit 86d3751

File tree

3 files changed

+38
-31
lines changed

3 files changed

+38
-31
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,36 +1822,30 @@ defmodule Module.Types.Descr do
18221822
case tag do
18231823
:closed ->
18241824
with %{__struct__: struct_descr} <- fields,
1825-
{_, [struct]} <- atom_fetch(struct_descr) do
1826-
fields = Map.delete(fields, :__struct__)
1825+
{_, [struct]} <- atom_fetch(struct_descr),
1826+
[_ | _] = info <- maybe_struct(struct),
1827+
true <- map_size(fields) == length(info) + 1,
1828+
true <- Enum.all?(info, &is_map_key(fields, &1.field)) do
1829+
collapse? = Keyword.get(opts, :collapse_structs, false)
18271830

18281831
fields =
1829-
with true <- Keyword.get(opts, :collapse_structs, false),
1830-
[_ | _] = info <- maybe_struct(struct),
1831-
true <- Enum.all?(info, &is_map_key(fields, &1.field)) do
1832-
Enum.reduce(info, fields, fn %{field: field}, acc ->
1833-
# TODO: This should consider the struct default value
1834-
if Map.fetch!(acc, field) == term() do
1835-
Map.delete(acc, field)
1836-
else
1837-
acc
1838-
end
1839-
end)
1840-
else
1841-
_ -> fields
1842-
end
1832+
for %{field: field} <- info,
1833+
type = Map.fetch!(fields, field),
1834+
# TODO: This should consider the struct default type
1835+
not collapse? or type != term(),
1836+
do: {field, type}
18431837

18441838
{:%, [],
18451839
[
18461840
literal_to_quoted(struct),
18471841
{:%{}, [], map_fields_to_quoted(tag, fields, opts)}
18481842
]}
18491843
else
1850-
_ -> {:%{}, [], map_fields_to_quoted(tag, fields, opts)}
1844+
_ -> {:%{}, [], map_fields_to_quoted(tag, Enum.sort(fields), opts)}
18511845
end
18521846

18531847
:open ->
1854-
{:%{}, [], [{:..., [], nil} | map_fields_to_quoted(tag, fields, opts)]}
1848+
{:%{}, [], [{:..., [], nil} | map_fields_to_quoted(tag, Enum.sort(fields), opts)]}
18551849
end
18561850
end
18571851

@@ -1863,8 +1857,7 @@ defmodule Module.Types.Descr do
18631857
end
18641858
end
18651859

1866-
defp map_fields_to_quoted(tag, map, opts) do
1867-
sorted = Enum.sort(Map.to_list(map))
1860+
defp map_fields_to_quoted(tag, sorted, opts) do
18681861
keyword? = Inspect.List.keyword?(sorted)
18691862

18701863
for {key, type} <- sorted,

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
Code.require_file("type_helper.exs", __DIR__)
22

3+
defmodule Decimal do
4+
defstruct [:sign, :coef, :exp]
5+
end
6+
37
defmodule Module.Types.DescrTest do
48
use ExUnit.Case, async: true
59

@@ -1354,8 +1358,8 @@ defmodule Module.Types.DescrTest do
13541358
|> to_quoted_string() ==
13551359
"""
13561360
dynamic(
1357-
:error or {%Decimal{coef: :NaN or :inf, exp: integer(), sign: integer()}, binary()} or
1358-
{%Decimal{coef: :NaN or :inf or integer(), exp: integer(), sign: integer()}, term()}
1361+
:error or {%Decimal{sign: integer(), coef: :NaN or :inf, exp: integer()}, binary()} or
1362+
{%Decimal{sign: integer(), coef: :NaN or :inf or integer(), exp: integer()}, term()}
13591363
)\
13601364
"""
13611365
end
@@ -1470,16 +1474,26 @@ defmodule Module.Types.DescrTest do
14701474
end
14711475

14721476
test "structs" do
1473-
assert open_map(__struct__: atom([URI])) |> to_quoted_string() == "%{..., __struct__: URI}"
1477+
assert open_map(__struct__: atom([URI])) |> to_quoted_string() ==
1478+
"%{..., __struct__: URI}"
14741479

14751480
assert closed_map(__struct__: atom([URI])) |> to_quoted_string() ==
1476-
"%URI{}"
1477-
1478-
assert closed_map(__struct__: atom([URI]), path: atom([nil])) |> to_quoted_string() ==
1479-
"%URI{path: nil}"
1481+
"%{__struct__: URI}"
14801482

14811483
assert closed_map(__struct__: atom([URI, Another])) |> to_quoted_string() ==
14821484
"%{__struct__: Another or URI}"
1485+
1486+
assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: term())
1487+
|> to_quoted_string() ==
1488+
"%Decimal{sign: term(), coef: term(), exp: term()}"
1489+
1490+
assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: term())
1491+
|> to_quoted_string(collapse_structs: true) ==
1492+
"%Decimal{}"
1493+
1494+
assert closed_map(__struct__: atom([Decimal]), coef: term(), exp: term(), sign: integer())
1495+
|> to_quoted_string(collapse_structs: true) ==
1496+
"%Decimal{sign: integer()}"
14831497
end
14841498
end
14851499

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -801,14 +801,14 @@ defmodule Module.Types.ExprTest do
801801
the given type does not have the given key:
802802
803803
dynamic(%URI{
804+
scheme: term(),
804805
authority: term(),
805-
fragment: term(),
806+
userinfo: term(),
806807
host: term(),
807-
path: term(),
808808
port: term(),
809+
path: term(),
809810
query: term(),
810-
scheme: term(),
811-
userinfo: term()
811+
fragment: term()
812812
})
813813
814814
where "x" was given the type:

0 commit comments

Comments
 (0)