X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=tests%2Fclos.impure.lisp;h=a94d8423ae89b7d99df0c45191519408cd0198c7;hb=3cc4b17d770f3fe95e5e94f6ac39820784968c4d;hp=03a3ee0439574cf514fab939a2d322a010ded4e7;hpb=ea652c139bb060d821f3010b3b106bdbcec983aa;p=sbcl.git diff --git a/tests/clos.impure.lisp b/tests/clos.impure.lisp index 03a3ee0..a94d842 100644 --- a/tests/clos.impure.lisp +++ b/tests/clos.impure.lisp @@ -11,9 +11,11 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(defpackage "FOO" - (:use "CL")) -(in-package "FOO") +(load "assertoid.lisp") + +(defpackage "CLOS-IMPURE" + (:use "CL" "ASSERTOID")) +(in-package "CLOS-IMPURE") ;;; It should be possible to do DEFGENERIC and DEFMETHOD referring to ;;; structure types defined earlier in the file. @@ -68,7 +70,7 @@ (assert (expect-error (defgeneric foo2 (x a &rest)))) (defgeneric foo3 (x &rest y)) (defmethod foo3 ((x t) &rest y) nil) -(defmethod foo4 ((x t) &key y &rest z) nil) +(defmethod foo4 ((x t) &rest z &key y) nil) (defgeneric foo4 (x &rest z &key y)) (assert (expect-error (defgeneric foo5 (x &rest)))) (assert (expect-error (macroexpand-1 '(defmethod foo6 (x &rest))))) @@ -174,8 +176,16 @@ ;;; that it doesn't happen again. ;;; ;;; First, the forward references: -(defclass a (b) ()) -(defclass b () ()) +(defclass forward-ref-a (forward-ref-b) ()) +(defclass forward-ref-b () ()) +;;; (a couple more complicated examples found by Paul Dietz' test +;;; suite): +(defclass forward-ref-c1 (forward-ref-c2) ()) +(defclass forward-ref-c2 (forward-ref-c3) ()) + +(defclass forward-ref-d1 (forward-ref-d2 forward-ref-d3) ()) +(defclass forward-ref-d2 (forward-ref-d4 forward-ref-d5) ()) + ;;; Then change-class (defclass class-with-slots () ((a-slot :initarg :a-slot :accessor a-slot) @@ -310,7 +320,31 @@ (assert-program-error (defclass foo008 () (a :initarg :a) (:default-initargs :a 1) - (:default-initargs :a 2)))) + (:default-initargs :a 2))) + ;; and also BUG 47d, fixed in sbcl-0.8alpha.0.26 + (assert-program-error (defgeneric if (x))) + ;; DEFCLASS should detect an error if slot names aren't suitable as + ;; variable names: + (assert-program-error (defclass foo009 () + ((:a :initarg :a)))) + (assert-program-error (defclass foo010 () + (("a" :initarg :a)))) + (assert-program-error (defclass foo011 () + ((#1a() :initarg :a)))) + (assert-program-error (defclass foo012 () + ((t :initarg :t)))) + (assert-program-error (defclass foo013 () ("a"))) + ;; specialized lambda lists have certain restrictions on ordering, + ;; repeating keywords, and the like: + (assert-program-error (defmethod foo014 ((foo t) &rest) nil)) + (assert-program-error (defmethod foo015 ((foo t) &rest x y) nil)) + (assert-program-error (defmethod foo016 ((foo t) &allow-other-keys) nil)) + (assert-program-error (defmethod foo017 ((foo t) + &optional x &optional y) nil)) + (assert-program-error (defmethod foo018 ((foo t) &rest x &rest y) nil)) + (assert-program-error (defmethod foo019 ((foo t) &rest x &optional y) nil)) + (assert-program-error (defmethod foo020 ((foo t) &key x &optional y) nil)) + (assert-program-error (defmethod foo021 ((foo t) &key x &rest y) nil))) ;;; DOCUMENTATION's argument-precedence-order wasn't being faithfully ;;; preserved through the bootstrap process until sbcl-0.7.8.39. @@ -399,26 +433,17 @@ form))) 'dmc-test-return)) -;;; DEFMETHOD should signal a PROGRAM-ERROR if an incompatible lambda -;;; list is given: +;;; DEFMETHOD should signal an ERROR if an incompatible lambda list is +;;; given: (defmethod incompatible-ll-test-1 (x) x) -(multiple-value-bind (result error) - (ignore-errors (defmethod incompatible-ll-test-1 (x y) y)) - (assert (null result)) - (assert (typep error 'program-error))) -(multiple-value-bind (result error) - (ignore-errors (defmethod incompatible-ll-test-1 (x &rest y) y)) - (assert (null result)) - (assert (typep error 'program-error))) +(assert (raises-error? (defmethod incompatible-ll-test-1 (x y) y))) +(assert (raises-error? (defmethod incompatible-ll-test-1 (x &rest y) y))) ;;; Sneakily using a bit of MOPness to check some consistency (assert (= (length (sb-pcl:generic-function-methods #'incompatible-ll-test-1)) 1)) (defmethod incompatible-ll-test-2 (x &key bar) bar) -(multiple-value-bind (result error) - (ignore-errors (defmethod incompatible-ll-test-2 (x) x)) - (assert (null result)) - (assert (typep error 'program-error))) +(assert (raises-error? (defmethod incompatible-ll-test-2 (x) x))) (defmethod incompatible-ll-test-2 (x &rest y) y) (assert (= (length (sb-pcl:generic-function-methods #'incompatible-ll-test-2)) 1)) @@ -491,5 +516,150 @@ (assert (equal *d-m-c-args-test* '("unlock" "object-lock" "lock" "object-lock"))) +;;; The walker (on which DEFMETHOD depended) didn't know how to handle +;;; SYMBOL-MACROLET properly. In fact, as of sbcl-0.7.10.20 it still +;;; doesn't, but it does well enough to compile the following without +;;; error (the problems remain in asking for a complete macroexpansion +;;; of an arbitrary form). +(symbol-macrolet ((x 1)) + (defmethod bug222 (z) + (macrolet ((frob (form) `(progn ,form ,x))) + (frob (print x))))) +(assert (= (bug222 t) 1)) + +;;; also, a test case to guard against bogus environment hacking: +(eval-when (:compile-toplevel :load-toplevel :execute) + (setq bug222-b 3)) +;;; this should at the least compile: +(let ((bug222-b 1)) + (defmethod bug222-b (z stream) + (macrolet ((frob (form) `(progn ,form ,bug222-b))) + (frob (format stream "~D~%" bug222-b))))) +;;; and it would be nice (though not specified by ANSI) if the answer +;;; were as follows: +(let ((x (make-string-output-stream))) + ;; not specified by ANSI + (assert (= (bug222-b t x) 3)) + ;; specified. + (assert (char= (char (get-output-stream-string x) 0) #\1))) + +;;; REINITIALIZE-INSTANCE, in the ctor optimization, wasn't checking +;;; for invalid initargs where it should: +(defclass class234 () ()) +(defclass subclass234 (class234) ()) +(defvar *bug234* 0) +(defun bug-234 () + (reinitialize-instance (make-instance 'class234) :dummy 0)) +(defun subbug-234 () + (reinitialize-instance (make-instance 'subclass234) :dummy 0)) +(assert (raises-error? (bug-234) program-error)) +(defmethod shared-initialize :after ((i class234) slots &key dummy) + (incf *bug234*)) +(assert (typep (subbug-234) 'subclass234)) +(assert (= *bug234* + ;; once for MAKE-INSTANCE, once for REINITIALIZE-INSTANCE + 2)) + +;;; also, some combinations of MAKE-INSTANCE and subclassing missed +;;; new methods (Gerd Moellmann sbcl-devel 2002-12-29): +(defclass class234-b1 () ()) +(defclass class234-b2 (class234-b1) ()) +(defvar *bug234-b* 0) +(defun bug234-b () + (make-instance 'class234-b2)) +(compile 'bug234-b) +(bug234-b) +(assert (= *bug234-b* 0)) +(defmethod initialize-instance :before ((x class234-b1) &rest args) + (declare (ignore args)) + (incf *bug234-b*)) +(bug234-b) +(assert (= *bug234-b* 1)) + +;;; we should be able to make classes with uninterned names: +(defclass #:class-with-uninterned-name () ()) + +;;; SLOT-MISSING should be called when there are missing slots. +(defclass class-with-all-slots-missing () ()) +(defmethod slot-missing (class (o class-with-all-slots-missing) + slot-name op + &optional new-value) + op) +(assert (eq (slot-value (make-instance 'class-with-all-slots-missing) 'foo) + 'slot-value)) +(assert (eq (funcall (lambda (x) (slot-value x 'bar)) + (make-instance 'class-with-all-slots-missing)) + 'slot-value)) +(assert (eq (funcall (lambda (x) (setf (slot-value x 'baz) 'baz)) + (make-instance 'class-with-all-slots-missing)) + 'setf)) + +;;; we should be able to specialize on anything that names a class. +(defclass name-for-class () ()) +(defmethod something-that-specializes ((x name-for-class)) 1) +(setf (find-class 'other-name-for-class) (find-class 'name-for-class)) +(defmethod something-that-specializes ((x other-name-for-class)) 2) +(assert (= (something-that-specializes (make-instance 'name-for-class)) 2)) +(assert (= (something-that-specializes (make-instance 'other-name-for-class)) + 2)) + +;;; more forward referenced classes stuff +(defclass frc-1 (frc-2) ()) +(assert (subtypep 'frc-1 (find-class 'frc-2))) +(assert (subtypep (find-class 'frc-1) 'frc-2)) +(assert (not (subtypep (find-class 'frc-2) 'frc-1))) +(defclass frc-2 (frc-3) ((a :initarg :a))) +(assert (subtypep 'frc-1 (find-class 'frc-3))) +(defclass frc-3 () ()) +(assert (typep (make-instance 'frc-1 :a 2) (find-class 'frc-1))) +(assert (typep (make-instance 'frc-2 :a 3) (find-class 'frc-2))) + +;;; check that we can define classes with two slots of different names +;;; (even if it STYLE-WARNs). +(defclass odd-name-class () + ((name :initarg :name) + (cl-user::name :initarg :name2))) +(let ((x (make-instance 'odd-name-class :name 1 :name2 2))) + (assert (= (slot-value x 'name) 1)) + (assert (= (slot-value x 'cl-user::name) 2))) + +;;; ALLOCATE-INSTANCE should work on structures, even if defined by +;;; DEFSTRUCT (and not DEFCLASS :METACLASS STRUCTURE-CLASS). +(defstruct allocatable-structure a) +(assert (typep (allocate-instance (find-class 'allocatable-structure)) + 'allocatable-structure)) + +;;; Bug found by Paul Dietz when devising CPL tests: somewhat +;;; amazingly, calls to CPL would work a couple of times, and then +;;; start returning NIL. A fix was found (relating to the +;;; applicability of constant-dfun optimization) by Gerd Moellmann. +(defgeneric cpl (x) + (:method-combination list) + (:method list ((x broadcast-stream)) 'broadcast-stream) + (:method list ((x integer)) 'integer) + (:method list ((x number)) 'number) + (:method list ((x stream)) 'stream) + (:method list ((x structure-object)) 'structure-object)) +(assert (equal (cpl 0) '(integer number))) +(assert (equal (cpl 0) '(integer number))) +(assert (equal (cpl 0) '(integer number))) +(assert (equal (cpl 0) '(integer number))) +(assert (equal (cpl 0) '(integer number))) +(assert (equal (cpl (make-broadcast-stream)) + '(broadcast-stream stream structure-object))) +(assert (equal (cpl (make-broadcast-stream)) + '(broadcast-stream stream structure-object))) +(assert (equal (cpl (make-broadcast-stream)) + '(broadcast-stream stream structure-object))) + +;;; Bug in CALL-NEXT-METHOD: assignment to the method's formal +;;; parameters shouldn't affect the arguments to the next method for a +;;; no-argument call to CALL-NEXT-METHOD +(defgeneric cnm-assignment (x) + (:method (x) x) + (:method ((x integer)) (setq x 3) + (list x (call-next-method) (call-next-method x)))) +(assert (equal (cnm-assignment 1) '(3 1 3))) + ;;;; success (sb-ext:quit :unix-status 104)