1 ;;;; miscellaneous tests of LOOP-related stuff
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.
14 (in-package "CL-USER")
16 (load "compiler-test-util.lisp")
18 ;;; The bug reported by Alexei Dejneka on sbcl-devel 2001-09-03
20 (assert (equal (let ((hash (make-hash-table)))
21 (setf (gethash 'key1 hash
) 'val1
)
22 (setf (gethash 'key2 hash
) 'val2
)
23 (sort (loop for key being each hash-key in hash
28 ;;; Bug 81, reported by Wolfhard Buss on cmucl-help 2001-02-14, was
29 ;;; fixed by Alexey Dejneka's patch on sbcl-devel 2001-09-30.
30 (assert (equal '(0.0
1.0 2.0 3.0)
31 (loop with
(a . b
) of-type float
= '(0.0 .
1.0)
32 and
(c . d
) of-type float
= '(2.0 .
3.0)
33 return
(list a b c d
))))
35 ;;; a bug reported and fixed by Alexey Dejneka sbcl-devel 2001-10-05:
36 ;;; The type declarations should apply, hence under Python's
37 ;;; declarations-are-assertions rule, the code should signal a type
38 ;;; error. (Except when running interpreted code)
39 #+#.
(cl:if
(cl:eq sb-ext
:*evaluator-mode
* :compile
) '(and) '(or))
40 (assert (typep (nth-value 1
44 of-type float
= '(5 .
5)
45 return
(list a b
))))))
48 ;;; bug 103, reported by Arthur Lemmens sbcl-devel 2001-05-05,
49 ;;; fixed by Alexey Dejneka patch sbcl-devel 2001-10-05:
50 ;;; LOOP syntax requires that forms after INITIALLY, FINALLY, and DO
51 ;;; must be compound forms.
52 (multiple-value-bind (function warnings-p failure-p
)
58 (declare (ignore function warnings-p
))
61 ;;; a bug reported by Paul F. Dietz (in his ANSI test suite):
62 ;;; duplicate bindings in LOOP must signal errors of type
64 (assert (typep (nth-value 1
67 (loop for
(a . a
) in
'((1 .
2) (3 .
4))
71 ;;; similar to gcl/ansi-test LOOP.1.27, and fixed at the same time:
72 (assert (equal (loop for x downto
7 by
2 from
13 collect x
) '(13 11 9 7)))
74 ;;; some more from gcl/ansi-test:
75 (let ((table (make-hash-table)))
76 (setf (gethash 'foo table
) '(bar baz
))
77 (assert (= (loop for nil being the hash-keys of table count t
) 1))
78 (assert (equal (loop for nil being the hash-keys of table
79 using
(hash-value (v1 . v2
))
84 (assert (= (loop for nil being the external-symbols of
:cl count t
) 978))
85 (assert (= (loop for x being the external-symbols of
:cl count x
) 977))
87 (let ((*package
* (find-package :cl
)))
88 (assert (= (loop for x being each external-symbol count t
) 978)))
90 (assert (eq (loop for a
= (return t
) return nil
) t
))
92 (multiple-value-bind (result error
)
94 (loop for nil being the external-symbols of
:nonexistent-package
96 (assert (null result
))
97 (assert (typep error
'package-error
)))
99 (assert (equal (loop for i from
1 repeat
(the (integer 7 7) 7) collect i
)
102 (multiple-value-bind (result error
)
104 (eval '(loop for i from
1 repeat
7 of-type fixnum collect i
)))
105 (assert (null result
))
106 (assert (typep error
'program-error
)))
109 (ignore-errors (loop for i from
1 repeat
6.5 collect i
))
110 (ignore-errors (loop for i from
1 repeat
(eval '6.5) collect i
))))
112 (assert (eq (block nil
113 (loop named foo do
(loop-finish) finally
(return :good
))
117 (assert (= (loop with
(a nil
) = '(1 2) return a
) 1))
118 (assert (= (loop with
(nil a
) = '(1 2) return a
) 2))
119 (assert (= (loop with
(a . nil
) = '(1 2) return a
) 1))
120 (assert (equal (loop with
(nil . a
) = '(1 2) return a
) '(2)))
122 (multiple-value-bind (result error
)
124 (loop for i in
'(1 2 3) collect i always
(< i
4)))
125 (assert (null result
))
126 (assert (typep error
'program-error
)))
128 (loop for i in
'(1 2 3) collect i into foo always
(< i
4)
129 finally
(return foo
))
132 (loop for i in
'(1 2 3) collect i into foo always
(= i
4)
133 finally
(return foo
))
135 (multiple-value-bind (result error
)
137 (loop for i in
'(1 2 3) always
(< i
4) collect i
))
138 (assert (null result
))
139 (assert (typep error
'program-error
)))
141 (loop for i in
'(1 2 3) always
(< i
4) collect i into foo
142 finally
(return foo
))
145 (loop for i in
'(1 2 3) always
(= i
4) collect i into foo
146 finally
(return foo
))
148 (multiple-value-bind (result error
)
150 (loop for i in
'(1 2 3) thereis
(= i
3) collect i
))
151 (assert (null result
))
152 (assert (typep error
'program-error
)))
154 (multiple-value-bind (result error
)
156 (loop with i
= 1 for x from
1 to
3 collect x into i
))
157 (assert (null result
))
158 (assert (typep error
'program-error
)))
159 (multiple-value-bind (result error
)
160 ;; this one has a plausible interpretation in terms of LET*, but
161 ;; ANSI seems specifically to disallow it
163 (loop with i
= 1 with i
= (1+ i
)
166 (assert (null result
))
167 (assert (typep error
'program-error
)))
171 ;; this one just seems weird. Nevertheless...
172 (loop for i in
'(a b c d
)
176 '(a z b z c z d z
))))
178 (let ((ht (make-hash-table)))
179 (setf (gethash 1 ht
) 3)
180 (setf (gethash 7 ht
) 15)
181 (assert (= (loop for v fixnum being each hash-key in ht sum v
) 8))
182 (assert (= (loop for v fixnum being each hash-value in ht sum v
) 18))
183 #+#.
(cl:if
(cl:eq sb-ext
:*evaluator-mode
* :compile
) '(and) '(or))
184 (assert-error (loop for v float being each hash-value in ht sum v
)
187 ;; arithmetic indexes can be NIL or symbols.
188 (assert (equal (loop for nil from
0 to
2 collect nil
)
190 (assert (equal (loop for nil to
2 collect nil
)
193 ;; although allowed by the loop syntax definition in 6.2/LOOP,
194 ;; 6.1.2.1.1 says: "The variable var is bound to the value of form1 in
195 ;; the first iteration[...]"; since we can't bind (i j) to anything,
196 ;; we give a program error.
197 (multiple-value-bind (function warnings-p failure-p
)
200 (loop for
(i j
) from
4 to
6 collect nil
)))
203 ;; ...and another for indexes without FROM forms (these are treated
204 ;; differently by the loop code right now
205 (multiple-value-bind (function warnings-p failure-p
)
208 (loop for
(i j
) to
6 collect nil
)))
214 (loop for d of-type double-float from
0d0 to
10d0 by x collect d
))
215 '(0d0 2d0
4d0
6d0
8d0
10d0
)))
219 (loop for d of-type double-float downfrom
10d0 to
0d0 by x collect d
))
220 '(10d0 8d0
6d0
4d0
2d0
0d0
)))
222 (let ((fn (handler-case
223 (compile nil
'(lambda ()
224 (declare (special x y
))
225 (loop thereis
(pop x
) thereis
(pop y
))))
226 (warning (c) (error "Warned: ~S" c
)))))
227 (let ((x (list nil nil
1))
228 (y (list nil
2 nil
)))
229 (declare (special x y
))
230 (assert (= (funcall fn
) 2))))
232 ;;; Incorrect LIST type declaration, reported and patched by Teemu
233 ;;; Kalvas: end testing is done "as if by atom" so this is supposed
235 (assert (equal '(1 2) (loop for
(a . b
) on
'(1 2 .
3) collect a
)))
237 ;;; Detection of duplicate bindings, reported by Bruno Haible for CMUCL.
238 (multiple-value-bind (_ condition
)
240 (macroexpand '(LOOP WITH A
= 0 FOR A DOWNFROM
10 TO
0 DO
(PRINT A
))))
242 (assert (typep condition
'program-error
)))
244 ;;; Loop variable with a range excluding 0, reported by Andras Simon.
245 ;;; (Used to signal an error during macroexpansion.)
246 (assert (not (loop with foo of-type
(single-float 1.0 2.0) = 1.5 do
(return))))
248 ;;; 1.0.26.12 used to signal a bogus type error for this.
249 (loop with x of-type
(simple-vector 1) = (make-array '(1))
253 (with-test (:name
:bug-540186
)
254 (let ((fun (compile nil
`(lambda (x)
255 (loop for i from
0 below
(length x
)
256 for vec of-type vector
= (aref x i
)
258 (assert (equal '("foo" "bar")
260 (vector "foo" "bar"))))))
262 (with-test (:name
:bug-lp613871
)
263 (multiple-value-bind (function warnings-p failure-p
)
264 (compile nil
'(lambda () (loop with nil
= 1 repeat
2 collect t
)))
265 (assert (null warnings-p
))
266 (assert (null failure-p
))
267 (assert (equal '(t t
) (funcall function
))))
268 (multiple-value-bind (function warnings-p failure-p
)
269 (compile nil
'(lambda () (loop with nil repeat
2 collect t
)))
270 (assert (null warnings-p
))
271 (assert (null failure-p
))
272 (assert (equal '(t t
) (funcall function
)))))
274 (with-test (:name
:bug-654220-regression
)
275 (assert (= 32640 (loop for i to
255
276 sum i into sum of-type fixnum
277 finally
(return sum
)))))
279 (with-test (:name
:of-type-character-init
)
280 ;; The intention here is to if we initialize C to NIL before iteration start
281 ;; by looking for tell-tale types such as (OR NULL CHARACTER). ...not the
282 ;; most robust test ever, no.
283 (let* ((fun (compile nil
`(lambda (x)
284 (loop for c of-type character in x
285 collect
(char-code c
)))))
286 (consts (ctu:find-code-constants fun
:type
'(or symbol list
))))
287 (assert (or (null consts
) (equal 'character consts
)))))
289 (with-test (:name
:type-of-nilled-vars
)
290 (assert (equal (loop for
(a b
) float
= '(1.0
2.0)
293 (assert (equal (loop for
(a nil b
) float
= '(1.0
3.0 2.0)
297 (with-test (:name
:misplaced-diclarations
)
299 (compile nil
`(lambda ()
300 (loop with
(a) = '(1.0
)
305 (with-test (:name
:duplicate-bindings
)
307 (funcall (compile nil
`(lambda ()
308 (loop with
(a b
) = '(1.0
2.0)
309 and
(c a
) = '(3.0
4.0)
310 return
(list a b c
))))))
312 (funcall (compile nil
`(lambda ()
314 with
((a) b
) = '((1.0
) 2.0)
315 return
(list a b
))))))
317 (funcall (compile nil
`(lambda ()
318 (loop with
(b) = '(10)
323 (funcall (compile nil
`(lambda ()
324 (loop with
(a) = '(3)
326 collect a into b
))))))
328 (with-test (:name
:multiple-maximize
)
330 (compile nil
`(lambda ()
331 (loop for x to
10 maximize x minimize x
)))
334 (compile nil
`(lambda ()
335 (loop for x to
10 minimize x minimize x
)))
338 (compile nil
`(lambda ()
339 (loop for x to
10 minimize x into z minimize x into z finally
(return z
))))
342 (with-test (:name
:destructuring-less
)
343 (assert (equal (loop with
(a b
) = '() repeat
1 collect
(list a b
))
346 (with-test (:name
:count-with-sum
)
347 (assert (= (loop repeat
1 count
1 sum
#c
(1 2))
349 (assert (= (loop repeat
1 sum
1 count
1)
352 (with-test (:name
:iterate-over-complex
)
355 (loop for c from
#c
(0 1) repeat
5 collect c
)
356 '(#C
(0 1) #C
(1 1) #C
(2 1) #C
(3 1) #C
(4 1)))))
358 (with-test (:name
:side-effecting-start-form
)
359 (assert (equal (let ((n 0))
360 (loop for x from
(incf n
) to
(+ n
5) collect x
))
363 (with-test (:name
:summing-complex
)
364 (assert (equal (loop for i from
1 to
4
365 sum
(complex i
(1+ i
)) of-type complex
)
368 (with-test (:name
:negative-repeat
)
369 (assert (zerop (let ((z 0))
370 (loop repeat
0 do
(incf z
))
372 (assert (zerop (let ((z 0))
373 (loop repeat -
1.5 do
(incf z
))
375 (assert (zerop (let ((z 0))
376 (loop repeat -
1.5 do
(incf z
))
378 (assert (zerop (let ((z 0))
379 (loop repeat -
1000000 do
(incf z
))
382 (with-test (:name
:of-type-character
)
383 (assert (null (loop with a t return a
)))
385 (assert (typep (loop with a of-type extended-char return a
) 'extended-char
))
386 (assert (typep (loop with a of-type character return a
) 'character
))
387 (assert (typep (loop with a of-type base-char return a
) 'base-char
))
388 (assert (typep (loop with a of-type standard-char return a
) 'standard-char
)))
390 (with-test (:name
:empty-type
)
392 (compile nil
`(lambda ()
393 (loop with a of-type
(and fixnum string
) return a
)))
396 (compile nil
`(lambda ()
397 (loop for i to
10 sum i of-type
(and fixnum string
))))
400 (with-test (:name
:loop-repeat-const
)
401 ;; without explicit constant-folding in LOOP-DO-REPEAT, the type of this loop's
402 ;; counter is INTEGER which unfortunately resulted in generic math throughout,
403 ;; since a FOR/THEN clause interacts badly with type inference.
404 ;; [if there is no FOR/THEN, the compiler understands the code better,
405 ;; and is able to infer a lower bound on decrementing from (+ 1 5)]
407 (compile nil
'(lambda ()
408 (declare (optimize speed
))
409 (loop repeat
(+ 1 5) for baz
= 'this then
'that
412 (with-test (:name
:loop-default-init-type
)
413 (assert-no-signal (compile nil
415 (declare (optimize speed
))
416 (loop for a of-type
(simple-vector 4) in list
417 collect
(aref a
2))))
418 sb-ext
:compiler-note
))
420 (with-test (:name
:with-destructuring
)
421 (assert (= (loop with
((a . b
)) = '((1 .
2))
424 (assert (= (loop with
(((a) b
)) = '(((1) 3))