Skip to content

Commit 3a783bd

Browse files
committed
Check for compatibility, not subtyping
1 parent 63283d5 commit 3a783bd

File tree

5 files changed

+33
-77
lines changed

5 files changed

+33
-77
lines changed

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

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -637,15 +637,6 @@ defmodule Module.Types.Descr do
637637
def number_type?(%{bitmap: bitmap}) when (bitmap &&& @bit_number) != 0, do: true
638638
def number_type?(_), do: false
639639

640-
@doc """
641-
Optimized version of `not empty?(intersection(atom(), type))`.
642-
"""
643-
def atom_type?(:term), do: true
644-
def atom_type?(%{dynamic: :term}), do: true
645-
def atom_type?(%{dynamic: %{atom: _}}), do: true
646-
def atom_type?(%{atom: _}), do: true
647-
def atom_type?(_), do: false
648-
649640
## Bitmaps
650641

651642
defp bitmap_to_quoted(val) do
@@ -749,20 +740,6 @@ defmodule Module.Types.Descr do
749740
end
750741
end
751742

752-
@doc """
753-
Optimized version of `not empty?(intersection(atom([atom]), type))`.
754-
"""
755-
def atom_type?(:term, _atom), do: true
756-
757-
def atom_type?(%{} = descr, atom) do
758-
case Map.get(descr, :dynamic, descr) do
759-
:term -> true
760-
%{atom: {:union, set}} -> :sets.is_element(atom, set)
761-
%{atom: {:negation, set}} -> not :sets.is_element(atom, set)
762-
%{} -> false
763-
end
764-
end
765-
766743
@doc """
767744
Returns a set of all known atoms.
768745

lib/elixir/lib/module/types/expr.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ defmodule Module.Types.Expr do
360360
{timeout_type, context} = of_expr(timeout, {@timeout_type, after_expr}, stack, context)
361361
{body_type, context} = of_expr(body, expected_expr, stack, context)
362362

363-
if integer_type?(timeout_type) or atom_type?(timeout_type, :infinity) do
363+
if compatible?(timeout_type, @timeout_type) do
364364
{union(body_type, acc), reset_vars(context, original)}
365365
else
366366
error = {:badtimeout, timeout_type, timeout, context}
@@ -592,10 +592,9 @@ defmodule Module.Types.Expr do
592592

593593
defp for_clause({:<<>>, _, [{:<-, meta, [left, right]}]} = expr, stack, context) do
594594
{right_type, context} = of_expr(right, {binary(), expr}, stack, context)
595-
596595
context = Pattern.of_match(left, binary(), expr, :for, stack, context)
597596

598-
if binary_type?(right_type) do
597+
if compatible?(right_type, binary()) do
599598
context
600599
else
601600
error = {:badbinary, right_type, right, context}

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

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -618,48 +618,28 @@ defmodule Module.Types.Pattern do
618618
# This function is public as it is invoked from Of.binary/4.
619619

620620
# :atom
621-
def of_guard(atom, expected, expr, stack, context) when is_atom(atom) do
622-
if atom_type?(expected, atom) do
623-
{atom([atom]), context}
624-
else
625-
{error_type(), Of.incompatible_error(expr, expected, atom([atom]), stack, context)}
626-
end
621+
def of_guard(atom, _expected, _expr, _stack, context) when is_atom(atom) do
622+
{atom([atom]), context}
627623
end
628624

629625
# 12
630-
def of_guard(literal, expected, expr, stack, context) when is_integer(literal) do
631-
if integer_type?(expected) do
632-
{integer(), context}
633-
else
634-
{error_type(), Of.incompatible_error(expr, expected, integer(), stack, context)}
635-
end
626+
def of_guard(literal, _expected, _expr, _stack, context) when is_integer(literal) do
627+
{integer(), context}
636628
end
637629

638630
# 1.2
639-
def of_guard(literal, expected, expr, stack, context) when is_float(literal) do
640-
if float_type?(expected) do
641-
{float(), context}
642-
else
643-
{error_type(), Of.incompatible_error(expr, expected, float(), stack, context)}
644-
end
631+
def of_guard(literal, _expected, _expr, _stack, context) when is_float(literal) do
632+
{float(), context}
645633
end
646634

647635
# "..."
648-
def of_guard(literal, expected, expr, stack, context) when is_binary(literal) do
649-
if binary_type?(expected) do
650-
{binary(), context}
651-
else
652-
{error_type(), Of.incompatible_error(expr, expected, binary(), stack, context)}
653-
end
636+
def of_guard(literal, _expected, _expr, _stack, context) when is_binary(literal) do
637+
{binary(), context}
654638
end
655639

656640
# []
657-
def of_guard([], expected, expr, stack, context) do
658-
if empty_list_type?(expected) do
659-
{empty_list(), context}
660-
else
661-
{error_type(), Of.incompatible_error(expr, expected, empty_list(), stack, context)}
662-
end
641+
def of_guard([], _expected, _expr, _stack, context) do
642+
{empty_list(), context}
663643
end
664644

665645
# [expr, ...]
@@ -691,13 +671,9 @@ defmodule Module.Types.Pattern do
691671
end
692672

693673
# <<>>
694-
def of_guard({:<<>>, _meta, args}, expected, expr, stack, context) do
695-
if binary_type?(expected) do
696-
context = Of.binary(args, :guard, stack, context)
697-
{binary(), context}
698-
else
699-
{error_type(), Of.incompatible_error(expr, expected, binary(), stack, context)}
700-
end
674+
def of_guard({:<<>>, _meta, args}, _expected, _expr, stack, context) do
675+
context = Of.binary(args, :guard, stack, context)
676+
{binary(), context}
701677
end
702678

703679
# ^var

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

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -579,20 +579,6 @@ defmodule Module.Types.DescrTest do
579579
end
580580
end
581581

582-
describe "queries" do
583-
test "atom_type?" do
584-
assert atom_type?(term(), :foo)
585-
assert atom_type?(dynamic(), :foo)
586-
587-
assert atom_type?(atom([:foo, :bar]), :foo)
588-
refute atom_type?(atom([:foo, :bar]), :baz)
589-
assert atom_type?(negation(atom([:foo, :bar])), :baz)
590-
591-
refute atom_type?(union(atom([:foo, :bar]), integer()), :baz)
592-
refute atom_type?(dynamic(union(atom([:foo, :bar]), integer())), :baz)
593-
end
594-
end
595-
596582
describe "projections" do
597583
test "fun_fetch" do
598584
assert fun_fetch(term(), 1) == :error

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,17 @@ defmodule Module.Types.ExprTest do
12791279
# from: types_test.ex:LINE-5
12801280
x = :timeout
12811281
"""
1282+
1283+
# Check for compatibility, not subtyping
1284+
assert typeerror!(
1285+
[<<x::integer, y::float>>],
1286+
receive do
1287+
after
1288+
if(:rand.uniform(), do: x, else: y) -> :ok
1289+
end
1290+
) =~ "expected "
1291+
after
1292+
" timeout given to receive to be an integer"
12821293
end
12831294
end
12841295

@@ -1551,6 +1562,13 @@ defmodule Module.Types.ExprTest do
15511562
15521563
#{hints(:inferred_bitstring_spec)}
15531564
"""
1565+
1566+
# Check for compatibility, not subtyping
1567+
assert typeerror!(
1568+
[<<x::integer, y::binary>>],
1569+
for(<<i <- if(:rand.uniform() > 0.5, do: x, else: y)>>, do: i)
1570+
) =~
1571+
"expected the right side of <- in a binary generator to be a binary"
15541572
end
15551573

15561574
test "infers binary generators" do

0 commit comments

Comments
 (0)