Skip to content

Commit 00f593b

Browse files
committed
Initial work on removing tag from domain handling
1 parent 85be15c commit 00f593b

File tree

2 files changed

+32
-39
lines changed

2 files changed

+32
-39
lines changed

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

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ defmodule Module.Types.Descr do
6363
@not_non_empty_list Map.delete(@term, :list)
6464
@not_list Map.replace!(@not_non_empty_list, :bitmap, @bit_top - @bit_empty_list)
6565

66+
@not_set %{optional: 1}
67+
@term_or_optional Map.put(@term, :optional, 1)
68+
@term_or_dynamic_optional Map.put(@term, :dynamic, %{optional: 1})
69+
@not_atom_or_optional Map.delete(@term_or_optional, :atom)
70+
6671
@empty_intersection [0, @none]
6772
@empty_difference [0, []]
6873

@@ -88,12 +93,11 @@ defmodule Module.Types.Descr do
8893

8994
def closed_map(pairs) do
9095
{regular_pairs, domain_pairs} = split_domain_key_pairs(pairs)
91-
# Validate domain keys and make their types optional
9296
domain_pairs = validate_domain_keys(domain_pairs)
9397

9498
if domain_pairs == [],
9599
do: map_descr(:closed, regular_pairs),
96-
else: map_descr(:closed, regular_pairs, domain_pairs)
100+
else: map_descr(domain_pairs, regular_pairs)
97101
end
98102

99103
def empty_list(), do: %{bitmap: @bit_empty_list}
@@ -104,26 +108,20 @@ defmodule Module.Types.Descr do
104108
def non_empty_list(type, tail \\ @empty_list), do: list_descr(type, tail, false)
105109

106110
def open_map(), do: %{map: @map_top}
111+
def open_map(pairs), do: open_map(pairs, @term_or_optional, false)
112+
def open_map(pairs, default), do: open_map(pairs, if_set(default), true)
107113

108-
@doc "A map (closed or open is the same) with a default type %{term() => default}"
109-
def map_with_default(default) do
110-
map_descr(
111-
:closed,
112-
[],
113-
Enum.map(@domain_key_types, fn key_type ->
114-
{domain_key(key_type), if_set(default)}
115-
end)
116-
)
117-
end
118-
119-
def open_map(pairs) do
114+
defp open_map(pairs, default, force?) do
120115
{regular_pairs, domain_pairs} = split_domain_key_pairs(pairs)
121-
# Validate domain keys and make their types optional
122116
domain_pairs = validate_domain_keys(domain_pairs)
123117

124-
if domain_pairs == [],
125-
do: map_descr(:open, regular_pairs),
126-
else: map_descr(:open, regular_pairs, domain_pairs)
118+
if domain_pairs != [] or force?,
119+
do:
120+
Map.new(@domain_key_types, fn key_type -> {domain_key(key_type), default} end)
121+
|> Map.merge(Map.new(domain_pairs))
122+
|> Map.to_list()
123+
|> map_descr(regular_pairs),
124+
else: map_descr(:open, regular_pairs)
127125
end
128126

129127
def open_tuple(elements, _fallback \\ term()), do: tuple_descr(:open, elements)
@@ -289,16 +287,11 @@ defmodule Module.Types.Descr do
289287
# is equivalent to `%{:foo => integer() or not_set()}`.
290288
#
291289
# `not_set()` has no meaning outside of map types.
292-
293-
@not_set %{optional: 1}
294-
@term_or_optional Map.put(@term, :optional, 1)
295-
@term_or_dynamic_optional Map.put(@term, :dynamic, %{optional: 1})
296-
@not_atom_or_optional Map.delete(@term_or_optional, :atom)
297-
298290
def not_set(), do: @not_set
291+
299292
def if_set(:term), do: term_or_optional()
300-
# actually, if type contains a :dynamic part, :optional gets added there because
301-
# the dynamic
293+
294+
# If type contains a :dynamic part, :optional gets added there.
302295
def if_set(type) do
303296
case type do
304297
%{dynamic: dyn} -> Map.put(%{type | dynamic: Map.put(dyn, :optional, 1)}, :optional, 1)
@@ -2245,7 +2238,7 @@ defmodule Module.Types.Descr do
22452238
# The type %{..., atom() => integer()} represents maps with atom keys bound to integers,
22462239
# and other keys bound to any type, represented by {{:closed, %{atom: integer()}}, %{}, []}.
22472240

