diff --git a/priv/monkey/_next_ls_private_compiler.ex b/priv/monkey/_next_ls_private_compiler.ex index 133a5e54..311f1771 100644 --- a/priv/monkey/_next_ls_private_compiler.ex +++ b/priv/monkey/_next_ls_private_compiler.ex @@ -1545,6 +1545,29 @@ if Version.match?(System.version(), ">= 1.17.0-dev") do {{{:., meta, [module, fun]}, meta, args}, state, env} end + defp expand_local(meta, fun, args, state, env) when fun in [:for, :with] do + {params, blocks} = + Enum.split_while(args, fn + {:<-, _, _} -> true + _ -> false + end) + + {_, state, penv} = + for p <- params, reduce: {nil, state, env} do + {_, state, penv} -> + expand_pattern(p, state, penv) + end + + {blocks, state} = + for {type, block} <- blocks, reduce: {[], state} do + {acc, state} -> + {res, state, _env} = expand(block, state, penv) + {[{type, res} | acc], state} + end + + {blocks, state, env} + end + defp expand_local(meta, fun, args, state, env) do # A compiler may want to emit a :local_function trace in here. {args, state, env} = expand_list(args, state, env) diff --git a/test/next_ls/completions_test.exs b/test/next_ls/completions_test.exs index 1b69fada..e5422cc8 100644 --- a/test/next_ls/completions_test.exs +++ b/test/next_ls/completions_test.exs @@ -735,4 +735,78 @@ defmodule NextLS.CompletionsTest do assert_match %{"kind" => 6, "label" => "var"} in results assert_match %{"kind" => 6, "label" => "vim"} in results end + + test "<- matches dont leak from for", %{client: client, foo: foo} do + uri = uri(foo) + + did_open(client, foo, """ + defmodule Foo do + def run(items) do + names = + for item <- items do + item.name + end + + i + end + end + """) + + request client, %{ + method: "textDocument/completion", + id: 2, + jsonrpc: "2.0", + params: %{ + textDocument: %{ + uri: uri + }, + position: %{ + line: 7, + character: 5 + } + } + } + + assert_result 2, results + + assert_match %{"kind" => 6, "label" => "items"} in results + assert_match %{"kind" => 6, "label" => "item"} not in results + end + + test "<- matches dont leak from with", %{client: client, foo: foo} do + uri = uri(foo) + + did_open(client, foo, """ + defmodule Foo do + def run(items) do + names = + with item <- items do + item.name + end + + i + end + end + """) + + request client, %{ + method: "textDocument/completion", + id: 2, + jsonrpc: "2.0", + params: %{ + textDocument: %{ + uri: uri + }, + position: %{ + line: 7, + character: 5 + } + } + } + + assert_result 2, results + + assert_match %{"kind" => 6, "label" => "items"} in results + assert_match %{"kind" => 6, "label" => "item"} not in results + end end