Skip to content

Commit 54ba096

Browse files
committed
Remove boolean and number as builtin types (#10329)
1 parent 6042fd0 commit 54ba096

File tree

7 files changed

+86
-99
lines changed

7 files changed

+86
-99
lines changed

lib/elixir/lib/module/types.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,8 @@ defmodule Module.Types do
518518
defp map_type?(_other), do: false
519519

520520
defp atom_type?(:atom), do: true
521-
defp atom_type?(:boolean), do: true
522521
defp atom_type?({:atom, _}), do: false
522+
defp atom_type?({:union, union}), do: Enum.all?(union, &atom_type?/1)
523523
defp atom_type?(_other), do: false
524524

525525
defp integer_type?(:integer), do: true

lib/elixir/lib/module/types/of.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ defmodule Module.Types.Of do
173173
fun.(other)
174174
end
175175

176-
defp binary_type(:expr, {:float, _, _}), do: :number
176+
defp binary_type(:expr, {:float, _, _}), do: {:union, [:integer, :float]}
177177
defp binary_type(:expr, {:utf8, _, _}), do: {:union, [:integer, :binary]}
178178
defp binary_type(:expr, {:utf16, _, _}), do: {:union, [:integer, :binary]}
179179
defp binary_type(:expr, {:utf32, _, _}), do: {:union, [:integer, :binary]}

lib/elixir/lib/module/types/pattern.ex

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -217,43 +217,45 @@ defmodule Module.Types.Pattern do
217217
## GUARDS
218218

219219
# TODO: Some guards can be changed to intersection types or higher order types
220+
@boolean {:union, [{:atom, true}, {:atom, false}]}
221+
@number {:union, [:integer, :float]}
220222

221223
@guard_functions %{
222-
{:is_atom, 1} => {[:atom], :boolean},
223-
{:is_binary, 1} => {[:binary], :boolean},
224-
{:is_bitstring, 1} => {[:binary], :boolean},
225-
{:is_boolean, 1} => {[:boolean], :boolean},
226-
{:is_float, 1} => {[:float], :boolean},
227-
{:is_function, 1} => {[:fun], :boolean},
228-
{:is_function, 2} => {[:fun, :integer], :boolean},
229-
{:is_integer, 1} => {[:integer], :boolean},
230-
{:is_list, 1} => {[{:list, :dynamic}], :boolean},
231-
{:is_map, 1} => {[{:map, [{:optional, :dynamic, :dynamic}]}], :boolean},
224+
{:is_atom, 1} => {[:atom], @boolean},
225+
{:is_binary, 1} => {[:binary], @boolean},
226+
{:is_bitstring, 1} => {[:binary], @boolean},
227+
{:is_boolean, 1} => {[@boolean], @boolean},
228+
{:is_float, 1} => {[:float], @boolean},
229+
{:is_function, 1} => {[:fun], @boolean},
230+
{:is_function, 2} => {[:fun, :integer], @boolean},
231+
{:is_integer, 1} => {[:integer], @boolean},
232+
{:is_list, 1} => {[{:list, :dynamic}], @boolean},
233+
{:is_map, 1} => {[{:map, [{:optional, :dynamic, :dynamic}]}], @boolean},
232234
{:is_map_key, 2} => {[:dynamic, {:map, [{:optional, :dynamic, :dynamic}]}], :dynamic},
233-
{:is_number, 1} => {[:number], :boolean},
234-
{:is_pid, 1} => {[:pid], :boolean},
235-
{:is_port, 1} => {[:port], :boolean},
236-
{:is_reference, 1} => {[:reference], :boolean},
237-
{:is_tuple, 1} => {[:tuple], :boolean},
238-
{:<, 2} => {[:dynamic, :dynamic], :boolean},
239-
{:"=<", 2} => {[:dynamic, :dynamic], :boolean},
240-
{:>, 2} => {[:dynamic, :dynamic], :boolean},
241-
{:>=, 2} => {[:dynamic, :dynamic], :boolean},
242-
{:"/=", 2} => {[:dynamic, :dynamic], :boolean},
243-
{:"=/=", 2} => {[:dynamic, :dynamic], :boolean},
244-
{:==, 2} => {[:dynamic, :dynamic], :boolean},
245-
{:"=:=", 2} => {[:dynamic, :dynamic], :boolean},
246-
{:*, 2} => {[:number, :number], :number},
247-
{:+, 1} => {[:number], :number},
248-
{:+, 2} => {[:number, :number], :number},
249-
{:-, 1} => {[:number], :number},
250-
{:-, 2} => {[:number, :number], :number},
251-
{:/, 2} => {[:number, :number], :number},
252-
{:abs, 1} => {[:number], :number},
253-
{:ceil, 1} => {[:number], :integer},
254-
{:floor, 1} => {[:number], :integer},
255-
{:round, 1} => {[:number], :integer},
256-
{:trunc, 1} => {[:number], :integer},
235+
{:is_number, 1} => {[@number], @boolean},
236+
{:is_pid, 1} => {[:pid], @boolean},
237+
{:is_port, 1} => {[:port], @boolean},
238+
{:is_reference, 1} => {[:reference], @boolean},
239+
{:is_tuple, 1} => {[:tuple], @boolean},
240+
{:<, 2} => {[:dynamic, :dynamic], @boolean},
241+
{:"=<", 2} => {[:dynamic, :dynamic], @boolean},
242+
{:>, 2} => {[:dynamic, :dynamic], @boolean},
243+
{:>=, 2} => {[:dynamic, :dynamic], @boolean},
244+
{:"/=", 2} => {[:dynamic, :dynamic], @boolean},
245+
{:"=/=", 2} => {[:dynamic, :dynamic], @boolean},
246+
{:==, 2} => {[:dynamic, :dynamic], @boolean},
247+
{:"=:=", 2} => {[:dynamic, :dynamic], @boolean},
248+
{:*, 2} => {[@number, @number], @number},
249+
{:+, 1} => {[@number], @number},
250+
{:+, 2} => {[@number, @number], @number},
251+
{:-, 1} => {[@number], @number},
252+
{:-, 2} => {[@number, @number], @number},
253+
{:/, 2} => {[@number, @number], @number},
254+
{:abs, 1} => {[@number], @number},
255+
{:ceil, 1} => {[@number], :integer},
256+
{:floor, 1} => {[@number], :integer},
257+
{:round, 1} => {[@number], :integer},
258+
{:trunc, 1} => {[@number], :integer},
257259
{:element, 2} => {[:integer, :tuple], :dynamic},
258260
{:hd, 1} => {[{:list, :dynamic}], :dynamic},
259261
{:length, 1} => {[{:list, :dynamic}], :integer},
@@ -265,7 +267,7 @@ defmodule Module.Types.Pattern do
265267
{:binary_part, 3} => {[:binary, :integer, :integer], :binary},
266268
{:bit_size, 1} => {[:binary], :integer},
267269
{:byte_size, 1} => {[:binary], :integer},
268-
{:size, 1} => {[{:union, [:binary, :tuple]}], :boolean},
270+
{:size, 1} => {[{:union, [:binary, :tuple]}], @boolean},
269271
{:div, 2} => {[:integer, :integer], :integer},
270272
{:rem, 2} => {[:integer, :integer], :integer},
271273
{:node, 0} => {[], :atom},
@@ -276,15 +278,15 @@ defmodule Module.Types.Pattern do
276278
{:bxor, 2} => {[:integer, :integer], :integer},
277279
{:bsl, 2} => {[:integer, :integer], :integer},
278280
{:bsr, 2} => {[:integer, :integer], :integer},
279-
{:or, 2} => {[:boolean, :boolean], :boolean},
280-
{:and, 2} => {[:boolean, :boolean], :boolean},
281-
{:xor, 2} => {[:boolean, :boolean], :boolean},
282-
{:not, 1} => {[:boolean], :boolean}
281+
{:or, 2} => {[@boolean, @boolean], @boolean},
282+
{:and, 2} => {[@boolean, @boolean], @boolean},
283+
{:xor, 2} => {[@boolean, @boolean], @boolean},
284+
{:not, 1} => {[@boolean], @boolean}
283285

284286
# Following guards are matched explicitly to handle
285287
# type guard functions such as is_atom/1
286-
# {:andalso, 2} => {[:boolean, :boolean], :boolean}
287-
# {:orelse, 2} => {[:boolean, :boolean], :boolean}
288+
# {:andalso, 2} => {[@boolean, @boolean], @boolean}
289+
# {:orelse, 2} => {[@boolean, @boolean], @boolean}
288290
}
289291

290292
@type_guards [
@@ -320,9 +322,9 @@ defmodule Module.Types.Pattern do
320322
with {:ok, left_type, left_context} <- of_guard(left, stack, fresh_context),
321323
{:ok, right_type, right_context} <- of_guard(right, stack, fresh_context),
322324
{:ok, context} <- merge_context_and(context, stack, left_context, right_context),
323-
{:ok, _, context} <- unify(left_type, :boolean, stack, context),
324-
{:ok, _, context} <- unify(right_type, :boolean, stack, context),
325-
do: {:ok, :boolean, context}
325+
{:ok, _, context} <- unify(left_type, @boolean, stack, context),
326+
{:ok, _, context} <- unify(right_type, @boolean, stack, context),
327+
do: {:ok, @boolean, context}
326328
end
327329

328330
def of_guard({{:., _, [:erlang, :orelse]}, _, [left, right]} = expr, stack, context) do
@@ -332,8 +334,8 @@ defmodule Module.Types.Pattern do
332334
with {:ok, left_type, left_context} <- of_guard(left, stack, fresh_context),
333335
{:ok, _right_type, right_context} <- of_guard(right, stack, fresh_context),
334336
{:ok, context} <- merge_context_or(context, stack, left_context, right_context),
335-
{:ok, _, context} <- unify(left_type, :boolean, stack, context),
336-
do: {:ok, :boolean, context}
337+
{:ok, _, context} <- unify(left_type, @boolean, stack, context),
338+
do: {:ok, @boolean, context}
337339
end
338340

339341
# The unary operators + and - are special cased to avoid common warnings until

lib/elixir/lib/module/types/unify.ex

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ defmodule Module.Types.Unify do
2121
# {:union, [type]}
2222
# {:map, [{:required | :optional, key_type, value_type}]}
2323
#
24-
# TODO: Those types should be removed:
25-
#
26-
# :boolean
27-
# :number
28-
#
2924
# Once new types are added, they should be considered in:
3025
#
3126
# * unify (all)
@@ -515,11 +510,6 @@ defmodule Module.Types.Unify do
515510
def subtype?(_, :dynamic, _context), do: true
516511
def subtype?({:atom, atom}, :atom, _context) when is_atom(atom), do: true
517512

518-
def subtype?({:atom, boolean}, :boolean, _context) when is_boolean(boolean), do: true
519-
def subtype?(:boolean, :atom, _context), do: true
520-
def subtype?(:float, :number, _context), do: true
521-
def subtype?(:integer, :number, _context), do: true
522-
523513
# Composite
524514

525515
def subtype?({:tuple, _, _}, :tuple, _context), do: true

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,8 @@ defmodule Module.Types.MapTest do
307307
{:map,
308308
[
309309
{:required, {:atom, true}, {:atom, true}},
310-
{:required, :boolean, {:union, [{:atom, :bool}, {:atom, true}]}},
310+
{:required, {:union, [atom: true, atom: false]},
311+
{:union, [{:atom, :bool}, {:atom, true}]}},
311312
{:required, :atom, {:union, [{:atom, :atom}, {:atom, :bool}, {:atom, true}]}}
312313
]}}
313314

@@ -320,7 +321,8 @@ defmodule Module.Types.MapTest do
320321
{:map,
321322
[
322323
{:required, {:atom, true}, {:atom, true}},
323-
{:required, :boolean, {:union, [{:atom, :bool}, {:atom, true}]}},
324+
{:required, {:union, [atom: true, atom: false]},
325+
{:union, [{:atom, :bool}, {:atom, true}]}},
324326
{:required, :atom, {:union, [{:atom, :atom}, {:atom, :bool}, {:atom, true}]}}
325327
]}}
326328

