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
4 changes: 2 additions & 2 deletions lib/elixir/lib/kernel/parallel_compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ defmodule Kernel.ParallelCompiler do

defp spawn_workers(schedulers, checker, files, output, options) do
threshold = Keyword.get(options, :long_compilation_threshold, 10) * 1000
timer_ref = Process.send_after(self(), :threshold_check, threshold)
timer_ref = :erlang.send_after(threshold, self(), :threshold_check)

purge_compiler_modules =
if Keyword.get(options, :purge_compiler_modules, false) do
Expand Down Expand Up @@ -840,7 +840,7 @@ defmodule Kernel.ParallelCompiler do
end
end

timer_ref = Process.send_after(self(), :threshold_check, state.long_compilation_threshold)
timer_ref = :erlang.send_after(state.long_compilation_threshold, self(), :threshold_check)
state = %{state | timer_ref: timer_ref}
spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)

Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/lib/module/parallel_checker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ defmodule Module.ParallelChecker do

defp run_checkers(%{modules: [{module, pid, ref} | modules]} = state) do
send(pid, {ref, :check})
timer = Process.send_after(self(), {__MODULE__, :timeout, module, pid}, state.threshold)
timer = :erlang.send_after(state.threshold, self(), {__MODULE__, :timeout, module, pid})
spawned = Map.put(state.spawned, module, timer)
run_checkers(%{state | modules: modules, spawned: spawned})
end
Expand Down
216 changes: 198 additions & 18 deletions lib/elixir/lib/module/types/apply.ex
Original file line number Diff line number Diff line change
Expand Up @@ -236,24 +236,39 @@ defmodule Module.Types.Apply do
{:erlang, :tl, [{[non_empty_list(term(), term())], dynamic()}]},
{:erlang, :tuple_to_list, [{[open_tuple([])], dynamic(list(term()))}]},

## Kernel
{Kernel, :elem, [{[open_tuple([]), integer()], dynamic()}]},
{Kernel, :is_map_key, [{[open_map(), term()], boolean()}]},
{Kernel, :put_elem, [{[open_tuple([]), integer(), term()], dynamic(open_tuple([]))}]},

## Lists
{:lists, :member, [{[term(), list(term())], boolean()}]},

## Map
{Map, :delete, [{[open_map(), term()], open_map()}]},
{Map, :fetch,
[{[open_map(), term()], tuple([atom([:ok]), term()]) |> union(atom([:error]))}]},
{Map, :fetch!, [{[open_map(), term()], term()}]},
{Map, :from_struct, [{[open_map()], open_map(__struct__: not_set())}]},
{Map, :get, [{[open_map(), term()], term()}]},
{Map, :get, [{[open_map(), term(), term()], term()}]},
{Map, :get_lazy, [{[open_map(), term(), fun(0)], term()}]},
{Map, :has_key?, [{[open_map(), term()], boolean()}]},
{Map, :pop, [{[open_map(), term()], tuple([term(), open_map()])}]},
{Map, :pop, [{[open_map(), term(), term()], tuple([term(), open_map()])}]},
{Map, :pop!, [{[open_map(), term()], tuple([term(), open_map()])}]},
{Map, :pop_lazy, [{[open_map(), term(), fun(0)], tuple([term(), open_map()])}]},
{Map, :put, [{[open_map(), term(), term()], open_map()}]},
{Map, :put_new, [{[open_map(), term(), term()], open_map()}]},
{Map, :put_new_lazy, [{[open_map(), term(), fun(0)], open_map()}]},
{Map, :replace, [{[open_map(), term(), term()], open_map()}]},
{Map, :replace!, [{[open_map(), term(), term()], open_map()}]},
{Map, :replace_lazy, [{[open_map(), term(), fun(1)], open_map()}]},
{Map, :update, [{[open_map(), term(), term(), fun(1)], open_map()}]},
{Map, :update!, [{[open_map(), term(), fun(1)], open_map()}]},
{Tuple, :delete_at, [{[open_tuple([]), integer()], dynamic(open_tuple([]))}]},
{Tuple, :duplicate, [{[term(), integer()], tuple()}]},
{Tuple, :insert_at, [{[open_tuple([]), integer(), term()], dynamic(open_tuple([]))}]},
{:maps, :from_keys, [{[list(term()), term()], open_map()}]},
{:maps, :find,
[{[term(), open_map()], tuple([atom([:ok]), term()]) |> union(atom([:error]))}]},
Expand All @@ -270,8 +285,6 @@ defmodule Module.Types.Apply do
] do
[arity] = Enum.map(clauses, fn {args, _return} -> length(args) end) |> Enum.uniq()

true = Code.ensure_loaded?(mod)

domain_clauses =
case clauses do
[_] ->
Expand Down Expand Up @@ -487,31 +500,28 @@ defmodule Module.Types.Apply do
end
end

defp do_remote(:erlang, :setelement, [index, tuple, elem], _, expr, stack, context, of_fun)
when is_integer(index) and index < 1 do
{_, context} = of_fun.(tuple, open_tuple([]), expr, stack, context)
{_, context} = of_fun.(elem, term(), expr, stack, context)
remote_error({:negindex, index - 1}, :erlang, :setelement, 3, expr, stack, context)
end

