Skip to content

Commit a72a388

Browse files
authored
Remove type inversion (#9695)
1 parent 440850f commit a72a388

File tree

2 files changed

+2
-189
lines changed

2 files changed

+2
-189
lines changed

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

Lines changed: 2 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -226,20 +226,6 @@ defmodule Module.Types.Pattern do
226226

227227
## GUARDS
228228

229-
@top_union [
230-
:atom,
231-
:binary,
232-
:float,
233-
:fun,
234-
:integer,
235-
{:list, :dynamic},
236-
{:map, []},
237-
:pid,
238-
:port,
239-
:reference,
240-
:tuple
241-
]
242-
243229
# TODO: Some guards can be changed to intersection types or higher order types
244230

245231
@guard_functions %{
@@ -299,13 +285,13 @@ defmodule Module.Types.Pattern do
299285
{:bxor, 2} => {[:integer, :integer], :integer},
300286
{:bsl, 2} => {[:integer, :integer], :integer},
301287
{:bsr, 2} => {[:integer, :integer], :integer},
302-
{:xor, 2} => {[:boolean, :boolean], :boolean}
288+
{:xor, 2} => {[:boolean, :boolean], :boolean},
289+
{:not, 1} => {[:boolean], :boolean}
303290

304291
# Following guards are matched explicitly to handle
305292
# type guard functions such as is_atom/1
306293
# {:andalso, 2} => {[:boolean, :boolean], :boolean}
307294
# {:orelse, 2} => {[:boolean, :boolean], :boolean}
308-
# {:not, 1} => {[:boolean], :boolean}
309295
}
310296

311297
@type_guards [
@@ -354,19 +340,6 @@ defmodule Module.Types.Pattern do
354340
do: {:ok, :boolean, context}
355341
end
356342

357-
def of_guard({{:., _, [:erlang, :not]}, _, [arg]} = expr, stack, context) do
358-
stack = push_expr_stack(expr, stack)
359-
fresh_context = fresh_context(context)
360-
361-
with {:ok, type, arg_context} <- of_guard(arg, stack, fresh_context),
362-
arg_context = invert_types(stack, arg_context),
363-
{:ok, context} <- unify_new_types(context, stack, arg_context),
364-
{:ok, _, context} <- unify(type, :boolean, stack, context) do
365-
guard_sources = merge_guard_sources([context.guard_sources, arg_context.guard_sources])
366-
{:ok, :boolean, %{context | guard_sources: guard_sources}}
367-
end
368-
end
369-
370343
def of_guard({{:., _, [:erlang, guard]}, _, args} = expr, stack, context) do
371344
stack = push_expr_stack(expr, stack)
372345
{param_types, return_type} = guard_signature(guard, length(args))
@@ -556,52 +529,6 @@ defmodule Module.Types.Pattern do
556529
{:ok, context}
557530
end
558531

559-
defp invert_types(stack, context) do
560-
Enum.reduce(context.types, context, fn {index, type}, context ->
561-
sources = Map.get(context.guard_sources, index, [])
562-
563-
cond do
564-
:guarded_fail in sources ->
565-
remove_var(index, context)
566-
567-
:guarded in sources ->
568-
# Remove traces from inside `not(...)` when we invert the type
569-
# to avoid confusing error messages
570-
context = %{context | traces: Map.put(context.traces, index, [])}
571-
refine_var(index, invert_type(type, context), stack, context)
572-
573-
true ->
574-
context
575-
end
576-
end)
577-
end
578-
579-
defp invert_type({:union, _} = union, context) do
580-
union =
581-
Enum.flat_map(@top_union, fn top_type ->
582-
if subtype?(top_type, union, context) do
583-
[]
584-
else
585-
[top_type]
586-
end
587-
end)
588-
589-
to_union(union, context)
590-
end
591-
592-
defp invert_type(type, context) do
593-
union =
594-
Enum.flat_map(@top_union, fn top_type ->
595-
if subtype?(type, top_type, context) do
596-
[]
597-
else
598-
[top_type]
599-
end
600-
end)
601-
602-
to_union(union, context)
603-
end
604-
605532
# binary-pattern :: specifier
606533
defp of_binary({:"::", _meta, [expr, specifiers]} = full_expr, stack, context) do
607534
{expected_type, utf?} = collect_binary_type(specifiers) || {:integer, false}

lib/elixir/test/elixir/module/types_test.exs

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -203,120 +203,6 @@ defmodule Module.TypesTest do
203203
quoted_head([x], [elem(x, 1) and is_atom(x)])
204204
end
205205

206-
test "inverse guards" do
207-
assert quoted_head([x], [not is_tuple(x)]) ==
208-
{:ok,
209-
[
210-
{:union,
211-
[
212-
:atom,
213-
:binary,
214-
:float,
215-
:fun,
216-
:integer,
217-
{:list, :dynamic},
218-
{:map, []},
219-
:pid,
220-
:port,
221-
:reference
222-
]}
223-
]}
224-
225-
assert quoted_head([x], [not (not is_tuple(x))]) == {:ok, [:tuple]}
226-
227-
assert quoted_head([x], [not elem(x, 0)]) == {:ok, [:tuple]}
228-
229-
assert quoted_head([x], [not (is_tuple(x) and elem(x, 0))]) == {:ok, [{:var, 0}]}
230-
231-
assert quoted_head([x], [not (elem(x, 0) and is_tuple(x))]) == {:ok, [:tuple]}
232-
233-
# TODO: Requires lifting unions to unification
234-
# assert quoted_head([x], [not(is_tuple(x)) and not(is_list(x))]) == {
235-
# :ok,
236-
# [
237-
# {:union,
238-
# [
239-
# :atom,
240-
# :binary,
241-
# :float,
242-
# :fun,
243-
# :integer,
244-
# {:map, []},
245-
# :pid,
246-
# :port,
247-
# :reference
248-
# ]}
249-
# ]
250-
# }
251-
252-
assert quoted_head([x], [not (is_tuple(x) or is_list(x))]) == {
253-
:ok,
254-
[
255-
{:union,
256-
[
257-
:atom,
258-
:binary,
259-
:float,
260-
:fun,
261-
:integer,
262-
{:map, []},
263-
:pid,
264-
:port,
265-
:reference
266-
]}
267-
]
268-
}
269-
270-
assert quoted_head([x], [not is_tuple(x) or not is_list(x)]) == {
271-
:ok,
272-
[
273-
{:union,
274-
[
275-
:atom,
276-
:binary,
277-
:float,
278-
:fun,
279-
:integer,
280-
{:list, :dynamic},
281-
{:map, []},
282-
:pid,
283-
:port,
284-
:reference,
285-
:tuple
286-
]}
287-
]
288-
}
289-
290-
assert quoted_head([x], [is_integer(x) and not is_binary(x)]) == {:ok, [:integer]}
291-
292-
assert quoted_head([x, y], [is_integer(x) and not is_binary(y)]) ==
293-
{:ok,
294-
[
295-
:integer,
296-
{:union,
297-
[
298-
:atom,
299-
:float,
300-
:fun,
301-
:integer,
302-
{:list, :dynamic},
303-
{:map, []},
304-
:pid,
305-
:port,
306-
:reference,
307-
:tuple
308-
]}
309-
]}
310-
311-
assert quoted_head([x], [is_atom(x) and not (is_integer(x) and band(x, 1) == 1)]) ==
312-
{:ok, [:atom]}
313-
314-
assert {:error, {{:unable_unify, :tuple, {:list, :dynamic}, _, _}, _}} =
315-
quoted_head([x], [
316-
not (is_tuple(x) and is_list(x))
317-
])
318-
end
319-
320206
test "map" do
321207
assert quoted_head([%{true: false} = foo, %{} = foo]) ==
322208
{:ok,

0 commit comments

Comments
 (0)