@@ -333,7 +335,8 @@ defmodule Module.Types.MapTest do
333335
{:map,
334336
[
335337
{:required, {:atom, true}, {:atom, true}},
336-
{:required, :boolean, {:union, [{:atom, :bool}, {:atom, true}]}},
338+
{:required, {:union, [atom: true, atom: false]},
339+
{:union, [{:atom, :bool}, {:atom, true}]}},
337340
{:required, :atom, {:union, [{:atom, :atom}, {:atom, :bool}, {:atom, true}]}}
338341
]}}
339342
end

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,10 @@ defmodule Module.Types.PatternTest do
285285
{:ok, [{:union, [:tuple, :atom]}]}
286286

287287
assert quoted_head([x], [is_boolean(x) and is_atom(x)]) ==
288-
{:ok, [:boolean]}
288+
{:ok, [{:union, [atom: true, atom: false]}]}
289289

290290
assert quoted_head([x], [is_atom(x) and is_boolean(x)]) ==
291-
{:ok, [:boolean]}
291+
{:ok, [{:union, [atom: true, atom: false]}]}
292292

293293
assert quoted_head([x], [is_atom(x) > :foo]) == {:ok, [var: 0]}
294294

@@ -307,7 +307,7 @@ defmodule Module.Types.PatternTest do
307307
assert {:error, {:unable_unify, {:tuple, :atom, _}}} =
308308
quoted_head([x], [is_tuple(x) and is_atom(x)])
309309

310-
assert {:error, {:unable_unify, {:boolean, :tuple, _}}} =
310+
assert {:error, {:unable_unify, {{:union, [atom: true, atom: false]}, :tuple, _}}} =
311311
quoted_head([x], [is_tuple(is_atom(x))])
312312
end
313313

@@ -322,13 +322,16 @@ defmodule Module.Types.PatternTest do
322322
assert {:error, {:unable_unify, {{:atom, :foo}, {:list, :dynamic}, _}}} =
323323
quoted_head([x], [length(:foo)])
324324

325-
assert {:error, {:unable_unify, {:boolean, {:list, :dynamic}, _}}} =
325+
assert {:error,
326+
{:unable_unify, {{:union, [atom: true, atom: false]}, {:list, :dynamic}, _}}} =
326327
quoted_head([x], [length(is_tuple(x))])
327328

328-
assert {:error, {:unable_unify, {:boolean, :tuple, _}}} =
329+
assert {:error, {:unable_unify, {{:union, [atom: true, atom: false]}, :tuple, _}}} =
329330
quoted_head([x], [elem(is_tuple(x), 0)])
330331

331-
assert {:error, {:unable_unify, {:boolean, :number, _}}} =
332+
assert {:error,
333+
{:unable_unify,
334+
{{:union, [atom: true, atom: false]}, {:union, [:integer, :float]}, _}}} =
332335
quoted_head([x], [elem({}, is_tuple(x))])
333336

