Skip to content

Commit 0022964

Browse files
committed
WIP
1 parent d6bd53d commit 0022964

11 files changed

Lines changed: 87 additions & 133 deletions

File tree

lib/elixir/lib/kernel.ex

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4764,8 +4764,8 @@ defmodule Kernel do
47644764
defp in_range(left, first, last, step) do
47654765
quoted =
47664766
quote do
4767-
:erlang.is_integer(unquote(left)) and :erlang.is_integer(unquote(first)) and
4768-
:erlang.is_integer(unquote(last)) and
4767+
unquote(generated_is_integer(left)) and unquote(generated_is_integer(first)) and
4768+
unquote(generated_is_integer(last)) and
47694769
((:erlang.>(unquote(step), 0) and
47704770
unquote(increasing_compare(left, first, last))) or
47714771
(:erlang.<(unquote(step), 0) and
@@ -4782,8 +4782,8 @@ defmodule Kernel do
47824782
defp in_range_literal(left, first, last, step) when step > 0 do
47834783
quoted =
47844784
quote do
4785-
:erlang.andalso(
4786-
:erlang.is_integer(unquote(left)),
4785+
Kernel.and(
4786+
unquote(generated_is_integer(left)),
47874787
unquote(increasing_compare(left, first, last))
47884788
)
47894789
end
@@ -4794,8 +4794,8 @@ defmodule Kernel do
47944794
defp in_range_literal(left, first, last, step) when step < 0 do
47954795
quoted =
47964796
quote do
4797-
:erlang.andalso(
4798-
:erlang.is_integer(unquote(left)),
4797+
Kernel.and(
4798+
unquote(generated_is_integer(left)),
47994799
unquote(decreasing_compare(left, first, last))
48004800
)
48014801
end
@@ -4809,7 +4809,7 @@ defmodule Kernel do
48094809

48104810
defp in_range_step(quoted, left, first, step) do
48114811
quote do
4812-
:erlang.andalso(
4812+
Kernel.and(
48134813
unquote(quoted),
48144814
:erlang."=:="(:erlang.rem(unquote(left) - unquote(first), unquote(step)), 0)
48154815
)
@@ -4818,7 +4818,7 @@ defmodule Kernel do
48184818

48194819
defp in_list(left, head, tail, expand, right, in_body?) do
48204820
[head | tail] = :lists.map(&comp(left, &1, expand, right, in_body?), [head | tail])
4821-
:lists.foldl(&quote(do: :erlang.orelse(unquote(&2), unquote(&1))), head, tail)
4821+
:lists.foldl(&quote(do: Kernel.or(unquote(&2), unquote(&1))), head, tail)
48224822
end
48234823

48244824
defp comp(left, {:|, _, [head, tail]}, expand, right, in_body?) do
@@ -4828,15 +4828,15 @@ defmodule Kernel do
48284828

48294829
[tail_head | tail] ->
48304830
quote do
4831-
:erlang.orelse(
4831+
Kernel.or(
48324832
:erlang."=:="(unquote(left), unquote(head)),
48334833
unquote(in_list(left, tail_head, tail, expand, right, in_body?))
48344834
)
48354835
end
48364836

48374837
tail when in_body? ->
48384838
quote do
4839-
:erlang.orelse(
4839+
Kernel.or(
48404840
:erlang."=:="(unquote(left), unquote(head)),
48414841
:lists.member(unquote(left), unquote(tail))
48424842
)
@@ -4851,9 +4851,13 @@ defmodule Kernel do
48514851
quote(do: :erlang."=:="(unquote(left), unquote(right)))
48524852
end
48534853

4854+
defp generated_is_integer(arg) do
4855+
quote generated: true, do: :erlang.is_integer(unquote(arg))
4856+
end
4857+
48544858
defp increasing_compare(var, first, last) do
48554859
quote do
4856-
:erlang.andalso(
4860+
Kernel.and(
48574861
:erlang.>=(unquote(var), unquote(first)),
48584862
:erlang."=<"(unquote(var), unquote(last))
48594863
)
@@ -4862,7 +4866,7 @@ defmodule Kernel do
48624866

48634867
defp decreasing_compare(var, first, last) do
48644868
quote do
4865-
:erlang.andalso(
4869+
Kernel.and(
48664870
:erlang."=<"(unquote(var), unquote(first)),
48674871
:erlang.>=(unquote(var), unquote(last))
48684872
)

lib/elixir/lib/module/types/apply.ex

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ defmodule Module.Types.Apply do
217217
{[non_empty_list(term()), term()], dynamic(non_empty_list(term(), term()))}
218218
]},
219219
{:erlang, :--, [{[list(term()), list(term())], dynamic(list(term()))}]},
220-
{:erlang, :andalso, [{[boolean(), term()], dynamic()}]},
221220
{:erlang, :delete_element, [{[integer(), open_tuple([])], dynamic(open_tuple([]))}]},
222221
{:erlang, :hd, [{[non_empty_list(term(), term())], dynamic()}]},
223222
{:erlang, :element, [{[integer(), open_tuple([])], dynamic()}]},
@@ -226,7 +225,6 @@ defmodule Module.Types.Apply do
226225
{:erlang, :list_to_tuple, [{[list(term())], dynamic(open_tuple([]))}]},
227226
{:erlang, :max, [{[term(), term()], dynamic()}]},
228227
{:erlang, :min, [{[term(), term()], dynamic()}]},
229-
{:erlang, :orelse, [{[boolean(), term()], dynamic()}]},
230228
{:erlang, :send, [{[send_destination, term()], dynamic()}]},
231229
{:erlang, :setelement, [{[integer(), open_tuple([]), term()], dynamic(open_tuple([]))}]},
232230
{:erlang, :tl, [{[non_empty_list(term(), term())], dynamic()}]},
@@ -263,9 +261,7 @@ defmodule Module.Types.Apply do
263261
] do
264262
[arity] = Enum.map(clauses, fn {args, _return} -> length(args) end) |> Enum.uniq()
265263

266-
true =
267-
Code.ensure_loaded?(mod) and
268-
(function_exported?(mod, fun, arity) or fun in [:orelse, :andalso])
264+
true = Code.ensure_loaded?(mod)
269265

270266
domain_clauses =
271267
case clauses do

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,17 @@ defmodule Module.Types.Expr do
312312
{case_type, context} = of_expr(case_expr, @pending, case_expr, stack, context)
313313
info = {:case, meta, case_type, case_expr}
314314

315-
# If we are only type checking the expression and the expression is a literal,
316-
# let's mark it as generated, as it is most likely a macro code. However, if
317-
# no clause is matched, we should still check for that.
318-
if Macro.quoted_literal?(case_expr) do
315+
added_meta =
316+
if Macro.quoted_literal?(case_expr) do
317+
[generated: true]
318+
else
319+
case_expr |> get_meta() |> Keyword.take([:generated])
320+
end
321+
322+
# If the expression is generated or the construct is a literal,
323+
# it is most likely a macro code. However, if no clause is matched,
324+
# we should still check for that.
325+
if added_meta != [] do
319326
for {:->, meta, args} <- clauses, do: {:->, [generated: true] ++ meta, args}
320327
else
321328
clauses

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ defmodule Module.Types.Pattern do
760760
# the environment vars.
761761

762762
@atom_true atom([true])
763+
@atom_false atom([false])
763764

764765
defp of_guards([], _stack, context) do
765766
context
@@ -885,16 +886,28 @@ defmodule Module.Types.Pattern do
885886
end
886887
end
887888

888-
# TODO: Move orelse and andalso handling here, both may never be executed
889-
defp of_remote(fun, meta, [left, right], call, expected, stack, context)
890-
when fun in [:or, :orelse] do
891-
{info, [left_domain, right_domain], context} =
892-
Apply.remote_domain(:erlang, fun, [left, right], expected, meta, stack, context)
889+
defp of_remote(fun, _meta, [left, right], call, expected, stack, context)
890+
when fun in [:andalso, :orelse] do
891+
{both_domain, abort_domain} =
892+
case fun do
893+
:andalso -> {@atom_true, @atom_false}
894+
:orelse -> {@atom_false, @atom_true}
895+
end
896+
897+
# For example, if the expected type is true for andalso, then it can
898+
# only be true if both clauses are executed, so we know the first
899+
# argument has to be true and the second has to be expected.
900+
{left_domain, right_domain, surely_rhs?} =
901+
if subtype?(expected, both_domain) do
902+
{both_domain, expected, true}
903+
else
904+
{boolean(), term(), false}
905+
end
893906

894907
{left_type, context} = of_guard(left, left_domain, call, stack, context)
895908

896909
{right_type, context} =
897-
if fun == :or do
910+
if surely_rhs? do
898911
of_guard(right, right_domain, call, stack, context)
899912
else
900913
%{pattern_info: pattern_info} = context
@@ -903,8 +916,11 @@ defmodule Module.Types.Pattern do
903916
{type, %{context | pattern_info: pattern_info}}
904917
end
905918

906-
args_types = [left_type, right_type]
907-
Apply.remote_apply(info, :erlang, fun, args_types, call, stack, context)
919+
if compatible?(left_type, abort_domain) do
920+
{union(abort_domain, right_type), context}
921+
else
922+
{right_type, context}
923+
end
908924
end
909925

910926
defp of_remote(fun, meta, args, call, expected, stack, context) do

lib/elixir/lib/range.ex

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,6 @@ defmodule Range do
207207
%Range{first: first, last: last, step: step}
208208
end
209209

210-
def new(first, last) do
211-
raise ArgumentError,
212-
"ranges (first..last) expect both sides to be integers, " <>
213-
"got: #{inspect(first)}..#{inspect(last)}"
214-
end
215-
216210
@doc """
217211
Creates a new range with `step`.
218212

lib/elixir/test/elixir/enum_test.exs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,6 @@ defmodule EnumTest do
302302
assert Enum.drop([1, 2, 3], -2) == [1]
303303
assert Enum.drop([1, 2, 3], -4) == []
304304
assert Enum.drop([], 3) == []
305-
306-
assert_raise FunctionClauseError, fn ->
307-
Enum.drop([1, 2, 3], 0.0)
308-
end
309305
end
310306

311307
test "drop/2 with streams" do
@@ -542,10 +538,6 @@ defmodule EnumTest do
542538
Enum.map_every([1, 2, 3], -1, fn x -> x * 2 end)
543539
end
544540

545-
assert_raise FunctionClauseError, fn ->
546-
Enum.map_every(1..10, 3.33, fn x -> x * 2 end)
547-
end
548-
549541
assert Enum.map_every([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 9, fn x -> x + 1000 end) ==
550542
[1001, 2, 3, 4, 5, 6, 7, 8, 9, 1010]
551543

@@ -1204,10 +1196,6 @@ defmodule EnumTest do
12041196
assert_raise FunctionClauseError, fn ->
12051197
Enum.slice(list, 0.99, 0)
12061198
end
1207-
1208-
assert_raise FunctionClauseError, fn ->
1209-
Enum.slice(list, 0, 0.99)
1210-
end
12111199
end
12121200

12131201
test "slice on infinite streams" do
@@ -1432,10 +1420,6 @@ defmodule EnumTest do
14321420
assert Enum.split([1, 2, 3], -2) == {[1], [2, 3]}
14331421
assert Enum.split([1, 2, 3], -3) == {[], [1, 2, 3]}
14341422
assert Enum.split([1, 2, 3], -10) == {[], [1, 2, 3]}
1435-
1436-
assert_raise FunctionClauseError, fn ->
1437-
Enum.split([1, 2, 3], 0.0)
1438-
end
14391423
end
14401424

14411425
test "split_while/2" do
@@ -1537,10 +1521,6 @@ defmodule EnumTest do
15371521
assert Enum.take([1, 2, 3], -2) == [2, 3]
15381522
assert Enum.take([1, 2, 3], -4) == [1, 2, 3]
15391523
assert Enum.take([], 3) == []
1540-
1541-
assert_raise FunctionClauseError, fn ->
1542-
Enum.take([1, 2, 3], 0.0)
1543-
end
15441524
end
15451525

15461526
test "take_every/2" do
@@ -1554,10 +1534,6 @@ defmodule EnumTest do
15541534
assert_raise FunctionClauseError, fn ->
15551535
Enum.take_every([1, 2, 3], -1)
15561536
end
1557-
1558-
assert_raise FunctionClauseError, fn ->
1559-
Enum.take_every(1..10, 3.33)
1560-
end
15611537
end
15621538

15631539
test "take_random/2" do
@@ -1597,14 +1573,6 @@ defmodule EnumTest do
15971573
assert_raise FunctionClauseError, fn ->
15981574
Enum.take_random(1..10, -1)
15991575
end
1600-
1601-
assert_raise FunctionClauseError, fn ->
1602-
Enum.take_random(1..10, 10.0)
1603-
end
1604-
1605-
assert_raise FunctionClauseError, fn ->
1606-
Enum.take_random(1..10, 128.1)
1607-
end
16081576
end
16091577

16101578
test "take_while/2" do
@@ -2406,14 +2374,6 @@ defmodule EnumTest.Range do
24062374
Enum.slice(1..5, 0, -1)
24072375
end
24082376

2409-
assert_raise FunctionClauseError, fn ->
2410-
Enum.slice(1..5, 0.99, 0)
2411-
end
2412-
2413-
assert_raise FunctionClauseError, fn ->
2414-
Enum.slice(1..5, 0, 0.99)
2415-
end
2416-
24172377
assert Enum.slice(5..1//-1, 0, 0) == []
24182378
assert Enum.slice(5..1//-1, 0, 1) == [5]
24192379
assert Enum.slice(5..1//-1, 0, 2) == [5, 4]

lib/elixir/test/elixir/kernel_test.exs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ defmodule KernelTest do
658658
end
659659

660660
test "inside and/2" do
661-
response = %{code: 200}
661+
response = Process.get(:unused, %{code: 200})
662662

663663
if is_map(response) and response.code in 200..299 do
664664
:pass
@@ -712,20 +712,13 @@ defmodule KernelTest do
712712
""")
713713
end
714714

715-
test "with a non-integer range" do
716-
message = "ranges (first..last) expect both sides to be integers, got: 0..5.0"
717-
718-
assert_raise ArgumentError, message, fn ->
719-
last = 5.0
720-
1 in 0..last
721-
end
722-
end
723-
724715
test "hoists variables and keeps order" do
725716
# Ranges
726717
result = expand_to_string(quote(do: rand() in 1..2))
727718
assert result =~ "var = rand()"
728719

720+
result = expand_to_string(quote(do: var in 1..2), :guard)
721+
729722
assert result =~ """
730723
:erlang.andalso(
731724
:erlang.is_integer(var),
@@ -740,6 +733,8 @@ defmodule KernelTest do
740733
# Lists
741734
result = expand_to_string(quote(do: rand() in [1, 2]))
742735
assert result =~ "var = rand()"
736+
737+
result = expand_to_string(quote(do: var in [1, 2]), :guard)
743738
assert result =~ ":erlang.orelse(:erlang.\"=:=\"(var, 1), :erlang.\"=:=\"(var, 2))"
744739

745740
result = expand_to_string(quote(do: rand() in [1 | [2]]))
@@ -750,34 +745,34 @@ defmodule KernelTest do
750745
end
751746

752747
test "is optimized" do
753-
assert expand_to_string(quote(do: foo in [])) ==
754-
"_ = foo\nfalse"
748+
assert expand_to_string(quote(do: foo in []), :guard) ==
749+
"false"
755750

756-
assert expand_to_string(quote(do: foo in [1, 2, 3])) == """
751+
assert expand_to_string(quote(do: foo in [1, 2, 3]), :guard) == """
757752
:erlang.orelse(
758753
:erlang.orelse(:erlang.\"=:=\"(foo, 1), :erlang.\"=:=\"(foo, 2)),
759754
:erlang.\"=:=\"(foo, 3)
760755
)\
761756
"""
762757

763-
assert expand_to_string(quote(do: foo in 0..1)) == """
758+
assert expand_to_string(quote(do: foo in 0..1), :guard) == """
764759
:erlang.andalso(
765760
:erlang.is_integer(foo),
766761
:erlang.andalso(:erlang.>=(foo, 0), :erlang.\"=<\"(foo, 1))
767762
)\
768763
"""
769764

770-
assert expand_to_string(quote(do: foo in -1..0)) == """
765+
assert expand_to_string(quote(do: foo in -1..0), :guard) == """
771766
:erlang.andalso(
772767
:erlang.is_integer(foo),
773768
:erlang.andalso(:erlang.>=(foo, -1), :erlang.\"=<\"(foo, 0))
774769
)\
775770
"""
776771

777-
assert expand_to_string(quote(do: foo in 1..1)) ==
772+
assert expand_to_string(quote(do: foo in 1..1), :guard) ==
778773
":erlang.\"=:=\"(foo, 1)"
779774

780-
assert expand_to_string(quote(do: 2 in 1..3)) ==
775+
assert expand_to_string(quote(do: 2 in 1..3), :guard) ==
781776
":erlang.andalso(:erlang.is_integer(2), :erlang.andalso(:erlang.>=(2, 1), :erlang.\"=<\"(2, 3)))"
782777
end
783778

0 commit comments

Comments
 (0)