defmodule TypeCheck.TypeError do
@moduledoc """
Exception to be returned or raised when a value is not of the expected type.
This exception has two fields:
- `:raw`, which will contain the problem tuple of the type check failure.
- `:message`, which will contain a the humanly-readable representation of the raw problem_tuple
`:message` is constructed from `:raw` using the TypeCheck.TypeError.DefaultFormatter.
(TODO at some point this might be configured to use your custom formatter instead)
"""
defexception [:message, :raw, :location]
@type t() :: %__MODULE__{message: String.t(), raw: problem_tuple(), location: location()}
@typedoc """
Any built-in TypeCheck struct (c.f. `TypeCheck.Builtin.*`), whose check(s) failed.
"""
@type type_checked_against :: TypeCheck.Type.t()
@typedoc """
The name of the particular check. Might be `:no_match` for simple types,
but for more complex types that have multiple checks, it disambugates between them.
For instance, for `TypeCheck.Builtin.List` we have `:not_a_list`, `:different_length`, and `:element_error`.
"""
@type check_name :: atom()
@type location :: [] | [file: binary(), line: non_neg_integer()]
@typedoc """
An extra map with any information related to the check that failed.
For instance, if the check was a compound check, will contain the field `problem:` with the child problem_tuple
as well as `:index` or `:key` etc. to indicate _where_ in the compound structure the check failed.
"""
@type extra_information :: %{optional(atom) => any()}
@typedoc """
The value that was passed in which failed the check.
It is included for the easy creation of `value did not match y`-style messages.
"""
@type problematic_value :: any()
@typedoc """
A problem_tuple contains all information about a failed type check.
c.f. TypeCheck.TypeError.Formatter.problem_tuple for a more precise definition
"""
@type problem_tuple ::
{type_checked_against(), check_name(), extra_information(), problematic_value()}
@impl true
def exception({problem_tuple, location}) do
message = TypeCheck.TypeError.DefaultFormatter.format(problem_tuple, location)
%__MODULE__{message: message, raw: problem_tuple, location: location}
end
def exception(problem_tuple) do
exception({problem_tuple, []})
end
end