SXHASH-related changes in the layout of CLOS data structures
changes in sbcl-0.7.11 relative to sbcl-0.7.10:
- * fixed some bugs shown by Paul Dietz' test suite:
+ * fixed some more bugs revealed by Paul Dietz' test suite:
** As required by ANSI, LOOP now disallows anonymous collection
clauses such as COLLECT I in conjunction with aggregate boolean
clauses such as THEREIS (= I 1);
+ ** LOOP now signals an error when any variable is reused in the
+ same loop (including the potentially useful construct analogous
+ to WITH A = 1 WITH A = (1+ A);
+ ** IT is only a special loop symbol within the first clause of a
+ conditional loop clause;
planned incompatible changes in 0.7.x:
* (not done yet, but planned:) When the profiling interface settles
*loop-desetq-crocks* nil
*loop-wrappers* nil)))
+(defun loop-var-p (name)
+ (do ((entry *loop-bind-stack* (cdr entry)))
+ (nil)
+ (cond
+ ((null entry) (return nil))
+ ((assoc name (caar entry) :test #'eq) (return t)))))
+
(defun loop-make-var (name initialization dtype &optional iteration-var-p)
(cond ((null name)
(cond ((not (null initialization))
(loop-make-var (gensym "LOOP-BIND-") form data-type)))
\f
(defun loop-do-if (for negatep)
- (let ((form (loop-get-form)) (*loop-inside-conditional* t) (it-p nil))
+ (let ((form (loop-get-form))
+ (*loop-inside-conditional* t)
+ (it-p nil)
+ (first-clause-p t))
(flet ((get-clause (for)
(do ((body nil)) (nil)
(let ((key (car *loop-source-code*)) (*loop-body* nil) data)
key for))
(t (setq *loop-source-context* *loop-source-code*)
(loop-pop-source)
- (when (loop-tequal (car *loop-source-code*) 'it)
+ (when (and (loop-tequal (car *loop-source-code*) 'it)
+ first-clause-p)
(setq *loop-source-code*
(cons (or it-p
(setq it-p
"~S does not introduce a LOOP clause that can follow ~S."
key for))
(t (setq body (nreconc *loop-body* body)))))))
+ (setq first-clause-p nil)
(if (loop-tequal (car *loop-source-code*) :and)
(loop-pop-source)
(return (if (cdr body)
(let ((cruft (find (the symbol name) *loop-collection-cruft*
:key #'loop-collector-name)))
(cond ((not cruft)
+ (when (and name (loop-var-p name))
+ (loop-error "Variable ~S in INTO clause is a duplicate" name))
(push (setq cruft (make-loop-collector
:name name :class class
:history (list collector) :dtype dtype))
(loop-pop-source)
(loop-get-form))
(t nil)))
+ (when (and var (loop-var-p var))
+ (loop-error "Variable ~S has already been used" var))
(loop-make-var var val dtype)
(if (loop-tequal (car *loop-source-code*) :and)
(loop-pop-source)
(ignore-errors
(loop for i in '(1 2 3) thereis (= i 3) collect i))
(assert (null result))
- (assert (typep error 'program-error)))
\ No newline at end of file
+ (assert (typep error 'program-error)))
+
+(multiple-value-bind (result error)
+ (ignore-errors
+ (loop with i = 1 for x from 1 to 3 collect x into i))
+ (assert (null result))
+ (assert (typep error 'program-error)))
+(multiple-value-bind (result error)
+ ;; this one has a plausible interpretation in terms of LET*, but
+ ;; ANSI seems specifically to disallow it
+ (ignore-errors
+ (loop with i = 1 with i = (1+ i)
+ for x from 1 to 3
+ collect (+ x i)))
+ (assert (null result))
+ (assert (typep error 'program-error)))
+
+(let ((it 'z))
+ (assert (equal
+ ;; this one just seems weird. Nevertheless...
+ (loop for i in '(a b c d)
+ when i
+ collect it
+ and collect it)
+ '(a z b z c z d z))))
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.7.10.1"
+"0.7.10.2"