;;;; -*- coding: utf-8; fill-column: 78 -*-
changes relative to sbcl-1.1.6
+ * bug fix: CLASS-DIRECT-DEFAULT-INITARGS now works for condition classes
+ (lp#1164970)
+ * bug fix: function constants now work as initforms and default initarg
+ values of conditions (lp#539517)
* bug fix: svref/(setf svref) on symbol macros don't crash the compiler
anymore. (Minimal test case provided by James M. Lawrence on sbcl-devel)
* bug fix: no more bogus ## references when pretty printing backquoted
;; ..and macros..
"COLLECT"
- "DO-ANONYMOUS" "DOHASH" "DOVECTOR"
+ "DO-ANONYMOUS" "DOVECTOR" "DOHASH" "DOPLIST"
"NAMED-LET"
"ONCE-ONLY"
"DEFENUM"
(class-slots nil :type list)
;; report function or NIL
(report nil :type (or function null))
- ;; list of alternating initargs and initforms
- (default-initargs () :type list)
+ ;; list of specifications of the form
+ ;;
+ ;; (INITARG INITFORM THUNK)
+ ;;
+ ;; where THUNK, when called without arguments, returns the value for
+ ;; INITARG.
+ (direct-default-initargs () :type list)
;; class precedence list as a list of CLASS objects, with all
;; non-CONDITION classes removed
(cpl () :type list)
(defun find-slot-default (class slot)
(let ((initargs (condition-slot-initargs slot))
(cpl (condition-classoid-cpl class)))
+ ;; When CLASS or a superclass has a default initarg for SLOT, use
+ ;; that.
(dolist (class cpl)
- (let ((default-initargs (condition-classoid-default-initargs class)))
+ (let ((direct-default-initargs
+ (condition-classoid-direct-default-initargs class)))
(dolist (initarg initargs)
- (let ((val (getf default-initargs initarg *empty-condition-slot*)))
- (unless (eq val *empty-condition-slot*)
- (return-from find-slot-default
- (if (functionp val)
- (funcall val)
- val)))))))
+ (let ((initfunction (third (assoc initarg direct-default-initargs))))
+ (when initfunction
+ (return-from find-slot-default (funcall initfunction)))))))
+ ;; Otherwise use the initform of SLOT, if there is one.
(if (condition-slot-initform-p slot)
(let ((initform (condition-slot-initform slot)))
(if (functionp initform)
:datum type
:expected-type 'condition-class
:format-control
- "~s doesn't designate a condition class."
+ "~s does not designate a condition class."
:format-arguments (list type)))))
(res (make-condition-object args)))
(setf (%instance-layout res) (classoid-layout class))
report))
(defun %define-condition (name parent-types layout slots documentation
- default-initargs all-readers all-writers
+ direct-default-initargs all-readers all-writers
source-location)
(with-single-package-locked-error
(:symbol name "defining ~A as a condition")
(setf (layout-source-location layout)
source-location))
(let ((class (find-classoid name)))
- (setf (condition-classoid-slots class) slots)
- (setf (condition-classoid-default-initargs class) default-initargs)
- (setf (fdocumentation name 'type) documentation)
+ (setf (condition-classoid-slots class) slots
+ (condition-classoid-direct-default-initargs class) direct-default-initargs
+ (fdocumentation name 'type) documentation)
(dolist (slot slots)
(let ((eslots (compute-effective-slots class))
(e-def-initargs
(reduce #'append
- (mapcar #'condition-classoid-default-initargs
- (condition-classoid-cpl class)))))
+ (mapcar #'condition-classoid-direct-default-initargs
+ (condition-classoid-cpl class)))))
(dolist (slot eslots)
(ecase (condition-slot-allocation slot)
(:class
(setf (condition-slot-allocation slot) :instance)
(when (or (functionp (condition-slot-initform slot))
(dolist (initarg (condition-slot-initargs slot) nil)
- (when (functionp (getf e-def-initargs initarg))
+ (when (functionp (third (assoc initarg e-def-initargs)))
(return t))))
(push slot (condition-classoid-hairy-slots class)))))))
(when (boundp '*define-condition-hooks*)
(layout (find-condition-layout name parent-types))
(documentation nil)
(report nil)
- (default-initargs ()))
+ (direct-default-initargs ()))
(collect ((slots)
(all-readers nil append)
(all-writers nil append))
:writers ',(writers)
:initform-p ',initform-p
:documentation ',documentation
- :initform
- ,(if (sb!xc:constantp initform)
- `',(constant-form-value initform)
- `#'(lambda () ,initform)))))))
+ :initform ,(when initform-p
+ `#'(lambda () ,initform)))))))
(dolist (option options)
(unless (consp option)
`#'(lambda (condition stream)
(funcall #',arg condition stream))))))
(:default-initargs
- (do ((initargs (rest option) (cddr initargs)))
- ((endp initargs))
- (let ((val (second initargs)))
- (setq default-initargs
- (list* `',(first initargs)
- (if (sb!xc:constantp val)
- `',(constant-form-value val)
- `#'(lambda () ,val))
- default-initargs)))))
+ (doplist (initarg initform) (rest option)
+ (push ``(,',initarg ,',initform ,#'(lambda () ,initform))
+ direct-default-initargs)))
(t
(error "unknown option: ~S" (first option)))))
',layout
(list ,@(slots))
,documentation
- (list ,@default-initargs)
+ (list ,@direct-default-initargs)
',(all-readers)
',(all-writers)
(sb!c:source-location))
(eq (car clause) 'ignore))))
(cdr decl))))
decls))
-
;;; just like DOLIST, but with one-dimensional arrays
(defmacro dovector ((elt vector &optional result) &body body)
(multiple-value-bind (forms decls) (parse-body body :doc-string-allowed nil)
`(with-locked-system-table (,n-table)
,iter-form)
iter-form))))))
+
+;;; Executes BODY for all entries of PLIST with KEY and VALUE bound to
+;;; the respective keys and values.
+(defmacro doplist ((key val) plist &body body)
+ (with-unique-names (tail)
+ `(let ((,tail ,plist) ,key ,val)
+ (loop (when (null ,tail) (return nil))
+ (setq ,key (pop ,tail))
+ (when (null ,tail)
+ (error "malformed plist, odd number of elements"))
+ (setq ,val (pop ,tail))
+ (progn ,@body)))))
+
\f
;;;; hash cache utility
(/show "pcl/macros.lisp 85")
-(defmacro doplist ((key val) plist &body body)
- `(let ((.plist-tail. ,plist) ,key ,val)
- (loop (when (null .plist-tail.) (return nil))
- (setq ,key (pop .plist-tail.))
- (when (null .plist-tail.)
- (error "malformed plist, odd number of elements"))
- (setq ,val (pop .plist-tail.))
- (progn ,@body))))
-
(/show "pcl/macros.lisp 101")
(defmacro dolist-carefully ((var list improper-list-handler) &body body)
&key direct-slots direct-superclasses)
(declare (ignore slot-names))
(let ((classoid (find-classoid (slot-value class 'name))))
- (with-slots (wrapper %class-precedence-list cpl-available-p
- prototype (direct-supers direct-superclasses))
+ (with-slots (wrapper
+ %class-precedence-list cpl-available-p finalized-p
+ prototype (direct-supers direct-superclasses)
+ plist)
class
(setf (slot-value class 'direct-slots)
(mapcar (lambda (pl) (make-direct-slotd class pl))
- direct-slots))
- (setf (slot-value class 'finalized-p) t)
- (setf (classoid-pcl-class classoid) class)
- (setq direct-supers direct-superclasses)
- (setq wrapper (classoid-layout classoid))
- (setq %class-precedence-list (compute-class-precedence-list class))
- (setq cpl-available-p t)
+ direct-slots)
+ finalized-p t
+ (classoid-pcl-class classoid) class
+ direct-supers direct-superclasses
+ wrapper (classoid-layout classoid)
+ %class-precedence-list (compute-class-precedence-list class)
+ cpl-available-p t
+ (getf plist 'direct-default-initargs)
+ (sb-kernel::condition-classoid-direct-default-initargs classoid))
(add-direct-subclasses class direct-superclasses)
(let ((slots (compute-slots class)))
(setf (slot-value class 'slots) slots)
(return-from restart-test-finds-restarts 42))
:test-function
(lambda (condition)
+ (declare (ignore condition))
(find-restart 'qux))))
(when (find-restart 'bar)
(invoke-restart 'bar))))
(assert
(eq (eval `(define-condition ,name () ()))
name))))
+
+;;; bug-1164970
+
+(define-condition condition-with-default-initargs (condition)
+ ()
+ (:default-initargs :foo 1))
+
+(with-test (:name (sb-mop:class-direct-default-initargs :for-condition-class
+ :bug-1164970))
+ ;; CLASS-DIRECT-DEFAULT-INITARGS used to return nil for all
+ ;; condition classes.
+ (let ((initargs (sb-mop:class-direct-default-initargs
+ (find-class 'condition-with-default-initargs))))
+ (assert (equal (subseq (first initargs) 0 2) '(:foo 1)))))
+
+;;; bug-539517
+
+(defconstant +error-when-called+ (lambda () (error "oops")))
+
+(define-condition condition-with-constant-function-initarg ()
+ ((foo :initarg :foo
+ :reader condition-with-constant-function-initarg-foo))
+ (:default-initargs :foo +error-when-called+))
+
+(with-test (:name (:condition-with-constant-function-initarg :bug-539517))
+ ;; The default initarg handling for condition classes used to
+ ;; confuse constant functions (thus +ERROR-WHEN-CALLED+) and
+ ;; initfunctions. This lead to +ERROR-WHEN-CALLED+ being called as
+ ;; if it was an initfunction.
+ (assert (functionp
+ (condition-with-constant-function-initarg-foo
+ (make-condition 'condition-with-constant-function-initarg))))
+ (assert (functionp
+ (condition-with-constant-function-initarg-foo
+ (make-instance 'condition-with-constant-function-initarg)))))
+
+;; Same problem
+
+(define-condition condition-with-constant-function-initform ()
+ ((foo :initarg :foo
+ :reader condition-with-constant-function-initform-foo
+ :initform +error-when-called+)))
+
+(with-test (:name (:condition-with-constant-function-slot-initform))
+ (assert (functionp
+ (condition-with-constant-function-initform-foo
+ (make-condition 'condition-with-constant-function-initform))))
+ (assert (functionp
+ (condition-with-constant-function-initform-foo
+ (make-instance 'condition-with-constant-function-initform)))))