334337
assert quoted_head([x], [elem({}, 1)]) == {:ok, [var: 0]}
@@ -371,7 +374,11 @@ defmodule Module.Types.PatternTest do
371374
assert quoted_head([%{true: bool}], [is_boolean(bool)]) ==
372375
{:ok,
373376
[
374-
{:map, [{:required, {:atom, true}, :boolean}, {:optional, :dynamic, :dynamic}]}
377+
{:map,
378+
[
379+
{:required, {:atom, true}, {:union, [atom: true, atom: false]}},
380+
{:optional, :dynamic, :dynamic}
381+
]}
375382
]}
376383

377384
assert quoted_head([%{true: true} = foo, %{false: false} = foo]) ==

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

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,17 @@ defmodule Module.Types.UnifyTest do
5353
assert unify_lift(:integer, :integer) == {:ok, :integer}
5454
assert unify_lift(:binary, :binary) == {:ok, :binary}
5555
assert unify_lift(:atom, :atom) == {:ok, :atom}
56-
assert unify_lift(:boolean, :boolean) == {:ok, :boolean}
5756

58-
assert {:error, {:unable_unify, {:integer, :boolean, _}}} = unify_lift(:integer, :boolean)
57+
assert {:error, {:unable_unify, {:integer, :atom, _}}} = unify_lift(:integer, :atom)
5958
end
6059

