sly icon indicating copy to clipboard operation
sly copied to clipboard

Reader macro on "[" breaks unused variable warnings

Open anlsh opened this issue 5 years ago • 6 comments

I originally filed this as a bug over at sbcl, but Jan Moringen indicates there that the bug is might be in sly/slime itself: I'll post their response as a comment below

Brief

Once a certain reader macro has been defined, unused variable warnings from file compilation where said reader macro is used turn into errors. These errors appear (incorrectly) to originate from the reader macro itself.

Detailed Description & Tests

In a fresh image, we eval the following block to define a reader macro on [. Its objective is to turn expressions of the sort [ls index] --> (elt ls index), though that shouldn't be important.

(defun bracketed-access (stream char)
  (declare (ignore char))
  (destructuring-bind (place i0 &rest indices) (read-delimited-list #\] stream t)
    (when indices (error "bracketed-access ignores the &rest indices argument but is passed here"))
    `(elt ,place ,i0)))

(set-macro-character #\[ #'bracketed-access)
(set-syntax-from-char #\] #\))

However, this confuses file compilation somehow. This file will compile without any issues, and produces the correct output when evaluated

;; let1.lisp
(let ()
  ['(a b c) 2])

However, file compilation of this one gives errors

;; let2.lisp
(let (a)
  ['(a b c) 2])

The error (end of this section) is only thrown when using sly-compile-file & sly-compile-and-load-file (or, as phoe helped me confirm on discord, their slime counterparts). Compilation of the let using the compile-region or compile-defun functions works fine.

The only difference between let1 and let2 should be that the second generates an unused variable warning. In fact, inserting a (declare (ignore a)) in let2 will allow file compilation without issue.

Below is the error generated by file compilation. Somehow, the message is flatly incorrect.

error while parsing arguments to DESTRUCTURING-BIND:
  too few elements in
    ()
  to satisfy lambda list
    (PLACE I0 &REST INDICES):
  at least 2 expected, but got 0
   [Condition of type SB-KERNEL::ARG-COUNT-ERROR]

Restarts:
 0: [MUFFLE-WARNING] Skip warning.
 1: [ABORT] Abort compilation.
 2: [*ABORT] Return to SLY's top level.
 3: [ABORT] abort thread (#<THREAD "slynk-worker" RUNNING {1003246663}>)

...

anlsh avatar May 19 '20 18:05 anlsh

From Jan's reply

This looks comes form an interaction between the custom reader macro and SLIME/SLY. The interesting part of the complete backtrace is:

Error while parsing arguments to DESTRUCTURING-BIND:
  too few elements in
    ()
  to satisfy lambda list
    (PLACE I0 &REST INDICES):
  at least 2 expected, but got 0
   [Condition of type SB-KERNEL::ARG-COUNT-ERROR]

Restarts:
 0: [MUFFLE-WARNING] Skip warning.
 1: [ABORT] Abort compilation.
 2: [*ABORT] Return to SLIME's top level.
 3: [ABORT] abort thread (#<THREAD "worker" RUNNING {100DD63093}>)

Backtrace:
  0: (SB-C::CHECK-DS-LIST/&REST #<unavailable argument> #<unavailable argument> #<unavailable argument> #<unavailable argument>)
  1: (BRACKETED-ACCESS #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> #<unused argument>)
  2: (SB-IMPL::READ-MAYBE-NOTHING #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> #\[)
  3: (SB-IMPL::READ-LIST #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> #<unused argument>)
  4: (SB-IMPL::READ-MAYBE-NOTHING #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> #\()
  5: (SB-IMPL::%READ-PRESERVING-WHITESPACE #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> T (NIL) T)
  6: (SB-IMPL::%READ-PRESERVING-WHITESPACE #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> T (NIL) NIL)
  7: (READ #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}> T NIL NIL)
  8: (SWANK/SOURCE-PATH-PARSER::SKIP-TOPLEVEL-FORMS 1 #<SB-SYS:FD-STREAM for "file /tmp/let1.lisp" {100DDB40F3}>)
  9: (SWANK/SOURCE-PATH-PARSER:SOURCE-PATH-FILE-POSITION (0) #P"/tmp/let1.lisp")
 10: (SWANK/SBCL::LOCATE-COMPILER-NOTE #P"/tmp/let1.lisp" (0) " (LET (A) ..)
 11: (SWANK/SBCL::COMPILER-NOTE-LOCATION #<SB-INT:SIMPLE-STYLE-WARNING "The variable ~S is defined but never used." {100DDB2443}> #<SB-C::COMPILER-ERROR-CONTEXT >)
 12: (SWANK/SBCL::SIGNAL-COMPILER-CONDITION #<SB-INT:SIMPLE-STYLE-WARNING "The variable ~S is defined but never used." {100DDB2443}> #<SB-C::COMPILER-ERROR-CONTEXT >)
 13: (SB-KERNEL::%SIGNAL #<SB-INT:SIMPLE-STYLE-WARNING "The variable ~S is defined but never used." {100DDB2443}>)
 14: (SB-C::COMPILER-STYLE-WARNING-HANDLER #<SB-INT:SIMPLE-STYLE-WARNING "The variable ~S is defined but never used." {100DDB2443}>)
 15: (SB-KERNEL::%SIGNAL #<SB-INT:SIMPLE-STYLE-WARNING "The variable ~S is defined but never used." {100DDB2443}>)
 16: ((FLET SB-KERNEL::%WARN :IN "SYS:SRC;CODE;WARM-ERROR.LISP") "The variable ~S is defined but never used." #<SB-KERNEL::CONDITION-CLASSOID STYLE-WARNING> SB-INT:SIMPLE-STYLE-WARNING A)
 17: (SB-C:COMPILER-STYLE-WARN "The variable ~S is defined but never used." A)
 18: (SB-C::NOTE-UNREFERENCED-VARS (#<SB-C::LAMBDA-VAR :%SOURCE-NAME A {100DDAECA3}>) #<SB-KERNEL:BIND :LAMBDA #<SB-C::CLAMBDA :%SOURCE-NAME SB-C::.ANONYMOUS. :%DEBUG-NAME (LET #) :KIND :LET :TYPE #<SB-KER..

So the compiler signals a style-warning which SLIME handles by invoking its source parser which intern calls the reader macro. The reader macro then signals an error presumably it was invoked at a position in the input that does not have the expected form.

anlsh avatar May 19 '20 18:05 anlsh

To state what is probably already obvious, I think the problem in is s**nk-source-file-parser, which the SBCL, CMUCL and SCL backends use.

Thanks for the report: I'll have a better look at this later on. I still haven't read your reports very carefully, but it seems the problems affects SLIEM too. Si we can page @luismbo, SLIME maintainer, to help us have a look. For now I'll just note that extensive use of reader macros will bring you problems, such as the inability of SLY to discover the "symbols at point" or place stickers. However a reasonably well-behaved reader macro on [ and ] shouldn't be very problematic.

joaotavora avatar May 19 '20 18:05 joaotavora

So the compiler signals a style-warning which SLIME handles by invoking its source parser which intern calls the reader macro. The reader macro then signals an error presumably it was invoked at a position in the input that does not have the expected form.

In this example, you're compiling let1.lisp, right? That doesn't have the unused variable as far as I can tell.

joaotavora avatar May 19 '20 19:05 joaotavora

The problem indeed affects Slime too, as @phoe helped me confirm.

Again that second comment wasn't me, but Jan Moringen's (@scymtym) over on the sbcl bug tracker. I think they must have been compiling let2.lisp, since like you said let1 doesn't signal any warnings at all

anlsh avatar May 19 '20 19:05 anlsh

I think they must have been compiling let2.lisp,

The backtrace mentions let1.lisp. maybe they added the variable manually and forgot to update the file name.

joaotavora avatar May 19 '20 19:05 joaotavora

I think they must have been compiling let2.lisp,

The backtrace mentions let1.lisp. maybe they added the variable manually and forgot to update the file name.

Yes, I started with let1.lisp and then changed it to introduce the warning. Sorry for the confusion.

To reproduce the complete backtrace, comment out the line

(sb-debug:*stack-top-hint* (or sb-debug:*stack-top-hint* '%signal))

in SBCL's %signal function. The function can be redefined in the running Lisp image.

scymtym avatar May 19 '20 20:05 scymtym