Opened 12 years ago

Closed 12 years ago

#240 closed defect (invalid)

setf expander not macroexpanded

Reported by: hans Owned by: gb
Priority: major Milestone:
Component: Compiler Version:
Keywords: Cc:

Description

I'm trying to define a setf expander that itself is a macro which uses other macros. This does not work:

(in-package :cl-user)

(defvar *foo* 0)

(defmacro foo () '*foo*) (defmacro set-foo (new) `(setf *foo* ,new))

(defmacro set-bar (new)

(set-foo new))

(defsetf foo set-bar)

(incf (foo))

; The error is ; value #:G25 is not of the expected type NUMBER. ; The expansion of the (incf (foo)) form is ; (LET* ((#:G1 1) (#:G0 (+ (FOO) #:G1))) (SET-BAR #:G0))

Change History (6)

comment:1 Changed 12 years ago by hans

  • Resolution set to invalid
  • Status changed from new to closed

This appears not to be a bug. I will fix UFFI accordingly.

comment:2 Changed 12 years ago by hans

  • Resolution invalid deleted
  • Status changed from closed to reopened

(in-package :cl-user)

(defvar *foo* 0)

(defmacro foo () '*foo*) (defmacro set-foo (new) `(setf *foo* ,new))

(defmacro set-bar (new)

(set-foo new))

(defsetf foo set-bar)

(incf (foo))

; The error is ; value #:G25 is not of the expected type NUMBER. ; The expansion of the (incf (foo)) form is ; (LET* ((#:G1 1) (#:G0 (+ (FOO) #:G1))) (SET-BAR #:G0)) A

comment:3 Changed 12 years ago by hans

;; Sorry, I meant to reopen the ticket and edit the source snippet.  It appears
;; that the setf expansion below (now with corrected quoting) does not work when
;; compiled.  The same thing works with CLISP and SBCL.  I don't understand the
;; DEFSETF documentation well enough to judge whether CCLs behavior is legal, yet
;; I'd expect it to work.

(in-package :cl-user)

(defvar *foo* 0)

(defmacro foo () '*foo*)
(defmacro set-foo (new) `(setf *foo* ,new))

(defmacro set-bar (new)
    (set-foo new))

(defsetf foo set-bar)

(incf (foo))

; The error is ; value #:G25 is not of the expected type NUMBER.
; The expansion of the (incf (foo)) form is
; (LET* ((#:G1 1) (#:G0 (+ (FOO) #:G1))) (SET-BAR #:G0))

comment:4 in reply to: ↑ description Changed 12 years ago by hans

;; AGAIN, SORRY FOR THE NOISE.  I would have deleted the ticket and started afresh,
;; but that is beyond what Trac lets me do.  So here is the (really) corrected
;; version of the code to reproduce the problem:

;; Sorry, I meant to reopen the ticket and edit the source snippet.  It appears
;; that the setf expansion below (now with corrected quoting) does not work when
;; compiled.  The same thing works with CLISP and SBCL.  I don't understand the
;; DEFSETF documentation well enough to judge whether CCLs behavior is legal, yet
;; I'd expect it to work.

(in-package :cl-user)

(defvar *foo* 0)

(defmacro foo () '*foo*)
(defmacro set-foo (new) `(setf *foo* ,new))

(defmacro set-bar (new)
    `(set-foo ,new))

(defsetf foo set-bar)

(incf (foo))

; The error is
; value #:G25 is not of the expected type NUMBER.
; The expansion of the (incf (foo)) form is
; (LET* ((#:G1 1) (#:G0 (+ (FOO) #:G1))) (SET-BAR #:G0))

comment:5 Changed 12 years ago by gb

I wish that I had something profound to say here, but I can't reproduce this.

[~] gb@sensei> cat foo.lisp
 (in-package :cl-user)

 (defvar *foo* 0)

 (defmacro foo () '*foo*)
 (defmacro set-foo (new) `(setf *foo* ,new))

 (defmacro set-bar (new)
     `(set-foo ,new))

 (defsetf foo set-bar)

 (incf (foo))
[~] gb@sensei> openmcl64 -n
Welcome to Clozure Common Lisp Version 1.2-r8491MS  (LinuxX8664)!
? (compile-file "home:foo.lisp")
#P"/home/gb/foo.lx64fsl"
NIL
NIL
? (load *)
#P"/home/gb/foo.lx64fsl"
? (foo)
1
? 

(I tried this in several other versions of ccl/openmcl and didn't observe any errors.)

So, what's different that causes this to fail for you ?

CCL is generally more conservative about whether defining macros in a file being compiled pervasively affect the global environment at compile time than other implementations may be; if you just compile the example file without loading it, then (for instance) (MACRO-FUNCTION 'FOO) would be false (but the definition would have been present in the lexical environment at compile-time.) Other implementations may have arranged that the global (MACRO-FUNCTION 'FOO) was changed as a result of compiling the DEFMACRO form. Both behaviors are legal; people sometimes write code that depends on the global-side-effecting behavior and find that it isn't portable.

Interesting as that may be, it's not clear how it applies in this example.

comment:6 Changed 12 years ago by hans

  • Resolution set to invalid
  • Status changed from reopened to closed

I think I have isolated the problem to the point where it actually shows up not being a CCL bug, but an invalid use of Common Lisp and setf expanders. Consider:

(in-package :cl-user)

(defvar *foo* 0)

(defmacro foo () '*foo*)
(defmacro set-foo (new) `(setf *foo* ,new))

(defmacro set-bar (new)
  `(set-foo ,(+ 2 new)))

(defsetf foo set-bar)

(defun test-it ()
  (incf (foo)))

In SET-BAR, there now is a compile-time computation. All three compilers I tested this with complain in the same vein:

Error: value #:G25 is not of the expected type NUMBER.

or

; (SET-BAR #:G23) ; ; caught ERROR: ; (in macroexpansion of (SET-BAR #:G23)) ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.) ; The value #:G23 is not of type NUMBER.

I guess that this has to do with evaluation rules in setf expanders, although I don't fully understand the CLHS entry. If there is an easy explanation, please help me out. I will try to work around the problem in UFFI by some other means.

Thanks, and apologies for the incomplete initial analysis.

Note: See TracTickets for help on using tickets.