6160
test "subtype undirected" do
62-
assert unify_lift(:boolean, :atom) == {:ok, :boolean}
63-
assert unify_lift(:atom, :boolean) == {:ok, :boolean}
64-
assert unify_lift(:boolean, {:atom, true}) == {:ok, {:atom, true}}
65-
assert unify_lift({:atom, true}, :boolean) == {:ok, {:atom, true}}
6661
assert unify_lift(:atom, {:atom, true}) == {:ok, {:atom, true}}
6762
assert unify_lift({:atom, true}, :atom) == {:ok, {:atom, true}}
6863
end
6964

7065
test "subtype directed" do
71-
assert unify_directed_lift(:boolean, :atom) == {:ok, :boolean}
72-
assert unify_directed_lift({:atom, true}, :boolean) == {:ok, {:atom, true}}
7366
assert unify_directed_lift({:atom, true}, :atom) == {:ok, {:atom, true}}
74-
75-
assert {:error, _} = unify_directed_lift(:atom, :boolean)
76-
assert {:error, _} = unify_directed_lift(:boolean, {:atom, true})
7767
assert {:error, _} = unify_directed_lift(:atom, {:atom, true})
7868
end
7969

@@ -83,8 +73,8 @@ defmodule Module.Types.UnifyTest do
8373
assert unify_lift({:tuple, 1, [:integer]}, {:tuple, 1, [:integer]}) ==
8474
{:ok, {:tuple, 1, [:integer]}}
8575

86-
assert unify_lift({:tuple, 1, [:boolean]}, {:tuple, 1, [:atom]}) ==
87-
{:ok, {:tuple, 1, [:boolean]}}
76+
assert unify_lift({:tuple, 1, [{:atom, :foo}]}, {:tuple, 1, [:atom]}) ==
77+
{:ok, {:tuple, 1, [{:atom, :foo}]}}
8878

8979
assert {:error, {:unable_unify, {{:tuple, 1, [:integer]}, {:tuple, 0, []}, _}}} =
9080
unify_lift({:tuple, 1, [:integer]}, {:tuple, 0, []})
@@ -134,10 +124,10 @@ defmodule Module.Types.UnifyTest do
134124
{:ok, {:map, [{:required, :integer, :atom}]}}
135125

136126
assert unify_lift(
137-
{:map, [{:required, {:atom, :foo}, :boolean}]},
127+
{:map, [{:required, {:atom, :foo}, {:atom, :bar}}]},
138128
{:map, [{:required, {:atom, :foo}, :atom}]}
139129
) ==
140-
{:ok, {:map, [{:required, {:atom, :foo}, :boolean}]}}
130+
{:ok, {:map, [{:required, {:atom, :foo}, {:atom, :bar}}]}}
141131

