elixir_sense
elixir_sense copied to clipboard
Type info not able to properly expand var types
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
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