Skip to content

Commit

Permalink
Much more default overrides
Browse files Browse the repository at this point in the history
  • Loading branch information
Qqwy committed May 29, 2022
1 parent b06eb68 commit 00278ec
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ Details:
- Desugaring `%{}` has changed from 'any map' to 'the empty map' in line with Elixir's Typespecs. _This is a minor backwards-incompatible change._
- Support for the builtin types `port()`, `reference()` and (based on these) `identifier()`.
- Support for the builtin type `struct()`.
- Support for the builtin type `timeout()`.
- Improvements to the default type overrides for modules like `Calendar`, `Enum`, `Enumerable`, etc. now that optional keys in struct types and higher-order function types are supported.
- Addition of many more default type override modules, to ensure all of Elixir's standard library is covered.
- `TypeCheck.Credo.Check.Readability.Specs` is an opt-in alternative Credo check which will check whether all functions have either a `@spec!` or 'normal' `@spec`. (Fixes #102).
- 0.10.8 -
- Fixes:
Expand Down
10 changes: 10 additions & 0 deletions lib/type_check/builtin.ex
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ defmodule TypeCheck.Builtin do
build_struct(TypeCheck.Builtin.Number)
end

@doc typekind: :builtin
@doc """
Builtin type. Syntactic sugar for `:infinity | non_neg_integer()`
"""
def timeout() do
one_of([literal(:infinity), non_neg_integer()])
end

@doc typekind: :builtin
@doc """
A (proper) list with any type of elements;
Expand Down Expand Up @@ -640,6 +648,8 @@ defmodule TypeCheck.Builtin do
- for integers, atoms and booleans: the primitive value itself.
- for binaries, a more general `binary()` is used
as Elixir's builtin typespecs do not support literal UTF-8 binaries as literal values.
- For other kinds of values which Elixir's builtin typespecs do not support as literals,
we similarly represent it as a more general type.
C.f. `TypeCheck.Builtin.Literal`
"""
Expand Down
10 changes: 10 additions & 0 deletions lib/type_check/default_overrides.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ defmodule TypeCheck.DefaultOverrides do

@elixir_modules ~w[
Access
Agent
Application
Calendar
Calendar.ISO
Calendar.TimeZoneDatabase
Collectable
Config.Provider
Date
Date.Range
DateTime
DynamicSupervisor
Enum
Enumerable
Exception
Expand All @@ -33,6 +37,7 @@ defmodule TypeCheck.DefaultOverrides do
File.Stream
Float
Function
GenServer
Inspect
IO
IO.ANSI
Expand All @@ -42,14 +47,19 @@ defmodule TypeCheck.DefaultOverrides do
MapSet
Module
NaiveDateTime
Node
OptionParser
Path
Port
Process
Range
Regex
Registry
Stream
String
Supervisor
System
Task
Time
URI
Version
Expand Down
11 changes: 11 additions & 0 deletions lib/type_check/default_overrides/agent.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule TypeCheck.DefaultOverrides.Agent do
use TypeCheck

@type! agent() :: pid() | {atom(), node()} | name()

@type! name() :: atom() | {:global, term()} | {:via, module(), term()}

@type! on_start() :: {:ok, pid()} | {:error, {:already_started, pid()} | term()}

@type! state() :: term()
end
28 changes: 28 additions & 0 deletions lib/type_check/default_overrides/application.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule TypeCheck.DefaultOverrides.Application do
use TypeCheck
@type! app() :: atom()

@type! application_key() ::
:start_phases
| :mod
| :applications
| :optional_applications
| :included_applications
| :registered
| :maxT
| :maxP
| :modules
| :vsn
| :id
| :description

@type! key() :: atom()

@type! restart_type() :: :permanent | :transient | :temporary

@type! start_type() :: :normal | {:takeover, node()} | {:failover, node()}

@type! state() :: term()

@type! value() :: term()
end
9 changes: 9 additions & 0 deletions lib/type_check/default_overrides/config/provider.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule TypeCheck.DefaultOverrides.Config.Provider do
use TypeCheck

@type! config() :: keyword()

@type! config_path() :: {:system, binary(), binary()} | binary()

@type! state() :: term()
end
29 changes: 29 additions & 0 deletions lib/type_check/default_overrides/dynamic_supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule TypeCheck.DefaultOverrides.DynamicSupervisor do
use TypeCheck
alias TypeCheck.DefaultOverrides.GenServer

@type! init_option() ::
{:strategy, strategy()}
| {:max_restarts, non_neg_integer()}
| {:max_seconds, pos_integer()}
| {:max_children, non_neg_integer() | :infinity}
| {:extra_arguments, [term()]}

@type! on_start_child() ::
{:ok, pid()}
| {:ok, pid(), info :: term()}
| :ignore
| {:error, {:already_started, pid()} | :max_children | term()}

@type! option() :: GenServer.option()

@type! strategy() :: :one_for_one

@type! sup_flags() :: %{
strategy: strategy(),
intensity: non_neg_integer(),
period: pos_integer(),
max_children: non_neg_integer() | :infinity,
extra_arguments: [term()]
}
end
26 changes: 26 additions & 0 deletions lib/type_check/default_overrides/gen_server.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule TypeCheck.DefaultOverrides.GenServer do
use TypeCheck
alias TypeCheck.DefaultOverrides.Process

# TODO
# @type! debug() :: [:trace | :log | :statistics | {:log_to_file, Path.t()}]
@type! debug() :: [:trace | :log | :statistics | {:log_to_file, any()}]

@type! from() :: {pid(), tag :: term()}

@type! name() :: atom() | {:global, term()} | {:via, module(), term()}

@type! on_start() ::
{:ok, pid()} | :ignore | {:error, {:already_started, pid()} | term()}

@type! option() ::
{:debug, debug()}
| {:name, name()}
| {:timeout, timeout()}
| {:spawn_opt, [Process.spawn_opt()]}
| {:hibernate_after, timeout()}

@type! options() :: [option()]

@type! server() :: pid() | name() | {atom(), node()}
end
7 changes: 7 additions & 0 deletions lib/type_check/default_overrides/node.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule TypeCheck.DefaultOverrides.Node do
use TypeCheck

@type! state() :: :visible | :hidden | :connected | :this | :known

@type! t() :: node()
end
33 changes: 33 additions & 0 deletions lib/type_check/default_overrides/process.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule TypeCheck.DefaultOverrides.Process do
use TypeCheck

@type! dest() ::
pid()
| port()
| (registered_name :: atom())
| {registered_name :: atom(), node()}

@typep! heap_size() ::
non_neg_integer()
| %{size: non_neg_integer(), kill: boolean(), error_logger: boolean()}

@typep! monitor_option() :: list(
{:alias, :explicit_unalias | :demonitor | :reply_demonitor} |
{:tag, term()}
)

# @typep! priority_level() :: :low | :normal | :high | :max

@type! spawn_opt() ::
:link
| :monitor
| {:monitor, monitor_option()}
| {:priority, :low | :normal | :high}
| {:fullsweep_after, non_neg_integer()}
| {:min_heap_size, non_neg_integer()}
| {:min_bin_vheap_size, non_neg_integer()}
| {:max_heap_size, heap_size()}
| {:message_queue_data, :off_heap | :on_heap}

@type! spawn_opts() :: [spawn_opt()]
end
32 changes: 32 additions & 0 deletions lib/type_check/default_overrides/registry.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule TypeCheck.DefaultOverrides.Registry do
use TypeCheck

@type body() :: [term()]

@type guard() :: atom() | tuple()

@type guards() :: [guard()]

@type key() :: term()

@type keys() :: :unique | :duplicate

@type match_pattern() :: atom() | term()

@type meta_key() :: atom() | tuple()

@type meta_value() :: term()

@type registry() :: atom()

@type spec() :: [{match_pattern(), guards(), body()}]

@type start_option() ::
{:keys, keys()}
| {:name, registry()}
| {:partitions, pos_integer()}
| {:listeners, [atom()]}
| {:meta, [{meta_key(), meta_value()}]}

@type value() :: term()
end
37 changes: 37 additions & 0 deletions lib/type_check/default_overrides/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule TypeCheck.DefaultOverrides.Supervisor do
use TypeCheck

@type! child() :: pid() | :undefined

@type! child_spec() :: %{
:id => atom() | term(),
:start => {module(), atom(), [term()]},
optional(:restart) => :permanent | :transient | :temporary,
optional(:shutdown) => timeout() | :brutal_kill,
optional(:type) => :worker | :supervisor,
optional(:modules) => [module()] | :dynamic
}

@type! init_option() ::
{:strategy, strategy()}
| {:max_restarts, non_neg_integer()}
| {:max_seconds, pos_integer()}

@type! name() :: atom() | {:global, term()} | {:via, module(), term()}

@type! on_start() ::
{:ok, pid()}
| :ignore
| {:error, {:already_started, pid()} | {:shutdown, term()} | term()}

@type! on_start_child() ::
{:ok, child()}
| {:ok, child(), info :: term()}
| {:error, {:already_started, child()} | :already_present | term()}

@type! option() :: {:name, name()}

@type! strategy() :: :one_for_one | :one_for_all | :rest_for_one

@type! supervisor() :: pid() | name() | {atom(), node()}
end
5 changes: 5 additions & 0 deletions lib/type_check/default_overrides/task.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defmodule TypeCheck.DefaultOverrides.Task do
use TypeCheck

@type! t() :: %Task{owner: pid(), pid: pid() | nil, ref: reference()}
end
6 changes: 6 additions & 0 deletions lib/type_check/default_overrides/task/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule TypeCheck.DefaultOverrides.Task.Supervisor do
use TypeCheck
alias TypeCheck.DefaultOverrides.DynamicSupervisor

@type! option() :: DynamicSupervisor.option() | DynamicSupervisor.init_option()
end

0 comments on commit 00278ec

Please sign in to comment.