(assert (= (substandard-defgeneric 1 2) 3))
(assert (string= (substandard-defgeneric "1" "2") "12"))
\f
+(let* ((x (find-class 'pathname))
+ (xs (class-direct-subclasses x)))
+ (assert (>= (length xs) 1))
+ (assert (member (find-class 'logical-pathname) xs)))
+
+;;; BUG 338: "MOP specializers as type specifiers"
+;;; (reported by Bruno Haible sbcl-devel 2004-06-11)
+(let* ((m (defmethod eql-specialized-method ((x (eql 4.0))) 3.0))
+ (spec (first (sb-mop:method-specializers m))))
+ (assert (not (typep 1 spec)))
+ (assert (typep 4.0 spec)))
+\f
+;;; BUG #334, relating to programmatic addition of slots to a class
+;;; with COMPUTE-SLOTS.
+;;;
+;;; FIXME: the DUMMY classes here are to prevent class finalization
+;;; before the compute-slots method is around. This should probably
+;;; be done by defining the COMPUTE-SLOTS methods on a metaclass,
+;;; which can be defined before.
+;;;
+;;; a. adding an :allocation :instance slot
+(defclass class-to-add-instance-slot (dummy-ctais) ())
+(defmethod compute-slots ((c (eql (find-class 'class-to-add-instance-slot))))
+ (append (call-next-method)
+ (list (make-instance 'standard-effective-slot-definition
+ :name 'y
+ :allocation :instance))))
+(defclass dummy-ctais () ((x :allocation :class)))
+(assert (equal (mapcar #'slot-definition-allocation
+ (class-slots (find-class 'class-to-add-instance-slot)))
+ ;; FIXME: is the order really guaranteed?
+ '(:class :instance)))
+(assert (typep (slot-definition-location
+ (cadr (class-slots (find-class 'class-to-add-instance-slot))))
+ 'unsigned-byte))
+#| (assert (typep (slot-definition-location (car ...)) '???)) |#
+(let ((x (make-instance 'class-to-add-instance-slot)))
+ (assert (not (slot-boundp x 'x)))
+ (setf (slot-value x 'x) t)
+ (assert (not (slot-boundp x 'y)))
+ (setf (slot-value x 'y) 1)
+ (assert (= 1 (slot-value x 'y))))
+(let ((x (make-instance 'class-to-add-instance-slot)))
+ (assert (slot-boundp x 'x))
+ (assert (eq t (slot-value x 'x)))
+ (assert (not (slot-boundp x 'y))))
+
+;;; b. adding an :allocation :class slot
+(defclass class-to-add-class-slot (dummy-ctacs) ())
+(defmethod compute-slots ((c (eql (find-class 'class-to-add-class-slot))))
+ (append (call-next-method)
+ (list (make-instance 'standard-effective-slot-definition
+ :name 'y
+ :allocation :class))))
+(defclass dummy-ctacs () ((x :allocation :class)))
+(assert (equal (mapcar #'slot-definition-allocation
+ (class-slots (find-class 'class-to-add-class-slot)))
+ '(:class :class)))
+(let ((x (make-instance 'class-to-add-class-slot)))
+ (assert (not (slot-boundp x 'x)))
+ (setf (slot-value x 'x) nil)
+ (assert (not (slot-boundp x 'y)))
+ (setf (slot-value x 'y) 1)
+ (assert (= 1 (slot-value x 'y))))
+(let ((x (make-instance 'class-to-add-class-slot)))
+ (assert (slot-boundp x 'x))
+ (assert (eq nil (slot-value x 'x)))
+ (assert (slot-boundp x 'y))
+ (assert (= 1 (slot-value x 'y))))
+;;; extra paranoia: check that we haven't broken the instance-slot class
+(let ((x (make-instance 'class-to-add-instance-slot)))
+ (assert (slot-boundp x 'x))
+ (assert (eq t (slot-value x 'x)))
+ (assert (not (slot-boundp x 'y))))
+\f
+;;;; the CTOR optimization was insufficiently careful about its
+;;;; assumptions: firstly, it failed with a failed AVER for
+;;;; non-standard-allocation slots:
+(defclass class-with-frob-slot ()
+ ((frob-slot :initarg :frob-slot :allocation :frob)))
+(handler-case
+ (funcall (compile nil '(lambda ()
+ (make-instance 'class-with-frob-slot
+ :frob-slot 1))))
+ (sb-int:bug (c) (error c))
+ (error () "Probably OK: haven't implemented SLOT-BOUNDP-USING-CLASS"))
+;;; secondly, it failed to take account of the fact that we might wish
+;;; to customize (setf slot-value-using-class)
+(defclass class-with-special-ssvuc ()
+ ((some-slot :initarg :some-slot)))
+(defvar *special-ssvuc-counter* 0)
+(defmethod (setf slot-value-using-class) :before
+ (new-value class (instance class-with-special-ssvuc) slotd)
+ (incf *special-ssvuc-counter*))
+(let ((fun (compile nil '(lambda () (make-instance 'class-with-special-ssvuc
+ :some-slot 1)))))
+ (assert (= *special-ssvuc-counter* 0))
+ (funcall fun)
+ (assert (= *special-ssvuc-counter* 1))
+ (funcall fun)
+ (assert (= *special-ssvuc-counter* 2)))
+;;; and now with the customization after running the function once
+(defclass class-with-special-ssvuc-2 ()
+ ((some-slot :initarg :some-slot)))
+(defvar *special-ssvuc-counter-2* 0)
+(let ((fun (compile nil '(lambda () (make-instance 'class-with-special-ssvuc-2
+ :some-slot 1)))))
+ (assert (= *special-ssvuc-counter-2* 0))
+ (funcall fun)
+ (assert (= *special-ssvuc-counter-2* 0))
+ (defmethod (setf slot-value-using-class) :before
+ (new-value class (instance class-with-special-ssvuc-2) slotd)
+ (incf *special-ssvuc-counter-2*))
+ (funcall fun)
+ (assert (= *special-ssvuc-counter-2* 1)))
+\f
;;;; success
(sb-ext:quit :unix-status 104)