defp do_remote(:erlang, :setelement, [index, tuple, elem], _, expr, stack, context, of_fun)
when is_integer(index) do
tuple_type = open_tuple(List.duplicate(term(), max(index, 1)))

{tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)
{elem_type, context} = of_fun.(elem, term(), expr, stack, context)

case tuple_replace_at(tuple_type, index - 1, elem_type) do
value_type when is_descr(value_type) ->
{return(value_type, [tuple_type, elem_type], stack), context}
if index < 1 do
remote_error({:negindex, index - 1}, :erlang, :setelement, 3, expr, stack, context)
else
case tuple_replace_at(tuple_type, index - 1, elem_type) do
value_type when is_descr(value_type) ->
{return(value_type, [tuple_type, elem_type], stack), context}

:badtuple ->
args_types = [integer(), tuple_type, elem_type]
remote_error(:erlang, :setelement, args_types, expr, stack, context)
:badtuple ->
args_types = [integer(), tuple_type, elem_type]
remote_error(:erlang, :setelement, args_types, expr, stack, context)

:badindex ->
error = {:badindex, index, tuple_type}
remote_error(error, :erlang, :setelement, 3, expr, stack, context)
:badindex ->
error = {:badindex, index, tuple_type}
remote_error(error, :erlang, :setelement, 3, expr, stack, context)
end
end
end

Expand All @@ -537,6 +547,105 @@ defmodule Module.Types.Apply do
end
end

defp do_remote(Kernel, :elem, [tuple, index], expected, expr, stack, context, of_fun)
when is_integer(index) do
tuple_type = open_tuple(List.duplicate(term(), max(index, 0)) ++ [expected])
{tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)

if index < 0 do
remote_error({:negindex, index}, Kernel, :elem, 2, expr, stack, context)
else
case tuple_fetch(tuple_type, index) do
{_optional?, value_type} ->
{return(value_type, [tuple_type], stack), context}

:badtuple ->
remote_error(Kernel, :elem, [tuple_type, integer()], expr, stack, context)

:badindex ->
remote_error({:badindex, index + 1, tuple_type}, Kernel, :elem, 2, expr, stack, context)
end
end
end

defp do_remote(Kernel, :put_elem, [tuple, index, elem], _, expr, stack, context, of_fun)
when is_integer(index) do
tuple_type = open_tuple(List.duplicate(term(), max(index + 1, 1)))

{tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)
{elem_type, context} = of_fun.(elem, term(), expr, stack, context)

if index < 0 do
remote_error({:negindex, index}, Kernel, :put_elem, 3, expr, stack, context)
else
case tuple_replace_at(tuple_type, index, elem_type) do
value_type when is_descr(value_type) ->
{return(value_type, [tuple_type, elem_type], stack), context}

:badtuple ->
args_types = [tuple_type, integer(), elem_type]
remote_error(Kernel, :put_elem, args_types, expr, stack, context)

:badindex ->
error = {:badindex, index + 1, tuple_type}
remote_error(error, Kernel, :put_elem, 3, expr, stack, context)
end
end
end

defp do_remote(Tuple, :duplicate, [elem, size], _, expr, stack, context, of_fun)
when is_integer(size) and size >= 0 do
{elem_type, context} = of_fun.(elem, term(), expr, stack, context)
{return(tuple(List.duplicate(elem_type, size)), [elem_type], stack), context}
end

defp do_remote(Tuple, :insert_at, [tuple, index, elem], _, expr, stack, context, of_fun)
when is_integer(index) do
tuple_type = open_tuple(List.duplicate(term(), max(index, 0)))

{tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)
{elem_type, context} = of_fun.(elem, term(), expr, stack, context)

if index < 0 do
remote_error({:negindex, index}, Tuple, :insert_at, 3, expr, stack, context)
else
case tuple_insert_at(tuple_type, index, elem_type) do
value_type when is_descr(value_type) ->
{return(value_type, [tuple_type, elem_type], stack), context}

:badtuple ->
args_types = [tuple_type, integer(), elem_type]
remote_error(Tuple, :insert_at, args_types, expr, stack, context)

:badindex ->
error = {:badindex, index, tuple_type}
remote_error(error, Tuple, :insert_at, 3, expr, stack, context)
end
end
end

defp do_remote(Tuple, :delete_at, [tuple, index], _, expr, stack, context, of_fun)
when is_integer(index) do
tuple_type = open_tuple(List.duplicate(term(), max(index + 1, 1)))
{tuple_type, context} = of_fun.(tuple, tuple_type, expr, stack, context)

if index < 0 do
remote_error({:negindex, index}, Tuple, :delete_at, 2, expr, stack, context)
else
case tuple_delete_at(tuple_type, index) do
value_type when is_descr(value_type) ->
{return(value_type, [tuple_type], stack), context}

:badtuple ->
remote_error(Tuple, :delete_at, [tuple_type, integer()], expr, stack, context)

