Open lukaszsamson opened 1 year ago
Some examples of broken stuff
defmodule ElixirSenseExample.ModuleWithTypespecs do
defmodule Remote do
@typedoc "Remote type"
@type remote_t :: atom
@typedoc "Remote type with params"
@type remote_t(a, b) :: {a, b}
@typedoc "Remote list type"
@type remote_list_t :: [remote_t]
@type remote_option_t :: {:remote_option_1, remote_t} | {:remote_option_2, remote_list_t}
end
defmodule OtherRemote do
@type other :: Remote.remote_option_t()
@type bounded_type(t) :: {t, integer}
@type some :: :a
end
defmodule Local do
alias Remote, as: R
@typep private_t :: atom
@typedoc "Local opaque type"
@opaque opaque_t :: atom
@typedoc "Local type"
@type local_t :: atom
@typedoc "Local type with params"
@type local_t(a, b) :: {a, b}
@typedoc "Local union type"
@type union_t :: atom | integer
@typedoc "Local list type"
@type list_t :: [:trace | :log]
@typedoc "Local type with large spec"
@type large_t :: pid | port | (registered_name :: atom) | {registered_name :: atom, node}
@typedoc "Remote type from aliased module"
@type remote_aliased_t :: R.remote_t() | R.remote_list_t()
@type tuple_opt_t :: {:opt_name, :opt_value}
@typedoc "Local keyword-value type"
@type option_t ::
{:local_o, local_t}
| {:local_with_params_o, local_t(atom, integer)}
| {:union_o, union_t}
| {:inline_union_o, :a | :b}
| {:list_o, list_t}
| {:inline_list_o, [:trace | :log]}
| {:basic_o, pid}
| {:basic_with_params_o, nonempty_list(atom)}
| {:builtin_o, keyword}
| {:builtin_with_params_o, keyword(term)}
| {:remote_o, Remote.remote_t()}
| {:remote_with_params_o, Remote.remote_t(atom, integer)}
| {:remote_aliased_o, remote_aliased_t}
| {:remote_aliased_inline_o, R.remote_t()}
| {:private_o, private_t}
| {:opaque_o, opaque_t}
| {:non_existent_o, Remote.non_existent()}
| {:large_o, large_t}
@typedoc "Extra option"
@type extra_option_t :: {:option_1, atom} | {:option_2, integer}
@typedoc "Options"
@type options_t :: [option_t]
@typedoc "Option | Extra option"
@type option_or_extra_option_t ::
{:option_1, boolean} | {:option_2, timeout} | Remote.remote_option_t()
@type extra_option_1_t :: extra_option_t
@type atom_opt_t :: :atom_opt
@type bounded_type(t) :: {t, integer}
@spec func_with_options(options_t) :: any
def func_with_options(options) do
options
end
@spec func_with_union_of_options([option_t | extra_option_t]) :: any
def func_with_union_of_options(options) do
options
end
@spec func_with_union_of_options_as_type([option_or_extra_option_t]) :: any
def func_with_union_of_options_as_type(options) do
options
end
@spec func_with_union_of_options_inline([{:option_1, atom} | {:option_2, integer} | option_t]) ::
any
def func_with_union_of_options_inline(options) do
options
end
@spec func_with_named_options(options :: options_t) :: any
def func_with_named_options(options) do
options
end
@spec func_with_options_as_inline_list([{:local_o, local_t} | {:builtin_o, keyword}]) :: any
def func_with_options_as_inline_list(options) do
options
end
@spec func_with_option_var_defined_in_when([opt]) :: any when opt: option_t
def func_with_option_var_defined_in_when(options) do
options
end
@spec func_with_options_var_defined_in_when(opts) :: any when opts: [option_t]
def func_with_options_var_defined_in_when(options) do
options
end
@spec func_with_one_option([{:option_1, integer}]) :: any
def func_with_one_option(options) do
options
end
@spec fun_without_options([integer]) :: integer
def fun_without_options(a), do: length(a)
@spec fun_with_atom_option([:option_name]) :: any
def fun_with_atom_option(a), do: a
@spec fun_with_atom_option_in_when(opts) :: any when opts: [:option_name]
def fun_with_atom_option_in_when(a), do: a
@spec fun_with_recursive_remote_type_option([OtherRemote.other()]) :: any
def fun_with_recursive_remote_type_option(a), do: a
@spec fun_with_recursive_user_type_option([extra_option_1_t]) :: any
def fun_with_recursive_user_type_option(a), do: a
@spec fun_with_tuple_option_in_when(opt) :: any when opt: [tuple_opt_t]
def fun_with_tuple_option_in_when(a), do: a
@spec fun_with_tuple_option([tuple_opt_t]) :: any
def fun_with_tuple_option(a), do: a
@spec fun_with_atom_user_type_option_in_when(opt) :: any when opt: [atom_opt_t]
def fun_with_atom_user_type_option_in_when(a), do: a
@spec fun_with_atom_user_type_option([atom_opt_t]) :: any
def fun_with_atom_user_type_option(a), do: a
@spec fun_with_list_of_lists([opt]) :: any when opt: [tuple_opt_t]
def fun_with_list_of_lists(a), do: a
@spec fun_with_recursive_type(opt) :: any when opt: [term :: opt]
def fun_with_recursive_type(a), do: a
@spec fun_with_multiple_specs(nil) :: any
@spec fun_with_multiple_specs([tuple_opt_t]) :: any
def fun_with_multiple_specs(a), do: a
@spec fun_with_multiple_specs_when(nil) :: any
@spec fun_with_multiple_specs_when([opts]) :: any when opts: tuple_opt_t
def fun_with_multiple_specs_when(a), do: a
@spec fun_with_bounded_type([bounded_type(:a | :b)]) :: any
def fun_with_bounded_type(a), do: a
@spec fun_with_bounded_type_when([opt]) :: any when opt: bounded_type(:a | :b)
def fun_with_bounded_type_when(a), do: a
@spec fun_with_bounded_type_remote([OtherRemote.bounded_type(:a | :b)]) :: any
def fun_with_bounded_type_remote(a), do: a
@spec fun_with_bounded_type_remote_local_arg([OtherRemote.bounded_type(atom_opt_t)]) :: any
def fun_with_bounded_type_remote_local_arg(a), do: a
@spec fun_with_bounded_type_remote_local_arg_union([OtherRemote.bounded_type(atom_opt_t | :l)]) :: any
def fun_with_bounded_type_remote_local_arg_union(a), do: a
@spec fun_with_bounded_type_remote_arg([bounded_type(OtherRemote.some)]) :: any
def fun_with_bounded_type_remote_arg(a), do: a
@spec fun_with_keyword_list([key: integer]) :: any
def fun_with_keyword_list(a), do: a
@spec fun_with_bounded_type_arg_from_when([local_t(v, integer | binary)]) :: any when v: :a | :b
def fun_with_bounded_type_arg_from_when(a), do: a
@spec fun_with_remote_bounded_type_arg_from_when([OtherRemote.bounded_type(v)]) :: any when v: :a | :b
def fun_with_remote_bounded_type_arg_from_when(a), do: a
@type m_true(l, _r)::l
@type m_false(_l, r)::r
@type m_0(_l, r)::r
@type m_1(l, r)::l(r)
end
end
test "fun_with_bounded_type" do
assert [
{Local, :a, {:type, _, :integer, []}},
{Local, :b, {:type, _, :integer, []}}
] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type, 0)
end
test "fun_with_bounded_type_when" do
assert [
{Local, :a, {:type, _, :integer, []}},
{Local, :b, {:type, _, :integer, []}}
] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_when, 0)
end
test "fun_with_bounded_type_remote" do
assert [
{OtherRemote, :a, {:type, _, :integer, []}},
{OtherRemote, :b, {:type, _, :integer, []}}
] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_remote, 0)
end
test "fun_with_bounded_type_remote_arg" do
assert [{Local, :a, {:type, _, :integer, []}}] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_remote_arg, 0)
end
test "fun_with_bounded_type_remote_local_arg" do
assert [{OtherRemote, :atom_opt, {:type, _, :integer, []}}] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_remote_local_arg, 0)
end
test "fun_with_bounded_type_remote_local_arg_union" do
assert [{OtherRemote, :atom_opt, {:type, _, :integer, []}}] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_remote_local_arg_union, 0)
end
test "fun_with_bounded_type_arg_from_when" do
assert [
{Local, :a, {:type, _, :union, [{:type, _, :integer, []}, {:type, _, :binary, []}]}},
{Local, :b, {:type, _, :union, [{:type, _, :integer, []}, {:type, _, :binary, []}]}}
] = TypeInfo.extract_param_options(Local, :fun_with_bounded_type_arg_from_when, 0)
end
test "fun_with_remote_bounded_type_arg_from_when" do
assert [
{OtherRemote, :a, {:type, _, :integer, []}},
{OtherRemote, :b, {:type, _, :integer, []}}
] = TypeInfo.extract_param_options(Local, :fun_with_remote_bounded_type_arg_from_when, 0)
end
test "fun_with_keyword_list" do
assert [{Local, :key, {:type, _, :integer, []}}] = TypeInfo.extract_param_options(Local, :fun_with_keyword_list, 0)
end
var params in fun, remote and local type expansion is broken in
TypeInfo
. Maybe we should remove it completely. It's used only in param options completions