1 ;;;; the DESCRIBE system
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 ;;; SB-IMPL, not SB!IMPL, since we're built in warm load.
13 (in-package "SB-IMPL")
15 ;;;; Utils, move elsewhere.
17 (defun class-name-or-class (class)
18 (let ((name (class-name class)))
19 (if (eq class (find-class name nil))
24 (if (typep x 'standard-generic-function)
25 (sb-pcl:generic-function-name x)
28 ;;;; the ANSI interface to function names (and to other stuff too)
29 ;;; Note: this function gets called by the compiler (as of 1.0.17.x,
30 ;;; in MAYBE-INLINE-SYNTACTIC-CLOSURE), and so although ANSI says
31 ;;; we're allowed to return NIL here freely, it seems plausible that
32 ;;; small changes to the circumstances under which this function
33 ;;; returns non-NIL might have subtle consequences on the compiler.
34 ;;; So it might be desirable to have the compiler not rely on this
35 ;;; function, eventually.
36 (defun function-lambda-expression (fun)
38 "Return (VALUES DEFINING-LAMBDA-EXPRESSION CLOSURE-P NAME), where
39 DEFINING-LAMBDA-EXPRESSION is NIL if unknown, or a suitable argument
40 to COMPILE otherwise, CLOSURE-P is non-NIL if the function's definition
41 might have been enclosed in some non-null lexical environment, and
42 NAME is some name (for debugging only) or NIL if there is no name."
43 (declare (type function fun))
46 (sb-eval:interpreted-function
47 (let ((name (sb-eval:interpreted-function-name fun))
48 (lambda-list (sb-eval:interpreted-function-lambda-list fun))
49 (declarations (sb-eval:interpreted-function-declarations fun))
50 (body (sb-eval:interpreted-function-body fun)))
51 (values `(lambda ,lambda-list
52 ,@(when declarations `((declare ,@declarations)))
56 (let* ((name (fun-name fun))
57 (fun (%simple-fun-self (%fun-fun fun)))
58 (code (sb-di::fun-code-header fun))
59 (info (sb-kernel:%code-debug-info code)))
61 (let ((source (sb-c::debug-info-source info)))
62 (cond ((and (sb-c::debug-source-form source)
63 (eq (sb-c::debug-source-function source) fun))
64 (values (sb-c::debug-source-form source)
67 ((legal-fun-name-p name)
68 (let ((exp (fun-name-inline-expansion name)))
69 (values exp (not exp) name)))
71 (values nil t name))))
72 (values nil t name))))))
74 ;;; Prints X on a single line, limiting output length by *PRINT-RIGHT-MARGIN*
75 ;;; -- good for printing object parts, etc.
76 (defun prin1-to-line (x &key (columns 1) (reserve 0))
77 (let* ((line (write-to-string x :escape t :readably nil :lines 2 :circle t))
78 (p (position #\newline line))
79 (limit (truncate (- *print-right-margin* reserve) columns)))
80 (flet ((trunc (&optional end)
81 (let ((line-end (- limit 2)))
82 (with-output-to-string (s)
83 (write-string line s :end (if end
86 (write-string ".." s)))))
89 ((> (length line) limit)
94 (defun describe (object &optional (stream-designator *standard-output*))
96 "Print a description of OBJECT to STREAM-DESIGNATOR."
97 (let ((stream (out-synonym-of stream-designator))
98 (*print-right-margin* (or *print-right-margin* 72))
100 (*suppress-print-errors*
101 (if (subtypep 'serious-condition *suppress-print-errors*)
102 *suppress-print-errors*
103 'serious-condition)))
104 ;; Until sbcl-0.8.0.x, we did
105 ;; (FRESH-LINE STREAM)
106 ;; (PPRINT-LOGICAL-BLOCK (STREAM NIL)
108 ;; here. However, ANSI's specification of DEFUN DESCRIBE,
109 ;; DESCRIBE exists as an interface primarily to manage argument
110 ;; defaulting (including conversion of arguments T and NIL into
111 ;; stream objects) and to inhibit any return values from
113 ;; doesn't mention either FRESH-LINEing or PPRINT-LOGICAL-BLOCKing,
114 ;; and the example of typical DESCRIBE-OBJECT behavior in ANSI's
115 ;; specification of DESCRIBE-OBJECT will work poorly if we do them
116 ;; here. (The example method for DESCRIBE-OBJECT does its own
117 ;; FRESH-LINEing, which is a physical directive which works poorly
118 ;; inside a pretty-printer logical block.)
119 (handler-bind ((print-not-readable #'print-unreadably))
120 (describe-object object stream))
121 ;; We don't TERPRI here either (any more since sbcl-0.8.0.x), because
122 ;; again ANSI's specification of DESCRIBE doesn't mention it and
123 ;; ANSI's example of DESCRIBE-OBJECT does its own final TERPRI.
130 ;;;; * Each interesting class has a primary method of its own.
132 ;;;; * Output looks like
134 ;;;; object-self-string
135 ;;;; [object-type-string]
144 ;;;; * The newline policy that gets the whitespace right is for
145 ;;;; each block to both start and end with a newline.
147 (defgeneric object-self-string (x))
149 (defmethod object-self-string (x)
152 (defmethod object-self-string ((x symbol))
153 (let ((*package* (find-package :keyword)))
154 (prin1-to-string x)))
156 (defgeneric object-type-string (x))
158 (defmethod object-type-string (x)
159 (let ((type (class-name-or-class (class-of x))))
161 (string-downcase type)
162 (prin1-to-string type))))
164 (defmethod object-type-string ((x cons))
165 (if (listp (cdr x)) "list" "cons"))
167 (defmethod object-type-string ((x hash-table))
170 (defmethod object-type-string ((x condition))
173 (defmethod object-type-string ((x structure-object))
176 (defmethod object-type-string ((x standard-object))
179 (defmethod object-type-string ((x function))
181 (simple-fun "compiled function")
182 (closure "compiled closure")
184 (sb-eval:interpreted-function
185 "interpreted function")
189 "funcallable-instance")))
191 (defmethod object-type-string ((x stream))
194 (defmethod object-type-string ((x sb-gray:fundamental-stream))
197 (defmethod object-type-string ((x package))
200 (defmethod object-type-string ((x array))
201 (cond ((or (stringp x) (bit-vector-p x))
202 (format nil "~@[simple-~*~]~A"
203 (typep x 'simple-array)
205 (base-string "base-string")
209 (if (simple-vector-p x)
211 (format nil "~@[simple ~*~]~@[specialized ~*~]~:[array~;vector~]"
212 (typep x 'simple-array)
213 (neq t (array-element-type x))
216 (defmethod object-type-string ((x character))
218 (standard-char "standard-char")
219 (base-char "base-char")
222 (defun print-standard-describe-header (x stream)
223 (format stream "~&~A~% [~A]~%"
224 (object-self-string x)
225 (object-type-string x)))
227 (defgeneric describe-object (x stream))
231 (defmethod describe-object ((x t) s)
232 (print-standard-describe-header x s))
234 (defmethod describe-object ((x cons) s)
235 (print-standard-describe-header x s)
236 (describe-function x nil s))
238 (defmethod describe-object ((x function) s)
239 (print-standard-describe-header x s)
240 (describe-function nil x s))
242 (defmethod describe-object ((x class) s)
243 (print-standard-describe-header x s)
244 (describe-class nil x s)
245 (describe-instance x s))
247 (defmethod describe-object ((x sb-pcl::slot-object) s)
248 (print-standard-describe-header x s)
249 (describe-instance x s))
251 (defmethod describe-object ((x character) s)
252 (print-standard-describe-header x s)
253 (format s "~%Char-code: ~S" (char-code x))
254 (format s "~%Char-name: ~A" (char-name x)))
256 (defmethod describe-object ((x array) s)
257 (print-standard-describe-header x s)
258 (format s "~%Element-type: ~S" (array-element-type x))
260 (if (array-has-fill-pointer-p x)
261 (format s "~%Fill-pointer: ~S~%Size: ~S"
263 (array-total-size x))
264 (format s "~%Length: ~S" (length x)))
265 (format s "~%Dimensions: ~S" (array-dimensions x)))
266 (let ((*print-array* nil))
267 (unless (typep x 'simple-array)
268 (format s "~%Adjustable: ~A" (if (adjustable-array-p x) "yes" "no"))
269 (multiple-value-bind (to offset) (array-displacement x)
270 (if (format s "~%Displaced-to: ~A~%Displaced-offset: ~S"
273 (format s "~%Displaced: no"))))
274 (when (and (not (array-displacement x)) (array-header-p x))
275 (format s "~%Storage vector: ~A"
276 (prin1-to-line (array-storage-vector x))))
279 (defmethod describe-object ((x hash-table) s)
280 (print-standard-describe-header x s)
281 ;; Don't print things which are already apparent from the printed
282 ;; representation -- COUNT, TEST, and WEAKNESS
283 (format s "~%Occupancy: ~,1F" (float (/ (hash-table-count x)
284 (hash-table-size x))))
285 (format s "~%Rehash-threshold: ~S" (hash-table-rehash-threshold x))
286 (format s "~%Rehash-size: ~S" (hash-table-rehash-size x))
287 (format s "~%Size: ~S" (hash-table-size x))
288 (format s "~%Synchronized: ~A" (if (hash-table-synchronized-p x) "yes" "no"))
291 (defmethod describe-object ((symbol symbol) stream)
292 (print-standard-describe-header symbol stream)
293 ;; Describe the value cell.
294 (let* ((kind (info :variable :kind symbol))
296 (:special "a special variable")
297 (:macro "a symbol macro")
298 (:constant "a constant variable")
299 (:global "a global variable")
300 (:unknown "an undefined variable")
301 (:alien "an alien variable"))))
302 (when (or (not (eq :unknown kind)) (boundp symbol))
303 (pprint-logical-block (stream nil)
304 (format stream "~@:_~A names ~A:" symbol wot)
305 (pprint-indent :block 2 stream)
306 (when (eq (info :variable :where-from symbol) :declared)
307 (format stream "~@:_Declared type: ~S"
308 (type-specifier (info :variable :type symbol))))
309 (when (info :variable :always-bound symbol)
310 (format stream "~@:_Declared always-bound."))
313 (let ((info (info :variable :alien-info symbol)))
314 (format stream "~@:_Value: ~S" (eval symbol))
315 (format stream "~@:_Type: ~S"
316 (sb-alien-internals:unparse-alien-type
317 (sb-alien::heap-alien-info-type info)))
318 (format stream "~@:_Address: #x~8,'0X"
319 (sap-int (sb-alien::heap-alien-info-sap info)))))
321 (let ((expansion (info :variable :macro-expansion symbol)))
322 (format stream "~@:_Expansion: ~S" expansion)))
324 (format stream "~:@_Value: ~S" (symbol-value symbol)))
325 ((not (eq kind :unknown))
326 (format stream "~:@_Currently unbound.")))
327 (describe-documentation symbol 'variable stream)
330 ;; TODO: We could grovel over all packages looking for and
331 ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
332 ;; availability in some package even after (SYMBOL-PACKAGE SYMBOL) has
335 ;; TODO: It might also be nice to describe (find-package symbol)
336 ;; if one exists. Maybe not all the exports, etc, but the package
338 (describe-function symbol nil stream)
339 (describe-class symbol nil stream)
342 (let* ((kind (info :type :kind symbol))
345 (or (info :type :expander symbol) t))
347 (or (info :type :translator symbol) t)))))
349 (pprint-newline :mandatory stream)
350 (pprint-logical-block (stream nil)
351 (format stream "~@:_~A names a ~@[primitive~* ~]type-specifier:"
353 (eq kind :primitive))
354 (pprint-indent :block 2 stream)
355 (describe-documentation symbol 'type stream (eq t fun))
357 (describe-lambda-list (if (eq :primitive kind)
358 (%fun-lambda-list fun)
359 (info :type :lambda-list symbol))
361 (multiple-value-bind (expansion ok)
362 (handler-case (typexpand-1 symbol)
363 (error () (values nil nil)))
365 (format stream "~@:_Expansion: ~S" expansion)))))
368 (when (or (member symbol sb-c::*policy-qualities*)
369 (assoc symbol sb-c::*policy-dependent-qualities*))
370 (pprint-logical-block (stream nil)
371 (pprint-newline :mandatory stream)
372 (pprint-indent :block 2 stream)
373 (format stream "~A names a~:[ dependent~;n~] optimization policy quality:"
375 (member symbol sb-c::*policy-qualities*))
376 (describe-documentation symbol 'optimize stream t))
379 ;; Print out properties.
380 (let ((plist (symbol-plist symbol)))
382 (pprint-logical-block (stream nil)
383 (format stream "~%Symbol-plist:")
384 (pprint-indent :block 2 stream)
385 (sb-pcl::doplist (key value) plist
386 (format stream "~@:_~A -> ~A"
387 (prin1-to-line key :columns 2 :reserve 5)
388 (prin1-to-line value :columns 2 :reserve 5))))
391 (defmethod describe-object ((package package) stream)
392 (print-standard-describe-header package stream)
393 (pprint-logical-block (stream nil)
394 (describe-documentation package t stream)
395 (flet ((humanize (list)
396 (sort (mapcar (lambda (x)
403 (describe-stuff label list stream :escape nil)))
404 (let ((implemented (humanize (package-implemented-by-list package)))
405 (implements (humanize (package-implements-list package)))
406 (nicks (humanize (package-nicknames package)))
407 (uses (humanize (package-use-list package)))
408 (used (humanize (package-used-by-list package)))
409 (shadows (humanize (package-shadowing-symbols package)))
410 (this (list (package-name package)))
412 (do-external-symbols (ext package)
414 (setf exports (humanize exports))
415 (when (package-locked-p package)
416 (format stream "~@:_Locked."))
417 (when (set-difference implemented this :test #'string=)
418 (out "Implemented-by-list" implemented))
419 (when (set-difference implements this :test #'string=)
420 (out "Implements-list" implements))
421 (out "Nicknames" nicks)
422 (out "Use-list" uses)
423 (out "Used-by-list" used)
424 (out "Shadows" shadows)
425 (out "Exports" exports)
426 (format stream "~@:_~S internal symbols."
427 (package-internal-symbol-count package))))
430 ;;;; Helpers to deal with shared functionality
432 (defun describe-class (name class stream)
433 (let* ((by-name (not class))
434 (name (if class (class-name class) name))
435 (class (if class class (find-class name nil))))
437 (let ((metaclass-name (class-name (class-of class))))
438 (pprint-logical-block (stream nil)
440 (format stream "~@:_~A names the ~(~A~) ~S:"
444 (pprint-indent :block 2 stream))
445 (describe-documentation class t stream)
446 (when (sb-mop:class-finalized-p class)
447 (describe-stuff "Class precedence-list"
448 (mapcar #'class-name-or-class (sb-mop:class-precedence-list class))
450 (describe-stuff "Direct superclasses"
451 (mapcar #'class-name-or-class (sb-mop:class-direct-superclasses class))
453 (let ((subs (mapcar #'class-name-or-class (sb-mop:class-direct-subclasses class))))
455 (describe-stuff "Direct subclasses" subs stream)
456 (format stream "~@:_No subclasses.")))
457 (unless (sb-mop:class-finalized-p class)
458 (format stream "~@:_Not yet finalized."))
459 (if (eq 'structure-class metaclass-name)
460 (let* ((dd (find-defstruct-description name))
461 (slots (dd-slots dd)))
463 (format stream "~@:_Slots:~:{~@:_ ~S~
464 ~@:_ Type: ~A ~@[~A~]~
466 (mapcar (lambda (dsd)
470 (unless (eq t (dsd-raw-type dsd))
474 (format stream "~@:_No slots.")))
475 (let ((slots (sb-mop:class-direct-slots class)))
477 (format stream "~@:_Direct slots:~:{~@:_ ~S~
479 ~@[~@:_ Allocation: ~S~]~
480 ~@[~@:_ Initargs: ~{~S~^, ~}~]~
481 ~@[~@:_ Initform: ~S~]~
482 ~@[~@:_ Readers: ~{~S~^, ~}~]~
483 ~@[~@:_ Writers: ~{~S~^, ~}~]~
484 ~@[~@:_ Documentation:~@:_ ~@<~@;~A~:>~]~}"
485 (mapcar (lambda (slotd)
486 (list (sb-mop:slot-definition-name slotd)
487 (let ((type (sb-mop:slot-definition-type slotd)))
488 (unless (eq t type) type))
489 (let ((alloc (sb-mop:slot-definition-allocation slotd)))
490 (unless (eq :instance alloc) alloc))
491 (sb-mop:slot-definition-initargs slotd)
492 (sb-mop:slot-definition-initform slotd)
493 (sb-mop:slot-definition-readers slotd)
494 (sb-mop:slot-definition-writers slotd)
495 ;; FIXME: does this get the prefix right?
496 (quiet-doc slotd t)))
498 (format stream "~@:_No direct slots."))))
499 (pprint-indent :block 0 stream)
500 (pprint-newline :mandatory stream))))))
502 (defun describe-instance (object stream)
503 (let* ((class (class-of object))
504 (slotds (sb-mop:class-slots class))
505 (max-slot-name-length 0)
508 ;; Figure out a good width for the slot-name column.
509 (flet ((adjust-slot-name-length (name)
510 (setf max-slot-name-length
511 (max max-slot-name-length (length (symbol-name name))))))
512 (dolist (slotd slotds)
513 (adjust-slot-name-length (sb-mop:slot-definition-name slotd))
514 (push slotd (getf plist (sb-mop:slot-definition-allocation slotd))))
515 (setf max-slot-name-length (min (+ max-slot-name-length 3) 30)))
517 ;; Now that we know the width, we can print.
518 (flet ((describe-slot (name value)
519 (format stream "~% ~A~VT = ~A" name max-slot-name-length
520 (prin1-to-line value))))
521 (sb-pcl::doplist (allocation slots) plist
522 (format stream "~%Slots with ~S allocation:" allocation)
523 (dolist (slotd (nreverse slots))
525 (sb-mop:slot-definition-name slotd)
526 (sb-pcl::slot-value-or-default object (sb-mop:slot-definition-name slotd))))))
528 (format stream "~@:_No slots."))
531 (defun quiet-doc (object type)
532 (handler-bind ((warning #'muffle-warning))
533 (documentation object type)))
535 (defun describe-documentation (object type stream &optional undoc newline)
536 (let ((doc (quiet-doc object type)))
538 (format stream "~@:_Documentation:~@:_")
539 (pprint-logical-block (stream nil :per-line-prefix " ")
542 (format stream "~@:_(undocumented)")))
544 (pprint-newline :mandatory stream))))
546 (defun describe-stuff (label list stream &key (escape t))
549 (format stream "~@:_~A:~@<~;~{ ~S~^,~:_~}~;~:>" label list)
550 (format stream "~@:_~A:~@<~;~{ ~A~^,~:_~}~;~:>" label list))))
552 (defun describe-lambda-list (lambda-list stream)
553 (let ((*print-circle* nil)
556 (format stream "~@:_Lambda-list: ~:A" lambda-list)))
558 (defun describe-function-source (function stream)
559 (if (compiled-function-p function)
560 (let* ((code (fun-code-header (%fun-fun function)))
561 (info (sb-kernel:%code-debug-info code)))
563 (let ((source (sb-c::debug-info-source info)))
565 (let ((namestring (sb-c::debug-source-namestring source)))
566 ;; This used to also report the times the source was created
567 ;; and compiled, but that seems more like noise than useful
568 ;; information -- but FWIW that are to be had as
569 ;; SB-C::DEBUG-SOUCE-CREATED/COMPILED.
571 (format stream "~@:_Source file: ~A" namestring))
572 ((sb-di:debug-source-form source)
573 (format stream "~@:_Source form:~@:_ ~S"
574 (sb-di:debug-source-form source)))))))))
576 (let ((source (sb-eval:interpreted-function-source-location function)))
578 (let ((namestring (sb-c:definition-source-location-namestring source)))
580 (format stream "~@:_Source file: ~A" namestring)))))))
582 (defun describe-function (name function stream)
583 (let ((name (if function (fun-name function) name)))
584 (if (not (or function (and (legal-fun-name-p name) (fboundp name))))
585 ;; Not defined, but possibly the type is declared, or we have
586 ;; compiled calls to it.
587 (when (legal-fun-name-p name)
588 (multiple-value-bind (from sure) (info :function :where-from name)
589 (when (or (eq :declared from) (and sure (eq :assumed from)))
590 (pprint-logical-block (stream nil)
591 (format stream "~%~A names an undefined function" name)
592 (pprint-indent :block 2 stream)
593 (format stream "~@:_~:(~A~) type: ~S"
595 (type-specifier (info :function :type name)))))))
597 (multiple-value-bind (fun what lambda-list ftype from inline methods)
598 (cond ((and (not function) (symbolp name) (special-operator-p name))
599 (let ((fun (symbol-function name)))
600 (values fun "a special operator" (%fun-lambda-list fun))))
601 ((and (not function) (symbolp name) (macro-function name))
602 (let ((fun (macro-function name)))
603 (values fun "a macro" (%fun-lambda-list fun))))
605 (let ((fun (or function (fdefinition name))))
606 (multiple-value-bind (ftype from)
608 (values (%fun-type function) :derived)
609 (let ((ctype (info :function :type name)))
610 (values (when ctype (type-specifier ctype))
612 ;; Ensure lazy pickup of information
614 (sb-c::maybe-update-info-for-gf name)
615 (ecase (info :function :where-from name)
616 (:declared :declared)
617 ;; This is hopefully clearer to users
618 ((:defined-method :defined) :derived))))))
619 (if (typep fun 'generic-function)
622 (sb-mop:generic-function-lambda-list fun)
626 (or (sb-mop:generic-function-methods fun)
629 (if (compiled-function-p fun)
630 "a compiled function"
631 "an interpreted function")
632 (%fun-lambda-list fun)
637 (info :function :inlinep name)
638 (info :function :inline-expansion-designator name)))))))))
639 (pprint-logical-block (stream nil)
641 (format stream "~%~A names ~A:" name what)
642 (pprint-indent :block 2 stream))
643 (describe-lambda-list lambda-list stream)
644 (when (and ftype from)
645 (format stream "~@:_~:(~A~) type: ~S" from ftype))
646 (when (eq :declared from)
647 (let ((derived-ftype (%fun-type fun)))
648 (unless (equal derived-ftype ftype)
649 (format stream "~@:_Derived type: ~S" derived-ftype))))
650 (describe-documentation name 'function stream)
652 (format stream "~@:_Inline proclamation: ~A (~:[no ~;~]inline expansion available)"
655 (awhen (info :function :info name)
656 (awhen (sb-c::decode-ir1-attributes (sb-c::fun-info-attributes it))
657 (format stream "~@:_Known attributes: ~(~{~A~^, ~}~)" it)))
659 (format stream "~@:_Method-combination: ~S"
660 (sb-pcl::method-combination-type-name
661 (sb-pcl:generic-function-method-combination fun)))
662 (cond ((eq :none methods)
663 (format stream "~@:_No methods."))
665 (pprint-newline :mandatory stream)
666 (pprint-logical-block (stream nil)
667 (format stream "Methods:")
668 (dolist (method methods)
669 (pprint-indent :block 2 stream)
670 (format stream "~@:_(~A ~{~S ~}~:S)"
672 (method-qualifiers method)
673 (sb-pcl::unparse-specializers fun (sb-mop:method-specializers method)))
674 (pprint-indent :block 4 stream)
675 (describe-documentation method t stream nil))))))
676 (describe-function-source fun stream)
679 (awhen (and (legal-fun-name-p name) (compiler-macro-function name))
680 (pprint-logical-block (stream nil)
681 (format stream "~@:_~A has a compiler-macro:" name)
682 (pprint-indent :block 2 stream)
683 (describe-documentation it t stream)
684 (describe-function-source it stream))
686 (when (and (consp name) (eq 'setf (car name)) (not (cddr name)))
687 (let* ((name2 (second name))
688 (inverse (info :setf :inverse name2))
689 (expander (info :setf :expander name2)))
691 (pprint-logical-block (stream nil)
692 (format stream "~&~A has setf-expansion: ~S"
694 (pprint-indent :block 2 stream)
695 (describe-documentation name2 'setf stream))
698 (pprint-logical-block (stream nil)
699 (format stream "~&~A has a complex setf-expansion:"
701 (pprint-indent :block 2 stream)
702 (describe-lambda-list (%fun-lambda-list expander) stream)
703 (describe-documentation name2 'setf stream t)
704 (describe-function-source expander stream))
707 (describe-function `(setf ,name) nil stream))))