Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions lib/elixir/lib/calendar/date_range.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,20 @@ defmodule Date.Range do
end

# TODO: Remove me on v2.0
def member?(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range,
date
) do
member? =
quote generated: true do
member?(
%{
__struct__: Date.Range,
first_in_iso_days: var!(first_days),
last_in_iso_days: var!(last_days)
} =
var!(date_range),
var!(date)
)
end

def unquote(member?) do
step = if first_days <= last_days, do: 1, else: -1
member?(Map.put(date_range, :step, step), date)
end
Expand Down Expand Up @@ -218,11 +227,11 @@ defmodule Date.Range do
defimpl Inspect do
import Kernel, except: [inspect: 2]

def inspect(%Date.Range{first: first, last: last, step: 1}, _) do
def inspect(%Date.Range{first: first, last: last, step: 1}, %Inspect.Opts{}) do
"Date.range(" <> inspect(first) <> ", " <> inspect(last) <> ")"
end

def inspect(%Date.Range{first: first, last: last, step: step}, _) do
def inspect(%Date.Range{first: first, last: last, step: step}, %Inspect.Opts{}) do
"Date.range(" <> inspect(first) <> ", " <> inspect(last) <> ", #{step})"
end

Expand Down
31 changes: 23 additions & 8 deletions lib/elixir/lib/enum.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5168,7 +5168,16 @@ defimpl Enumerable, for: Range do
end

# TODO: Remove me on v2.0
def reduce(%{__struct__: Range, first: first, last: last} = range, acc, fun) do
reduce =
quote generated: true do
reduce(
%{__struct__: Range, first: var!(first), last: var!(last)} = var!(range),
var!(acc),
var!(fun)
)
end

def unquote(reduce) do
step = if first <= last, do: 1, else: -1
reduce(Map.put(range, :step, step), acc, fun)
end
Expand All @@ -5191,12 +5200,12 @@ defimpl Enumerable, for: Range do
{:done, acc}
end

