describe: show the same information about functions for 'x and #'x.
[sbcl.git] / src / code / describe.lisp
1 ;;;; the DESCRIBE system
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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.
11
12 ;;; SB-IMPL, not SB!IMPL, since we're built in warm load.
13 (in-package "SB-IMPL")
14
15 ;;;; Utils, move elsewhere.
16
17 (defun class-name-or-class (class)
18   (let ((name (class-name class)))
19     (if (eq class (find-class name nil))
20         name
21         class)))
22
23 (defun fun-name (x)
24   (if (typep x 'standard-generic-function)
25       (sb-pcl:generic-function-name x)
26       (%fun-name x)))
27
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)
37   #+sb-doc
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))
44   (etypecase fun
45     #+sb-eval
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)))
53                   ,@body)
54                t name)))
55     (function
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)))
60        (if info
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)
65                             nil
66                             name))
67                    ((legal-fun-name-p name)
68                     (let ((exp (fun-name-inline-expansion name)))
69                       (values exp (not exp) name)))
70                    (t
71                     (values nil t name))))
72            (values nil t name))))))
73
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
84                                                (min end line-end)
85                                                line-end))
86                  (write-string ".." s)))))
87       (cond (p
88              (trunc p))
89             ((> (length line) limit)
90              (trunc))
91             (t
92              line)))))
93
94 (defun describe (object &optional (stream-designator *standard-output*))
95   #+sb-doc
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))
99         (*print-circle* t)
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)
107     ;;     ...
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
112     ;;   DESCRIBE-OBJECT.
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.
124     (values)))
125 \f
126 ;;;; DESCRIBE-OBJECT
127 ;;;;
128 ;;;; Style guide:
129 ;;;;
130 ;;;; * Each interesting class has a primary method of its own.
131 ;;;;
132 ;;;; * Output looks like
133 ;;;;
134 ;;;;    object-self-string
135 ;;;;      [object-type-string]
136 ;;;;
137 ;;;;    Block1:
138 ;;;;      Sublabel1: text
139 ;;;;      Sublabel2: text
140 ;;;;
141 ;;;;    Block2:
142 ;;;;      ...
143 ;;;;
144 ;;;; * The newline policy that gets the whitespace right is for
145 ;;;;   each block to both start and end with a newline.
146
147 (defgeneric object-self-string (x))
148
149 (defmethod object-self-string (x)
150   (prin1-to-line x))
151
152 (defmethod object-self-string ((x symbol))
153   (let ((*package* (find-package :keyword)))
154     (prin1-to-string x)))
155
156 (defgeneric object-type-string (x))
157
158 (defmethod object-type-string (x)
159   (let ((type (class-name-or-class (class-of x))))
160     (if (symbolp type)
161         (string-downcase type)
162         (prin1-to-string type))))
163
164 (defmethod object-type-string ((x cons))
165   (if (listp (cdr x)) "list" "cons"))
166
167 (defmethod object-type-string ((x hash-table))
168   "hash-table")
169
170 (defmethod object-type-string ((x condition))
171   "condition")
172
173 (defmethod object-type-string ((x structure-object))
174   "structure-object")
175
176 (defmethod object-type-string ((x standard-object))
177   "standard-object")
178
179 (defmethod object-type-string ((x function))
180   (typecase x
181     (simple-fun "compiled function")
182     (closure "compiled closure")
183     #+sb-eval
184     (sb-eval:interpreted-function
185      "interpreted function")
186     (generic-function
187      "generic-function")
188     (t
189      "funcallable-instance")))
190
191 (defmethod object-type-string ((x stream))
192   "stream")
193
194 (defmethod object-type-string ((x sb-gray:fundamental-stream))
195   "gray stream")
196
197 (defmethod object-type-string ((x package))
198   "package")
199
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)
204                  (typecase x
205                    (base-string "base-string")
206                    (string "string")
207                    (t "bit-vector"))))
208         (t
209          (if (simple-vector-p x)
210              "simple-vector"
211              (format nil "~@[simple ~*~]~@[specialized ~*~]~:[array~;vector~]"
212                      (typep x 'simple-array)
213                      (neq t (array-element-type x))
214                      (vectorp x))))))
215
216 (defmethod object-type-string ((x character))
217   (typecase x
218     (standard-char "standard-char")
219     (base-char "base-char")
220     (t "character")))
221
222 (defun print-standard-describe-header (x stream)
223   (format stream "~&~A~%  [~A]~%"
224           (object-self-string x)
225           (object-type-string x)))
226
227 (defgeneric describe-object (x stream))
228
229 ;;; Catch-all.
230
231 (defmethod describe-object ((x t) s)
232   (print-standard-describe-header x s))
233
234 (defmethod describe-object ((x cons) s)
235   (print-standard-describe-header x s)
236   (describe-function x nil s))
237
238 (defmethod describe-object ((x function) s)
239   (print-standard-describe-header x s)
240   (describe-function nil x s))
241
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))
246
247 (defmethod describe-object ((x sb-pcl::slot-object) s)
248   (print-standard-describe-header x s)
249   (describe-instance x s))
250
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)))
255
256 (defmethod describe-object ((x array) s)
257   (print-standard-describe-header x s)
258   (format s "~%Element-type: ~S" (array-element-type x))
259   (if (vectorp x)
260       (if (array-has-fill-pointer-p x)
261           (format s "~%Fill-pointer: ~S~%Size: ~S"
262                   (fill-pointer x)
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"
271                     (prin1-to-line to)
272                     offset)
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))))
277     (terpri s)))
278
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"))
289   (terpri s))
290
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))
295          (wot (ecase kind
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."))
311         (cond
312           ((eq kind :alien)
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)))))
320           ((eq kind :macro)
321            (let ((expansion (info :variable :macro-expansion symbol)))
322              (format stream "~@:_Expansion: ~S" expansion)))
323           ((boundp symbol)
324            (format stream "~:@_Value: ~S" (symbol-value symbol)))
325           ((not (eq kind :unknown))
326            (format stream "~:@_Currently unbound.")))
327         (describe-documentation symbol 'variable stream)
328         (terpri stream))))
329
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
333   ;; been set to NIL.
334   ;;
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
337   ;; documentation.
338   (describe-function symbol nil stream)
339   (describe-class symbol nil stream)
340
341   ;; Type specifier
342   (let* ((kind (info :type :kind symbol))
343          (fun (case kind
344                 (:defined
345                  (or (info :type :expander symbol) t))
346                 (:primitive
347                  (or (info :type :translator symbol) t)))))
348     (when fun
349       (pprint-newline :mandatory stream)
350       (pprint-logical-block (stream nil)
351         (format stream "~@:_~A names a ~@[primitive~* ~]type-specifier:"
352                 symbol
353                 (eq kind :primitive))
354         (pprint-indent :block 2 stream)
355         (describe-documentation symbol 'type stream (eq t fun))
356         (unless (eq t fun)
357           (describe-lambda-list (if (eq :primitive kind)
358                                     (%fun-lambda-list fun)
359                                     (info :type :lambda-list symbol))
360                                 stream)
361           (multiple-value-bind (expansion ok)
362               (handler-case (typexpand-1 symbol)
363                 (error () (values nil nil)))
364             (when ok
365               (format stream "~@:_Expansion: ~S" expansion)))))
366       (terpri stream)))
367
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:"
374               symbol
375               (member symbol sb-c::*policy-qualities*))
376       (describe-documentation symbol 'optimize stream t))
377     (terpri stream))
378
379   ;; Print out properties.
380   (let ((plist (symbol-plist symbol)))
381     (when plist
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))))
389       (terpri stream))))
390
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)
397                              (if (packagep x)
398                                  (package-name x)
399                                  x))
400                            list)
401                    #'string<))
402            (out (label list)
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)))
411             (exports nil))
412         (do-external-symbols (ext package)
413           (push ext exports))
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))))
428     (terpri stream)))
429 \f
430 ;;;; Helpers to deal with shared functionality
431
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))))
436     (when class
437       (let ((metaclass-name (class-name (class-of class))))
438         (pprint-logical-block (stream nil)
439           (when by-name
440             (format stream "~@:_~A names the ~(~A~) ~S:"
441                     name
442                     metaclass-name
443                     class)
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))
449                             stream))
450           (describe-stuff "Direct superclasses"
451                           (mapcar #'class-name-or-class (sb-mop:class-direct-superclasses class))
452                           stream)
453           (let ((subs (mapcar #'class-name-or-class (sb-mop:class-direct-subclasses class))))
454             (if subs
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)))
462                 (if slots
463                     (format stream "~@:_Slots:~:{~@:_  ~S~
464                                     ~@:_    Type: ~A ~@[~A~]~
465                                     ~@:_    Initform: ~S~}"
466                             (mapcar (lambda (dsd)
467                                       (list
468                                        (dsd-name dsd)
469                                        (dsd-type dsd)
470                                        (unless (eq t (dsd-raw-type dsd))
471                                          "(unboxed)")
472                                        (dsd-default dsd)))
473                                     slots))
474                     (format stream "~@:_No slots.")))
475               (let ((slots (sb-mop:class-direct-slots class)))
476                 (if slots
477                     (format stream "~@:_Direct slots:~:{~@:_  ~S~
478                                     ~@[~@:_    Type: ~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)))
497                                     slots))
498                     (format stream "~@:_No direct slots."))))
499           (pprint-indent :block 0 stream)
500           (pprint-newline :mandatory stream))))))
501
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)
506          (plist nil))
507
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)))
516
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))
524           (describe-slot
525            (sb-mop:slot-definition-name slotd)
526            (sb-pcl::slot-value-or-default object (sb-mop:slot-definition-name slotd))))))
527     (unless slotds
528       (format stream "~@:_No slots."))
529     (terpri stream)))
530
531 (defun quiet-doc (object type)
532   (handler-bind ((warning #'muffle-warning))
533     (documentation object type)))
534
535 (defun describe-documentation (object type stream &optional undoc newline)
536   (let ((doc (quiet-doc object type)))
537     (cond (doc
538            (format stream "~@:_Documentation:~@:_")
539            (pprint-logical-block (stream nil :per-line-prefix "  ")
540              (princ doc stream)))
541           (undoc
542            (format stream "~@:_(undocumented)")))
543     (when newline
544       (pprint-newline :mandatory stream))))
545
546 (defun describe-stuff (label list stream &key (escape t))
547   (when list
548     (if escape
549         (format stream "~@:_~A:~@<~;~{ ~S~^,~:_~}~;~:>" label list)
550         (format stream "~@:_~A:~@<~;~{ ~A~^,~:_~}~;~:>" label list))))
551
552 (defun describe-lambda-list (lambda-list stream)
553   (let ((*print-circle* nil)
554         (*print-level* 24)
555         (*print-length* 24))
556     (format stream "~@:_Lambda-list: ~:A" lambda-list)))
557
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)))
562         (when info
563           (let ((source (sb-c::debug-info-source info)))
564             (when source
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.
570                 (cond (namestring
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)))))))))
575       #+sb-eval
576       (let ((source (sb-eval:interpreted-function-source-location function)))
577         (when source
578           (let ((namestring (sb-c:definition-source-location-namestring source)))
579             (when namestring
580               (format stream "~@:_Source file: ~A" namestring)))))))
581
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"
594                         from
595                         (type-specifier (info :function :type name)))))))
596         ;; Defined.
597         (multiple-value-bind (fun what lambda-list derived-type declared-type
598                               inline methods)
599             (cond ((and (not function) (symbolp name) (special-operator-p name))
600                    (let ((fun (symbol-function name)))
601                      (values fun "a special operator" (%fun-lambda-list fun))))
602                   ((and (not function) (symbolp name) (macro-function name))
603                    (let ((fun (macro-function name)))
604                      (values fun "a macro" (%fun-lambda-list fun))))
605                   (t
606                    (let* ((fun (or function (fdefinition name)))
607                           (derived-type (and function
608                                              (%fun-type function)))
609                           (legal-name-p (legal-fun-name-p name))
610                           (ctype (and legal-name-p
611                                       (info :function :type name)))
612                           (type (and ctype (type-specifier ctype)))
613                           (from (and legal-name-p
614                                      (info :function :where-from name)))
615                           declared-type)
616                      ;; Ensure lazy pickup of information
617                      ;; from methods.
618                      (when legal-name-p
619                        (sb-c::maybe-update-info-for-gf name))
620                      (cond ((not type))
621                            ((eq from :declared)
622                             (setf declared-type type))
623                            ((and (not derived-type)
624                                  (member from '(:defined-method :defined)))
625                             (setf derived-type type)))
626                      (unless derived-type
627                        (setf derived-type (%fun-type fun)))
628                      (if (typep fun 'standard-generic-function)
629                          (values fun
630                                  "a generic function"
631                                  (sb-mop:generic-function-lambda-list fun)
632                                  derived-type
633                                  declared-type
634                                  nil
635                                  (or (sb-mop:generic-function-methods fun)
636                                      :none))
637                          (values fun
638                                  (if (compiled-function-p fun)
639                                      "a compiled function"
640                                      "an interpreted function")
641                                  (%fun-lambda-list fun)
642                                  derived-type
643                                  declared-type
644                                  (cons
645                                   (info :function :inlinep name)
646                                   (info :function :inline-expansion-designator
647                                         name)))))))
648           (pprint-logical-block (stream nil)
649             (unless function
650               (format stream "~%~A names ~A:" name what)
651               (pprint-indent :block 2 stream))
652             (describe-lambda-list lambda-list stream)
653             (when declared-type
654               (format stream "~@:_Declared type: ~S" declared-type))
655             (when (and derived-type
656                        (not (equal declared-type derived-type)))
657               (format stream "~@:_Derived type: ~S" derived-type))
658             (describe-documentation name 'function stream)
659             (when (car inline)
660               (format stream "~@:_Inline proclamation: ~
661                               ~A (~:[no ~;~]inline expansion available)"
662                       (car inline)
663                       (cdr inline)))
664             (awhen (info :function :info name)
665               (awhen (sb-c::decode-ir1-attributes (sb-c::fun-info-attributes it))
666                   (format stream "~@:_Known attributes: ~(~{~A~^, ~}~)" it)))
667             (when methods
668               (format stream "~@:_Method-combination: ~S"
669                       (sb-pcl::method-combination-type-name
670                        (sb-pcl:generic-function-method-combination fun)))
671               (cond ((eq :none methods)
672                      (format stream "~@:_No methods."))
673                     (t
674                      (pprint-newline :mandatory stream)
675                      (pprint-logical-block (stream nil)
676                        (format stream "Methods:")
677                        (dolist (method methods)
678                          (pprint-indent :block 2 stream)
679                          (format stream "~@:_(~A ~{~S ~}~:S)"
680                                  name
681                                  (method-qualifiers method)
682                                  (sb-pcl::unparse-specializers
683                                   fun (sb-mop:method-specializers method)))
684                          (pprint-indent :block 4 stream)
685                          (describe-documentation method t stream nil))))))
686             (describe-function-source fun stream)
687             (terpri stream)))))
688   (unless function
689     (awhen (and (legal-fun-name-p name) (compiler-macro-function name))
690       (pprint-logical-block (stream nil)
691         (format stream "~@:_~A has a compiler-macro:" name)
692         (pprint-indent :block 2 stream)
693         (describe-documentation it t stream)
694         (describe-function-source it stream))
695       (terpri stream))
696     (when (and (consp name) (eq 'setf (car name)) (not (cddr name)))
697       (let* ((name2 (second name))
698              (inverse (info :setf :inverse name2))
699              (expander (info :setf :expander name2)))
700         (cond (inverse
701                (pprint-logical-block (stream nil)
702                  (format stream "~&~A has setf-expansion: ~S"
703                          name inverse)
704                  (pprint-indent :block 2 stream)
705                  (describe-documentation name2 'setf stream))
706                (terpri stream))
707               (expander
708                (pprint-logical-block (stream nil)
709                  (format stream "~&~A has a complex setf-expansion:"
710                          name)
711                  (pprint-indent :block 2 stream)
712                  (describe-lambda-list (%fun-lambda-list expander) stream)
713                  (describe-documentation name2 'setf stream t)
714                  (describe-function-source expander stream))
715                (terpri stream)))))
716     (when (symbolp name)
717       (describe-function `(setf ,name) nil stream))))