142132
assert {:error,
143133
{:unable_unify,
@@ -166,28 +156,28 @@ defmodule Module.Types.UnifyTest do
166156

167157
test "map required/optional key" do
168158
assert unify_lift(
169-
{:map, [{:required, {:atom, :foo}, :boolean}]},
159+
{:map, [{:required, {:atom, :foo}, {:atom, :bar}}]},
170160
{:map, [{:required, {:atom, :foo}, :atom}]}
171161
) ==
172-
{:ok, {:map, [{:required, {:atom, :foo}, :boolean}]}}
162+
{:ok, {:map, [{:required, {:atom, :foo}, {:atom, :bar}}]}}
173163

174164
assert unify_lift(
175-
{:map, [{:optional, {:atom, :foo}, :boolean}]},
165+
{:map, [{:optional, {:atom, :foo}, {:atom, :bar}}]},
176166
{:map, [{:required, {:atom, :foo}, :atom}]}
177167
) ==
178-
{:ok, {:map, [{:required, {:atom, :foo}, :boolean}]}}
168+
{:ok, {:map, [{:required, {:atom, :foo}, {:atom, :bar}}]}}
179169

180170
assert unify_lift(
181-
{:map, [{:required, {:atom, :foo}, :boolean}]},
171+
{:map, [{:required, {:atom, :foo}, {:atom, :bar}}]},
182172
{:map, [{:optional, {:atom, :foo}, :atom}]}
183173
) ==
184-
{:ok, {:map, [{:required, {:atom, :foo}, :boolean}]}}
174+
{:ok, {:map, [{:required, {:atom, :foo}, {:atom, :bar}}]}}
185175

186176
assert unify_lift(
187-
{:map, [{:optional, {:atom, :foo}, :boolean}]},
177+
{:map, [{:optional, {:atom, :foo}, {:atom, :bar}}]},
188178
{:map, [{:optional, {:atom, :foo}, :atom}]}
189179
) ==
190-
{:ok, {:map, [{:optional, {:atom, :foo}, :boolean}]}}
180+
{:ok, {:map, [{:optional, {:atom, :foo}, {:atom, :bar}}]}}
191181
end
192182

193183
test "map with subtyped keys" do
@@ -277,8 +267,8 @@ defmodule Module.Types.UnifyTest do
277267
assert unify_lift({:union, [:integer, :atom]}, {:union, [:atom, :integer]}) ==
278268
{:ok, {:union, [:integer, :atom]}}
279269

280-
assert unify_lift({:union, [:atom]}, {:union, [:boolean]}) == {:ok, {:union, [:boolean]}}
281-
assert unify_lift({:union, [:boolean]}, {:union, [:atom]}) == {:ok, {:union, [:boolean]}}
270+
assert unify_lift({:union, [:atom]}, {:union, [{:atom, :bar}]}) ==
271+
{:ok, {:union, [{:atom, :bar}]}}
282272

283273
assert {:error, {:unable_unify, {{:union, [:integer]}, {:union, [:atom]}, _}}} =
284274
unify_lift({:union, [:integer]}, {:union, [:atom]})
@@ -425,15 +415,11 @@ defmodule Module.Types.UnifyTest do
425415
describe "subtype?/3" do
426416
test "with simple types" do
427417
assert subtype?({:atom, :foo}, :atom, new_context())
428-
assert subtype?({:atom, true}, :boolean, new_context())
429418
assert subtype?({:atom, true}, :atom, new_context())
430-
assert subtype?(:boolean, :atom, new_context())
431419

432420
refute subtype?(:integer, :binary, new_context())
433421
refute subtype?(:atom, {:atom, :foo}, new_context())
434-
refute subtype?(:boolean, {:atom, true}, new_context())
435422
refute subtype?(:atom, {:atom, true}, new_context())
436-
refute subtype?(:atom, :boolean, new_context())
437423
end
438424

439425
test "with composite types" do
@@ -503,8 +489,7 @@ defmodule Module.Types.UnifyTest do
503489
test "to_union/2" do
504490
assert to_union([:atom], new_context()) == :atom
505491
assert to_union([:integer, :integer], new_context()) == :integer
506-
assert to_union([:boolean, :atom], new_context()) == :atom
507-
assert to_union([{:atom, :foo}, :boolean, :atom], new_context()) == :atom
492+
assert to_union([{:atom, :foo}, {:atom, :bar}, :atom], new_context()) == :atom
508493

509494
assert to_union([:binary, :atom], new_context()) == {:union, [:binary, :atom]}
510495
assert to_union([:atom, :binary, :atom], new_context()) == {:union, [:atom, :binary]}

0 commit comments

Comments
 (0)