1 ;;;; various tests of the new interpreter
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
15 (sb-ext:exit
:code
104)
17 (setf sb-ext
:*evaluator-mode
* :interpret
)
19 (in-package sb-interpreter
)
21 (test-util:with-test
(:name
:type-checker-for-function
)
22 ;; The test for (FUNCTION (HAIR) (MORE-HAIR)) is just FUNCTIONP.
23 ;; The test for not that is (NOT FUNCTION).
24 (assert (eq (type-checker (specifier-type '(function (cons) cons
)))
26 (assert (type-checker (specifier-type
27 '(not (function (integer) integer
))))))
29 (defvar *invocation-count
* 0)
31 (defmacro what-cell
(x)
32 (incf *invocation-count
*)
35 (defun foo (x &optional
(howmuch 1)) (incf (what-cell x
) howmuch
))
37 (test-util:with-test
(:name
:interpreter-macro-cache-flush
)
38 (let ((cell (cons 0 0)))
42 (assert (= *invocation-count
* 1)) ; once only
43 (assert (= (car cell
) 3))
44 (defmacro what-cell
(x)
45 (incf *invocation-count
*)
47 ;; Even though INCF's definition is unchanged, the expansion of INCF
48 ;; is invalidated by the change to the definition of WHAT-CELL.
52 (assert (= *invocation-count
* 2)) ; once more
53 (assert (= (cdr cell
) 30))))
55 (test-util:with-test
(:name
:interpreter-eval-if-cond-nil-nil
)
57 (flet ((foo () (setq x
1)))
58 ;; this was accidentally optimizing out the call to FOO
62 (defmacro expect-type-error
(form)
65 (:no-error
() (error "Should have gotten a TYPE-ERROR"))))
67 (defmacro expect-bad-key-error
(form)
70 (assert (search "not in the allowed set"
71 (write-to-string c
:escape nil
))))
72 (:no-error
() (error "Expected an error"))))
74 (defmacro expect-odd-keys-error
(form)
77 (assert (search "odd number" (simple-condition-format-control c
))))
78 (:no-error
() (error "Expected an error"))))
80 (test-util:with-test
(:name
:interpreter-keyword-parsing
)
82 ;; No error - &allow-other-keys was specified.
83 (validate-keywords '(:foo
3 :bar
2 :baz
3) 1 #(:foo
))
85 (expect-odd-keys-error (validate-keywords '(:bar
) 1 #(:foo
)))
87 ;; :ALLOW-OTHER-KEYS key is always allowed even if its value is nil.
88 (validate-keywords '(:a
1 :allow-other-keys nil
:b
2)
89 (ash 3 3) #(:a
:b
:c
))
93 (validate-keywords '(:a
1 :x nil
:b
2) (ash 3 3) #(:a
:b
:c
)))
95 ;; As with all keywords, only the first value matters.
97 (validate-keywords '(:a
1 :allow-other-keys nil
:allow-other-keys t
:x
2)
98 (ash 3 3) #(:a
:b
:c
)))
101 (validate-keywords '(:a
1 :allow-other-keys t
:allow-other-keys nil
:x
2)
102 (ash 3 3) #(:a
:b
:c
))
103 ;; here we short-cicuit after seeing T but still have to check for ODDP
104 (expect-odd-keys-error
105 (validate-keywords '(:a
1 :allow-other-keys t
:allow-other-keys nil
:x
)
106 (ash 3 3) #(:a
:b
:c
)))
108 (defun foo (x &optional b c
&key akey
) (list x b c akey
))
109 ;; The ODDP check occurs only on actual args that remain after
110 ;; processing optional arguments.
111 ;; No errors should result from these calls.
114 (foo 1 2 3 :akey
'hi
))
116 (test-util:with-test
(:name
:interpreter-type-checking
)
118 (expect-type-error (the integer
(values 'a
1 2)))
121 (locally (declare (optimize (safety 0))) (the integer
(values 'a
1 2)))
123 ;; THE returns multiple values even if not a VALUES type-specifier.
124 (let ((l (multiple-value-call #'list
125 (the integer
(values 1 'foo
'bar
)))))
126 (assert (= (length l
) 3)))
128 ;; Too many values in a "strict" THE form are not permitted.
129 (expect-type-error (the (values integer
&optional
) (values 1 2)))
131 ;; A trailing type of which NIL is a member (so LIST,SYMBOL,T at least)
132 ;; causes (THE VALUES ...) to accept absence of a value. By definition the
133 ;; missing values are NIL. While this seems liberal, so far as VALUES
134 ;; expressing a shape similar to DESTRUCTURING-BIND, CLHS draws attention
135 ;; to it specifically:
137 ;; "It is permissible for _form_ to yield a different number of values than
138 ;; are specified by value-type, provided that the values for which types are
139 ;; declared are indeed of those types. Missing values are treated as nil
140 ;; for the purpose of checking their types"
141 (dolist (trailing-type '(symbol t
))
142 (eval `(the (values integer
,trailing-type
) 4))
143 (eval `(the (values integer
,trailing-type
) (values 4 'foo
)))
144 (eval `(the (values integer
,trailing-type
) (values 4 'foo
5))))
146 ;; But a strict THE form does not allow this liberty.
147 (expect-type-error (the (values integer symbol
&optional
) 4))
150 (defun g (x) (length (string x
)))
157 ;; The first binding of X in h is to a symbol, which is fine.
158 ;; The FIXNUM declaration applies to the _second_ binding named X.
161 ;; The SETQ is not valid because X is restricted to fixnum.
165 (declare (fixnum x
))))
168 (the (values integer symbol
&optional string
) (bar)))
170 (the (values integer symbol string
) (bar)))
172 (the (values integer
&optional
) (bar)))
174 (defun bar () (values 1 'hi
))
177 (expect-type-error (foo2)) ; didn't get a string as 3rd value
178 (expect-type-error (foo3)) ; got too many values
181 (the (values integer symbol string
) (bar)))
183 (defun no-vals () (values))
185 (handler-case (let ((x (the integer
(no-vals)))) x
)
187 (:no-error
() (error "Should have gotten an ERROR")))
189 (defmacro nice-macro
(a b
)
190 (declare (type (member :first
:second
) a
))
193 (:second
`(cadr ,b
))))
195 (assert (equal (macroexpand-1 '(nice-macro :first
(x)))
197 ;; macro should fail.
198 (expect-type-error (macroexpand '(nice-macro :third
(x))))
200 ;; SETQ of MUMBLE which is a "free" (not bound) typed special variable
202 (let* ((foo 3) (baz foo
))
203 (declare (special foo mumble
) (real mumble
))
208 (declare (special x
) (integer x
))
213 (locally (declare (special x
))
215 ;; this references the special X, not the lexical X
218 ;; This works due to short-circuiting within TYPEP
219 (let ((x 3)) (declare (type (or integer blurf
) x
)) x
)
221 ;; This fails because the unknown type is tested first
222 (handler-case (let ((x 3)) (declare (type (or blurf integer
) x
)) x
)
223 (simple-error ()) ; "unknown type"
224 (:no-error
() "Expected an ERROR")))
226 (test-util:with-test
(:name
:tagbody-if-optimizer
)
229 (with-output-to-string (*standard-output
*)
242 (macrolet ((foo= (x y
) `(= (the fixnum
,x
) (the fixnum
,y
))))
243 (declare (optimize speed
))
244 (declaim (inline foo-compare
))
245 (defun foo-compare (a b
) (foo= a b
)))
247 (test-util:with-test
(:name
:inline-lexenv-not-too-hairy
)
248 (assert (sb-c::fun-name-inline-expansion
'foo-compare
)))
250 (defmacro use-hairy-env
(x &environment e
)
252 (eql (sb-interpreter::env-from-lexenv e
) :compile
)
253 (sb-int:eval-in-lexenv x e
)))
255 ;;; Assert that USE-HAIRY-ENV can be invoked such that when it calls
256 ;;; EVAL-IN-LEXENV on an environment object that is too complex,
257 ;;; it works anyway. Of course don't actually do this :-)
258 ;;; Arguably the interpreter could be modified such that it only chokes
259 ;;; if you _actually_ try to reference parts of the complex lexenv
260 ;;; that you're not allowed to, but that's a whole other ball of wax.
261 (test-util:with-test
(:name
:eval-in-complex-lexenv
)
263 (funcall (compile nil
'(lambda (a) (cons a
(use-hairy-env (+ 1 2)))))
265 (assert (eql (first answer
) 45))
266 ;; ensure that the lambda environment could not be handled by the interpreter
267 (assert (eql (second answer
) t
))
268 (assert (eql (third answer
) 3))))
270 (test-util:with-test
(:name
:exited-block
)
271 (handler-case (funcall (let ((x 1)) (block b
(lambda () (return-from b
)))))
273 (assert (and (typep c
'sb-int
:simple-control-error
)
274 (search "exited block" (simple-condition-format-control c
)))))
275 (:no-error
(&rest whatever
) (error "Expected an error"))))
277 (test-util:with-test
(:name
:exited-tagbody
)
278 (handler-case (funcall
281 (return-from zot
(let ((x 1)) (lambda () (go foo
))))
284 (assert (and (typep c
'sb-int
:simple-control-error
)
285 (search "exited tagbody"
286 (simple-condition-format-control c
)))))
287 (:no-error
(&rest whatever
) (error "Expected an error"))))