lexical-lsp / lexical

Lexical is a next-generation elixir language server
776 stars 77 forks source link

Request textDocument/completion failed while piping tuple to function. #779

Open Frid-Yuandu opened 1 week ago

Frid-Yuandu commented 1 week ago

I got a Request textDocument/completion failed. error. Here is the log:

2024-06-21 16:38:18.822 [info] [Error - 4:38:18 PM] Request textDocument/completion failed.

2024-06-21 16:38:18.822 [info]   Message: ** (FunctionClauseError) no function clause matching in LXical.Ast.Tokens.get_start_pos/1

    (lx_common 0.5.0) LXical.Ast.Tokens.get_start_pos([{:"{", {124, 45, nil}}, {:identifier, {124, 46, ~c"addr"}, :addr}, {:",", {124, 50, 0}}, {:identifier, {124, 52, ~c"port"}, :port}, {:"}", {124, 56, nil}}, {:arrow_op, {124, 58, nil}, :|>}, {:paren_identifier, {124, 61, ~c"inspect_peername"}, :inspect_peername}, {:"(", {124, 77, nil}}, {:")", {124, 78, nil}}])

    (lx_common 0.5.0) lib/lexical/ast/tokens.ex:158: anonymous fn/2 in LXical.Ast.Tokens.interpolation_ranges/1

    (elixir 1.15.7) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3

    (lx_common 0.5.0) lib/lexical/ast/tokens.ex:151: LXical.Ast.Tokens.interpolation_ranges/1

    (lx_common 0.5.0) lib/lexical/ast/tokens.ex:97: LXical.Ast.Tokens.normalize_token/1

    (elixir 1.15.7) lib/stream.ex:613: anonymous fn/4 in Stream.map/2

    (elixir 1.15.7) lib/enum.ex:4830: Enumerable.List.reduce/3

    (elixir 1.15.7) lib/stream.ex:1667: Stream.do_list_resource/6

I referenced previous issues related to this error, but it didn't help much. So I went back and checked the source code pointed out in the log.

# origin code
{addr, port} = extract_addr_port(uri)
Logger.debug("request to destination: #{{addr, port} |> inspect_peername()}")

I tried changing the code to the following form and the error magically disappeared. So I tried a few different ways of writing it and found that none of these below triggered the error:

# first test code
dst = extract_addr_port(uri)
Logger.debug("request to destination: #{inspect_peername(dst)}")

# second test code
dst = extract_addr_port(uri)
Logger.debug("request to destination: #{dst |> inspect_peername()}")

# third test code
{addr, port} = extract_addr_port(uri)
Logger.debug("request to destination: #{inspect_peername({addr, port})}")
scohen commented 1 week ago

Thanks for the report, I'll take a look. Lexical shouldn't crash here.

If i was reviewing that code, I would offer that the pipeline is unnecessary in that case and just adds noise. The first code you have there seems more idiomatic to me.

Frid-Yuandu commented 1 week ago

If i was reviewing that code, I would offer that the pipeline is unnecessary in that case and just adds noise. The first code you have there seems more idiomatic to me.

You are right, it is a edge case and not so idiomatic.

I make more test, i presume this error occurs when piping a collection type literal (I'm not sure if this is accurate) to a function in a formatting string?

require Record
Record.defrecord(:foo, hello: "world")

# these will triggered error
"test: #{{"localhost", 443} |> inspect_peername()}"
"test: #{["localhost", 443] |> inspect_peername()}"
"test: #{%{} |> inspect_peername()}"

# these below won triggered error
"test: #{foo() |> inspect()}"
"test: #{"localhost" |> inspect_peername()}"
"test: #{65535 |> inspect()}"
"test: #{connect_to_server() |> elem(1) |> inspect()}"
"test: #{:localhost |> inspect()}"