From 4709c6a4818ca4cf796e766e5eb5a77b4e634730 Mon Sep 17 00:00:00 2001 From: Marten/Qqwy Date: Mon, 13 Jun 2022 23:39:03 +0200 Subject: [PATCH 1/5] Simplify problem tuples in ToCheck implementations. Will not work without extra changes to Formatter. --- lib/type_check/builtin/atom.ex | 4 ++-- lib/type_check/builtin/binary.ex | 4 ++-- lib/type_check/builtin/bitstring.ex | 4 ++-- lib/type_check/builtin/boolean.ex | 4 ++-- lib/type_check/builtin/compound_fixed_map.ex | 18 +++++++++--------- lib/type_check/builtin/fixed_list.ex | 14 +++++++------- lib/type_check/builtin/fixed_map.ex | 16 ++++++++-------- lib/type_check/builtin/fixed_tuple.ex | 12 ++++++------ lib/type_check/builtin/float.ex | 4 ++-- lib/type_check/builtin/function.ex | 6 +++--- lib/type_check/builtin/guarded.ex | 4 ++-- lib/type_check/builtin/implements_protocol.ex | 4 ++-- lib/type_check/builtin/integer.ex | 4 ++-- lib/type_check/builtin/list.ex | 8 ++++---- lib/type_check/builtin/literal.ex | 4 ++-- lib/type_check/builtin/map.ex | 12 ++++++------ lib/type_check/builtin/maybe_improper_list.ex | 12 ++++++------ lib/type_check/builtin/named_type.ex | 4 ++-- lib/type_check/builtin/neg_integer.ex | 4 ++-- lib/type_check/builtin/non_neg_integer.ex | 4 ++-- lib/type_check/builtin/none.ex | 4 ++-- lib/type_check/builtin/number.ex | 4 ++-- lib/type_check/builtin/one_of.ex | 4 ++-- lib/type_check/builtin/pid.ex | 4 ++-- lib/type_check/builtin/port.ex | 4 ++-- lib/type_check/builtin/pos_integer.ex | 4 ++-- lib/type_check/builtin/range.ex | 8 ++++---- lib/type_check/builtin/reference.ex | 4 ++-- lib/type_check/builtin/sized_bitstring.ex | 12 ++++++------ lib/type_check/builtin/tuple.ex | 4 ++-- 30 files changed, 99 insertions(+), 99 deletions(-) diff --git a/lib/type_check/builtin/atom.ex b/lib/type_check/builtin/atom.ex index 054fd18f..fe0e6967 100644 --- a/lib/type_check/builtin/atom.ex +++ b/lib/type_check/builtin/atom.ex @@ -9,7 +9,7 @@ defmodule TypeCheck.Builtin.Atom do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -19,7 +19,7 @@ defmodule TypeCheck.Builtin.Atom do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/binary.ex b/lib/type_check/builtin/binary.ex index 241e39a9..a3e750cf 100644 --- a/lib/type_check/builtin/binary.ex +++ b/lib/type_check/builtin/binary.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Binary do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Binary do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/bitstring.ex b/lib/type_check/builtin/bitstring.ex index 578a8a2c..9674914f 100644 --- a/lib/type_check/builtin/bitstring.ex +++ b/lib/type_check/builtin/bitstring.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Bitstring do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Bitstring do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/boolean.ex b/lib/type_check/builtin/boolean.ex index 12ec2ca3..7ee0557a 100644 --- a/lib/type_check/builtin/boolean.ex +++ b/lib/type_check/builtin/boolean.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Boolean do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Boolean do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/compound_fixed_map.ex b/lib/type_check/builtin/compound_fixed_map.ex index bd75b8f8..0afd8536 100644 --- a/lib/type_check/builtin/compound_fixed_map.ex +++ b/lib/type_check/builtin/compound_fixed_map.ex @@ -12,12 +12,12 @@ defmodule TypeCheck.Builtin.CompoundFixedMap do @type! t :: %__MODULE__{fixed: TypeCheck.Builtin.FixedMap.t(), flexible: TypeCheck.Builtin.Map.t()} @type! problem_tuple :: - {t(), :not_a_map, %{}, any()} - | {t(), :missing_keys, %{keys: list(atom())}, map()} - | {t(), :superfluous_keys, %{keys: list(atom())}, map()} - | {t(), :value_error, + {:not_a_map, %{}, any()} + | {:missing_keys, %{keys: list(atom())}, map()} + | {:superfluous_keys, %{keys: list(atom())}, map()} + | {:value_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), key: any()}, map()} - | {t(), :key_error, + | {:key_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), key: any()}, map()} defimpl TypeCheck.Protocols.ToCheck do @@ -36,21 +36,21 @@ defmodule TypeCheck.Builtin.CompoundFixedMap do do {:ok, bindings1 ++ bindings2, Map.merge(fixed_part, flexible_part)} else - {:error, {_, reason, info, _val}} -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), reason, info, unquote(param)}} + {:error, {reason, info, _val}} -> + {:error, {reason, info, unquote(param)}} end end res end - defp map_check(param, s) do + defp map_check(param, _s) do quote generated: true, location: :keep do case unquote(param) do val when is_map(val) -> {:ok, [], val} other -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :not_a_map, %{}, other}} + {:error, {:not_a_map, %{}, other}} end end end diff --git a/lib/type_check/builtin/fixed_list.ex b/lib/type_check/builtin/fixed_list.ex index 2ad639e0..b00a7836 100644 --- a/lib/type_check/builtin/fixed_list.ex +++ b/lib/type_check/builtin/fixed_list.ex @@ -14,9 +14,9 @@ defmodule TypeCheck.Builtin.FixedList do @type! t :: %__MODULE__{element_types: list(TypeCheck.Type.t())} @type! problem_tuple :: - {t(), :not_a_list, %{}, any()} - | {t(), :different_length, %{expected_length: non_neg_integer()}, list()} - | {t(), :element_error, + {:not_a_list, %{}, any()} + | {:different_length, %{expected_length: non_neg_integer()}, list()} + | {:element_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), index: non_neg_integer()}, list()} @@ -28,11 +28,11 @@ defmodule TypeCheck.Builtin.FixedList do quote generated: :true, location: :keep do case unquote(param) do x when not is_list(x) -> - {:error, {unquote(Macro.escape(s)), :not_a_list, %{}, x}} + {:error, {:not_a_list, %{}, x}} x when length(x) != unquote(expected_length) -> {:error, - {unquote(Macro.escape(s)), :different_length, + {:different_length, %{expected_length: unquote(expected_length)}, x}} _ -> @@ -41,7 +41,7 @@ defmodule TypeCheck.Builtin.FixedList do end end - def build_element_checks_ast(element_types, param, s) do + def build_element_checks_ast(element_types, param, _s) do element_checks = element_types |> Enum.with_index() @@ -75,7 +75,7 @@ defmodule TypeCheck.Builtin.FixedList do else {{:error, error}, index, _rest} -> {:error, - {unquote(Macro.escape(s)), :element_error, %{problem: error, index: index}, + {:element_error, %{problem: error, index: index}, unquote(param)}} end end diff --git a/lib/type_check/builtin/fixed_map.ex b/lib/type_check/builtin/fixed_map.ex index ac34adb1..fc55c775 100644 --- a/lib/type_check/builtin/fixed_map.ex +++ b/lib/type_check/builtin/fixed_map.ex @@ -14,10 +14,10 @@ defmodule TypeCheck.Builtin.FixedMap do @type! t :: %__MODULE__{keypairs: list({term(), TypeCheck.Type.t()})} @type! problem_tuple :: - {t(), :not_a_map, %{}, any()} - | {t(), :missing_keys, %{keys: list(atom())}, map()} - | {t(), :superfluous_keys, %{keys: list(atom())}, map()} - | {t(), :value_error, + {:not_a_map, %{}, any()} + | {:missing_keys, %{keys: list(atom())}, map()} + | {:superfluous_keys, %{keys: list(atom())}, map()} + | {:value_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), key: any()}, map()} @@ -55,7 +55,7 @@ defmodule TypeCheck.Builtin.FixedMap do val when is_map(val) -> {:ok, [], val} other -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :not_a_map, %{}, other}} + {:error, {:not_a_map, %{}, other}} end end end @@ -76,7 +76,7 @@ defmodule TypeCheck.Builtin.FixedMap do missing_keys -> {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :missing_keys, %{keys: missing_keys}, unquote(param)}} + {:missing_keys, %{keys: missing_keys}, unquote(param)}} end end end @@ -96,7 +96,7 @@ defmodule TypeCheck.Builtin.FixedMap do superfluous_keys -> {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :superfluous_keys, %{keys: superfluous_keys}, + {:superfluous_keys, %{keys: superfluous_keys}, unquote(param)}} end end @@ -133,7 +133,7 @@ defmodule TypeCheck.Builtin.FixedMap do else {{:error, error}, key} -> {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :value_error, %{problem: error, key: key}, unquote(param)}} + {:value_error, %{problem: error, key: key}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/fixed_tuple.ex b/lib/type_check/builtin/fixed_tuple.ex index fc2fecbc..fb80ad41 100644 --- a/lib/type_check/builtin/fixed_tuple.ex +++ b/lib/type_check/builtin/fixed_tuple.ex @@ -5,9 +5,9 @@ defmodule TypeCheck.Builtin.FixedTuple do @type! t :: %__MODULE__{element_types: list(TypeCheck.Type.t())} @type! problem_tuple :: - {t(), :not_a_tuple, %{}, any()} - | {t(), :different_size, %{expected_size: integer()}, tuple()} - | {t(), :element_error, + {:not_a_tuple, %{}, any()} + | {:different_size, %{expected_size: integer()}, tuple()} + | {:element_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), index: integer()}, tuple()} @@ -25,11 +25,11 @@ defmodule TypeCheck.Builtin.FixedTuple do quote generated: true, location: :keep do case unquote(param) do x when not is_tuple(x) -> - {:error, {unquote(Macro.escape(s)), :not_a_tuple, %{}, x}} + {:error, {:not_a_tuple, %{}, x}} x when tuple_size(x) != unquote(expected_size) -> {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :different_size, %{expected_size: unquote(expected_size)}, + {:different_size, %{expected_size: unquote(expected_size)}, x}} _ -> @@ -69,7 +69,7 @@ defmodule TypeCheck.Builtin.FixedTuple do else {{:error, error}, index} -> {:error, - {unquote(Macro.escape(s)), :element_error, %{problem: error, index: index}, + {:element_error, %{problem: error, index: index}, unquote(param)}} end end diff --git a/lib/type_check/builtin/float.ex b/lib/type_check/builtin/float.ex index 1e99338d..c4e89ea4 100644 --- a/lib/type_check/builtin/float.ex +++ b/lib/type_check/builtin/float.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Float do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Float do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/function.ex b/lib/type_check/builtin/function.ex index b58888a3..cf805558 100644 --- a/lib/type_check/builtin/function.ex +++ b/lib/type_check/builtin/function.ex @@ -7,7 +7,7 @@ defmodule TypeCheck.Builtin.Function do param_types: list(TypeCheck.Type.t()) | nil, return_type: TypeCheck.Type.t() } - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.Escape do def escape(s) do @@ -31,7 +31,7 @@ defmodule TypeCheck.Builtin.Function do {:ok, [], wrapped_fun} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end @@ -84,7 +84,7 @@ defmodule TypeCheck.Builtin.Function do {:error, problem} -> raise TypeCheck.TypeError, - {unquote(Macro.escape(s)), :return_error, + {:return_error, %{problem: problem, arguments: unquote(clean_params)}, var!(result, nil)} end diff --git a/lib/type_check/builtin/guarded.ex b/lib/type_check/builtin/guarded.ex index d96edb31..e2cfdb58 100644 --- a/lib/type_check/builtin/guarded.ex +++ b/lib/type_check/builtin/guarded.ex @@ -95,13 +95,13 @@ defmodule TypeCheck.Builtin.Guarded do {:ok, bindings, altered_param} else {:error, - {unquote(Macro.escape(s)), :guard_failed, %{bindings: bindings_map}, + {:guard_failed, %{bindings: bindings_map}, unquote(param)}} end {:error, problem} -> {:error, - {unquote(Macro.escape(s)), :type_failed, %{problem: problem}, unquote(param)}} + {:type_failed, %{problem: problem}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/implements_protocol.ex b/lib/type_check/builtin/implements_protocol.ex index b59af07f..9f8c2861 100644 --- a/lib/type_check/builtin/implements_protocol.ex +++ b/lib/type_check/builtin/implements_protocol.ex @@ -9,7 +9,7 @@ defmodule TypeCheck.Builtin.ImplementsProtocol do use TypeCheck @type! t :: %__MODULE__{protocol: module()} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -17,7 +17,7 @@ defmodule TypeCheck.Builtin.ImplementsProtocol do x = unquote(param) case unquote(s.protocol).impl_for(x) do nil -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, x}} + {:error, {:no_match, %{}, x}} _ -> {:ok, [], x} end diff --git a/lib/type_check/builtin/integer.ex b/lib/type_check/builtin/integer.ex index 8082196d..1842d5e0 100644 --- a/lib/type_check/builtin/integer.ex +++ b/lib/type_check/builtin/integer.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Integer do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Integer do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/list.ex b/lib/type_check/builtin/list.ex index aee96b97..cfdb1c67 100644 --- a/lib/type_check/builtin/list.ex +++ b/lib/type_check/builtin/list.ex @@ -6,8 +6,8 @@ defmodule TypeCheck.Builtin.List do @type! t(element_type) :: %__MODULE__{element_type: element_type} @type! problem_tuple :: - {t(), :not_a_list, %{}, any()} - | {t(), :element_error, + {:not_a_list, %{}, any()} + | {:element_error, %{ problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), index: non_neg_integer() @@ -24,7 +24,7 @@ defmodule TypeCheck.Builtin.List do quote generated: true, location: :keep do case unquote(param) do x when not is_list(x) -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :not_a_list, %{}, unquote(param)}} + {:error, {:not_a_list, %{}, unquote(param)}} _ -> unquote(build_element_check(element_type, param, s)) @@ -58,7 +58,7 @@ defmodule TypeCheck.Builtin.List do {:error, problem} -> problem = {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :element_error, %{problem: problem, index: index}, + {:element_error, %{problem: problem, index: index}, orig_param}} {:halt, problem} diff --git a/lib/type_check/builtin/literal.ex b/lib/type_check/builtin/literal.ex index 63f26049..82c85868 100644 --- a/lib/type_check/builtin/literal.ex +++ b/lib/type_check/builtin/literal.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Literal do use TypeCheck @type! t :: %__MODULE__{value: term()} - @type! problem_tuple :: {t(), :not_same_value, %{}, value :: term()} + @type! problem_tuple :: {:not_same_value, %{}, value :: term()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s = %{value: value}, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Literal do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :not_same_value, %{}, unquote(param)}} + {:error, {:not_same_value, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/map.ex b/lib/type_check/builtin/map.ex index 2ea21494..7573862d 100644 --- a/lib/type_check/builtin/map.ex +++ b/lib/type_check/builtin/map.ex @@ -5,10 +5,10 @@ defmodule TypeCheck.Builtin.Map do @opaque! t :: %__MODULE__{key_type: TypeCheck.Type.t(), value_type: TypeCheck.Type.t()} @type! problem_tuple :: - {t(), :not_a_map, %{}, any()} - | {t(), :key_error, + {:not_a_map, %{}, any()} + | {:key_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), key: any()}, any()} - | {t(), :value_error, + | {:value_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), key: any()}, any()} defimpl TypeCheck.Protocols.Escape do @@ -22,7 +22,7 @@ defmodule TypeCheck.Builtin.Map do quote generated: true, location: :keep do case unquote(param) do x when not is_map(x) -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :not_a_map, %{}, unquote(param)}} + {:error, {:not_a_map, %{}, unquote(param)}} _ -> unquote(build_keypairs_check(s.key_type, s.value_type, param, s)) @@ -64,7 +64,7 @@ defmodule TypeCheck.Builtin.Map do {{:error, problem}, _} -> res = {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :key_error, %{problem: problem, key: key}, + {:key_error, %{problem: problem, key: key}, orig_param}} {:halt, res} @@ -72,7 +72,7 @@ defmodule TypeCheck.Builtin.Map do {_, {:error, problem}} -> res = {:error, - {unquote(TypeCheck.Internals.Escaper.escape(s)), :value_error, %{problem: problem, key: key}, + {:value_error, %{problem: problem, key: key}, orig_param}} {:halt, res} diff --git a/lib/type_check/builtin/maybe_improper_list.ex b/lib/type_check/builtin/maybe_improper_list.ex index fecd25c9..1e4bdb66 100644 --- a/lib/type_check/builtin/maybe_improper_list.ex +++ b/lib/type_check/builtin/maybe_improper_list.ex @@ -10,13 +10,13 @@ defmodule TypeCheck.Builtin.MaybeImproperList do @type! problem_tuple :: - {t(), :not_a_list, %{}, any()} - | {t(), :element_error, + {:not_a_list, %{}, any()} + | {:element_error, %{ problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple()), index: non_neg_integer() }, any()} - | {t(), :terminator_error, + | {:terminator_error, %{problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple())}, any()} defimpl TypeCheck.Protocols.Escape do @@ -30,7 +30,7 @@ defmodule TypeCheck.Builtin.MaybeImproperList do quote generated: true, location: :keep do case unquote(param) do x when not is_list(x) -> - {:error, {unquote(Macro.escape(s)), :not_a_list, %{}, unquote(param)}} + {:error, {:not_a_list, %{}, unquote(param)}} _ -> unquote(build_element_check(s, param)) @@ -70,7 +70,7 @@ defmodule TypeCheck.Builtin.MaybeImproperList do {:error, problem} -> {:error, - {unquote(Macro.escape(s)), :terminator_error, %{problem: problem, index: index}, + {:terminator_error, %{problem: problem, index: index}, orig_param}} end else @@ -81,7 +81,7 @@ defmodule TypeCheck.Builtin.MaybeImproperList do {:error, problem} -> problem = {:error, - {unquote(Macro.escape(s)), :element_error, %{problem: problem, index: index}, + {:element_error, %{problem: problem, index: index}, orig_param}} {:halt, problem} diff --git a/lib/type_check/builtin/named_type.ex b/lib/type_check/builtin/named_type.ex index eb37cdf8..c0fc7ae8 100644 --- a/lib/type_check/builtin/named_type.ex +++ b/lib/type_check/builtin/named_type.ex @@ -45,7 +45,7 @@ defmodule TypeCheck.Builtin.NamedType do # Reset bindings {:ok, [], altered_inner} {:error, problem} -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :named_type, %{problem: problem}, unquote(param)}} + {:error, {:named_type, %{problem: problem}, unquote(param)}} end end else @@ -59,7 +59,7 @@ defmodule TypeCheck.Builtin.NamedType do {:ok, [{unquote(s.name), unquote(param)} | bindings], altered_inner} {:error, problem} -> - {:error, {unquote(TypeCheck.Internals.Escaper.escape(s)), :named_type, %{problem: problem}, unquote(param)}} + {:error, {:named_type, %{problem: problem}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/neg_integer.ex b/lib/type_check/builtin/neg_integer.ex index d8380b00..ed1b2235 100644 --- a/lib/type_check/builtin/neg_integer.ex +++ b/lib/type_check/builtin/neg_integer.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.NegInteger do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.NegInteger do {:ok, [], unquote(param)} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/non_neg_integer.ex b/lib/type_check/builtin/non_neg_integer.ex index dec5f633..29b838f7 100644 --- a/lib/type_check/builtin/non_neg_integer.ex +++ b/lib/type_check/builtin/non_neg_integer.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.NonNegInteger do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.NonNegInteger do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/none.ex b/lib/type_check/builtin/none.ex index 8b412020..e03aabdb 100644 --- a/lib/type_check/builtin/none.ex +++ b/lib/type_check/builtin/none.ex @@ -15,12 +15,12 @@ defmodule TypeCheck.Builtin.None do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, val :: any()} + @type! problem_tuple :: {:no_match, %{}, val :: any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do quote generated: true, location: :keep do - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/number.ex b/lib/type_check/builtin/number.ex index 1212fd46..d89b9808 100644 --- a/lib/type_check/builtin/number.ex +++ b/lib/type_check/builtin/number.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.Number do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, val :: any()} + @type! problem_tuple :: {:no_match, %{}, val :: any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Number do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/one_of.ex b/lib/type_check/builtin/one_of.ex index 503e80ba..da49d64a 100644 --- a/lib/type_check/builtin/one_of.ex +++ b/lib/type_check/builtin/one_of.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.OneOf do use TypeCheck @type! t() :: %TypeCheck.Builtin.OneOf{choices: list(TypeCheck.Type.t())} - @type! problem_tuple :: {t(), :all_failed, %{problems: list(lazy(TypeCheck.TypeError.Formatter.problem_tuple))}, term()} + @type! problem_tuple :: {:all_failed, %{problems: list(lazy(TypeCheck.TypeError.Formatter.problem_tuple))}, term()} defimpl TypeCheck.Protocols.Escape do @@ -32,7 +32,7 @@ defmodule TypeCheck.Builtin.OneOf do with unquote_splicing(snippets) do {:error, - {unquote(TypeCheck.Internals.Escaper.escape(x)), :all_failed, %{problems: Enum.reverse(problems)}, + {:all_failed, %{problems: Enum.reverse(problems)}, unquote(param)}} else {:ok, bindings, altered_param} -> diff --git a/lib/type_check/builtin/pid.ex b/lib/type_check/builtin/pid.ex index 8b4c81f8..48d02dbc 100644 --- a/lib/type_check/builtin/pid.ex +++ b/lib/type_check/builtin/pid.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.PID do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.PID do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/port.ex b/lib/type_check/builtin/port.ex index b940db50..e92aaea9 100644 --- a/lib/type_check/builtin/port.ex +++ b/lib/type_check/builtin/port.ex @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.Port do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -22,7 +22,7 @@ defmodule TypeCheck.Builtin.Port do x when is_port(x) -> {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/pos_integer.ex b/lib/type_check/builtin/pos_integer.ex index c4fa7105..c7854de4 100644 --- a/lib/type_check/builtin/pos_integer.ex +++ b/lib/type_check/builtin/pos_integer.ex @@ -3,7 +3,7 @@ defmodule TypeCheck.Builtin.PosInteger do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -13,7 +13,7 @@ defmodule TypeCheck.Builtin.PosInteger do {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/range.ex b/lib/type_check/builtin/range.ex index 07755366..68002dee 100644 --- a/lib/type_check/builtin/range.ex +++ b/lib/type_check/builtin/range.ex @@ -10,18 +10,18 @@ defmodule TypeCheck.Builtin.Range do end @type! problem_tuple :: - {t(), :not_an_integer, %{}, any()} - | {t(), :not_in_range, %{}, integer()} + {:not_an_integer, %{}, any()} + | {:not_in_range, %{}, integer()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s = %{range: range}, param) do quote generated: true, location: :keep do case unquote(param) do x when not is_integer(x) -> - {:error, {unquote(Macro.escape(s)), :not_an_integer, %{}, unquote(param)}} + {:error, {:not_an_integer, %{}, unquote(param)}} x when x not in unquote(Macro.escape(range)) -> - {:error, {unquote(Macro.escape(s)), :not_in_range, %{}, unquote(param)}} + {:error, {:not_in_range, %{}, unquote(param)}} correct_value -> {:ok, [], correct_value} diff --git a/lib/type_check/builtin/reference.ex b/lib/type_check/builtin/reference.ex index 1ef5ff78..2e7661f3 100644 --- a/lib/type_check/builtin/reference.ex +++ b/lib/type_check/builtin/reference.ex @@ -14,7 +14,7 @@ defmodule TypeCheck.Builtin.Reference do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -23,7 +23,7 @@ defmodule TypeCheck.Builtin.Reference do x when is_reference(x) -> {:ok, [], x} _ -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} end end end diff --git a/lib/type_check/builtin/sized_bitstring.ex b/lib/type_check/builtin/sized_bitstring.ex index cabb4b82..c014d218 100644 --- a/lib/type_check/builtin/sized_bitstring.ex +++ b/lib/type_check/builtin/sized_bitstring.ex @@ -5,8 +5,8 @@ defmodule TypeCheck.Builtin.SizedBitstring do @type! t :: %__MODULE__{prefix_size: non_neg_integer(), unit_size: nil | 1..256} @type! problem_tuple :: - {t(), :no_match, %{}, any()} - | {t(), :wrong_size, %{}, any()} + {:no_match, %{}, any()} + | { :wrong_size, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -14,9 +14,9 @@ defmodule TypeCheck.Builtin.SizedBitstring do quote generated: true, location: :keep do case unquote(param) do x when not is_bitstring(x) -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}} + {:error, {:no_match, %{}, unquote(param)}} x when bit_size(x) != unquote(s.prefix_size) -> - {:error, {unquote(Macro.escape(s)), :wrong_size, %{}, unquote(param)}} + {:error, {:wrong_size, %{}, unquote(param)}} _ -> {:ok, [], unquote(param)} end @@ -25,9 +25,9 @@ defmodule TypeCheck.Builtin.SizedBitstring do quote generated: true, location: :keep do case unquote(param) do x when not is_bitstring(x) -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, x}} + {:error, {:no_match, %{}, x}} x when bit_size(x) < unquote(s.prefix_size) or rem(bit_size(x) - unquote(s.prefix_size), unquote(s.unit_size)) != 0 -> - {:error, {unquote(Macro.escape(s)), :wrong_size, %{}, x}} + {:error, {:wrong_size, %{}, x}} correct_value -> {:ok, [], correct_value} end diff --git a/lib/type_check/builtin/tuple.ex b/lib/type_check/builtin/tuple.ex index 8edde997..694c9d0d 100644 --- a/lib/type_check/builtin/tuple.ex +++ b/lib/type_check/builtin/tuple.ex @@ -9,7 +9,7 @@ defmodule TypeCheck.Builtin.Tuple do use TypeCheck @type! t :: %__MODULE__{} - @type! problem_tuple :: {t(), :no_match, %{}, any()} + @type! problem_tuple :: {:no_match, %{}, any()} defimpl TypeCheck.Protocols.ToCheck do def to_check(s, param) do @@ -19,7 +19,7 @@ defmodule TypeCheck.Builtin.Tuple do {:ok, [], x} other -> - {:error, {unquote(Macro.escape(s)), :no_match, %{}, other}} + {:error, {:no_match, %{}, other}} end end end From 16b01c0dd44dc7b5793877eb3bda69d3152af268 Mon Sep 17 00:00:00 2001 From: Marten/Qqwy Date: Mon, 13 Jun 2022 23:47:12 +0200 Subject: [PATCH 2/5] Comment out formatter impl for now --- lib/type_check/spec.ex | 4 ++-- lib/type_check/type_error.ex | 3 +++ .../type_error/default_formatter.ex | 20 +++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/type_check/spec.ex b/lib/type_check/spec.ex index 76c23b22..e9eeba51 100644 --- a/lib/type_check/spec.ex +++ b/lib/type_check/spec.ex @@ -12,8 +12,8 @@ defmodule TypeCheck.Spec do use TypeCheck alias TypeCheck.DefaultOverrides.String @type! t() :: %__MODULE__{name: String.t(), param_types: list(TypeCheck.Type.t()), return_type: TypeCheck.Type.t(), location: [] | list({:file, String.t()} | {:line, non_neg_integer()})} - @type! problem_tuple :: {t(), :param_error, %{index: non_neg_integer(), problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple())}, list(any())} - | {t(), :return_error, %{arguments: list(term()), problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple())}, list(any())} + @type! problem_tuple :: {:param_error, %{index: non_neg_integer(), problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple())}, list(any())} + | {:return_error, %{arguments: list(term()), problem: lazy(TypeCheck.TypeError.Formatter.problem_tuple())}, list(any())} end defp spec_fun_name(function, arity) do diff --git a/lib/type_check/type_error.ex b/lib/type_check/type_error.ex index 8c81e53c..d54c93e3 100644 --- a/lib/type_check/type_error.ex +++ b/lib/type_check/type_error.ex @@ -63,4 +63,7 @@ defmodule TypeCheck.TypeError do def exception(problem_tuple) do exception({problem_tuple, []}) end + + def hydrate_problem_tuple(s, problem_tuple) do + end end diff --git a/lib/type_check/type_error/default_formatter.ex b/lib/type_check/type_error/default_formatter.ex index 166a6aa9..11921d34 100644 --- a/lib/type_check/type_error/default_formatter.ex +++ b/lib/type_check/type_error/default_formatter.ex @@ -1,17 +1,21 @@ defmodule TypeCheck.TypeError.DefaultFormatter do @behaviour TypeCheck.TypeError.Formatter - @spec format(TypeCheck.TypeError.problem_tuple(), TypeCheck.TypeError.location()) :: String.t() def format(problem_tuple, location \\ []) do - res = - do_format(problem_tuple) - |> indent() # Ensure we start with four spaces, which multi-line exception pretty-printing expects - |> indent() - - location_string(location) <> res - |> String.trim() + inspect(problem_tuple) end + # @spec format(TypeCheck.TypeError.problem_tuple(), TypeCheck.TypeError.location()) :: String.t() + # def format(problem_tuple, location \\ []) do + # res = + # do_format(problem_tuple) + # |> indent() # Ensure we start with four spaces, which multi-line exception pretty-printing expects + # |> indent() + + # location_string(location) <> res + # |> String.trim() + # end + defp location_string([]), do: "" defp location_string(location) do raw_file = location[:file] From a3e632600d36bffc9a37c5875948fd57b18ab6b2 Mon Sep 17 00:00:00 2001 From: Marten/Qqwy Date: Tue, 14 Jun 2022 13:53:46 +0200 Subject: [PATCH 3/5] Attempt to hydrate problem tuples --- lib/type_check/builtin/guarded.ex | 2 + lib/type_check/spec.ex | 8 ++-- lib/type_check/type_error.ex | 64 +++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/lib/type_check/builtin/guarded.ex b/lib/type_check/builtin/guarded.ex index e2cfdb58..61e57e37 100644 --- a/lib/type_check/builtin/guarded.ex +++ b/lib/type_check/builtin/guarded.ex @@ -10,6 +10,8 @@ defmodule TypeCheck.Builtin.Guarded do @type! t() :: %TypeCheck.Builtin.Guarded{type: TypeCheck.Type.t(), guard: ast()} + # TODO problem_tuple type + defimpl TypeCheck.Protocols.Escape do def escape(s) do diff --git a/lib/type_check/spec.ex b/lib/type_check/spec.ex index e9eeba51..e29f6150 100644 --- a/lib/type_check/spec.ex +++ b/lib/type_check/spec.ex @@ -202,8 +202,8 @@ defmodule TypeCheck.Spec do {{:error, problem}, index} -> raise TypeCheck.TypeError, { - {__MODULE__.unquote(spec_fun_name(name, arity))(), :param_error, - %{index: index, problem: problem}, unquote(clean_params)}, unquote(Macro.Env.location(caller))} + {__MODULE__.unquote(spec_fun_name(name, arity))(), {:param_error, + %{index: index, problem: problem}, unquote(clean_params)}, unquote(Macro.Env.location(caller))}} end end end @@ -234,8 +234,8 @@ defmodule TypeCheck.Spec do {:error, problem} -> raise TypeCheck.TypeError, - {__MODULE__.unquote(spec_fun_name(name, arity))(), :return_error, - %{problem: problem, arguments: unquote(clean_params)}, var!(super_result, nil)} + {{__MODULE__.unquote(spec_fun_name(name, arity))(), {:return_error, + %{problem: problem, arguments: unquote(clean_params)}, var!(super_result, nil)}} end end end diff --git a/lib/type_check/type_error.ex b/lib/type_check/type_error.ex index d54c93e3..7bfd4691 100644 --- a/lib/type_check/type_error.ex +++ b/lib/type_check/type_error.ex @@ -64,6 +64,70 @@ defmodule TypeCheck.TypeError do exception({problem_tuple, []}) end + @simple_problems ~w[no_match not_same_value not_a_map not_a_list missing_keys superfluous_keys different_length different_size not_an_integer not_in_range wrong_size]a + + def hydrate_problem_tuple(s = %TypeCheck.Type.StreamData{}, problem_tuple) do + hydrate_problem_tuple(s.type, problem_tuple) + end + def hydrate_problem_tuple(s, problem_tuple) do + case problem_tuple do + {simple, meta, param} when simple in @simple_problems -> {s, simple, meta, param} + {:value_error, meta, param} -> + # TODO CompoundFixedMap + s2 = s.keypairs[meta.key] + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :value_error, meta2, param} + {:key_error, meta, param} -> + s2 = meta.key + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :key_error, meta2, param} + {:element_error, meta, param} -> # Handles both fixed_list and fixed_tuple + case s do + %TypeCheck.Builtin.List{} -> + s2 = s.element_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :element_error, meta2, param} + %TypeCheck.Builtin.MaybeImproperList{} -> + s2 = s.element_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :element_error, meta2, param} + %TypeCheck.Builtin.FixedList{} -> + s2 = Enum.at(s.element_types, meta.index) + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :element_error, meta2, param} + %TypeCheck.Builtin.FixedTuple{} -> + s2 = Enum.at(s.element_types, meta.index) + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :element_error, meta2, param} + end + {:terminator_error, meta, param} -> + s2 = s.terminator_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {:terminator_error, meta2, param} + {:named_type, meta, param} -> + s2 = s.type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {:named_type, meta2, param} + {:all_failed, meta, param} -> + hydrated_problems = + Enum.zip(s.choices, meta.problems) + |> Enum.map(fn s2, problem -> + hydrate_problem_tuple(s2, problem) + end) + meta2 = put_in(meta.problems, hydrated_problems) + {:all_failed, meta2, param} + {:return_error, meta, param} -> + s2 = s.return_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :return_error, meta2, param} + {:param_error, meta, param} -> + s2 = Enum.at(s.param_types, meta.index) + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :param_error, meta2, param} + other -> + IO.warn("TODO: #{inspect({s, problem_tuple})}") + other + end end end From 1ff4f9e09d2147ef236e8df4f20b5460103e2917 Mon Sep 17 00:00:00 2001 From: Marten/Qqwy Date: Tue, 14 Jun 2022 14:41:13 +0200 Subject: [PATCH 4/5] Hydration seems to work well. --- lib/type_check.ex | 10 +++-- lib/type_check/spec.ex | 2 +- lib/type_check/type_error.ex | 40 ++++++++++++++----- .../type_error/default_formatter.ex | 24 +++++------ 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/lib/type_check.ex b/lib/type_check.ex index 68a4b558..acd68658 100644 --- a/lib/type_check.ex +++ b/lib/type_check.ex @@ -177,7 +177,7 @@ defmodule TypeCheck do case unquote(check) do {:ok, bindings, altered_value} -> {:ok, altered_value} {:error, problem} -> - exception = TypeCheck.TypeError.exception({problem, unquote(Macro.Env.location(__CALLER__))}) + exception = TypeCheck.TypeError.exception({unquote(TypeCheck.Internals.Escaper.escape(type)), {problem, unquote(Macro.Env.location(__CALLER__))}}) {:error, exception} end end @@ -230,7 +230,11 @@ defmodule TypeCheck do res = quote generated: true, location: :keep do case unquote(check) do {:ok, _bindings, altered_value} -> altered_value - {:error, other} -> raise TypeCheck.TypeError, other + {:error, other} -> + type = unquote(TypeCheck.Internals.Escaper.escape(type)) + IO.inspect(type, label: :conforms_type) + exception = TypeCheck.TypeError.exception({type, {other, []}}) + raise exception end end @@ -281,7 +285,7 @@ defmodule TypeCheck do {:current_stacktrace, [_ , _, caller | _]} = Process.info(self(), :current_stacktrace) location = elem(caller, 3) location = update_in(location[:file], &to_string/1) - exception = TypeCheck.TypeError.exception({problem, location}) + exception = TypeCheck.TypeError.exception({type, {problem, location}}) {:error, exception} end end diff --git a/lib/type_check/spec.ex b/lib/type_check/spec.ex index e29f6150..8079a4c6 100644 --- a/lib/type_check/spec.ex +++ b/lib/type_check/spec.ex @@ -234,7 +234,7 @@ defmodule TypeCheck.Spec do {:error, problem} -> raise TypeCheck.TypeError, - {{__MODULE__.unquote(spec_fun_name(name, arity))(), {:return_error, + {__MODULE__.unquote(spec_fun_name(name, arity))(), {:return_error, %{problem: problem, arguments: unquote(clean_params)}, var!(super_result, nil)}} end end diff --git a/lib/type_check/type_error.ex b/lib/type_check/type_error.ex index 7bfd4691..4806b224 100644 --- a/lib/type_check/type_error.ex +++ b/lib/type_check/type_error.ex @@ -54,6 +54,14 @@ defmodule TypeCheck.TypeError do @impl true + + def exception({s, {problem_tuple, location}}) do + hydrated_problem_tuple = hydrate_problem_tuple(s, problem_tuple) + message = TypeCheck.TypeError.DefaultFormatter.format(hydrated_problem_tuple, location) + + %__MODULE__{message: message, raw: hydrated_problem_tuple, location: location} + end + def exception({problem_tuple, location}) do message = TypeCheck.TypeError.DefaultFormatter.format(problem_tuple, location) @@ -64,7 +72,7 @@ defmodule TypeCheck.TypeError do exception({problem_tuple, []}) end - @simple_problems ~w[no_match not_same_value not_a_map not_a_list missing_keys superfluous_keys different_length different_size not_an_integer not_in_range wrong_size]a + @simple_problems ~w[no_match not_same_value not_a_map not_a_list missing_keys superfluous_keys different_length different_size not_an_integer not_in_range wrong_size guard_failed]a def hydrate_problem_tuple(s = %TypeCheck.Type.StreamData{}, problem_tuple) do hydrate_problem_tuple(s.type, problem_tuple) @@ -74,15 +82,25 @@ defmodule TypeCheck.TypeError do case problem_tuple do {simple, meta, param} when simple in @simple_problems -> {s, simple, meta, param} {:value_error, meta, param} -> - # TODO CompoundFixedMap - s2 = s.keypairs[meta.key] - meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) - {s, :value_error, meta2, param} + case s do + %TypeCheck.Builtin.CompoundFixedMap{} -> + s2 = s.fixed.keypairs[meta.key] || s.flexible.value_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :value_error, meta2, param} + %TypeCheck.Builtin.FixedMap{} -> + s2 = s.keypairs[meta.key] + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :value_error, meta2, param} + %TypeCheck.Builtin.Map{} -> + s2 = s.value_type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :value_error, meta2, param} + end {:key_error, meta, param} -> s2 = meta.key meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) {s, :key_error, meta2, param} - {:element_error, meta, param} -> # Handles both fixed_list and fixed_tuple + {:element_error, meta, param} -> case s do %TypeCheck.Builtin.List{} -> s2 = s.element_type @@ -104,11 +122,15 @@ defmodule TypeCheck.TypeError do {:terminator_error, meta, param} -> s2 = s.terminator_type meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) - {:terminator_error, meta2, param} + {s, :terminator_error, meta2, param} {:named_type, meta, param} -> s2 = s.type meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) - {:named_type, meta2, param} + {s, :named_type, meta2, param} + {:type_failed, meta, param} -> + s2 = s.type + meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) + {s, :type_failed, meta2, param} {:all_failed, meta, param} -> hydrated_problems = Enum.zip(s.choices, meta.problems) @@ -116,7 +138,7 @@ defmodule TypeCheck.TypeError do hydrate_problem_tuple(s2, problem) end) meta2 = put_in(meta.problems, hydrated_problems) - {:all_failed, meta2, param} + {s, :all_failed, meta2, param} {:return_error, meta, param} -> s2 = s.return_type meta2 = update_in(meta.problem, &hydrate_problem_tuple(s2, &1)) diff --git a/lib/type_check/type_error/default_formatter.ex b/lib/type_check/type_error/default_formatter.ex index 11921d34..4f8be967 100644 --- a/lib/type_check/type_error/default_formatter.ex +++ b/lib/type_check/type_error/default_formatter.ex @@ -1,21 +1,21 @@ defmodule TypeCheck.TypeError.DefaultFormatter do @behaviour TypeCheck.TypeError.Formatter - def format(problem_tuple, location \\ []) do - inspect(problem_tuple) - end - - # @spec format(TypeCheck.TypeError.problem_tuple(), TypeCheck.TypeError.location()) :: String.t() # def format(problem_tuple, location \\ []) do - # res = - # do_format(problem_tuple) - # |> indent() # Ensure we start with four spaces, which multi-line exception pretty-printing expects - # |> indent() - - # location_string(location) <> res - # |> String.trim() + # inspect(problem_tuple) # end + @spec format(TypeCheck.TypeError.problem_tuple(), TypeCheck.TypeError.location()) :: String.t() + def format(problem_tuple, location \\ []) do + res = + do_format(problem_tuple) + |> indent() # Ensure we start with four spaces, which multi-line exception pretty-printing expects + |> indent() + + location_string(location) <> res + |> String.trim() + end + defp location_string([]), do: "" defp location_string(location) do raw_file = location[:file] From 6542ff2f46526f3b27f256a006480fc256d33a40 Mon Sep 17 00:00:00 2001 From: Marten/Qqwy Date: Tue, 14 Jun 2022 14:47:38 +0200 Subject: [PATCH 5/5] Fix some exception construction code --- lib/type_check/spec.ex | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/type_check/spec.ex b/lib/type_check/spec.ex index 8079a4c6..15aa11a8 100644 --- a/lib/type_check/spec.ex +++ b/lib/type_check/spec.ex @@ -200,10 +200,10 @@ defmodule TypeCheck.Spec do # Run actual code else {{:error, problem}, index} -> - raise TypeCheck.TypeError, - { - {__MODULE__.unquote(spec_fun_name(name, arity))(), {:param_error, - %{index: index, problem: problem}, unquote(clean_params)}, unquote(Macro.Env.location(caller))}} + type = __MODULE__.unquote(spec_fun_name(name, arity))() + problem_tuple = {:param_error, %{index: index, problem: problem}, unquote(clean_params)} + location = unquote(Macro.Env.location(caller)) + raise TypeCheck.TypeError, {type, {problem_tuple, location}} end end end @@ -220,7 +220,7 @@ defmodule TypeCheck.Spec do end end - defp return_check_code(name, arity, clean_params, return_type, _caller, _location) do + defp return_check_code(name, arity, clean_params, return_type, caller, _location) do return_code_check = TypeCheck.Protocols.ToCheck.to_check(return_type, Macro.var(:super_result, nil)) @@ -233,9 +233,10 @@ defmodule TypeCheck.Spec do altered_return_value {:error, problem} -> - raise TypeCheck.TypeError, - {__MODULE__.unquote(spec_fun_name(name, arity))(), {:return_error, - %{problem: problem, arguments: unquote(clean_params)}, var!(super_result, nil)}} + type = __MODULE__.unquote(spec_fun_name(name, arity))() + problem_tuple = {:return_error, %{problem: problem, arguments: unquote(clean_params)}, var!(super_result, nil)} + location = unquote(Macro.Env.location(caller)) + raise TypeCheck.TypeError, {type, {problem_tuple, location}} end end end