0.6.8.19:
[sbcl.git] / src / code / early-setf.lisp
1 ;;;; SETF and friends (except for stuff defined with COLLECT, which
2 ;;;; comes later)
3 ;;;;
4 ;;;; Note: The expansions for SETF and friends sometimes create
5 ;;;; needless LET-bindings of argument values. The compiler will
6 ;;;; remove most of these spurious bindings, so SETF doesn't worry too
7 ;;;; much about creating them.
8
9 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; more information.
11 ;;;;
12 ;;;; This software is derived from the CMU CL system, which was
13 ;;;; written at Carnegie Mellon University and released into the
14 ;;;; public domain. The software is in the public domain and is
15 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
16 ;;;; files for more information.
17
18 (in-package "SB!IMPL")
19
20 ;;; The inverse for a generalized-variable reference function is stored in
21 ;;; one of two ways:
22 ;;;
23 ;;; A SETF inverse property corresponds to the short form of DEFSETF. It is
24 ;;; the name of a function takes the same args as the reference form, plus a
25 ;;; new-value arg at the end.
26 ;;;
27 ;;; A SETF method expander is created by the long form of DEFSETF or
28 ;;; by DEFINE-SETF-EXPANDER. It is a function that is called on the reference
29 ;;; form and that produces five values: a list of temporary variables, a list
30 ;;; of value forms, a list of the single store-value form, a storing function,
31 ;;; and an accessing function.
32 (declaim (ftype (function (t &optional (or null sb!c::lexenv))) sb!xc:get-setf-expansion))
33 (defun sb!xc:get-setf-expansion (form &optional environment)
34   #!+sb-doc
35   "Returns five values needed by the SETF machinery: a list of temporary
36    variables, a list of values with which to fill them, a list of temporaries
37    for the new values, the setting function, and the accessing function."
38   (let (temp)
39     (cond ((symbolp form)
40            (multiple-value-bind (expansion expanded)
41                (sb!xc:macroexpand-1 form environment)
42              (if expanded
43                  (sb!xc:get-setf-expansion expansion environment)
44                  (let ((new-var (gensym)))
45                    (values nil nil (list new-var)
46                            `(setq ,form ,new-var) form)))))
47           ;; Local functions inhibit global SETF methods.
48           ((and environment
49                 (let ((name (car form)))
50                   (dolist (x (sb!c::lexenv-functions environment))
51                     (when (and (eq (car x) name)
52                                (not (sb!c::defined-function-p (cdr x))))
53                       (return t)))))
54            (expand-or-get-setf-inverse form environment))
55           ((setq temp (info :setf :inverse (car form)))
56            (get-setf-method-inverse form `(,temp) nil))
57           ((setq temp (info :setf :expander (car form)))
58            ;; KLUDGE: It may seem as though this should go through
59            ;; *MACROEXPAND-HOOK*, but the ANSI spec seems fairly explicit
60            ;; that *MACROEXPAND-HOOK* is a hook for MACROEXPAND-1, not
61            ;; for macroexpansion in general. -- WHN 19991128
62            (funcall temp
63                     form
64                     ;; As near as I can tell from the ANSI spec, macroexpanders
65                     ;; have a right to expect an actual lexical environment,
66                     ;; not just a NIL which is to be interpreted as a null
67                     ;; lexical environment. -- WHN 19991128
68                     (or environment (make-null-lexenv))))
69           (t
70            (expand-or-get-setf-inverse form environment)))))
71
72 ;;; GET-SETF-METHOD existed in pre-ANSI Common Lisp, and various code inherited
73 ;;; from CMU CL uses it repeatedly, so rather than rewrite a lot of code to not
74 ;;; use it, we just define it in terms of ANSI's GET-SETF-EXPANSION (or
75 ;;; actually, the cross-compiler version of that, i.e.
76 ;;; SB!XC:GET-SETF-EXPANSION).
77 (declaim (ftype (function (t &optional (or null sb!c::lexenv))) get-setf-method))
78 (defun get-setf-method (form &optional environment)
79   #!+sb-doc
80   "This is a specialized-for-one-value version of GET-SETF-EXPANSION (and
81 a relic from pre-ANSI Common Lisp). Portable ANSI code should use
82 GET-SETF-EXPANSION directly."
83   (multiple-value-bind (temps value-forms store-vars store-form access-form)
84       (sb!xc:get-setf-expansion form environment)
85     (when (cdr store-vars)
86       (error "GET-SETF-METHOD used for a form with multiple store ~
87               variables:~%  ~S"
88              form))
89     (values temps value-forms store-vars store-form access-form)))
90
91 ;;; If a macro, expand one level and try again. If not, go for the
92 ;;; SETF function.
93 (declaim (ftype (function (t sb!c::lexenv)) expand-or-get-setf-inverse))
94 (defun expand-or-get-setf-inverse (form environment)
95   (multiple-value-bind (expansion expanded)
96       (sb!xc:macroexpand-1 form environment)
97     (if expanded
98         (sb!xc:get-setf-expansion expansion environment)
99         (get-setf-method-inverse form
100                                  `(funcall #'(setf ,(car form)))
101                                  t))))
102
103 (defun get-setf-method-inverse (form inverse setf-function)
104   (let ((new-var (gensym))
105         (vars nil)
106         (vals nil))
107     (dolist (x (cdr form))
108       (push (gensym) vars)
109       (push x vals))
110     (setq vals (nreverse vals))
111     (values vars vals (list new-var)
112             (if setf-function
113                 `(,@inverse ,new-var ,@vars)
114                 `(,@inverse ,@vars ,new-var))
115             `(,(car form) ,@vars))))
116 \f
117 ;;;; SETF itself
118
119 ;;; Except for atoms, we always call GET-SETF-EXPANSION, since it has some
120 ;;; non-trivial semantics. But when there is a setf inverse, and G-S-E uses
121 ;;; it, then we return a call to the inverse, rather than returning a hairy let
122 ;;; form. This is probably important mainly as a convenience in allowing the
123 ;;; use of SETF inverses without the full interpreter.
124 (defmacro-mundanely setf (&rest args &environment env)
125   #!+sb-doc
126   "Takes pairs of arguments like SETQ. The first is a place and the second
127   is the value that is supposed to go into that place. Returns the last
128   value. The place argument may be any of the access forms for which SETF
129   knows a corresponding setting form."
130   (let ((nargs (length args)))
131     (cond
132      ((= nargs 2)
133       (let ((place (first args))
134             (value-form (second args)))
135         (if (atom place)
136           `(setq ,place ,value-form)
137           (multiple-value-bind (dummies vals newval setter getter)
138               (sb!xc:get-setf-expansion place env)
139             (declare (ignore getter))
140             (let ((inverse (info :setf :inverse (car place))))
141               (if (and inverse (eq inverse (car setter)))
142                 `(,inverse ,@(cdr place) ,value-form)
143                 `(let* (,@(mapcar #'list dummies vals))
144                    (multiple-value-bind ,newval ,value-form
145                      ,setter))))))))
146      ((oddp nargs)
147       (error "odd number of args to SETF"))
148      (t
149       (do ((a args (cddr a))
150            (reversed-setfs nil))
151           ((null a)
152            `(progn ,@(nreverse reversed-setfs)))
153         (push (list 'setf (car a) (cadr a)) reversed-setfs))))))
154 \f
155 ;;;; various SETF-related macros
156
157 (defmacro-mundanely shiftf (&whole form &rest args &environment env)
158   #!+sb-doc
159   "One or more SETF-style place expressions, followed by a single
160    value expression. Evaluates all of the expressions in turn, then
161    assigns the value of each expression to the place on its left,
162    returning the value of the leftmost."
163   (when (< (length args) 2)
164     (error "~S called with too few arguments: ~S" 'shiftf form))
165   (let ((resultvar (gensym)))
166     (do ((arglist args (cdr arglist))
167          (bindlist nil)
168          (storelist nil)
169          (lastvar resultvar))
170         ((atom (cdr arglist))
171          (push `(,lastvar ,(first arglist)) bindlist)
172          `(let* ,(nreverse bindlist) ,@(nreverse storelist) ,resultvar))
173       (multiple-value-bind (sm1 sm2 sm3 sm4 sm5)
174           (get-setf-method (first arglist) env)
175         (mapc #'(lambda (var val)
176                   (push `(,var ,val) bindlist))
177               sm1
178               sm2)
179         (push `(,lastvar ,sm5) bindlist)
180         (push sm4 storelist)
181         (setq lastvar (first sm3))))))
182
183 (defmacro-mundanely push (obj place &environment env)
184   #!+sb-doc
185   "Takes an object and a location holding a list. Conses the object onto
186   the list, returning the modified list. OBJ is evaluated before PLACE."
187   (if (symbolp place)
188       `(setq ,place (cons ,obj ,place))
189       (multiple-value-bind
190           (dummies vals newval setter getter)
191           (get-setf-method place env)
192         (let ((g (gensym)))
193           `(let* ((,g ,obj)
194                   ,@(mapcar #'list dummies vals)
195                   (,(car newval) (cons ,g ,getter)))
196             ,setter)))))
197
198 (defmacro-mundanely pushnew (obj place &rest keys &environment env)
199   #!+sb-doc
200   "Takes an object and a location holding a list. If the object is already
201   in the list, does nothing. Else, conses the object onto the list. Returns
202   NIL. If there is a :TEST keyword, this is used for the comparison."
203   (if (symbolp place)
204       `(setq ,place (adjoin ,obj ,place ,@keys))
205       (multiple-value-bind (dummies vals newval setter getter)
206           (get-setf-method place env)
207         (do* ((d dummies (cdr d))
208               (v vals (cdr v))
209               (let-list nil))
210              ((null d)
211               (push (list (car newval) `(adjoin ,obj ,getter ,@keys))
212                     let-list)
213               `(let* ,(nreverse let-list)
214                  ,setter))
215           (push (list (car d) (car v)) let-list)))))
216
217 (defmacro-mundanely pop (place &environment env)
218   #!+sb-doc
219   "The argument is a location holding a list. Pops one item off the front
220   of the list and returns it."
221   (if (symbolp place)
222       `(prog1 (car ,place) (setq ,place (cdr ,place)))
223       (multiple-value-bind (dummies vals newval setter getter)
224           (get-setf-method place env)
225         (do* ((d dummies (cdr d))
226               (v vals (cdr v))
227               (let-list nil))
228              ((null d)
229               (push (list (car newval) getter) let-list)
230               `(let* ,(nreverse let-list)
231                  (prog1 (car ,(car newval))
232                         (setq ,(car newval) (cdr ,(car newval)))
233                         ,setter)))
234           (push (list (car d) (car v)) let-list)))))
235
236 (defmacro-mundanely remf (place indicator &environment env)
237   #!+sb-doc
238   "Place may be any place expression acceptable to SETF, and is expected
239   to hold a property list or (). This list is destructively altered to
240   remove the property specified by the indicator. Returns T if such a
241   property was present, NIL if not."
242   (multiple-value-bind (dummies vals newval setter getter)
243       (get-setf-method place env)
244     (do* ((d dummies (cdr d))
245           (v vals (cdr v))
246           (let-list nil)
247           (ind-temp (gensym))
248           (local1 (gensym))
249           (local2 (gensym)))
250          ((null d)
251           (push (list (car newval) getter) let-list)
252           (push (list ind-temp indicator) let-list)
253           `(let* ,(nreverse let-list)
254              (do ((,local1 ,(car newval) (cddr ,local1))
255                   (,local2 nil ,local1))
256                  ((atom ,local1) nil)
257                (cond ((atom (cdr ,local1))
258                       (error "Odd-length property list in REMF."))
259                      ((eq (car ,local1) ,ind-temp)
260                       (cond (,local2
261                              (rplacd (cdr ,local2) (cddr ,local1))
262                              (return t))
263                             (t (setq ,(car newval) (cddr ,(car newval)))
264                                ,setter
265                                (return t))))))))
266       (push (list (car d) (car v)) let-list))))
267 \f
268 ;;;; DEFINE-MODIFY-MACRO stuff
269
270 (def!macro sb!xc:define-modify-macro (name lambda-list function &optional doc-string)
271   #!+sb-doc
272   "Creates a new read-modify-write macro like PUSH or INCF."
273   (let ((other-args nil)
274         (rest-arg nil)
275         (env (gensym))
276         (reference (gensym)))
277     ;; Parse out the variable names and &REST arg from the lambda list.
278     (do ((ll lambda-list (cdr ll))
279          (arg nil))
280         ((null ll))
281       (setq arg (car ll))
282       (cond ((eq arg '&optional))
283             ((eq arg '&rest)
284              (if (symbolp (cadr ll))
285                (setq rest-arg (cadr ll))
286                (error "Non-symbol &REST argument in definition of ~S." name))
287              (if (null (cddr ll))
288                (return nil)
289                (error "Illegal stuff after &REST argument.")))
290             ((memq arg '(&key &allow-other-keys &aux))
291              (error "~S not allowed in DEFINE-MODIFY-MACRO lambda list." arg))
292             ((symbolp arg)
293              (push arg other-args))
294             ((and (listp arg) (symbolp (car arg)))
295              (push (car arg) other-args))
296             (t (error "Illegal stuff in lambda list."))))
297     (setq other-args (nreverse other-args))
298     `(#-sb-xc-host sb!xc:defmacro
299       #+sb-xc-host defmacro-mundanely
300          ,name (,reference ,@lambda-list &environment ,env)
301        ,doc-string
302        (multiple-value-bind (dummies vals newval setter getter)
303            (get-setf-method ,reference ,env)
304          (do ((d dummies (cdr d))
305               (v vals (cdr v))
306               (let-list nil (cons (list (car d) (car v)) let-list)))
307              ((null d)
308               (push (list (car newval)
309                           ,(if rest-arg
310                              `(list* ',function getter ,@other-args ,rest-arg)
311                              `(list ',function getter ,@other-args)))
312                     let-list)
313               `(let* ,(nreverse let-list)
314                  ,setter)))))))
315
316 (sb!xc:define-modify-macro incf (&optional (delta 1)) +
317   #!+sb-doc
318   "The first argument is some location holding a number. This number is
319   incremented by the second argument, DELTA, which defaults to 1.")
320
321 (sb!xc:define-modify-macro decf (&optional (delta 1)) -
322   #!+sb-doc
323   "The first argument is some location holding a number. This number is
324   decremented by the second argument, DELTA, which defaults to 1.")
325 \f
326 ;;;; DEFSETF
327
328 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
329   ;;; Assign setf macro information for NAME, making all appropriate checks.
330   (defun assign-setf-macro (name expander inverse doc)
331     (cond ((gethash name sb!c:*setf-assumed-fboundp*)
332            (warn
333             "defining setf macro for ~S when ~S was previously ~
334              treated as a function"
335             name
336             `(setf ,name)))
337           ((not (fboundp `(setf ,name)))
338            ;; All is well, we don't need any warnings.
339            (values))
340           ((info :function :accessor-for name)
341            (warn "defining SETF macro for DEFSTRUCT slot ~
342                  accessor; redefining as a normal function: ~S"
343                  name)
344            (sb!c::proclaim-as-function-name name))
345           ((not (eq (symbol-package name) (symbol-package 'aref)))
346            (style-warn "defining setf macro for ~S when ~S is fbound"
347                        name `(setf ,name))))
348     (remhash name sb!c:*setf-assumed-fboundp*)
349     ;; FIXME: It's probably possible to join these checks into one form which
350     ;; is appropriate both on the cross-compilation host and on the target.
351     (when (or inverse (info :setf :inverse name))
352       (setf (info :setf :inverse name) inverse))
353     (when (or expander (info :setf :expander name))
354       (setf (info :setf :expander name) expander))
355     (when doc
356       (setf (fdocumentation name 'setf) doc))
357     name))
358
359 (def!macro sb!xc:defsetf (access-fn &rest rest)
360   #!+sb-doc
361   "Associates a SETF update function or macro with the specified access
362   function or macro. The format is complex. See the manual for details."
363   (cond ((not (listp (car rest)))
364          `(eval-when (:load-toplevel :compile-toplevel :execute)
365             (assign-setf-macro ',access-fn
366                                nil
367                                ',(car rest)
368                                 ,(when (and (car rest) (stringp (cadr rest)))
369                                    `',(cadr rest)))))
370         ((and (cdr rest) (listp (cadr rest)))
371          (destructuring-bind
372              (lambda-list (&rest store-variables) &body body)
373              rest
374            (let ((arglist-var (gensym "ARGS-"))
375                  (access-form-var (gensym "ACCESS-FORM-"))
376                  (env-var (gensym "ENVIRONMENT-")))
377              (multiple-value-bind (body local-decs doc)
378                  (parse-defmacro `(,lambda-list ,@store-variables)
379                                  arglist-var body access-fn 'defsetf
380                                  :anonymousp t)
381                `(eval-when (:compile-toplevel :load-toplevel :execute)
382                   (assign-setf-macro
383                    ',access-fn
384                    #'(lambda (,access-form-var ,env-var)
385                        (declare (ignore ,env-var))
386                        (%defsetf ,access-form-var ,(length store-variables)
387                                  #'(lambda (,arglist-var)
388                                      ,@local-decs
389                                      (block ,access-fn
390                                        ,body))))
391                    nil
392                    ',doc))))))
393         (t
394          (error "ill-formed DEFSETF for ~S" access-fn))))
395
396 (defun %defsetf (orig-access-form num-store-vars expander)
397   (let (subforms
398         subform-vars
399         subform-exprs
400         store-vars)
401     (dolist (subform (cdr orig-access-form))
402       (if (constantp subform)
403         (push subform subforms)
404         (let ((var (gensym)))
405           (push var subforms)
406           (push var subform-vars)
407           (push subform subform-exprs))))
408     (dotimes (i num-store-vars)
409       (push (gensym) store-vars))
410     (let ((r-subforms (nreverse subforms))
411           (r-subform-vars (nreverse subform-vars))
412           (r-subform-exprs (nreverse subform-exprs))
413           (r-store-vars (nreverse store-vars)))
414       (values r-subform-vars
415               r-subform-exprs
416               r-store-vars
417               (funcall expander (cons r-subforms r-store-vars))
418               `(,(car orig-access-form) ,@r-subforms)))))
419 \f
420 ;;;; DEFMACRO DEFINE-SETF-EXPANDER and various DEFINE-SETF-EXPANDERs
421
422 ;;; DEFINE-SETF-EXPANDER is a lot like DEFMACRO.
423 (def!macro sb!xc:define-setf-expander (access-fn lambda-list &body body)
424   #!+sb-doc
425   "Syntax like DEFMACRO, but creates a Setf-Method generator. The body
426   must be a form that returns the five magical values."
427   (unless (symbolp access-fn)
428     (error "DEFINE-SETF-EXPANDER access-function name ~S is not a symbol."
429            access-fn))
430   (let ((whole (gensym "WHOLE-"))
431         (environment (gensym "ENV-")))
432     (multiple-value-bind (body local-decs doc)
433         (parse-defmacro lambda-list whole body access-fn
434                         'sb!xc:define-setf-expander
435                         :environment environment)
436       `(eval-when (:compile-toplevel :load-toplevel :execute)
437          (assign-setf-macro ',access-fn
438                             #'(lambda (,whole ,environment)
439                                 ,@local-decs
440                                 (block ,access-fn ,body))
441                             nil
442                             ',doc)))))
443
444 (sb!xc:define-setf-expander getf (place prop
445                                   &optional default
446                                   &environment env)
447   (declare (type sb!c::lexenv env))
448   (multiple-value-bind (temps values stores set get)
449       (get-setf-method place env)
450     (let ((newval (gensym))
451           (ptemp (gensym))
452           (def-temp (if default (gensym))))
453       (values `(,@temps ,ptemp ,@(if default `(,def-temp)))
454               `(,@values ,prop ,@(if default `(,default)))
455               `(,newval)
456               `(let ((,(car stores) (%putf ,get ,ptemp ,newval)))
457                  ,set
458                  ,newval)
459               `(getf ,get ,ptemp ,@(if default `(,def-temp)))))))
460
461 (sb!xc:define-setf-expander get (symbol prop &optional default)
462   (let ((symbol-temp (gensym))
463         (prop-temp (gensym))
464         (def-temp (gensym))
465         (newval (gensym)))
466     (values `(,symbol-temp ,prop-temp ,@(if default `(,def-temp)))
467             `(,symbol ,prop ,@(if default `(,default)))
468             (list newval)
469             `(%put ,symbol-temp ,prop-temp ,newval)
470             `(get ,symbol-temp ,prop-temp ,@(if default `(,def-temp))))))
471
472 (sb!xc:define-setf-expander gethash (key hashtable &optional default)
473   (let ((key-temp (gensym))
474         (hashtable-temp (gensym))
475         (default-temp (gensym))
476         (new-value-temp (gensym)))
477     (values
478      `(,key-temp ,hashtable-temp ,@(if default `(,default-temp)))
479      `(,key ,hashtable ,@(if default `(,default)))
480      `(,new-value-temp)
481      `(%puthash ,key-temp ,hashtable-temp ,new-value-temp)
482      `(gethash ,key-temp ,hashtable-temp ,@(if default `(,default-temp))))))
483
484 (sb!xc:define-setf-expander logbitp (index int &environment env)
485   (declare (type sb!c::lexenv env))
486   (multiple-value-bind (temps vals stores store-form access-form)
487       (get-setf-method int env)
488     (let ((ind (gensym))
489           (store (gensym))
490           (stemp (first stores)))
491       (values `(,ind ,@temps)
492               `(,index
493                 ,@vals)
494               (list store)
495               `(let ((,stemp
496                       (dpb (if ,store 1 0) (byte 1 ,ind) ,access-form)))
497                  ,store-form
498                  ,store)
499               `(logbitp ,ind ,access-form)))))
500
501 ;;; CMU CL had a comment here that:
502 ;;;   Evil hack invented by the gnomes of Vassar Street (though not as evil as
503 ;;;   it used to be.)  The function arg must be constant, and is converted to
504 ;;;   an APPLY of the SETF function, which ought to exist.
505 ;;;
506 ;;; It may not be clear (wasn't to me..) that this is a standard thing, but See
507 ;;; "5.1.2.5 APPLY Forms as Places" in the ANSI spec. I haven't actually
508 ;;; verified that this code has any correspondence to that code, but at least
509 ;;; ANSI has some place for SETF APPLY. -- WHN 19990604
510 (sb!xc:define-setf-expander apply (functionoid &rest args)
511   (unless (and (listp functionoid)
512                (= (length functionoid) 2)
513                (eq (first functionoid) 'function)
514                (symbolp (second functionoid)))
515     (error "SETF of APPLY is only defined for function args like #'SYMBOL."))
516   (let ((function (second functionoid))
517         (new-var (gensym))
518         (vars (make-gensym-list (length args))))
519     (values vars args (list new-var)
520             `(apply #'(setf ,function) ,new-var ,@vars)
521             `(apply #',function ,@vars))))
522
523 ;;; Special-case a BYTE bytespec so that the compiler can recognize it.
524 (sb!xc:define-setf-expander ldb (bytespec place &environment env)
525   #!+sb-doc
526   "The first argument is a byte specifier. The second is any place form
527   acceptable to SETF. Replaces the specified byte of the number in this
528   place with bits from the low-order end of the new value."
529   (declare (type sb!c::lexenv env))
530   (multiple-value-bind (dummies vals newval setter getter)
531       (get-setf-method place env)
532     (if (and (consp bytespec) (eq (car bytespec) 'byte))
533         (let ((n-size (gensym))
534               (n-pos (gensym))
535               (n-new (gensym)))
536           (values (list* n-size n-pos dummies)
537                   (list* (second bytespec) (third bytespec) vals)
538                   (list n-new)
539                   `(let ((,(car newval) (dpb ,n-new (byte ,n-size ,n-pos)
540                                              ,getter)))
541                      ,setter
542                      ,n-new)
543                   `(ldb (byte ,n-size ,n-pos) ,getter)))
544         (let ((btemp (gensym))
545               (gnuval (gensym)))
546           (values (cons btemp dummies)
547                   (cons bytespec vals)
548                   (list gnuval)
549                   `(let ((,(car newval) (dpb ,gnuval ,btemp ,getter)))
550                      ,setter
551                      ,gnuval)
552                   `(ldb ,btemp ,getter))))))
553
554 (sb!xc:define-setf-expander mask-field (bytespec place &environment env)
555   #!+sb-doc
556   "The first argument is a byte specifier. The second is any place form
557   acceptable to SETF. Replaces the specified byte of the number in this place
558   with bits from the corresponding position in the new value."
559   (declare (type sb!c::lexenv env))
560   (multiple-value-bind (dummies vals newval setter getter)
561       (get-setf-method place env)
562     (let ((btemp (gensym))
563           (gnuval (gensym)))
564       (values (cons btemp dummies)
565               (cons bytespec vals)
566               (list gnuval)
567               `(let ((,(car newval) (deposit-field ,gnuval ,btemp ,getter)))
568                  ,setter
569                  ,gnuval)
570               `(mask-field ,btemp ,getter)))))
571
572 (sb!xc:define-setf-expander the (type place &environment env)
573   (declare (type sb!c::lexenv env))
574   (multiple-value-bind (dummies vals newval setter getter)
575       (get-setf-method place env)
576     (values dummies
577               vals
578               newval
579               (subst `(the ,type ,(car newval)) (car newval) setter)
580               `(the ,type ,getter))))