Skip to content

Error: wrong-type-argument when go to definition with pyrefly #4879

@daanturo

Description

@daanturo

Thank you for the bug report

  • I am using the latest version of lsp-mode related packages.
  • I checked FAQ and Troubleshooting sections
  • You may also try reproduce the issue using clean environment using the following command: M-x lsp-start-plain

Bug description

With the pyrefly server added via custom config, cannot use xref-find-definitions.

Steps to reproduce

  1. Enable pyrefly integration, or minimally:
(lsp-register-client
 (make-lsp-client
  :new-connection (lsp-stdio-connection (lambda () '("pyrefly" "lsp")))
  :activation-fn (lsp-activate-on "python")
  :add-on? t
  :multi-root t
  :server-id 'my-pyrefly))
  1. Use xref-find-definitions on any valid identifier, such as this minimal case:
x = 1
print(x)
#     ^
# xref-find-definitions here

The error will appear after some timeouts, if any.

Expected behavior

xref-find-definitions works correctly.

Which Language Server did you use?

Pyrefly

OS

Linux

Error callstack

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
  =(nil nil)
  (if (= left-line right-line) (> left-character right-character) (> left-line right-line))
  (let* ((left-line (plist-get input0 :line)) (left-character (plist-get input0 :character)) (right-line (plist-get input1 :line)) (right-character (plist-get input1 :character))) (if (= left-line right-line) (> left-character right-character) (> left-line right-line)))
  lsp--position-compare(nil nil)
  (let* ((left-start (plist-get input0 :start)) (right-start (plist-get input1 :start))) (lsp--position-compare right-start left-start))
  (let ((input0 (lsp--location-range left)) (input1 (lsp--location-range right))) (let* ((left-start (plist-get input0 :start)) (right-start (plist-get input1 :start))) (lsp--position-compare right-start left-start)))
  (if (not (string= left-uri right-uri)) (string< left-uri right-uri) (let ((input0 (lsp--location-range left)) (input1 (lsp--location-range right))) (let* ((left-start (plist-get input0 :start)) (right-start (plist-get input1 :start))) (lsp--position-compare right-start left-start))))
  (let ((left-uri (lsp--location-uri left)) (right-uri (lsp--location-uri right))) (if (not (string= left-uri right-uri)) (string< left-uri right-uri) (let ((input0 (lsp--location-range left)) (input1 (lsp--location-range right))) (let* ((left-start (plist-get input0 :start)) (right-start (plist-get input1 :start))) (lsp--position-compare right-start left-start)))))
  #f(lambda (left right) [eldoc-documentation-default cl-struct-lsp--log-entry-tags cl-struct-lsp-session-tags cl-struct-lsp--workspace-tags cl-struct-lsp--registered-capability-tags lsp-mode-menu cl-struct-lsp--folding-range-tags cl-struct-lsp-watch-tags cl-struct-lsp--client-tags lsp--log-lines company-minimum-prefix-length dap-ui-menu-items dap-auto-configure-mode yas-also-auto-indent-first-line yas-wrap-around-region yas-indent-line yas-inhibit-overlay-modification-protection t] "Sort first by file, then by line, then by column." (let ((left-uri (lsp--location-uri left)) (right-uri (lsp--location-uri right))) (if (not (string= left-uri right-uri)) (string< left-uri right-uri) (let ((input0 (lsp--location-range left)) (input1 (lsp--location-range right))) (let* ((left-start (plist-get input0 :start)) (right-start (plist-get input1 :start))) (lsp--position-compare right-start left-start))))))((:end (:character 1 :line 0) :start (:character 0 :line 0)) :range)
  sort(((:originSelectionRange (:end (:character 7 :line 1) :start (:character 6 :line 1)) :targetRange (:end (:character 5 :line 0) :start (:character 0 :line 0)) :targetSelectionRange (:end (:character 1 :line 0) :start (:character 0 :line 0)) :targetUri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") :range (:end (:character 1 :line 0) :start (:character 0 :line 0)) :uri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") lsp--location-before-p)
  #f(compiled-function (pred list) #<bytecode 0x1872bfc40bbfcaf5>)(lsp--location-before-p ((:originSelectionRange (:end (:character 7 :line 1) :start (:character 6 :line 1)) :targetRange (:end (:character 5 :line 0) :start (:character 0 :line 0)) :targetSelectionRange (:end (:character 1 :line 0) :start (:character 0 :line 0)) :targetUri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") :range (:end (:character 1 :line 0) :start (:character 0 :line 0)) :uri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py"))
  apply(#f(compiled-function (pred list) #<bytecode 0x1872bfc40bbfcaf5>) lsp--location-before-p ((:originSelectionRange (:end (:character 7 :line 1) :start (:character 6 :line 1)) :targetRange (:end (:character 5 :line 0) :start (:character 0 :line 0)) :targetSelectionRange (:end (:character 1 :line 0) :start (:character 0 :line 0)) :targetUri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") :range (:end (:character 1 :line 0) :start (:character 0 :line 0)) :uri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") nil)
  seq-sort(lsp--location-before-p ((:originSelectionRange (:end (:character 7 :line 1) :start (:character 6 :line 1)) :targetRange (:end (:character 5 :line 0) :start (:character 0 :line 0)) :targetSelectionRange (:end (:character 1 :line 0) :start (:character 0 :line 0)) :targetUri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") :range (:end (:character 1 :line 0) :start (:character 0 :line 0)) :uri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py"))
  (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri) (seq-sort #'lsp--location-before-p locations))
  (seq-map --cl-get-xrefs-in-file-- (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri) (seq-sort #'lsp--location-before-p locations)))
  (apply #'nconc (seq-map --cl-get-xrefs-in-file-- (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri) (seq-sort #'lsp--location-before-p locations))))
  (let* ((--cl-get-xrefs-in-file-- #'(lambda (file-locs) (let* ((--dash-source-717-- file-locs) (filename ...) (matches --dash-source-717--)) (condition-case err (let ... ...) (error ...) (file-error ...)))))) (apply #'nconc (seq-map --cl-get-xrefs-in-file-- (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri) (seq-sort #'lsp--location-before-p locations)))))
  lsp--locations-to-xref-items(((:originSelectionRange (:end (:character 7 :line 1) :start (:character 6 :line 1)) :targetRange (:end (:character 5 :line 0) :start (:character 0 :line 0)) :targetSelectionRange (:end (:character 1 :line 0) :start (:character 0 :line 0)) :targetUri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py") :range (:end (:character 1 :line 0) :start (:character 0 :line 0)) :uri "file:///home/dan/temp/test/lsp-pyrefly-reproduce.py"))
  (save-excursion (if (get-text-property 0 'identifier-at-point identifier) nil (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache) (user-error "Unable to find symbol %s in current document" identifier))))) (lsp--locations-to-xref-items (lsp-request "textDocument/definition" (lsp--text-document-position-params))))
  (progn (save-excursion (if (get-text-property 0 'identifier-at-point identifier) nil (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache) (user-error "Unable to find symbol %s in current document" identifier))))) (lsp--locations-to-xref-items (lsp-request "textDocument/definition" (lsp--text-document-position-params)))))
  #f(lambda (_backend identifier) [view-inhibit-help-message lsp-help-mode-abbrev-table lsp-help-mode-syntax-table eldoc-documentation-default cl-struct-lsp--log-entry-tags cl-struct-lsp-session-tags cl-struct-lsp--workspace-tags cl-struct-lsp--registered-capability-tags lsp-mode-menu cl-struct-lsp--folding-range-tags cl-struct-lsp-watch-tags cl-struct-lsp--client-tags lsp--log-lines company-minimum-prefix-length dap-ui-menu-items dap-auto-configure-mode yas-also-auto-indent-first-line yas-wrap-around-region yas-indent-line yas-inhibit-overlay-modification-protection t] (progn (save-excursion (if (get-text-property 0 'identifier-at-point identifier) nil (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache) (user-error "Unable to find symbol %s in current document" identifier))))) (lsp--locations-to-xref-items (lsp-request "textDocument/definition" (lsp--text-document-position-params))))))(xref-lsp #("x" 0 1 (identifier-at-point t fontified t)))
  apply(#f(lambda (_backend identifier) [view-inhibit-help-message lsp-help-mode-abbrev-table lsp-help-mode-syntax-table eldoc-documentation-default cl-struct-lsp--log-entry-tags cl-struct-lsp-session-tags cl-struct-lsp--workspace-tags cl-struct-lsp--registered-capability-tags lsp-mode-menu cl-struct-lsp--folding-range-tags cl-struct-lsp-watch-tags cl-struct-lsp--client-tags lsp--log-lines company-minimum-prefix-length dap-ui-menu-items dap-auto-configure-mode yas-also-auto-indent-first-line yas-wrap-around-region yas-indent-line yas-inhibit-overlay-modification-protection t] (progn (save-excursion (if (get-text-property 0 'identifier-at-point identifier) nil (goto-char (cl-rest (or ... ...)))) (lsp--locations-to-xref-items (lsp-request "textDocument/definition" (lsp--text-document-position-params)))))) xref-lsp #("x" 0 1 (identifier-at-point t fontified t)))
  xref-backend-definitions(xref-lsp #("x" 0 1 (identifier-at-point t fontified t)))
  #f(compiled-function () #<bytecode -0x1a307b6b1281ea37>)()
  xref-show-definitions-buffer(#f(compiled-function () #<bytecode -0x1a307b6b1281ea37>) ((window . #<window 3 on lsp-pyrefly-reproduce.py>) (display-action) (auto-jump)))
  xref--show-defs(#f(compiled-function () #<bytecode -0x1a307b6b1281ea37>) nil)
  xref--find-definitions(#("x" 0 1 (identifier-at-point t fontified t)) nil)
  xref-find-definitions(#("x" 0 1 (identifier-at-point t fontified t)))
  funcall-interactively(xref-find-definitions #("x" 0 1 (identifier-at-point t fontified t)))
  command-execute(xref-find-definitions)

Anything else?

The cause seems to be at https://github.com/emacs-lsp/lsp-mode/blob/7fcd17e7d8a06e9943dde059bb940ae80e3974fc/lsp-mode.el#L5354C1-L5360C31, lsp--locations-to-xref-items's pcase matching returns the wrong case.

I'm not sure how that pcase works, but this workaround solves the case for me:

(defun my-lsp--locations-to-xref-items--workaround-list-a (func locations &rest args)
  (condition-case _
      (apply func locations args)
    ((wrong-type-argument)
     (apply func (list locations) args))))
(advice-add #'lsp--locations-to-xref-items :around #'my-lsp--locations-to-xref-items--workaround-list-a)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions