@@ -50,7 +50,7 @@ defmodule Module.Types.Descr do
5050 def atom ( as ) , do: % { atom: atom_new ( as ) }
5151 def atom ( ) , do: % { atom: @ atom_top }
5252 def binary ( ) , do: % { bitmap: @ bit_binary }
53- def closed_map ( pairs ) , do: % { map: map_new ( :closed , :maps . from_list ( pairs ) ) }
53+ def closed_map ( pairs ) , do: map_descr ( :closed , pairs )
5454 def empty_list ( ) , do: % { bitmap: @ bit_empty_list }
5555 def empty_map ( ) , do: % { map: @ map_empty }
5656 def integer ( ) , do: % { bitmap: @ bit_integer }
@@ -59,7 +59,7 @@ defmodule Module.Types.Descr do
5959 def list ( ) , do: % { bitmap: @ bit_list }
6060 def non_empty_list ( ) , do: % { bitmap: @ bit_non_empty_list }
6161 def open_map ( ) , do: % { map: @ map_top }
62- def open_map ( pairs ) , do: % { map: map_new ( :open , :maps . from_list ( pairs ) ) }
62+ def open_map ( pairs ) , do: map_descr ( :open , pairs )
6363 def pid ( ) , do: % { bitmap: @ bit_pid }
6464 def port ( ) , do: % { bitmap: @ bit_port }
6565 def reference ( ) , do: % { bitmap: @ bit_reference }
@@ -597,15 +597,34 @@ defmodule Module.Types.Descr do
597597 # `%{..., a: if_set(not atom()), b: integer()}`. For maps with more keys,
598598 # each key in a negated literal may create a new union when eliminated.
599599
600+ defp map_descr ( tag , fields ) do
601+ case map_descr_pairs ( fields , [ ] , false ) do
602+ { fields , true } ->
603+ % { dynamic: % { map: map_new ( tag , fields |> Enum . reverse ( ) |> :maps . from_list ( ) ) } }
604+
605+ { _ , false } ->
606+ % { map: map_new ( tag , :maps . from_list ( fields ) ) }
607+ end
608+ end
609+
610+ defp map_descr_pairs ( [ { key , value } | rest ] , acc , dynamic? ) do
611+ case :maps . take ( :dynamic , value ) do
612+ :error -> map_descr_pairs ( rest , [ { key , value } | acc ] , dynamic? )
613+ { dynamic , _static } -> map_descr_pairs ( rest , [ { key , dynamic } | acc ] , true )
614+ end
615+ end
616+
617+ defp map_descr_pairs ( [ ] , acc , dynamic? ) do
618+ { acc , dynamic? }
619+ end
620+
600621 defp optional? ( % { bitmap: bitmap } ) when ( bitmap &&& @ bit_optional ) != 0 , do: true
601622 defp optional? ( _ ) , do: false
602623
603624 defp map_tag_to_type ( :open ) , do: term_or_optional ( )
604625 defp map_tag_to_type ( :closed ) , do: not_set ( )
605626
606- # TODO: We need to propagate any dynamic up
607- defp map_new ( tag , fields ) , do: [ { tag , fields , [ ] } ]
608- defp map_descr ( tag , fields ) , do: % { map: map_new ( tag , fields ) }
627+ defp map_new ( tag , fields = % { } ) , do: [ { tag , fields , [ ] } ]
609628
610629 @ doc """
611630 Fetches the type of the value returned by accessing `key` on `map`
@@ -834,8 +853,8 @@ defmodule Module.Types.Descr do
834853
835854 defp map_pop_key ( tag , fields , key ) do
836855 case :maps . take ( key , fields ) do
837- { value , fields } -> { value , map_descr ( tag , fields ) }
838- :error -> { map_tag_to_type ( tag ) , map_descr ( tag , fields ) }
856+ { value , fields } -> { value , % { map: map_new ( tag , fields ) } }
857+ :error -> { map_tag_to_type ( tag ) , % { map: map_new ( tag , fields ) } }
839858 end
840859 end
841860
0 commit comments