2248-
defp map_descr(tag, fields) do
2241+
defp map_descr(tag, fields) when is_atom(tag) do
22492242
case map_descr_pairs(fields, [], false) do
22502243
{fields, true} ->
22512244
%{dynamic: %{map: map_new(tag, fields |> Enum.reverse() |> :maps.from_list())}}
@@ -2255,17 +2248,17 @@ defmodule Module.Types.Descr do
22552248
end
22562249
end
22572250

2258-
def map_descr(tag, fields, domains) do
2251+
defp map_descr(domains, fields) do
22592252
{fields, fields_dynamic?} = map_descr_pairs(fields, [], false)
22602253
{domains, domains_dynamic?} = map_descr_pairs(domains, [], false)
22612254

22622255
fields_map = :maps.from_list(if fields_dynamic?, do: Enum.reverse(fields), else: fields)
22632256
domains_map = :maps.from_list(if domains_dynamic?, do: Enum.reverse(domains), else: domains)
22642257

22652258
if fields_dynamic? or domains_dynamic? do
2266-
%{dynamic: %{map: map_new(tag, fields_map, domains_map)}}
2259+
%{dynamic: %{map: map_new(:closed, fields_map, domains_map)}}
22672260
else
2268-
%{map: map_new(tag, fields_map, domains_map)}
2261+
%{map: map_new(:closed, fields_map, domains_map)}
22692262
end
22702263
end
22712264

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ end
1414
defmodule Module.Types.DescrTest do
1515
use ExUnit.Case, async: true
1616

17-
defmacrop domain_key(key), do: {:domain_key, key}
1817
import Module.Types.Descr, except: [fun: 1]
1918

19+
defmacrop domain_key(key), do: {:domain_key, key}
20+
21+
defp number(), do: union(integer(), float())
22+
defp empty_tuple(), do: tuple([])
23+
defp tuple_of_size_at_least(n) when is_integer(n), do: open_tuple(List.duplicate(term(), n))
24+
defp tuple_of_size(n) when is_integer(n) and n >= 0, do: tuple(List.duplicate(term(), n))
25+
defp list(elem_type, tail_type), do: union(empty_list(), non_empty_list(elem_type, tail_type))
26+
defp map_with_default(descr), do: open_map([], if_set(descr))
27+
2028
describe "union" do
2129
test "bitmap" do
2230
assert union(integer(), float()) == union(float(), integer())
@@ -343,8 +351,6 @@ defmodule Module.Types.DescrTest do
343351
assert equal?(intersection(t1, t2), empty_map())
344352
end
345353

346-
defp number(), do: union(integer(), float())
347-
348354
test "list" do
349355
assert intersection(list(term()), list(term())) == list(term())
350356
assert intersection(list(integer()), list(integer())) == list(integer())
@@ -456,10 +462,6 @@ defmodule Module.Types.DescrTest do
456462
assert empty?(difference(dynamic(integer()), integer()))
457463
end
458464

459-
defp empty_tuple(), do: tuple([])
460-
defp tuple_of_size_at_least(n) when is_integer(n), do: open_tuple(List.duplicate(term(), n))
461-
defp tuple_of_size(n) when is_integer(n) and n >= 0, do: tuple(List.duplicate(term(), n))
462-
463465
test "tuple" do
464466
assert empty?(difference(open_tuple([atom()]), open_tuple([term()])))
465467
refute empty?(difference(tuple(), empty_tuple()))
@@ -581,8 +583,6 @@ defmodule Module.Types.DescrTest do
581583
assert equal?(difference(a_number, atom_to_float), closed_map(a: integer()))
582584
end
583585

584-
defp list(elem_type, tail_type), do: union(empty_list(), non_empty_list(elem_type, tail_type))
585-
586586
test "list" do
587587
# Basic list type differences
588588
assert difference(list(term()), empty_list()) == non_empty_list(term())

0 commit comments

Comments
 (0)