@@ -251,8 +251,8 @@ defmodule Module.Types.Helpers do
251251
252252 We also undo some macro expressions done by the Kernel module.
253253 """
254- def expr_to_string ( expr ) do
255- string = prewalk_expr_to_string ( expr )
254+ def expr_to_string ( expr , opts \\ [ ] ) do
255+ string = prewalk_expr_to_string ( expr , opts )
256256
257257 case expr do
258258 { _ , meta , _ } ->
@@ -275,7 +275,9 @@ defmodule Module.Types.Helpers do
275275 end
276276 end
277277
278- defp prewalk_expr_to_string ( expr ) do
278+ defp prewalk_expr_to_string ( expr , opts ) do
279+ collapse_structs? = Keyword . get ( opts , :collapse_structs , true )
280+
279281 expr
280282 |> Macro . prewalk ( fn
281283 { :% , _ , [ Range , { :%{} , _ , fields } ] } = node ->
@@ -289,6 +291,26 @@ defmodule Module.Types.Helpers do
289291 node
290292 end
291293
294+ { :% , struct_meta , [ struct , { :%{} , map_meta , fields } ] } = node
295+ when collapse_structs? ->
296+ try do
297+ struct . __info__ ( :struct )
298+ rescue
299+ _ -> node
300+ else
301+ infos ->
302+ filtered =
303+ for { field , value } <- fields , not matches_default? ( infos , field , value ) do
304+ { field , value }
305+ end
306+
307+ if length ( fields ) != length ( filtered ) do
308+ { :% , struct_meta , [ struct , { :%{} , map_meta , [ { :... , [ ] , [ ] } | filtered ] } ] }
309+ else
310+ node
311+ end
312+ end
313+
292314 { { :. , _ , [ Elixir.String.Chars , :to_string ] } , meta , [ arg ] } ->
293315 { :to_string , meta , [ arg ] }
294316
@@ -340,6 +362,13 @@ defmodule Module.Types.Helpers do
340362 |> Macro . to_string ( )
341363 end
342364
365+ defp matches_default? ( infos , field , value ) do
366+ case Enum . find ( infos , & ( & 1 . field == field ) ) do
367+ % { default: default } -> Macro . escape ( default ) == value
368+ _ -> false
369+ end
370+ end
371+
343372 defp erl_to_ex (
344373 :erlang ,
345374 :error ,
0 commit comments