1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (defpackage :sb-introspect-test
11 (:use
"SB-INTROSPECT" "CL" "SB-RT"))
13 (in-package :sb-introspect-test
)
15 (defmacro deftest
* ((name &key fails-on
) form
&rest results
)
17 (when (sb-impl::featurep
',fails-on
)
18 (pushnew ',name sb-rt
::*expected-failures
*))
19 (deftest ,name
,form
,@results
)))
21 ;; When running the tests which query for a function type, sb-interpreter
22 ;; can return an answer if there were type declarations for the arguments,
23 ;; except that return type is always unknown. The compiler returns a
24 ;; definitive answer, and sb-eval always answers with just FUNCTION.
25 (defun expect-wild-return-type-p (f)
26 (declare (ignorable f
))
27 (or #+sb-fasteval
(typep f
'sb-interpreter
:interpreted-function
)))
29 (deftest function-lambda-list
.1
30 (function-lambda-list 'cl-user
::one
)
31 (cl-user::a cl-user
::b cl-user
::c
))
33 (deftest function-lambda-list
.2
34 (function-lambda-list 'the
)
35 (sb-c::value-type sb-c
::form
))
37 (deftest function-lambda-list
.3
38 (function-lambda-list #'(sb-pcl::slow-method cl-user
::j
(t)))
39 (sb-pcl::method-args sb-pcl
::next-methods
))
41 (deftest macro-lambda-list
.1
42 (equal (function-lambda-list (defmacro macro-lambda-list
.1-m
(x b
)
48 (deftest macro-lambda-list
.2
49 (equal (function-lambda-list (interpret (defmacro macro-lambda-list
.2-m
(x)
54 (deftest definition-source
.1
55 (values (consp (find-definition-sources-by-name 'vectorp
:vop
))
56 (consp (find-definition-sources-by-name 'check-type
:macro
)))
59 (deftest definition-source-plist
.1
60 (let* ((source (find-definition-source #'cl-user
::one
))
61 (plist (definition-source-plist source
))
62 (pathname (definition-source-pathname source
)))
63 (values (equalp pathname
#p
"SYS:CONTRIB;SB-INTROSPECT;TEST.LISP.NEWEST")
64 (= (definition-source-file-write-date source
)
65 (file-write-date pathname
))
66 (or (equal (getf plist
:test-outer
)
71 ;; Not sure why this fails when interpreted, and don't really care too much.
72 ;; The behavior seems right to me anyway.
73 #.
(if (eq sb-ext
:*evaluator-mode
* :compile
)
74 '(deftest definition-source-plist
.2
75 (let ((plist (definition-source-plist
76 (find-definition-source #'cl-user
::four
))))
77 (values (or (equal (getf plist
:test-outer
) "OUT")
79 (or (equal (getf plist
:test-inner
) "IN")
84 (defun matchp (object form-number
)
85 (let ((ds (sb-introspect:find-definition-source object
)))
86 (and (pathnamep (sb-introspect:definition-source-pathname ds
))
88 (first (sb-introspect:definition-source-form-path ds
))))))
90 (defun matchp-name (type object form-number
)
91 (let ((ds (car (sb-introspect:find-definition-sources-by-name object type
))))
92 (and (pathnamep (sb-introspect:definition-source-pathname ds
))
94 (first (sb-introspect:definition-source-form-path ds
))))))
96 (defun matchp-length (type object form-numbers
)
97 (let ((ds (sb-introspect:find-definition-sources-by-name object type
)))
98 (= (length ds
) form-numbers
)))
100 (deftest find-source-stuff
.1
101 (matchp-name :function
'cl-user
::one
2)
104 (deftest find-source-stuff
.2
105 (matchp #'cl-user
::one
2)
108 (deftest find-source-stuff
.3
109 (matchp-name :generic-function
'cl-user
::two
3)
112 (deftest find-source-stuff
.4
113 (matchp (car (sb-pcl:generic-function-methods
#'cl-user
::two
)) 4)
116 (deftest find-source-stuff
.5
117 (matchp-name :variable
'cl-user
::*a
* 8)
120 (deftest find-source-stuff
.6
121 (matchp-name :variable
'cl-user
::*b
* 9)
124 (deftest find-source-stuff
.7
125 (matchp-name :class
'cl-user
::a
10)
128 (deftest find-source-stuff
.8
129 (matchp-name :condition
'cl-user
::b
11)
132 (deftest find-source-stuff
.9
133 (matchp-name :structure
'cl-user
::c
12)
136 (deftest find-source-stuff
.10
137 (matchp-name :function
'cl-user
::make-c
12)
140 (deftest find-source-stuff
.11
141 (matchp-name :function
'cl-user
::c-e
12)
144 (deftest find-source-stuff
.12
145 (matchp-name :structure
'cl-user
::d
13)
148 (deftest find-source-stuff
.13
149 (matchp-name :function
'cl-user
::make-d
13)
152 (deftest find-source-stuff
.14
153 (matchp-name :function
'cl-user
::d-e
13)
156 (deftest find-source-stuff
.15
157 (matchp-name :package
'cl-user
::e
14)
160 (deftest find-source-stuff
.16
161 (matchp-name :symbol-macro
'cl-user
::f
15)
164 (deftest find-source-stuff
.17
165 (matchp-name :type
'cl-user
::g
16)
168 (deftest find-source-stuff
.18
169 (matchp-name :constant
'cl-user
::+h
+ 17)
172 (deftest find-source-stuff
.19
173 (matchp-length :method
'cl-user
::j
2)
176 (deftest find-source-stuff
.20
177 (matchp-name :macro
'cl-user
::l
20)
180 (deftest find-source-stuff
.21
181 (matchp-name :compiler-macro
'cl-user
::m
21)
184 (deftest find-source-stuff
.22
185 (matchp-name :setf-expander
'cl-user
::n
22)
188 (deftest find-source-stuff
.23
189 (matchp-name :function
'(setf cl-user
::o
) 23)
192 (deftest find-source-stuff
.24
193 (matchp-name :method
'(setf cl-user
::p
) 24)
196 (deftest find-source-stuff
.25
197 (matchp-name :macro
'cl-user
::q
25)
201 (deftest find-source-stuff
.26
202 (matchp-name :method-combination
'cl-user
::r
26)
206 (deftest find-source-stuff
.27
207 (matchp-name :setf-expander
'cl-user
::s
27)
210 (deftest find-source-stuff
.28
211 (let ((fin (make-instance 'sb-mop
:funcallable-standard-object
)))
212 (sb-mop:set-funcallable-instance-function fin
#'cl-user
::one
)
216 (deftest find-source-stuff
.29
219 (sb-profile:profile cl-user
::one
)
220 (matchp-name :function
'cl-user
::one
2))
221 (sb-profile:unprofile cl-user
::one
))
224 (deftest find-source-stuff
.30
225 ;; Test finding a type that isn't one
226 (not (find-definition-sources-by-name 'fboundp
:type
))
229 (deftest find-source-stuff
.31
230 (matchp-name :function
'cl-user
::compile-time-too-fun
28)
233 (deftest find-source-stuff
.32
234 (matchp-name :function
'cl-user
::loaded-as-source-fun
3)
237 (deftest find-source-stuff
.33
238 (matchp-name :variable
'cl-user
::**global
** 29)
241 ;;; Check wrt. interplay of generic functions and their methods.
243 (defgeneric xuuq
(gf.a gf.b
&rest gf.rest
&key gf.k-X
))
244 (defmethod xuuq ((m1.a number
) m1.b
&rest m1.rest
&key gf.k-X m1.k-Y m1.k-Z
)
245 (declare (ignore m1.a m1.b m1.rest gf.k-X m1.k-Y m1.k-Z
))
247 (defmethod xuuq ((m2.a string
) m2.b
&rest m2.rest
&key gf.k-X m1.k-Y m2.k-Q
)
248 (declare (ignore m2.a m2.b m2.rest gf.k-X m1.k-Y m2.k-Q
))
251 ;; XUUQ's lambda list should look similiar to
253 ;; (GF.A GF.B &REST GF.REST &KEY GF.K-X M1.K-Z M1.K-Y M2.K-Q)
255 (deftest gf-interplay
.1
256 (multiple-value-bind (llks required optional rest keys aux more
)
257 (sb-int:parse-lambda-list
(function-lambda-list #'xuuq
))
258 (and (equal required
'(gf.a gf.b
))
260 (eq (car rest
) 'gf.rest
)
261 (and (sb-int:ll-kwds-keyp llks
)
262 (member 'gf.k-X keys
)
263 (member 'm1.k-Y keys
)
264 (member 'm1.k-Z keys
)
265 (member 'm2.k-Q keys
))
266 (not (sb-int:ll-kwds-allowp llks
))
271 ;;; Check what happens when there's no explicit DEFGENERIC.
273 (defmethod kroolz (r1 r2
&optional opt
&aux aux
)
274 (declare (ignore r1 r2 opt aux
))
277 (deftest gf-interplay
.2
278 (equal (function-lambda-list #'kroolz
) '(r1 r2
&optional opt
))
281 ;;;; Check correctness of DEFTYPE-LAMBDA-LIST.
283 (&whole w
&environment e r1 r2
&optional o
&rest rest
&key k1 k2 k3
)
284 (declare (ignore w e r1 r2 o rest k1 k2 k3
))
287 (deftest deftype-lambda-list
.1
288 (deftype-lambda-list 'foobar-type
)
289 (r1 r2
&optional o
&rest rest
&key k1 k2 k3
)
292 (deftest deftype-lambda-list
.2
293 (deftype-lambda-list (gensym))
297 ;; ARRAY is a primitive type with associated translator function.
298 (deftest deftype-lambda-list
.3
299 (deftype-lambda-list 'array
)
300 (&optional
(sb-kernel::element-type
'*) (sb-kernel::dimensions
'*))
303 ;; VECTOR is a primitive type that is defined by means of DEFTYPE.
304 (deftest deftype-lambda-list
.4
305 (deftype-lambda-list 'vector
)
306 (&optional sb-kernel
::element-type sb-kernel
::size
)
309 ;;; Test allocation-information
311 (defun tai (x kind info
&key ignore
)
312 (multiple-value-bind (kind2 info2
) (sb-introspect:allocation-information x
)
313 (unless (eq kind kind2
)
314 (error "wanted ~S, got ~S" kind kind2
))
315 (when (not (null ignore
))
316 (setf info2
(copy-list info2
))
319 (setf info
(copy-list info
))
324 (deftest allocation-infromation
.1
325 (tai nil
:heap
'(:space
:static
))
328 (deftest allocation-information
.2
329 (tai t
:heap
'(:space
:static
))
332 (deftest allocation-information
.3
333 (tai 42 :immediate nil
)
336 (deftest allocation-information
.3b
337 (tai 42s0
:immediate nil
)
340 #.
(if (and (eq sb-ext
:*evaluator-mode
* :compile
) (member :sb-thread
*features
*))
341 '(deftest allocation-information.thread
.1
342 (let ((x (list 1 2 3)))
343 (declare (dynamic-extent x
))
344 (tai x
:stack sb-thread
:*current-thread
*))
351 (let ((x (list 1 2 3)))
352 (declare (dynamic-extent x
))
353 (let ((child (sb-thread:make-thread
355 (sb-introspect:allocation-information x
)))))
356 (equal (list :stack sb-thread
:*current-thread
*)
357 (multiple-value-list (sb-thread:join-thread child
))))))
359 (deftest allocation-information.thread
.2
363 (defun thread-tai2 ()
364 (let* ((sem (sb-thread:make-semaphore
))
366 (child (sb-thread:make-thread
368 (let ((x (list 1 2 3)))
369 (declare (dynamic-extent x
))
371 (sb-thread:wait-on-semaphore sem
)))
375 (equal (list :stack child
)
377 (sb-introspect:allocation-information obj
)))
378 (sb-thread:signal-semaphore sem
)
379 (sb-thread:join-thread child
))))
381 (deftest allocation-information.thread
.3
385 ;;;; Test FUNCTION-TYPE
387 (defun type-equal (typespec1 typespec2
)
388 (or (equal typespec1 typespec2
) ; TYPE= punts on &keywords in FTYPEs.
389 (sb-kernel:type
= (sb-kernel:values-specifier-type typespec1
)
390 (sb-kernel:values-specifier-type typespec2
))))
392 (defmacro interpret
(form)
393 `(let ((sb-ext:*evaluator-mode
* :interpret
))
398 (declaim (ftype (function (integer &optional string
) string
) moon
))
399 (defun moon (int &optional suffix
)
400 (concatenate 'string
(princ-to-string int
) suffix
))
402 (deftest function-type
.1
403 (values (type-equal (function-type 'moon
) (function-type #'moon
))
404 (type-equal (function-type #'moon
)
405 '(function (integer &optional string
)
406 (values string
&rest t
))))
409 (defun sun (x y
&key k1
)
410 (declare (fixnum x y
))
411 (declare (boolean k1
))
412 (declare (ignore x y k1
))
415 (deftest function-type
.2
416 (values (type-equal (function-type 'sun
) (function-type #'sun
))
417 (type-equal (function-type #'sun
)
418 '(function (fixnum fixnum
&key
(:k1
(member nil t
)))
419 (values (member t
) &optional
))))
424 (deftest function-type
.5
427 (values (symbol-name s
))))
428 (type-equal (function-type #'f
)
429 (if (expect-wild-return-type-p #'f
)
430 '(function (symbol) *)
431 '(function (symbol) (values simple-string
&optional
)))))
436 (deftest function-type
.6
442 (type-equal (function-type #'closure
)
443 (if (expect-wild-return-type-p #'closure
)
444 '(function (fixnum) *)
445 '(function (fixnum) (values fixnum
&optional
))))))
448 ;; Anonymous functions
450 (deftest function-type
.7
451 (let ((f #'(lambda (x) (declare (fixnum x
)) x
)))
452 (type-equal (function-type f
)
453 (if (expect-wild-return-type-p f
)
454 '(function (fixnum) *)
455 '(function (fixnum) (values fixnum
&optional
)))))
458 ;; Interpreted functions
461 (deftest function-type
.8
462 (type-equal (function-type (interpret (lambda (x) (declare (fixnum x
)) x
)))
463 '(function (&rest t
) *))
468 (defgeneric earth
(x y
))
470 (deftest function-type
+gfs
.1
471 (values (type-equal (function-type 'earth
) (function-type #'earth
))
472 (type-equal (function-type 'earth
) '(function (t t
) *)))
475 ;; Implicitly created generic functions.
477 ;; (FUNCTION-TYPE 'MARS) => FUNCTION at the moment. (1.0.31.26)
481 (defmethod mars (x y
) (+ x y
))
484 (deftest function-type
+gfs
.2
485 (values (type-equal (function-type 'mars
) (function-type #'mars
))
486 (type-equal (function-type 'mars
) '(function (t t
) *)))
491 (defstruct (struct (:predicate our-struct-p
)
492 (:copier copy-our-struct
))
495 ;; This test doesn't work because the XEP for the out-of-line accessor
496 ;; does not include the type test, and the function gets a signature
497 ;; of (FUNCTION (T) (VALUES FIXNUM &OPTIONAL)). This can easily be fixed
498 ;; by deleting (THE <struct> INSTANCE) from the access form
499 ;; and correspondingly adding a declaration on the type of INSTANCE.
501 ;; Yes, it can be fixed, but it is done this way because it produces
504 (deftest function-type
+defstruct
.1
505 (values (type-equal (function-type 'struct-a
)
506 (function-type #'struct-a
))
507 (type-equal (function-type 'struct-a
)
508 '(function (struct) (values fixnum
&optional
))))
511 (deftest function-type
+defstruct
.2
512 (values (type-equal (function-type 'our-struct-p
)
513 (function-type #'our-struct-p
))
514 (type-equal (function-type 'our-struct-p
)
515 '(function (t) (values (member t nil
) &optional
))))
518 (deftest function-type
+defstruct
.3
519 (values (type-equal (function-type 'copy-our-struct
)
520 (function-type #'copy-our-struct
))
521 (type-equal (function-type 'copy-our-struct
)
522 '(function (struct) (values struct
&optional
))))
525 (defstruct (typed-struct :named
(:type list
)
526 (:predicate typed-struct-p
))
529 (deftest function-type
+defstruct
.4
530 (values (type-equal (function-type 'typed-struct-a
)
531 (function-type #'typed-struct-a
))
532 (type-equal (function-type 'typed-struct-a
)
533 '(function (list) (values fixnum
&optional
))))
536 (deftest function-type
+defstruct
.5
537 (values (type-equal (function-type 'typed-struct-p
)
538 (function-type #'typed-struct-p
))
539 (type-equal (function-type 'typed-struct-p
)
540 '(function (t) (values (member t nil
) &optional
))))
547 (defun (setf sun
) (value x y
&key k1
)
548 (declare (boolean value
))
549 (declare (fixnum x y
))
550 (declare (boolean k1
))
551 (declare (ignore x y k1
))
554 (deftest function-type
+setf
.1
555 (values (type-equal (function-type '(setf sun
))
556 (function-type #'(setf sun
)))
557 (type-equal (function-type '(setf sun
))
558 '(function ((member nil t
)
560 &key
(:k1
(member nil t
)))
561 (values (member nil t
) &optional
))))
566 (deftest function-type
+misc
.1
568 (type-equal (function-type #'nullary
)
569 (if (expect-wild-return-type-p #'nullary
)
571 '(function () (values null
&optional
)))))
574 ;;; Defstruct accessor, copier, and predicate
576 (deftest defstruct-fun-sources
577 (let ((copier (find-definition-source #'cl-user
::copy-three
))
578 (accessor (find-definition-source #'cl-user
::three-four
))
579 (predicate (find-definition-source #'cl-user
::three-p
)))
580 (values (and (equalp copier accessor
)
581 (equalp copier predicate
))
582 (equal "TEST.LISP.NEWEST"
583 (file-namestring (definition-source-pathname copier
)))
585 (definition-source-form-path copier
))))
590 (deftest defstruct-fun-sources-by-name
591 (let ((copier (car (find-definition-sources-by-name 'cl-user
::copy-three
:function
)))
592 (accessor (car (find-definition-sources-by-name 'cl-user
::three-four
:function
)))
593 (predicate (car (find-definition-sources-by-name 'cl-user
::three-p
:function
))))
594 (values (and (equalp copier accessor
)
595 (equalp copier predicate
))
596 (equal "TEST.LISP.NEWEST"
597 (file-namestring (definition-source-pathname copier
)))
599 (definition-source-form-path copier
))))
604 (deftest alien-type
.1
605 (matchp-name :alien-type
'cl-user
::test-alien-type
30)
608 (deftest alien-type
.2
609 (matchp-name :alien-type
'cl-user
::test-alien-struct
31)
612 (deftest alien-variable
613 (matchp-name :variable
'cl-user
::test-alien-var
32)
616 (deftest condition-slot-reader
617 (matchp-name :method
'cl-user
::condition-slot-reader
33)
620 (deftest condition-slot-writer
621 (matchp-name :method
'cl-user
::condition-slot-writer
33)