:badindex ->
error = {:badindex, index + 1, tuple_type}
remote_error(error, Tuple, :delete_at, 2, expr, stack, context)
end
end
end

defp do_remote(:lists, :member, [arg, list] = args, expected, expr, stack, context, of_fun)
when is_list(list) do
if list == [] or Enum.any?(list, &match?({:|, _, [_, _]}, &1)) do
Expand Down Expand Up @@ -877,17 +986,40 @@ defmodule Module.Types.Apply do
{info, filter_domain(info, expected, 2), context}
end

def remote_domain(Kernel, :is_map_key, [_map, key], expected, _meta, _stack, context)
when is_atom(key) do
info =
{:strong, [open_map(), term()],
[
{[open_map([{key, term()}]), term()], atom([true])},
{[open_map([{key, not_set()}]), term()], atom([false])}
]}

{info, filter_domain(info, expected, 2), context}
end

def remote_domain(:erlang, :map_get, [key, _], expected, _meta, _stack, context)
when is_atom(key) do
domain = [term(), open_map([{key, expected}])]
{{:strong, nil, [{domain, term()}]}, domain, context}
end

def remote_domain(Map, :fetch!, [_, key], expected, _meta, _stack, context) when is_atom(key) do
domain = [open_map([{key, expected}]), term()]
{{:strong, nil, [{domain, term()}]}, domain, context}
end

def remote_domain(:maps, :get, [key, _], expected, _meta, _stack, context) when is_atom(key) do
domain = [term(), open_map([{key, expected}])]
{{:strong, nil, [{domain, term()}]}, domain, context}
end

def remote_domain(Map, :replace!, [_, key, _], _expected, _meta, _stack, context)
when is_atom(key) do
domain = [open_map([{key, term()}]), term(), term()]
{{:strong, nil, [{domain, open_map()}]}, domain, context}
end

def remote_domain(:maps, :update, [key, _, _], _expected, _meta, _stack, context)
when is_atom(key) do
domain = [term(), term(), open_map([{key, term()}])]
Expand Down Expand Up @@ -967,6 +1099,36 @@ defmodule Module.Types.Apply do
end
end

defp remote_apply(Map, :delete, _info, [map, key] = args_types, stack) do
case map_update(map, key, not_set(), false, true) do
{_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}
:badmap -> {:error, badremote(Map, :delete, args_types)}
{:error, _errors} -> {:ok, map}
end
end

defp remote_apply(Map, :fetch, _info, [map, key] = args_types, stack) do
case map_get(map, key) do
{_, value} ->
result = tuple([atom([:ok]), value]) |> union(atom([:error]))
{:ok, return(result, args_types, stack)}

:badmap ->
{:error, badremote(Map, :fetch, args_types)}

:error ->
{:error, {:badkeydomain, map, key, atom([:error])}}
end
end

defp remote_apply(Map, :fetch!, _info, [map, key] = args_types, stack) do
case map_get(map, key) do
{:ok, value} -> {:ok, return(value, args_types, stack)}
:badmap -> {:error, badremote(Map, :fetch!, args_types)}
:error -> {:error, {:badkeydomain, map, key, "raise"}}
end
end

defp remote_apply(Map, :get, _info, [map, key] = args_types, stack) do
case map_get(map, key) do
{:ok, value} -> {:ok, return(union(value, @nil_atom), args_types, stack)}
Expand Down Expand Up @@ -1048,6 +1210,14 @@ defmodule Module.Types.Apply do
end
end

defp remote_apply(Map, :put, _info, [map, key, value] = args_types, stack) do
case map_update(map, key, value, false, true) do
{_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}
:badmap -> {:error, badremote(Map, :put, args_types)}
{:error, _errors} -> {:ok, map}
end
end

defp remote_apply(Map, :pop!, _info, [map, key] = args_types, stack) do
case map_update(map, key, not_set(), true, false) do
{value, descr, _errors} -> {:ok, return(tuple([value, descr]), args_types, stack)}
Expand All @@ -1066,6 +1236,16 @@ defmodule Module.Types.Apply do
end
end

defp remote_apply(Map, :replace!, _info, [map, key, value] = args_types, stack) do
fun = fn optional?, _type -> if optional?, do: if_set(value), else: value end

case map_update_fun(map, key, fun, false, false) do
{_value, descr, _errors} -> {:ok, return(descr, args_types, stack)}
:badmap -> {:error, badremote(Map, :replace!, args_types)}
{:error, _errors} -> {:error, {:badkeydomain, map, key, "raise"}}
end
end

defp remote_apply(Map, :replace_lazy, _info, args_types, stack) do
map_update_or_replace_lazy(:replace_lazy, args_types, stack, "do nothing")
end
Expand Down
2 changes: 0 additions & 2 deletions lib/elixir/lib/process.ex
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,6 @@ defmodule Process do
automatically canceled when `dest` is an atom (as the atom resolution is done
on delivery).
Inlined by the compiler.
## Options
* `:abs` - (boolean) when `false`, `time` is treated as relative to the
Expand Down
Loading
Loading