@@ -367,16 +367,21 @@ defmodule Module.Types.Descr do
367367
368368 @ doc """
369369 Converts a descr to its quoted representation.
370+
371+ ## Options
372+
373+ * `:collapse_structs` - do not show struct fields that match
374+ their default type
370375 """
371- def to_quoted ( descr ) do
376+ def to_quoted ( descr , opts \\ [ ] ) do
372377 if term_type? ( descr ) do
373378 { :term , [ ] , [ ] }
374379 else
375380 # Dynamic always come first for visibility
376381 { dynamic , descr } =
377382 case :maps . take ( :dynamic , descr ) do
378383 :error -> { [ ] , descr }
379- { dynamic , descr } -> { to_quoted ( :dynamic , dynamic ) , descr }
384+ { dynamic , descr } -> { to_quoted ( :dynamic , dynamic , opts ) , descr }
380385 end
381386
382387 # Merge empty list and list together if they both exist
@@ -385,7 +390,7 @@ defmodule Module.Types.Descr do
385390 % { list: list , bitmap: bitmap } when ( bitmap &&& @ bit_empty_list ) != 0 ->
386391 descr = descr |> Map . delete ( :list ) |> Map . replace! ( :bitmap , bitmap - @ bit_empty_list )
387392
388- case list_to_quoted ( list , :list ) do
393+ case list_to_quoted ( list , :list , opts ) do
389394 [ ] -> { [ { :empty_list , [ ] , [ ] } ] , descr }
390395 unions -> { unions , descr }
391396 end
@@ -396,7 +401,9 @@ defmodule Module.Types.Descr do
396401
397402 unions =
398403 dynamic ++
399- Enum . sort ( extra ++ Enum . flat_map ( descr , fn { key , value } -> to_quoted ( key , value ) end ) )
404+ Enum . sort (
405+ extra ++ Enum . flat_map ( descr , fn { key , value } -> to_quoted ( key , value , opts ) end )
406+ )
400407
401408 case unions do
402409 [ ] -> { :none , [ ] , [ ] }
@@ -405,19 +412,19 @@ defmodule Module.Types.Descr do
405412 end
406413 end
407414
408- defp to_quoted ( :atom , val ) , do: atom_to_quoted ( val )
409- defp to_quoted ( :bitmap , val ) , do: bitmap_to_quoted ( val )
410- defp to_quoted ( :dynamic , descr ) , do: dynamic_to_quoted ( descr )
411- defp to_quoted ( :map , dnf ) , do: map_to_quoted ( dnf )
412- defp to_quoted ( :list , dnf ) , do: list_to_quoted ( dnf , :non_empty_list )
413- defp to_quoted ( :tuple , dnf ) , do: tuple_to_quoted ( dnf )
415+ defp to_quoted ( :atom , val , _opts ) , do: atom_to_quoted ( val )
416+ defp to_quoted ( :bitmap , val , _opts ) , do: bitmap_to_quoted ( val )
417+ defp to_quoted ( :dynamic , descr , opts ) , do: dynamic_to_quoted ( descr , opts )
418+ defp to_quoted ( :map , dnf , opts ) , do: map_to_quoted ( dnf , opts )
419+ defp to_quoted ( :list , dnf , opts ) , do: list_to_quoted ( dnf , :non_empty_list , opts )
420+ defp to_quoted ( :tuple , dnf , opts ) , do: tuple_to_quoted ( dnf , opts )
414421
415422 @ doc """
416423 Converts a descr to its quoted string representation.
417424 """
418- def to_quoted_string ( descr ) do
425+ def to_quoted_string ( descr , opts \\ [ ] ) do
419426 descr
420- |> to_quoted ( )
427+ |> to_quoted ( opts )
421428 |> Code.Formatter . to_algebra ( )
422429 |> Inspect.Algebra . format ( 98 )
423430 |> IO . iodata_to_binary ( )
@@ -1045,16 +1052,16 @@ defmodule Module.Types.Descr do
10451052 end
10461053 end
10471054
1048- defp list_to_quoted ( dnf , name ) do
1055+ defp list_to_quoted ( dnf , name , opts ) do
10491056 dnf = list_normalize ( dnf )
10501057
10511058 for { list_type , last_type , negs } <- dnf , reduce: [ ] do
10521059 acc ->
10531060 arguments =
10541061 if subtype? ( last_type , @ empty_list ) do
1055- [ to_quoted ( list_type ) ]
1062+ [ to_quoted ( list_type , opts ) ]
10561063 else
1057- [ to_quoted ( list_type ) , to_quoted ( last_type ) ]
1064+ [ to_quoted ( list_type , opts ) , to_quoted ( last_type , opts ) ]
10581065 end
10591066
10601067 if negs == [ ] do
@@ -1064,9 +1071,9 @@ defmodule Module.Types.Descr do
10641071 |> Enum . map ( fn { ty , lst } ->
10651072 args =
10661073 if subtype? ( lst , @ empty_list ) do
1067- [ to_quoted ( ty ) ]
1074+ [ to_quoted ( ty , opts ) ]
10681075 else
1069- [ to_quoted ( ty ) , to_quoted ( lst ) ]
1076+ [ to_quoted ( ty , opts ) , to_quoted ( lst , opts ) ]
10701077 end
10711078
10721079 { name , [ ] , args }
@@ -1176,7 +1183,7 @@ defmodule Module.Types.Descr do
11761183 end
11771184 end
11781185
1179- defp dynamic_to_quoted ( descr ) do
1186+ defp dynamic_to_quoted ( descr , opts ) do
11801187 cond do
11811188 term_type? ( descr ) ->
11821189 [ { :dynamic , [ ] , [ ] } ]
@@ -1185,7 +1192,7 @@ defmodule Module.Types.Descr do
11851192 [ single ]
11861193
11871194 true ->
1188- case to_quoted ( descr ) do
1195+ case to_quoted ( descr , opts ) do
11891196 { :none , _meta , [ ] } = none -> [ none ]
11901197 descr -> [ { :dynamic , [ ] , [ descr ] } ]
11911198 end
@@ -1786,51 +1793,77 @@ defmodule Module.Types.Descr do
17861793 end ) )
17871794 end
17881795
1789- defp map_to_quoted ( dnf ) do
1796+ defp map_to_quoted ( dnf , opts ) do
17901797 dnf
17911798 |> map_normalize ( )
1792- |> Enum . map ( & map_each_to_quoted / 1 )
1799+ |> Enum . map ( & map_each_to_quoted ( & 1 , opts ) )
17931800 end
17941801
1795- defp map_each_to_quoted ( { tag , positive_map , negative_maps } ) do
1802+ defp map_each_to_quoted ( { tag , positive_map , negative_maps } , opts ) do
17961803 case negative_maps do
17971804 [ ] ->
1798- map_literal_to_quoted ( { tag , positive_map } )
1805+ map_literal_to_quoted ( { tag , positive_map } , opts )
17991806
18001807 _ ->
18011808 negative_maps
1802- |> Enum . map ( & map_literal_to_quoted / 1 )
1809+ |> Enum . map ( & map_literal_to_quoted ( & 1 , opts ) )
18031810 |> Enum . reduce ( & { :or , [ ] , [ & 2 , & 1 ] } )
18041811 |> Kernel . then (
1805- & { :and , [ ] , [ map_literal_to_quoted ( { tag , positive_map } ) , { :not , [ ] , [ & 1 ] } ] }
1812+ & { :and , [ ] , [ map_literal_to_quoted ( { tag , positive_map } , opts ) , { :not , [ ] , [ & 1 ] } ] }
18061813 )
18071814 end
18081815 end
18091816
1810- def map_literal_to_quoted ( { :closed , fields } ) when map_size ( fields ) == 0 do
1817+ def map_literal_to_quoted ( { :closed , fields } , _opts ) when map_size ( fields ) == 0 do
18111818 { :empty_map , [ ] , [ ] }
18121819 end
18131820
1814- def map_literal_to_quoted ( { tag , fields } ) do
1821+ def map_literal_to_quoted ( { tag , fields } , opts ) do
18151822 case tag do
18161823 :closed ->
18171824 with % { __struct__: struct_descr } <- fields ,
18181825 { _ , [ struct ] } <- atom_fetch ( struct_descr ) do
1826+ fields = Map . delete ( fields , :__struct__ )
1827+
1828+ 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
1843+
18191844 { :% , [ ] ,
18201845 [
18211846 literal_to_quoted ( struct ) ,
1822- { :%{} , [ ] , map_fields_to_quoted ( tag , Map . delete ( fields , :__struct__ ) ) }
1847+ { :%{} , [ ] , map_fields_to_quoted ( tag , fields , opts ) }
18231848 ] }
18241849 else
1825- _ -> { :%{} , [ ] , map_fields_to_quoted ( tag , fields ) }
1850+ _ -> { :%{} , [ ] , map_fields_to_quoted ( tag , fields , opts ) }
18261851 end
18271852
18281853 :open ->
1829- { :%{} , [ ] , [ { :... , [ ] , nil } | map_fields_to_quoted ( tag , fields ) ] }
1854+ { :%{} , [ ] , [ { :... , [ ] , nil } | map_fields_to_quoted ( tag , fields , opts ) ] }
1855+ end
1856+ end
1857+
1858+ defp maybe_struct ( struct ) do
1859+ try do
1860+ struct . __info__ ( :struct )
1861+ rescue
1862+ _ -> nil
18301863 end
18311864 end
18321865
1833- defp map_fields_to_quoted ( tag , map ) do
1866+ defp map_fields_to_quoted ( tag , map , opts ) do
18341867 sorted = Enum . sort ( Map . to_list ( map ) )
18351868 keyword? = Inspect.List . keyword? ( sorted )
18361869
@@ -1846,9 +1879,9 @@ defmodule Module.Types.Descr do
18461879 { optional? , type } = pop_optional_static ( type )
18471880
18481881 cond do
1849- not optional? -> { key , to_quoted ( type ) }
1882+ not optional? -> { key , to_quoted ( type , opts ) }
18501883 empty? ( type ) -> { key , { :not_set , [ ] , [ ] } }
1851- true -> { key , { :if_set , [ ] , [ to_quoted ( type ) ] } }
1884+ true -> { key , { :if_set , [ ] , [ to_quoted ( type , opts ) ] } }
18521885 end
18531886 end
18541887 end
@@ -1969,11 +2002,11 @@ defmodule Module.Types.Descr do
19692002 # This is a cheap optimization that relies on structural equality.
19702003 defp tuple_union ( left , right ) , do: left ++ ( right -- left )
19712004
1972- defp tuple_to_quoted ( dnf ) do
2005+ defp tuple_to_quoted ( dnf , opts ) do
19732006 dnf
19742007 |> tuple_simplify ( )
19752008 |> tuple_fusion ( )
1976- |> Enum . map ( & tuple_each_to_quoted / 1 )
2009+ |> Enum . map ( & tuple_each_to_quoted ( & 1 , opts ) )
19772010 end
19782011
19792012 # Given a dnf of tuples, fuses the tuple unions when possible,
@@ -2020,27 +2053,27 @@ defmodule Module.Types.Descr do
20202053 { tag , fused_elements , [ ] }
20212054 end
20222055
2023- defp tuple_each_to_quoted ( { tag , positive_tuple , negative_tuples } ) do
2056+ defp tuple_each_to_quoted ( { tag , positive_tuple , negative_tuples } , opts ) do
20242057 case negative_tuples do
20252058 [ ] ->
2026- tuple_literal_to_quoted ( { tag , positive_tuple } )
2059+ tuple_literal_to_quoted ( { tag , positive_tuple } , opts )
20272060
20282061 _ ->
20292062 negative_tuples
2030- |> Enum . map ( & tuple_literal_to_quoted / 1 )
2063+ |> Enum . map ( & tuple_literal_to_quoted ( & 1 , opts ) )
20312064 |> Enum . reduce ( & { :or , [ ] , [ & 2 , & 1 ] } )
20322065 |> Kernel . then (
2033- & { :and , [ ] , [ tuple_literal_to_quoted ( { tag , positive_tuple } ) , { :not , [ ] , [ & 1 ] } ] }
2066+ & { :and , [ ] , [ tuple_literal_to_quoted ( { tag , positive_tuple } , opts ) , { :not , [ ] , [ & 1 ] } ] }
20342067 )
20352068 end
20362069 end
20372070
2038- defp tuple_literal_to_quoted ( { :closed , [ ] } ) , do: { :{} , [ ] , [ ] }
2071+ defp tuple_literal_to_quoted ( { :closed , [ ] } , _opts ) , do: { :{} , [ ] , [ ] }
20392072
2040- defp tuple_literal_to_quoted ( { tag , elements } ) do
2073+ defp tuple_literal_to_quoted ( { tag , elements } , opts ) do
20412074 case tag do
2042- :closed -> { :{} , [ ] , Enum . map ( elements , & to_quoted / 1 ) }
2043- :open -> { :{} , [ ] , Enum . map ( elements , & to_quoted / 1 ) ++ [ { :... , [ ] , nil } ] }
2075+ :closed -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) }
2076+ :open -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) ++ [ { :... , [ ] , nil } ] }
20442077 end
20452078 end
20462079
0 commit comments