emacs-elsa / Elsa

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

Elsa crashes when reading forms inside 'let-alist', prints: 'Scan error: "Containing expression ends prematurely"' #172

Closed spellcard199 closed 3 years ago

spellcard199 commented 4 years ago

I'm having this issue while writing a library in which I'm using (require 'indium). Indium is an emacs package on Melpa.

The error is: Scan error: "Containing expression ends prematurely", 10004, 10005. Even though it doesn't say in which file it happens eventually I managed to narrow the triggering code to specific lines in indium-client.el and elsa-reader.el:

To confirm that the error is triggered when Elsa tries to read let-alist I wrote a minimal example to reproduce the issue without Indium:

# Create a new directory and cd into it:
mkdir elsa-bug-report
cd elsa-bug-report

# Create a cask project:
echo '(source gnu) (source melpa) (depends-on "elsa")' > Cask

# Create a test file:
echo "(let-alist '((foo . 'ok)) (print .foo))" > test.el

# Install Elsa:
cask install

# Run Elsa:
cask exec elsa test.el

# If you want to confirm that the code in test.el is indeed correct:
cask emacs -Q --batch --load test.el
# It should print:
# (quote ok)

To find where in Elsa the error came from, from the same directory created above:

  1. I used this shell command to delete all the .elc files cask creates each time:
    find . -type f -name '*.elc' -exec rm {} +
  2. Then I inserted many print statements inside .cask/26.1/elpa/elsa-20200225.1440/elsa-reader.el until the (down-list) I linked above was surrounded by 2 print expressions, the latter of which wasn't executed when the error was raised

This was the farthest I could go. I wouldn't know how to fix this.

P.S. Is there a way to make the error messages when Elsa fails more verbose, like printing the Backtrace and which file it was reading?

Thanks for your work on Elsa.

Fuco1 commented 4 years ago

P.S. Is there a way to make the error messages when Elsa fails more verbose, like printing the Backtrace and which file it was reading?

I wish I knew how. The whole EIEIO thing doesn't help much either as it generates rather cryptic errors.

spellcard199 commented 4 years ago

I don't know if it's of interest, maybe it's too silly, but posting just in case. In a project I'm writing I added an hack to see in which file Elsa fails. It just adds a rudimentary advice around elsa-process-file.

If from my project directory I run Elsa with...:

cask exec elsa --load elsa-debug-hack.el --eval "(defun elsa-debug-hack-skip-file-p (file) nil)" elisp/qipmx.el

... the result looks like this:

"(scan-error \"Containing expression ends prematurely\" 10004 10005) - .../indium-client.el"
"(scan-error \"Containing expression ends prematurely\" 25061 25062) - .../company.el"
"(scan-error \"Containing expression ends prematurely\" 7936 7937) - .../indium-repl.el"
"(scan-error \"Containing expression ends prematurely\" 1620 1621) - .../indium-nodejs.el"
"(scan-error \"Containing expression ends prematurely\" 2481 2482) - .../indium-chrome.el"

(the actual culprits are indium-client.el and company.el, the others just require indium-client)

If instead I set the elsa-debug-hack-skip-if-error to nil...:

cask exec elsa --load elsa-debug-hack.el --eval "(progn (defun elsa-debug-hack-skip-file-p (file) nil) (setq elsa-debug-hack-skip-file-if-error nil))" elisp/qipmx.el

... after the first error it stops and prints a very long backtrace.

(The hack also contains a function called elsa-debug-hack-skip-file-p that is unrelated to this issue. I wrote that just to speedup both Elsa and flycheck-elsa, since I know that an error will be thrown anyway.)