From 894d9d60dd04a23853eb491909432be73f769cdf Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Mon, 6 Nov 2023 00:36:52 +0100 Subject: [PATCH] add missing expand call on union fix crash with expand call on unexpandable vars and other --- lib/elixir_sense/core/binding.ex | 13 +++++++++++-- test/elixir_sense/core/binding_test.exs | 19 ++++++++++++++++++- test/support/functions_with_return_spec.ex | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/elixir_sense/core/binding.ex b/lib/elixir_sense/core/binding.ex index e6f2d431..5869162e 100644 --- a/lib/elixir_sense/core/binding.ex +++ b/lib/elixir_sense/core/binding.ex @@ -948,10 +948,19 @@ defmodule ElixirSense.Core.Binding do # not a module defp expand_call(_env, {:atom, _mod}, _fun, _arity, _include_private, _stack), do: :none - defp expand_call(_env, target, fun, arity, include_private, _stack) do - raise "No clause matched #{inspect(target)}, #{inspect(fun)}, #{inspect(arity)}, #{inspect(include_private)}" + defp expand_call(env, {:union, variants}, fun, arity, include_private, stack) do + # TODO choose variant by args? + Enum.find_value(variants, fn variant -> + res = expand_call(env, variant |> dbg, fun, arity, include_private, stack) + + if res != :none do + res + end + end) end + defp expand_call(_env, _target, _fun, _arity, _include_private, _stack), do: nil + defp call_arity_match?(fun_arity, fun_defaults, call_arity) do fun_arity - fun_defaults <= call_arity and call_arity <= fun_arity end diff --git a/test/elixir_sense/core/binding_test.exs b/test/elixir_sense/core/binding_test.exs index ea8e1e96..2b2e3c90 100644 --- a/test/elixir_sense/core/binding_test.exs +++ b/test/elixir_sense/core/binding_test.exs @@ -923,7 +923,7 @@ defmodule ElixirSense.Core.BindingTest do end test "remote call fun with spec intersection different returns" do - assert {:union, [{:map, [abc: nil], nil}, {:atom, nil}]} == + assert {:union, [{:map, [abc: {:atom, String}], nil}, {:atom, nil}]} == Binding.expand( @env |> Map.put(:variables, [ @@ -936,6 +936,23 @@ defmodule ElixirSense.Core.BindingTest do ) end + test "remote call fun with spec intersection different returns nested" do + assert {:atom, String} == + Binding.expand( + @env + |> Map.put(:variables, [ + %VarInfo{ + name: :ref, + type: + {:call, + {:call, {:atom, ElixirSenseExample.FunctionsWithReturnSpec}, :f7, []}, + :abc, []} + } + ]), + {:variable, :ref} + ) + end + test "remote call fun with spec intersection same returns" do assert {:map, [abc: nil], nil} == Binding.expand( diff --git a/test/support/functions_with_return_spec.ex b/test/support/functions_with_return_spec.ex index 719697ba..a65a58ff 100644 --- a/test/support/functions_with_return_spec.ex +++ b/test/support/functions_with_return_spec.ex @@ -46,7 +46,7 @@ defmodule ElixirSenseExample.FunctionsWithReturnSpec do @spec f6() :: %{abc: atom} def f6(), do: :ok - @spec f7() :: %{abc: atom} + @spec f7() :: %{abc: String} @spec f7() :: nil def f7(), do: :ok