PCL walker doesn't know that SYMBOL-MACROLET can be shadowed by rebindings
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
Suppose we have macro GET-A-PROP which wants explicitly to expand something in its proper lexenv before deciding how to continue expanding. And suppose that there are two nested lexical environment contours in which the same symbol is used as a macro and not a macro. Here's a minimal example, on which the compiler (and interpreter) are totally correct:
* (defun hairball-get-thing (x) (format t "Got you thing ~S~%" x) 'yay)
* (defmacro get-a-prop (arg &environment e)
(let ((newform (macroexpand arg e)))
(if (keywordp newform) `(get ,newform 'foo) `(hairball-
* (symbol-macrolet ((a :mykeyword)) (let ((a (list 'foo (- 5)))) (get-a-prop a)))
Got you thing (FOO -5)
YAY
But the PCL code walker is sorely mistaken:
* (let ((SB-WALKER:
(sb-
=> (SYMBOL-MACROLET ((A :MYKEYWORD))
(LET ((A (LIST 'FOO (- 5)))) (GET :MYKEYWORD 'FOO)))
Or an even more contrived example:
* (let ((a 'frob)) (declare(special a)) (symbol-macrolet ((a :mykeyword)) (locally (declare (special a)) (get-a-prop a))))
Got you thing FROB
YAY
* (let ((SB-WALKER:
=> (LET ((A 'FROB))
(DECLARE (SPECIAL A))
(SYMBOL-MACROLET ((A :MYKEYWORD))
(LOCALLY (DECLARE (SPECIAL A)) (GET :MYKEYWORD 'FOO))))
This could have implications for the correctness of the CLOS implementation, in addition to being a pita.
The problem seems to date back to the original change in CMUCL:
commit 8d3b58a2b30d490
Author: pw <pw>
Date: Wed Nov 15 19:07:31 2000 +0000
Fix environment hacking code to feed symbol-macrolet variable
names to macroexpand-1. Added some commentary on how this code works.
So Paul fixed the opposite problem, that symbol-macrolets were never propagated from the walker bogo-environment into the actual lexical environment that EVAL (or equivalent) needs to execute macroexpander functions.
I'm working on a patch, maybe even one that does away with bogo-funs so that the walker env can never be out-of-sync with the true macro lexenv.
(For what it's worth, I also tested CMUCL's WALKER:
bash-3.2$ sbcl --version
SBCL 1.0.54.0-185b926
a simpler example I found while fixing this. Initially I thought that only the native lexenv fails to see the more deeply nested binding, but this also affects the walker's internal code for SETQ which does not call macroexpand. It just looks at its own replica of the lexenv and decides that A is a symbol-macro.
Good: (symbol-macrolet ((a (nosuchfun x))) (let () (declare (special a)) (setq a 9))) => 9
Bad: (let ((SB-WALKER: *WALK-FORM- EXPAND- MACROS- P* t))
(sb- walker: walk-form '(symbol-macrolet ((a (nosuchfun x))) (let () (declare (special a)) (setq a 9))))) MULTIPLE- VALUE-BIND (#:NEW599) 9 (FUNCALL #'(SETF NOSUCHFUN) #:NEW599 #:X600)))))
=> (SYMBOL-MACROLET ((A (FOO X)))
(LET ()
(DECLARE (SPECIAL A))
(LET* ((#:X600 X))
(