Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zls stuck with 100% CPU on a bad const bar = if (...) else null; statement (textDocument_hover) #2173

Open
AloisMahdal opened this issue Feb 7, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@AloisMahdal
Copy link

AloisMahdal commented Feb 7, 2025

Zig Version

0.13.0

ZLS Version

0.13.0

Client / Code Editor / Extensions

NVIM v0.10.3

Steps to Reproduce and Observed Behavior

Following code snippet will make zls hang, consuming 100% CPU:

const OPTIONAL_STR = ?[]const u8;
const OPTIONAL_USIZE = ?usize;
const AN_USIZE = usize;

const FOO = OPTIONAL_USIZE orelse @max(1, AN_USIZE);

//       ,-- Gets stuck here.
//    vvv
const BAR = if (OPTIONAL_STR == null) {
    (OPTIONAL_USIZE orelse (FOO + 1) / 2);
} else null;

When I try to use Hover Documentation, neovim just gets stuck, and in htop I can see zls using 100% of CPU cycles.

Expected Behavior

Documentation shows up in expected time. (The type is most probably unknown in this case.)

Relevant log output

[START][2025-02-07 15:43:38] LSP logging initiated
[INFO][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:731	"Starting RPC client"	{  cmd = { "/home/netvor/.local/share/nvim/mason/bin/zls" },  extra = {    cwd = "/home/netvor"  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      general = {        positionEncodings = { "utf-16" }      },      textDocument = {        callHierarchy = {          dynamicRegistration = false        },        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = true,          isPreferredSupport = true,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = true,            deprecatedSupport = true,            documentationFormat = { "markdown", "plaintext" },            insertReplaceSupport = true,            insertTextModeSupport = {              valueSet = { 1, 2 }            },            labelDetailsSupport = true,            preselectSupport = true,            resolveSupport = {              properties = { "documentation", "detail", "additionalTextEdits", "sortText", "filterText", "insertText", "textEdit", "insertTextFormat", "insertTextMode" }            },            snippetSupport = true,            tagSupport = {              valueSet = { 1 }            }          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          completionList = {            itemDefaults = { "commitCharacters", "editRange", "insertTextFormat", "insertTextMode", "data" }          },          contextSupport = true,          dynamicRegistration = false,          insertTextMode = 1        },        declaration = {          linkSupport = true        },        definition = {          dynamicRegistration = true,          linkSupport = true        },        diagnostic = {          dynamicRegistration = false        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        formatting = {          dynamicRegistration = true        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = true        },        implementation = {          linkSupport = true        },        inlayHint = {          dynamicRegistration = true,          resolveSupport = {            properties = { "textEdits", "tooltip", "location", "command" }          }        },        publishDiagnostics = {          dataSupport = true,          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        rangeFormatting = {          dynamicRegistration = true        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = true,          prepareSupport = true        },        semanticTokens = {          augmentsSyntaxTokens = true,          dynamicRegistration = false,          formats = { "relative" },          multilineTokenSupport = false,          overlappingTokenSupport = true,          requests = {            full = {              delta = true            },            range = false          },          serverCancelSupport = false,          tokenModifiers = { "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary" },          tokenTypes = { "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator", "decorator" }        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = true,          willSaveWaitUntil = true        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = true        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        didChangeConfiguration = {          dynamicRegistration = false        },        didChangeWatchedFiles = {          dynamicRegistration = false,          relativePatternSupport = true        },        inlayHint = {          refreshSupport = true        },        semanticTokens = {          refreshSupport = true        },        symbol = {          dynamicRegistration = false,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.10.3+g9b5ee7df4e"    },    initializationOptions = vim.empty_dict(),    processId = 3698395,    rootPath = vim.NIL,    rootUri = vim.NIL,    trace = "off",    workDoneToken = "1",    workspaceFolders = vim.NIL  }}
[ERROR][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:770	"rpc"	"/home/netvor/.local/share/nvim/mason/bin/zls"	"stderr""info : ( main ): Starting ZLS 0.13.0 @ '/home/netvor/.local/share/nvim/mason/bin/zls'\ninfo : (server): Client is 'Neovim-0.10.3+g9b5ee7df4e'\ninfo : (server): No config file zls.json found. This is not an error.\n"
[ERROR][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:770	"rpc"	"/home/netvor/.local/share/nvim/mason/bin/zls"	"stderr""info : (server): Set config option 'builtin_path' to '/home/netvor/.cache/zls/builtin.zig'\ninfo : (server): Set config option 'zig_lib_path' to '/opt/zigdev/zig-linux-x86_64/lib'\ninfo : (server): Set config option 'zig_exe_path' to '/usr/bin/zig'\ninfo : (server): Set config option 'build_runner_path' to '/home/netvor/.cache/zls/build_runner/21872970afd69e48a0847077e5196711/build_runner.zig'\ninfo : (server): Set config option 'global_cache_path' to '/home/netvor/.cache/zls'\n"
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      codeActionProvider = true,      colorProvider = false,      completionProvider = {        completionItem = {          labelDetailsSupport = true        },        resolveProvider = false,        triggerCharacters = { ".", ":", "@", "]", "/" }      },      declarationProvider = true,      definitionProvider = true,      documentFormattingProvider = true,      documentHighlightProvider = true,      documentRangeFormattingProvider = false,      documentSymbolProvider = true,      foldingRangeProvider = true,      hoverProvider = true,      implementationProvider = false,      inlayHintProvider = true,      positionEncoding = "utf-16",      referencesProvider = true,      renameProvider = true,      selectionRangeProvider = true,      semanticTokensProvider = {        full = true,        legend = {          tokenModifiers = { "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary", "generic", "_" },          tokenTypes = { "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator", "decorator", "errorTag", "builtin", "label", "keywordLiteral", "union", "opaque" }        },        range = true      },      signatureHelpProvider = {        retriggerCharacters = { "," },        triggerCharacters = { "(" }      },      textDocumentSync = {        change = 2,        openClose = true,        save = true,        willSave = true,        willSaveWaitUntil = true      },      typeDefinitionProvider = true,      workspace = {        workspaceFolders = {          changeNotifications = true,          supported = true        }      },      workspaceSymbolProvider = false    },    serverInfo = {      name = "zls",      version = "0.13.0"    }  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "zig",      text = "const OPTIONAL_STR = ?[]const u8;\nconst OPTIONAL_USIZE = ?usize;\nconst AN_USIZE = usize;\n\nconst FOO = OPTIONAL_USIZE orelse @max(1, AN_USIZE);\n\n//       ,-- Gets stuck here.\n//    vvv\nconst BAR = if (OPTIONAL_STR == null) {\n    (OPTIONAL_USIZE orelse (FOO + 1) / 2);\n} else null;\n",      uri = "file:///home/netvor/killzls.zig",      version = 0    }  }}
[INFO][2025-02-07 15:43:38] ...m/lsp/client.lua:620	"LSP[zls]"	"server_capabilities"	{  server_capabilities = {    codeActionProvider = true,    colorProvider = false,    completionProvider = {      completionItem = {        labelDetailsSupport = true      },      resolveProvider = false,      triggerCharacters = { ".", ":", "@", "]", "/" }    },    declarationProvider = true,    definitionProvider = true,    documentFormattingProvider = true,    documentHighlightProvider = true,    documentRangeFormattingProvider = false,    documentSymbolProvider = true,    foldingRangeProvider = true,    hoverProvider = true,    implementationProvider = false,    inlayHintProvider = true,    positionEncoding = "utf-16",    referencesProvider = true,    renameProvider = true,    selectionRangeProvider = true,    semanticTokensProvider = {      full = true,      legend = {        tokenModifiers = { "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary", "generic", "_" },        tokenTypes = { "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator", "decorator", "errorTag", "builtin", "label", "keywordLiteral", "union", "opaque" }      },      range = true    },    signatureHelpProvider = {      retriggerCharacters = { "," },      triggerCharacters = { "(" }    },    textDocumentSync = {      change = 2,      openClose = true,      save = true,      willSave = true,      willSaveWaitUntil = true    },    typeDefinitionProvider = true,    workspace = {      workspaceFolders = {        changeNotifications = true,        supported = true      }    },    workspaceSymbolProvider = false  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = "i_haz_configuration",  jsonrpc = "2.0",  method = "workspace/configuration",  params = {    items = { {        section = "zls.enable_snippets"      }, {        section = "zls.enable_argument_placeholders"      }, {        section = "zls.enable_build_on_save"      }, {        section = "zls.build_on_save_step"      }, {        section = "zls.enable_autofix"      }, {        section = "zls.semantic_tokens"      }, {        section = "zls.enable_inlay_hints"      }, {        section = "zls.inlay_hints_show_variable_type_hints"      }, {        section = "zls.inlay_hints_show_struct_literal_field_type"      }, {        section = "zls.inlay_hints_show_parameter_name"      }, {        section = "zls.inlay_hints_show_builtin"      }, {        section = "zls.inlay_hints_exclude_single_argument"      }, {        section = "zls.inlay_hints_hide_redundant_param_names"      }, {        section = "zls.inlay_hints_hide_redundant_param_names_last_token"      }, {        section = "zls.warn_style"      }, {        section = "zls.highlight_global_var_declarations"      }, {        section = "zls.dangerous_comptime_experiments_do_not_enable"      }, {        section = "zls.skip_std_references"      }, {        section = "zls.prefer_ast_check_as_child_process"      }, {        section = "zls.builtin_path"      }, {        section = "zls.zig_lib_path"      }, {        section = "zls.zig_exe_path"      }, {        section = "zls.build_runner_path"      }, {        section = "zls.global_cache_path"      }, {        section = "zls.completion_label_details"      } }  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///home/netvor/killzls.zig"  }}
[DEBUG][2025-02-07 15:43:38] ...m/lsp/client.lua:678	"LSP[zls]"	"client.request"	1	"textDocument/semanticTokens/full"	{  textDocument = {    uri = "file:///home/netvor/killzls.zig"  }}	<function 1>	1
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  method = "textDocument/semanticTokens/full",  params = {    textDocument = {      uri = "file:///home/netvor/killzls.zig"    }  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:423	"server_request: callback result"	{  result = { vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL },  status = true}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = "i_haz_configuration",  jsonrpc = "2.0",  result = { vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL, vim.NIL }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = 2,  jsonrpc = "2.0",  result = {    data = { 0, 0, 5, 15, 0, 0, 6, 12, 1, 1, 0, 13, 1, 21, 0, 0, 2, 1, 21, 0, 0, 3, 5, 15, 0, 0, 6, 2, 1, 0, 1, 0, 5, 15, 0, 0, 6, 14, 1, 1, 0, 15, 1, 21, 0, 0, 2, 1, 21, 0, 0, 1, 5, 1, 0, 1, 0, 5, 15, 0, 0, 6, 8, 1, 1, 0, 9, 1, 21, 0, 0, 2, 5, 1, 0, 2, 0, 5, 15, 0, 0, 6, 3, 8, 1, 0, 4, 1, 21, 0, 0, 2, 14, 1, 0, 0, 15, 6, 15, 0, 0, 7, 4, 24, 0, 0, 5, 1, 19, 0, 0, 3, 8, 1, 0, 2, 0, 29, 17, 0, 1, 0, 9, 17, 0, 1, 0, 5, 15, 0, 0, 6, 3, 8, 1, 0, 4, 1, 21, 0, 0, 2, 2, 15, 0, 0, 4, 12, 1, 0, 0, 13, 2, 21, 0, 0, 3, 4, 26, 0, 1, 5, 14, 1, 0, 0, 15, 6, 15, 0, 0, 8, 3, 8, 0, 0, 4, 1, 21, 0, 0, 2, 1, 19, 0, 0, 3, 1, 21, 0, 0, 2, 1, 19, 0, 1, 2, 4, 15, 0, 0, 5, 4, 26, 0 }  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = "semantic_tokens_refresh",  jsonrpc = "2.0",  method = "workspace/semanticTokens/refresh"}
[DEBUG][2025-02-07 15:43:38] ...m/lsp/client.lua:678	"LSP[zls]"	"client.request"	1	"textDocument/semanticTokens/full"	{  textDocument = {    uri = "file:///home/netvor/killzls.zig"  }}	<function 1>	1
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = 3,  jsonrpc = "2.0",  method = "textDocument/semanticTokens/full",  params = {    textDocument = {      uri = "file:///home/netvor/killzls.zig"    }  }}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:423	"server_request: callback result"	{  result = vim.NIL,  status = true}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = "semantic_tokens_refresh",  jsonrpc = "2.0",  result = vim.NIL}
[DEBUG][2025-02-07 15:43:38] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = 3,  jsonrpc = "2.0",  result = {    data = { 0, 0, 5, 15, 0, 0, 6, 12, 1, 1, 0, 13, 1, 21, 0, 0, 2, 1, 21, 0, 0, 3, 5, 15, 0, 0, 6, 2, 1, 0, 1, 0, 5, 15, 0, 0, 6, 14, 1, 1, 0, 15, 1, 21, 0, 0, 2, 1, 21, 0, 0, 1, 5, 1, 0, 1, 0, 5, 15, 0, 0, 6, 8, 1, 1, 0, 9, 1, 21, 0, 0, 2, 5, 1, 0, 2, 0, 5, 15, 0, 0, 6, 3, 8, 1, 0, 4, 1, 21, 0, 0, 2, 14, 1, 0, 0, 15, 6, 15, 0, 0, 7, 4, 24, 0, 0, 5, 1, 19, 0, 0, 3, 8, 1, 0, 2, 0, 29, 17, 0, 1, 0, 9, 17, 0, 1, 0, 5, 15, 0, 0, 6, 3, 8, 1, 0, 4, 1, 21, 0, 0, 2, 2, 15, 0, 0, 4, 12, 1, 0, 0, 13, 2, 21, 0, 0, 3, 4, 26, 0, 1, 5, 14, 1, 0, 0, 15, 6, 15, 0, 0, 8, 3, 8, 0, 0, 4, 1, 21, 0, 0, 2, 1, 19, 0, 0, 3, 1, 21, 0, 0, 2, 1, 19, 0, 1, 2, 4, 15, 0, 0, 5, 4, 26, 0 }  }}
[DEBUG][2025-02-07 15:43:41] ...m/lsp/client.lua:678	"LSP[zls]"	"client.request"	1	"textDocument/hover"	{  position = {    character = 6,    line = 8  },  textDocument = {    uri = "file:///home/netvor/killzls.zig"  }}	<function 1>	1
[DEBUG][2025-02-07 15:43:41] .../vim/lsp/rpc.lua:286	"rpc.send"	{  id = 4,  jsonrpc = "2.0",  method = "textDocument/hover",  params = {    position = {      character = 6,      line = 8    },    textDocument = {      uri = "file:///home/netvor/killzls.zig"    }  }}
[DEBUG][2025-02-07 15:43:41] .../vim/lsp/rpc.lua:408	"rpc.receive"	{  id = 4,  jsonrpc = "2.0",  result = {    contents = {      kind = "markdown",      value = "\nconst BAR = if (OPTIONAL_STR == null) {\n    (OPTIONAL_USIZE orelse (FOO + 1) / 2);\n} else null\n\n\n(@TypeOf(null))\n"    },    range = {      ["end"] = {        character = 9,        line = 8      },      start = {        character = 6,        line = 8      }    }  }}
@AloisMahdal AloisMahdal added the bug Something isn't working label Feb 7, 2025
@Kaikacy
Copy link

Kaikacy commented Feb 8, 2025

I have similar issue, but not for hover doc. I'm using blink.cmp for completions and it randomly gets stuck, using 100% cpu.
Weirdly, this only happens for zls and it consistently fails on one specific code snippet

fn parse(filename: []const u8) !i32 {
    var fd = try std.fs.cwd().openFile(filename, .{});
    defer fd.cl
    //         ^ 
    // cursor is here
}

as soon as close method becomes best match, nvim crashes.
I tried your provided snipped but that worked fine for me, so I think this might be blink.cmp issue,
but if so, then why does it only happen to zls

@NicoElbers
Copy link

related #2139

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants