Optimize out-of-line string CONCATENATE, part 2.
[sbcl.git] / src / code / describe.lisp
bloba1ea579a0b2fb86d31812bf8224432eaad37ae8c
1 ;;;; the DESCRIBE system
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.
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))
20 name
21 class)))
23 ;;;; the ANSI interface to function names (and to other stuff too)
24 ;;; Note: this function gets called by the compiler (as of 1.0.17.x,
25 ;;; in MAYBE-INLINE-SYNTACTIC-CLOSURE), and so although ANSI says
26 ;;; we're allowed to return NIL here freely, it seems plausible that
27 ;;; small changes to the circumstances under which this function
28 ;;; returns non-NIL might have subtle consequences on the compiler.
29 ;;; So it might be desirable to have the compiler not rely on this
30 ;;; function, eventually.
31 (defun function-lambda-expression (fun)
32 #+sb-doc
33 "Return (VALUES DEFINING-LAMBDA-EXPRESSION CLOSURE-P NAME), where
34 DEFINING-LAMBDA-EXPRESSION is NIL if unknown, or a suitable argument
35 to COMPILE otherwise, CLOSURE-P is non-NIL if the function's definition
36 might have been enclosed in some non-null lexical environment, and
37 NAME is some name (for debugging only) or NIL if there is no name."
38 (declare (type function fun))
39 (etypecase fun
40 #+sb-eval
41 (sb-eval:interpreted-function
42 (let ((name (sb-eval:interpreted-function-name fun))
43 (lambda-list (sb-eval:interpreted-function-lambda-list fun))
44 (declarations (sb-eval:interpreted-function-declarations fun))
45 (body (sb-eval:interpreted-function-body fun)))
46 (values `(lambda ,lambda-list
47 ,@(when declarations `((declare ,@declarations)))
48 ,@body)
49 t name)))
50 #+sb-fasteval
51 (sb-interpreter:interpreted-function
52 (sb-interpreter:fun-lambda-expression fun))
53 (function
54 (let* ((name (fun-name fun))
55 (fun (%simple-fun-self (%fun-fun fun)))
56 (code (sb-di::fun-code-header fun))
57 (info (sb-kernel:%code-debug-info code))
58 (source (if info (sb-c::debug-info-source info))))
59 (cond ((and source (sb-c::debug-source-form source)
60 (eq (sb-c::debug-source-function source) fun))
61 (values (sb-c::debug-source-form source) nil name))
62 ((legal-fun-name-p name)
63 (let ((exp (fun-name-inline-expansion name)))
64 (values exp (not exp) name)))
66 (values nil t name)))))))
68 ;;; Prints X on a single line, limiting output length by *PRINT-RIGHT-MARGIN*
69 ;;; -- good for printing object parts, etc.
70 (defun prin1-to-line (x &key (columns 1) (reserve 0))
71 (let* ((line (write-to-string x :escape t :readably nil :lines 2 :circle t))
72 (p (position #\newline line))
73 (limit (truncate (- *print-right-margin* reserve) columns)))
74 (flet ((trunc (&optional end)
75 (let ((line-end (- limit 2)))
76 (with-simple-output-to-string (s)
77 (write-string line s :end (if end
78 (min end line-end)
79 line-end))
80 (write-string ".." s)))))
81 (cond (p
82 (trunc p))
83 ((> (length line) limit)
84 (trunc))
86 line)))))
88 (defun describe (object &optional (stream-designator *standard-output*))
89 #+sb-doc
90 "Print a description of OBJECT to STREAM-DESIGNATOR."
91 (let ((stream (out-synonym-of stream-designator))
92 (*print-right-margin* (or *print-right-margin* 72))
93 (*print-circle* t)
94 (*suppress-print-errors*
95 (if (subtypep 'serious-condition *suppress-print-errors*)
96 *suppress-print-errors*
97 'serious-condition)))
98 ;; Until sbcl-0.8.0.x, we did
99 ;; (FRESH-LINE STREAM)
100 ;; (PPRINT-LOGICAL-BLOCK (STREAM NIL)
101 ;; ...
102 ;; here. However, ANSI's specification of DEFUN DESCRIBE,
103 ;; DESCRIBE exists as an interface primarily to manage argument
104 ;; defaulting (including conversion of arguments T and NIL into
105 ;; stream objects) and to inhibit any return values from
106 ;; DESCRIBE-OBJECT.
107 ;; doesn't mention either FRESH-LINEing or PPRINT-LOGICAL-BLOCKing,
108 ;; and the example of typical DESCRIBE-OBJECT behavior in ANSI's
109 ;; specification of DESCRIBE-OBJECT will work poorly if we do them
110 ;; here. (The example method for DESCRIBE-OBJECT does its own
111 ;; FRESH-LINEing, which is a physical directive which works poorly
112 ;; inside a pretty-printer logical block.)
113 (handler-bind ((print-not-readable #'print-unreadably))
114 (describe-object object stream))
115 ;; We don't TERPRI here either (any more since sbcl-0.8.0.x), because
116 ;; again ANSI's specification of DESCRIBE doesn't mention it and
117 ;; ANSI's example of DESCRIBE-OBJECT does its own final TERPRI.
118 (values)))
120 ;;;; DESCRIBE-OBJECT
121 ;;;;
122 ;;;; Style guide:
123 ;;;;
124 ;;;; * Each interesting class has a primary method of its own.
125 ;;;;
126 ;;;; * Output looks like
127 ;;;;
128 ;;;; object-self-string
129 ;;;; [object-type-string]
130 ;;;;
131 ;;;; Block1:
132 ;;;; Sublabel1: text
133 ;;;; Sublabel2: text
134 ;;;;
135 ;;;; Block2:
136 ;;;; ...
137 ;;;;
138 ;;;; * The newline policy that gets the whitespace right is for
139 ;;;; each block to both start and end with a newline.
141 (defgeneric object-self-string (x))
143 (defmethod object-self-string (x)
144 (prin1-to-line x))
146 (defmethod object-self-string ((x symbol))
147 (let ((*package* (find-package :keyword)))
148 (prin1-to-string x)))
150 (defgeneric object-type-string (x))
152 (defmethod object-type-string (x)
153 (let ((type (class-name-or-class (class-of x))))
154 (if (symbolp type)
155 (string-downcase type)
156 (prin1-to-string type))))
158 (defmethod object-type-string ((x cons))
159 (if (listp (cdr x)) "list" "cons"))
161 (defmethod object-type-string ((x hash-table))
162 "hash-table")
164 (defmethod object-type-string ((x condition))
165 "condition")
167 (defmethod object-type-string ((x structure-object))
168 "structure-object")
170 (defmethod object-type-string ((x standard-object))
171 "standard-object")
173 (defmethod object-type-string ((x function))
174 (typecase x
175 (simple-fun "compiled function")
176 (closure "compiled closure")
177 ((or #+sb-fasteval sb-interpreter:interpreted-function
178 #+sb-eval sb-eval:interpreted-function) "interpreted function")
179 (generic-function "generic-function")
180 (t "funcallable-instance")))
182 (defmethod object-type-string ((x stream))
183 "stream")
185 (defmethod object-type-string ((x sb-gray:fundamental-stream))
186 "gray stream")
188 (defmethod object-type-string ((x package))
189 "package")
191 (defmethod object-type-string ((x array))
192 (cond ((or (stringp x) (bit-vector-p x))
193 (format nil "~@[simple-~*~]~A"
194 (typep x 'simple-array)
195 (typecase x
196 (base-string "base-string")
197 (string "string")
198 (t "bit-vector"))))
200 (if (simple-vector-p x)
201 "simple-vector"
202 (format nil "~@[simple ~*~]~@[specialized ~*~]~:[array~;vector~]"
203 (typep x 'simple-array)
204 (neq t (array-element-type x))
205 (vectorp x))))))
207 (defmethod object-type-string ((x character))
208 (typecase x
209 (standard-char "standard-char")
210 (base-char "base-char")
211 (t "character")))
213 (defun print-standard-describe-header (x stream)
214 (format stream "~&~A~% [~A]~%"
215 (object-self-string x)
216 (object-type-string x)))
218 (defgeneric describe-object (x stream))
220 ;;; Catch-all.
222 (defmethod describe-object ((x t) s)
223 (print-standard-describe-header x s))
225 (defmethod describe-object ((x cons) s)
226 (print-standard-describe-header x s)
227 (describe-function x nil s))
229 (defmethod describe-object ((x function) s)
230 (print-standard-describe-header x s)
231 (describe-function nil x s))
233 (defmethod describe-object ((x class) s)
234 (print-standard-describe-header x s)
235 (describe-class nil x s)
236 (describe-instance x s))
238 (defmethod describe-object ((x sb-pcl::slot-object) s)
239 (print-standard-describe-header x s)
240 (describe-instance x s))
242 (defmethod describe-object ((x character) s)
243 (print-standard-describe-header x s)
244 (format s "~%Char-code: ~S" (char-code x))
245 (format s "~%Char-name: ~A" (char-name x)))
247 (defmethod describe-object ((x array) s)
248 (print-standard-describe-header x s)
249 (format s "~%Element-type: ~S" (array-element-type x))
250 (if (vectorp x)
251 (if (array-has-fill-pointer-p x)
252 (format s "~%Fill-pointer: ~S~%Size: ~S"
253 (fill-pointer x)
254 (array-total-size x))
255 (format s "~%Length: ~S" (length x)))
256 (format s "~%Dimensions: ~S" (array-dimensions x)))
257 (let ((*print-array* nil))
258 (unless (typep x 'simple-array)
259 (format s "~%Adjustable: ~A" (if (adjustable-array-p x) "yes" "no"))
260 (multiple-value-bind (to offset) (array-displacement x)
261 (if (format s "~%Displaced-to: ~A~%Displaced-offset: ~S"
262 (prin1-to-line to)
263 offset)
264 (format s "~%Displaced: no"))))
265 (when (and (not (array-displacement x)) (array-header-p x))
266 (format s "~%Storage vector: ~A"
267 (prin1-to-line (array-storage-vector x))))
268 (terpri s)))
270 (defmethod describe-object ((x hash-table) s)
271 (print-standard-describe-header x s)
272 ;; Don't print things which are already apparent from the printed
273 ;; representation -- COUNT, TEST, and WEAKNESS
274 (format s "~%Occupancy: ~,1F" (float (/ (hash-table-count x)
275 (hash-table-size x))))
276 (format s "~%Rehash-threshold: ~S" (hash-table-rehash-threshold x))
277 (format s "~%Rehash-size: ~S" (hash-table-rehash-size x))
278 (format s "~%Size: ~S" (hash-table-size x))
279 (format s "~%Synchronized: ~A" (if (hash-table-synchronized-p x) "yes" "no"))
280 (terpri s))
282 (defmethod describe-object ((symbol symbol) stream)
283 (print-standard-describe-header symbol stream)
285 ;; Describe the value cell.
286 (describe-variable symbol stream)
288 ;; TODO: We could grovel over all packages looking for and
289 ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
290 ;; availability in some package even after (SYMBOL-PACKAGE SYMBOL) has
291 ;; been set to NIL.
293 ;; TODO: It might also be nice to describe (find-package symbol)
294 ;; if one exists. Maybe not all the exports, etc, but the package
295 ;; documentation.
296 (describe-function symbol nil stream)
297 (describe-class symbol nil stream)
299 ;; Type specifier
300 (describe-type symbol stream)
302 (awhen (sb-c::policy-quality-name-p symbol)
303 (pprint-logical-block (stream nil)
304 (pprint-newline :mandatory stream)
305 (pprint-indent :block 2 stream)
306 (format stream "~A names a~:[ dependent~;n~] optimization policy quality:"
307 symbol (minusp it))
308 (describe-documentation symbol 'optimize stream t))
309 (terpri stream))
311 ;; Print out properties.
312 (let ((plist (symbol-plist symbol)))
313 (when plist
314 (pprint-logical-block (stream nil)
315 (format stream "~%Symbol-plist:")
316 (pprint-indent :block 2 stream)
317 (sb-pcl::doplist (key value) plist
318 (format stream "~@:_~A -> ~A"
319 (prin1-to-line key :columns 2 :reserve 5)
320 (prin1-to-line value :columns 2 :reserve 5))))
321 (terpri stream))))
323 (defmethod describe-object ((package package) stream)
324 (print-standard-describe-header package stream)
325 (pprint-logical-block (stream nil)
326 (describe-documentation package t stream)
327 (flet ((humanize (list)
328 (sort (mapcar (lambda (x)
329 (if (packagep x)
330 (package-name x)
332 list)
333 #'string<))
334 (out (label list)
335 (describe-stuff label list stream :escape nil)))
336 (let ((exports nil))
337 (do-external-symbols (ext package)
338 (push ext exports))
339 #+sb-package-locks
340 (let ((implemented (humanize (package-implemented-by-list package)))
341 (implements (humanize (package-implements-list package)))
342 (this (list (package-name package))))
343 (when (package-locked-p package)
344 (format stream "~@:_Locked."))
345 (when (set-difference implemented this :test #'string=)
346 (out "Implemented-by-list" implemented))
347 (when (set-difference implements this :test #'string=)
348 (out "Implements-list" implements)))
349 (out "Nicknames" (humanize (package-nicknames package)))
350 (out "Use-list" (humanize (package-use-list package)))
351 (out "Used-by-list" (humanize (package-used-by-list package)))
352 (out "Shadows" (humanize (package-shadowing-symbols package)))
353 (out "Exports" (humanize exports))
354 (format stream "~@:_~S internal symbols."
355 (package-internal-symbol-count package))))
356 (terpri stream)))
358 ;;;; Helpers to deal with shared functionality
360 (defun describe-deprecation (namespace name stream)
361 (multiple-value-bind (state since replacements)
362 (deprecated-thing-p namespace name)
363 (when state
364 (destructuring-bind (software version) since
365 (format stream "~@:_In ~A deprecation since ~@[~A ~]version ~A.~
366 ~@[ ~/sb-impl::print-deprecation-replacements/~]"
367 state software version replacements)))))
369 (defun describe-class (name class stream)
370 (binding* ((by-name (not class))
371 ((name class) (if class
372 (values (class-name class) name)
373 (values name (find-class name nil)))))
374 (when class
375 (let ((metaclass-name (class-name (class-of class))))
376 (pprint-logical-block (stream nil)
377 (when by-name
378 (format stream "~@:_~A names the ~(~A~) ~S:"
379 name metaclass-name class)
380 (pprint-indent :block 2 stream))
381 (describe-deprecation 'type name stream)
382 (describe-documentation class t stream)
383 (when (sb-mop:class-finalized-p class)
384 (describe-stuff "Class precedence-list"
385 (mapcar #'class-name-or-class (sb-mop:class-precedence-list class))
386 stream))
387 (describe-stuff "Direct superclasses"
388 (mapcar #'class-name-or-class (sb-mop:class-direct-superclasses class))
389 stream)
390 (let ((subs (mapcar #'class-name-or-class (sb-mop:class-direct-subclasses class))))
391 (if subs
392 (describe-stuff "Direct subclasses" subs stream)
393 (format stream "~@:_No subclasses.")))
394 (unless (sb-mop:class-finalized-p class)
395 (format stream "~@:_Not yet finalized."))
396 (if (eq 'structure-class metaclass-name)
397 (let* ((dd (find-defstruct-description name))
398 (slots (dd-slots dd)))
399 (if slots
400 (format stream "~@:_Slots:~:{~@:_ ~S~
401 ~@:_ Type: ~A ~@[~A~]~
402 ~@:_ Initform: ~S~}"
403 (mapcar (lambda (dsd)
404 (list
405 (dsd-name dsd)
406 (dsd-type dsd)
407 (unless (eq t (dsd-raw-type dsd))
408 "(unboxed)")
409 (dsd-default dsd)))
410 slots))
411 (format stream "~@:_No slots.")))
412 (let ((slots (sb-mop:class-direct-slots class)))
413 (if slots
414 (format stream "~@:_Direct slots:~:{~@:_ ~S~
415 ~@[~@:_ Type: ~S~]~
416 ~@[~@:_ Allocation: ~S~]~
417 ~@[~@:_ Initargs: ~{~S~^, ~}~]~
418 ~@[~@:_ Initform: ~S~]~
419 ~@[~@:_ Readers: ~{~S~^, ~}~]~
420 ~@[~@:_ Writers: ~{~S~^, ~}~]~
421 ~@[~@:_ Documentation:~@:_ ~@<~@;~A~:>~]~}"
422 (mapcar (lambda (slotd)
423 (list (sb-mop:slot-definition-name slotd)
424 (let ((type (sb-mop:slot-definition-type slotd)))
425 (unless (eq t type) type))
426 (let ((alloc (sb-mop:slot-definition-allocation slotd)))
427 (unless (eq :instance alloc) alloc))
428 (sb-mop:slot-definition-initargs slotd)
429 (sb-mop:slot-definition-initform slotd)
430 (sb-mop:slot-definition-readers slotd)
431 (sb-mop:slot-definition-writers slotd)
432 ;; FIXME: does this get the prefix right?
433 (quiet-doc slotd t)))
434 slots))
435 (format stream "~@:_No direct slots."))))
436 (pprint-indent :block 0 stream)
437 (pprint-newline :mandatory stream))))))
439 (defun describe-instance (object stream)
440 (let* ((class (class-of object))
441 (slotds (sb-mop:class-slots class))
442 (max-slot-name-length 0)
443 (plist nil))
445 ;; Figure out a good width for the slot-name column.
446 (flet ((adjust-slot-name-length (name)
447 (setf max-slot-name-length
448 (max max-slot-name-length (length (symbol-name name))))))
449 (dolist (slotd slotds)
450 (adjust-slot-name-length (sb-mop:slot-definition-name slotd))
451 (push slotd (getf plist (sb-mop:slot-definition-allocation slotd))))
452 (setf max-slot-name-length (min (+ max-slot-name-length 3) 30)))
454 ;; Now that we know the width, we can print.
455 (flet ((describe-slot (name value)
456 (format stream "~% ~A~VT = ~A" name max-slot-name-length
457 (prin1-to-line value))))
458 (sb-pcl::doplist (allocation slots) plist
459 (format stream "~%Slots with ~S allocation:" allocation)
460 (dolist (slotd (nreverse slots))
461 (describe-slot
462 (sb-mop:slot-definition-name slotd)
463 (sb-pcl::slot-value-or-default object (sb-mop:slot-definition-name slotd))))))
464 (unless slotds
465 (format stream "~@:_No slots."))
466 (terpri stream)))
468 (defun quiet-doc (object type)
469 (handler-bind ((warning #'muffle-warning))
470 (documentation object type)))
472 (defun describe-documentation (object type stream &optional undoc newline)
473 (let ((doc (quiet-doc object type)))
474 (cond (doc
475 (format stream "~@:_Documentation:~@:_")
476 (pprint-logical-block (stream nil :per-line-prefix " ")
477 (princ doc stream)))
478 (undoc
479 (format stream "~@:_(undocumented)")))
480 (when newline
481 (pprint-newline :mandatory stream))))
483 (defun describe-stuff (label list stream &key (escape t))
484 (when list
485 (if escape
486 (format stream "~@:_~A:~@<~;~{ ~S~^,~:_~}~;~:>" label list)
487 (format stream "~@:_~A:~@<~;~{ ~A~^,~:_~}~;~:>" label list))))
489 (defun describe-variable (name stream)
490 (let* ((kind (info :variable :kind name))
491 (wot (ecase kind
492 (:special "a special variable")
493 (:macro "a symbol macro")
494 (:constant "a constant variable")
495 (:global "a global variable")
496 (:unknown "an undefined variable")
497 (:alien "an alien variable"))))
498 (when (and (eq kind :unknown) (not (boundp name)))
499 (return-from describe-variable))
500 (pprint-logical-block (stream nil)
501 (format stream "~@:_~A names ~A:" name wot)
502 (pprint-indent :block 2 stream)
503 (describe-deprecation 'variable name stream)
504 (when (eq (info :variable :where-from name) :declared)
505 (format stream "~@:_Declared type: ~S"
506 (type-specifier (info :variable :type name))))
507 (when (info :variable :always-bound name)
508 (format stream "~@:_Declared always-bound."))
509 (cond
510 ((eq kind :alien)
511 (let ((info (info :variable :alien-info name)))
512 (format stream "~@:_Value: ~S" (eval name))
513 (format stream "~@:_Type: ~S"
514 (sb-alien-internals:unparse-alien-type
515 (sb-alien::heap-alien-info-type info)))
516 (format stream "~@:_Address: #x~8,'0X"
517 (sap-int (sb-alien::heap-alien-info-sap info)))))
518 ((eq kind :macro)
519 (let ((expansion (info :variable :macro-expansion name)))
520 (format stream "~@:_Expansion: ~S" expansion)))
521 ((boundp name)
522 (format stream "~:@_Value: ~S" (symbol-value name)))
523 ((not (eq kind :unknown))
524 (format stream "~:@_Currently unbound.")))
525 (describe-documentation name 'variable stream)
526 (terpri stream))))
528 (defun describe-lambda-list (lambda-list stream)
529 (let ((*print-circle* nil)
530 (*print-level* 24)
531 (*print-length* 24))
532 (format stream "~@:_Lambda-list: ~:A" lambda-list)))
534 (defun describe-function-source (function stream)
535 (if (compiled-function-p (the function function))
536 (let* ((code (fun-code-header (%fun-fun function)))
537 (info (sb-kernel:%code-debug-info code)))
538 (when info
539 (let ((source (sb-c::debug-info-source info)))
540 (when source
541 (let ((namestring (sb-c::debug-source-namestring source)))
542 ;; This used to also report the times the source was created
543 ;; and compiled, but that seems more like noise than useful
544 ;; information -- but FWIW that are to be had as
545 ;; SB-C::DEBUG-SOUCE-CREATED/COMPILED.
546 (cond (namestring
547 (format stream "~@:_Source file: ~A" namestring))
548 ((sb-di:debug-source-form source)
549 (format stream "~@:_Source form:~@:_ ~S"
550 (sb-di:debug-source-form source)))))))))
551 (let ((source
552 (typecase function
553 #+sb-eval
554 (sb-eval:interpreted-function
555 (sb-eval:interpreted-function-source-location function))
556 #+sb-fasteval
557 (sb-interpreter:interpreted-function
558 (sb-interpreter:fun-source-location function)))))
559 (when source
560 (let ((namestring (sb-c:definition-source-location-namestring source)))
561 (when namestring
562 (format stream "~@:_Source file: ~A" namestring)))))))
564 (defun describe-function (name function stream)
565 (let ((name (if function (fun-name function) name)))
566 (if (not (or function (and (legal-fun-name-p name) (fboundp name))))
567 ;; Not defined, but possibly the type is declared, or we have
568 ;; compiled calls to it.
569 (when (legal-fun-name-p name)
570 (multiple-value-bind (from sure) (info :function :where-from name)
571 (when (or (eq :declared from) (and sure (eq :assumed from)))
572 (pprint-logical-block (stream nil)
573 (format stream "~%~A names an undefined function" name)
574 (pprint-indent :block 2 stream)
575 (format stream "~@:_~:(~A~) type: ~S"
576 from
577 (type-specifier (proclaimed-ftype name)))))))
578 ;; Defined.
579 (multiple-value-bind (fun what lambda-list derived-type declared-type
580 inline methods)
581 (cond ((and (not function) (symbolp name) (special-operator-p name))
582 ;; The function in the symbol is irrelevant.
583 ;; Use the def-ir1-translator function for source location.
584 (let ((fun (info :function :ir1-convert name)))
585 (values fun "a special operator" (%fun-lambda-list fun))))
586 ((and (not function) (symbolp name) (macro-function name))
587 (let ((fun (macro-function name)))
588 (values fun "a macro" (%fun-lambda-list fun))))
590 (let* ((fun (or function (fdefinition name)))
591 (derived-type (and function
592 (%fun-type function)))
593 (legal-name-p (legal-fun-name-p name))
594 (ctype (and legal-name-p
595 (proclaimed-ftype name)))
596 (type (and ctype (type-specifier ctype)))
597 (from (and legal-name-p
598 (info :function :where-from name)))
599 declared-type)
600 (cond ((not type))
601 ((eq from :declared)
602 (setf declared-type type))
603 ((and (not derived-type)
604 (member from '(:defined-method :defined)))
605 (setf derived-type type)))
606 (unless derived-type
607 (setf derived-type (%fun-type fun)))
608 (if (typep fun 'standard-generic-function)
609 (values fun
610 "a generic function"
611 (sb-mop:generic-function-lambda-list fun)
612 derived-type
613 declared-type
615 (or (sb-mop:generic-function-methods fun)
616 :none))
617 (values fun
618 (if (compiled-function-p fun)
619 "a compiled function"
620 "an interpreted function")
621 (%fun-lambda-list fun)
622 derived-type
623 declared-type
624 (cons
625 (info :function :inlinep name)
626 (info :function :inline-expansion-designator
627 name)))))))
628 (pprint-logical-block (stream nil)
629 (unless function
630 (format stream "~%~A names ~A:" name what)
631 (pprint-indent :block 2 stream))
632 (describe-deprecation 'function name stream)
633 (describe-lambda-list lambda-list stream)
634 (when declared-type
635 (format stream "~@:_Declared type: ~S" declared-type))
636 (when (and derived-type
637 (not (equal declared-type derived-type)))
638 (format stream "~@:_Derived type: ~S" derived-type))
639 (describe-documentation name 'function stream)
640 (when (car inline)
641 (format stream "~@:_Inline proclamation: ~
642 ~A (~:[no ~;~]inline expansion available)"
643 (car inline)
644 (cdr inline)))
645 (awhen (info :function :info name)
646 (awhen (sb-c::decode-ir1-attributes (sb-c::fun-info-attributes it))
647 (format stream "~@:_Known attributes: ~(~{~A~^, ~}~)" it)))
648 (when methods
649 (format stream "~@:_Method-combination: ~S"
650 (sb-pcl::method-combination-type-name
651 (sb-pcl:generic-function-method-combination fun)))
652 (cond ((eq :none methods)
653 (format stream "~@:_No methods."))
655 (pprint-newline :mandatory stream)
656 (pprint-logical-block (stream nil)
657 (format stream "Methods:")
658 (dolist (method methods)
659 (pprint-indent :block 2 stream)
660 (format stream "~@:_(~A ~{~S ~}~:S)"
661 name
662 (method-qualifiers method)
663 (sb-pcl::unparse-specializers
664 fun (sb-mop:method-specializers method)))
665 (pprint-indent :block 4 stream)
666 (describe-documentation method t stream nil))))))
667 (describe-function-source fun stream)
668 (terpri stream)))))
669 (unless function
670 (awhen (and (legal-fun-name-p name) (compiler-macro-function name))
671 (pprint-logical-block (stream nil)
672 (format stream "~@:_~A has a compiler-macro:" name)
673 (pprint-indent :block 2 stream)
674 (describe-documentation it t stream)
675 (describe-function-source it stream))
676 (terpri stream))
677 (when (and (consp name) (eq 'setf (car name)) (not (cddr name)))
678 (let* ((name2 (second name))
679 (expander (info :setf :expander name2)))
680 (cond ((typep expander '(and symbol (not null)))
681 (pprint-logical-block (stream nil)
682 (format stream "~&~A has setf-expansion: ~S"
683 name expander)
684 (pprint-indent :block 2 stream)
685 (describe-documentation name2 'setf stream))
686 (terpri stream))
687 (expander
688 (when (listp expander)
689 (setq expander (cdr expander)))
690 (pprint-logical-block (stream nil)
691 (format stream "~&~A has a complex setf-expansion:"
692 name)
693 (pprint-indent :block 2 stream)
694 (describe-lambda-list (%fun-lambda-list expander) stream)
695 (describe-documentation name2 'setf stream t)
696 (describe-function-source expander stream))
697 (terpri stream)))))
698 (when (symbolp name)
699 (describe-function `(setf ,name) nil stream))))
701 (defun describe-type (name stream)
702 (let* ((kind (info :type :kind name))
703 (fun (and kind (info :type :expander name)))
704 (fun (if (listp fun) (car fun) fun)))
705 (when fun
706 (pprint-newline :mandatory stream)
707 (pprint-logical-block (stream nil)
708 (format stream "~@:_~A names a ~@[primitive~* ~]type-specifier:"
709 name (eq kind :primitive))
710 (pprint-indent :block 2 stream)
711 (describe-deprecation 'type name stream)
712 (describe-documentation name 'type stream (eq t fun))
713 (when (functionp fun)
714 (describe-lambda-list (%fun-lambda-list fun) stream)
715 (multiple-value-bind (expansion ok)
716 (handler-case (typexpand-1 name)
717 (error () (values nil nil)))
718 (when ok
719 (format stream "~@:_Expansion: ~S" expansion)))))
720 (terpri stream))))