def member?(first..last//step, value) when is_integer(value) do
if step > 0 do
{:ok, first <= value and value <= last and rem(value - first, step) == 0}
else
{:ok, last <= value and value <= first and rem(value - first, step) == 0}
end
def member?(first..last//step, value) when is_integer(value) and step > 0 do
{:ok, first <= value and value <= last and rem(value - first, step) == 0}
end

def member?(first..last//step, value) when is_integer(value) and step < 0 do
{:ok, last <= value and value <= first and rem(value - first, step) == 0}
end

# TODO: Remove me on v2.0
Expand All @@ -5219,7 +5228,13 @@ defimpl Enumerable, for: Range do
end

# TODO: Remove me on v2.0
def slice(%{__struct__: Range, first: first, last: last} = range) do

slice =
quote generated: true do
slice(%{__struct__: Range, first: var!(first), last: var!(last)} = var!(range))
end

def unquote(slice) do
step = if first <= last, do: 1, else: -1
slice(Map.put(range, :step, step))
end
Expand Down
10 changes: 9 additions & 1 deletion lib/elixir/lib/inspect.ex
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,15 @@ defimpl Inspect, for: Range do
end

# TODO: Remove me on v2.0
def inspect(%{__struct__: Range, first: first, last: last} = range, opts) do
inspect =
quote generated: true do
inspect(
%{__struct__: Range, first: var!(first), last: var!(last)} = var!(range),
var!(opts)
)
end

def unquote(inspect) do
step = if first <= last, do: 1, else: -1
inspect(Map.put(range, :step, step), opts)
end
Expand Down
19 changes: 10 additions & 9 deletions lib/elixir/lib/module/types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -319,16 +319,17 @@ defmodule Module.Types do
defp local_handler(mode, fun_arity, kind, meta, clauses, expected, stack, context) do
{fun, _arity} = fun_arity
stack = stack |> fresh_stack(mode, fun_arity) |> with_file_meta(meta)
base_info = {:def, kind, fun, expected}

{_, _, mapping, clauses_types, clauses_context} =
Enum.reduce(clauses, {0, 0, [], [], context}, fn
{meta, args, guards, body}, {index, total, mapping, inferred, context} ->
context = fresh_context(context)
info = {:def, kind, fun, args, guards, expected}
{_, _, _, mapping, clauses_types, clauses_context} =
Enum.reduce(clauses, {0, 0, [], [], [], context}, fn
{meta, args, guards, body}, {index, total, previous, mapping, inferred, acc_context} ->
fresh_context = fresh_context(acc_context)
info = {base_info, args, guards}

try do
{trees, _precise?, context} =
Pattern.of_head(args, guards, expected, info, meta, stack, context)
{trees, previous, context} =
Pattern.of_head(args, guards, expected, previous, info, meta, stack, fresh_context)

{return_type, context} =
Expr.of_expr(body, Descr.term(), body, stack, context)
Expand All @@ -339,9 +340,9 @@ defmodule Module.Types do
add_inferred(inferred, args_types, return_type, total - 1, [])

if type_index == -1 do
{index + 1, total + 1, [{index, total} | mapping], inferred, context}
{index + 1, total + 1, previous, [{index, total} | mapping], inferred, context}
else
{index + 1, total, [{index, type_index} | mapping], inferred, context}
{index + 1, total, previous, [{index, type_index} | mapping], inferred, context}
end
rescue
e ->
Expand Down
50 changes: 6 additions & 44 deletions lib/elixir/lib/module/types/expr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -719,62 +719,24 @@ defmodule Module.Types.Expr do
defp dynamic_unless_static({_, _} = output, %{mode: :static}), do: output
defp dynamic_unless_static({type, context}, %{mode: _}), do: {dynamic(type), context}

defp of_clauses(clauses, domain, expected, clause_info, stack, context, acc) do
defp of_clauses(clauses, domain, expected, base_info, stack, context, acc) do
fun = fn _args_types, result, _context, acc -> union(result, acc) end
of_clauses_fun(clauses, domain, expected, clause_info, stack, context, acc, fun)
of_clauses_fun(clauses, domain, expected, base_info, stack, context, acc, fun)
end

defp of_clauses_fun(clauses, domain, expected, clause_info, stack, original, acc, fun) do
defp of_clauses_fun(clauses, domain, expected, base_info, stack, original, acc, fun) do
%{failed: failed?} = original

{result, _previous, context} =
Enum.reduce(clauses, {acc, [], original}, fn
{:->, meta, [head, body]} = clause, {acc, previous, context} ->
{:->, meta, [head, body]}, {acc, previous, context} ->
{failed?, context} = reset_failed(context, failed?)
{patterns, guards} = extract_head(head)
info = {clause_info, head, previous}
info = {base_info, head}

{trees, precise?, context} =
{trees, previous, context} =
Pattern.of_head(patterns, guards, domain, previous, info, meta, stack, context)

# It failed, let's try to detect if it was due a previous or current clause.
# The current clause will be easier to understand, so we prefer that
{trees, precise?, context} =
if context.failed and previous != [] do
info = {clause_info, head, []}

case Pattern.of_head(patterns, guards, domain, info, meta, stack, context) do
{_, _, %{failed: true}} = result -> result
_ -> {trees, precise?, context}
end
else
{trees, precise?, context}
end

{previous, context} =
if context.failed do
{previous, context}
else
args_types =
Enum.map(trees, fn {tree, _, _} ->
tree
|> Pattern.of_pattern_tree(stack, context)
|> upper_bound()
end)

cond do
stack.mode != :infer and previous != [] and
Pattern.args_subtype?(args_types, previous) ->
{previous, Pattern.redundant_warn(clause, previous, stack, context)}

precise? ->
{[args_types | previous], context}

true ->
{previous, context}
end
end

{result, context} = of_expr(body, expected, body, stack, context)

{fun.(trees, result, context, acc), previous,
Expand Down
7 changes: 7 additions & 0 deletions lib/elixir/lib/module/types/of.ex
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ defmodule Module.Types.Of do
}),
do: %{context | subpatterns: subpatterns, vars: vars, conditional_vars: conditional_vars}

@doc """
Returns true if all entries have the same conditional vars.
"""
def all_same_conditional_vars?([{_, cond} | tail]) do
Enum.all?(tail, fn {_, tail_cond} -> cond == tail_cond end)
end

@doc """
Executes the args with acc using conditional variables.
"""
Expand Down
Loading
Loading