emacs-elsa / Elsa

Emacs Lisp Static Analyzer and gradual type system.
GNU General Public License v3.0
639 stars 26 forks source link

`elsa--get-requires` fails to process "cl-macs.el.gz" due to `syntax-ppss` #226

Open wtianyi opened 1 month ago

wtianyi commented 1 month ago

I'm running into a weird error with Elsa v20230621.1005 MELPA:

(elsa--get-requires "/opt/homebrew/Cellar/emacs-mac/emacs-29.1-mac-10.0/share/emacs/29.1/lisp/emacs-lisp/cl-macs.el.gz")

throws error wrong-type-argument stringp nil, and it turns out it's the matched library-name that becomes nil unexpectedly during the process of finding the required libraries.

Further digging shows that, the first required library "cl-lib" is processed successfully. However, after matching the second required library, "macroexp", (match-string 1) seems to be invalidated (evaluates to nil instead of "macroexp") after the (syntax-ppss) call in https://github.com/emacs-elsa/Elsa/blob/f719e2404ab6f3323df9341751469cb2e413e013/elsa-dependencies.el#L92

Interestingly, in debugger, if I stop right before line 92 and evaluate (syntax-ppss) manually from debugger, (match-string 1) would not be changed to nil after line 92, and the whole function call can be successful if such manual evaluation is done to "guard" each matched string. Adding a dummy (syntax-ppss) call before line 92, however, will only invalidates (match-string 1) even earlier. It seems that only the interactive evaluation from debugger could "guard" the match.

I could not make the debugger step into syntax-ppss to further understand what's happening.

As the file path suggests, my platform is "emacsmacport" 29.1 installed with Homebrew on macOS.

[1] For convenience, the link to cl-macs.el is https://github.com/emacs-mirror/emacs/blob/master/lisp/emacs-lisp/cl-macs.el

wtianyi commented 1 month ago

It seems that guarding the match data with save-match-data solves my problem:

          (let ((syntax-ppss-data (save-match-data (syntax-ppss))))
            (unless (or (nth 4 syntax-ppss-data)
                        (and (< 0 (car syntax-ppss-data))
                             (not (and (= 1 (car syntax-ppss-data))
                                       (save-excursion
                                         (backward-up-list)
                                         (down-list)
                                         (looking-at-p "eval-"))))) )
              (let* ((library-name (match-string 1))
                     (library (elsa--find-dependency library-name)))
                (when library
                  (push (list library library-name) this-file-requires))))
            )