[armedbear-cvs] r13569 - in trunk/abcl: src/org/armedbear/lisp test/lisp/abcl

ehuelsmann at common-lisp.net ehuelsmann at common-lisp.net
Sun Sep 4 13:34:50 UTC 2011


Author: ehuelsmann
Date: Sun Sep  4 06:34:50 2011
New Revision: 13569

Log:
Signal an error if unambiguous sorting of methods within a method group
is not possible due to the use of the same specializers.

Modified:
   trunk/abcl/src/org/armedbear/lisp/clos.lisp
   trunk/abcl/test/lisp/abcl/mop-tests.lisp

Modified: trunk/abcl/src/org/armedbear/lisp/clos.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/clos.lisp	Sun Sep  4 02:59:23 2011	(r13568)
+++ trunk/abcl/src/org/armedbear/lisp/clos.lisp	Sun Sep  4 06:34:50 2011	(r13569)
@@ -936,7 +936,8 @@
                           thereis (method-group-p item qualifiers)))
            :description ',description
            :order ',order
-           :required ',required-p)))
+           :required ',required-p
+           :*-selecter ,(equal selecters '(*)))))
 
 (defun extract-required-part (lambda-list)
   (flet ((skip (key lambda-list)
@@ -1027,27 +1028,38 @@
                   collect `(,var ,init-form)))
          , at forms))))
 
+(defun assert-unambiguous-method-sorting (group-name methods)
+  (let ((specializers (make-hash-table :test 'equal)))
+    (dolist (method methods)
+      (push method (gethash (method-specializers method) specializers)))
+    (loop for specializer-methods being each hash-value of specializers
+       using (hash-key method-specializers)
+       unless (= 1 (length specializer-methods))
+       do (error "Ambiguous method sorting in method group ~A due to multiple ~
+                  methods with specializers ~S: ~S"
+                 group-name method-specializers specializer-methods))))
+
 (defmacro with-method-groups (method-group-specs methods-form &body forms)
   (flet ((grouping-form (spec methods-var)
-                        (let ((predicate (coerce-to-function (getf spec :predicate)))
-                              (group (gensym))
-                              (leftovers (gensym))
-                              (method (gensym)))
-                          `(let ((,group '())
-                                 (,leftovers '()))
-                             (dolist (,method ,methods-var)
-                               (if (funcall ,predicate (method-qualifiers ,method))
-                                   (push ,method ,group)
-                                   (push ,method ,leftovers)))
-                             (ecase ,(getf spec :order)
-                               (:most-specific-last )
-                               (:most-specific-first (setq ,group (nreverse ,group))))
-                             ,@(when (getf spec :required)
-                                 `((when (null ,group)
-                                     (error "Method group ~S must not be empty."
-                                            ',(getf spec :name)))))
-                             (setq ,methods-var (nreverse ,leftovers))
-                             ,group))))
+           (let ((predicate (coerce-to-function (getf spec :predicate)))
+                 (group (gensym))
+                 (leftovers (gensym))
+                 (method (gensym)))
+             `(let ((,group '())
+                    (,leftovers '()))
+                (dolist (,method ,methods-var)
+                  (if (funcall ,predicate (method-qualifiers ,method))
+                      (push ,method ,group)
+                      (push ,method ,leftovers)))
+                (ecase ,(getf spec :order)
+                  (:most-specific-last )
+                  (:most-specific-first (setq ,group (nreverse ,group))))
+                ,@(when (getf spec :required)
+                        `((when (null ,group)
+                            (error "Method group ~S must not be empty."
+                                   ',(getf spec :name)))))
+                (setq ,methods-var (nreverse ,leftovers))
+                ,group))))
     (let ((rest (gensym))
           (method (gensym)))
       `(let* ((,rest ,methods-form)
@@ -1058,6 +1070,11 @@
            (invalid-method-error ,method
                                  "Method ~S with qualifiers ~S does not belong to any method group."
                                  ,method (method-qualifiers ,method)))
+         ,@(unless (and (= 1 (length method-group-specs))
+                        (getf (car method-group-specs) :*-selecter))
+             (mapcar #'(lambda (spec)
+                         `(assert-unambiguous-method-sorting ',(getf spec :name) ,(getf spec :name)))
+                     method-group-specs))
          , at forms))))
 
 (defun method-combination-type-lambda

Modified: trunk/abcl/test/lisp/abcl/mop-tests.lisp
==============================================================================
--- trunk/abcl/test/lisp/abcl/mop-tests.lisp	Sun Sep  4 02:59:23 2011	(r13568)
+++ trunk/abcl/test/lisp/abcl/mop-tests.lisp	Sun Sep  4 06:34:50 2011	(r13569)
@@ -410,7 +410,38 @@
   T)
 
 
+;;; Taken from SBCL: error when method sorting is ambiguous
 
+(define-method-combination dmc-test-mc.3a ()
+  ((around (:around))
+   (primary * :required t))
+  (let ((form (if (rest primary)
+                  `(call-method ,(first primary) ,(rest primary))
+                  `(call-method ,(first primary)))))
+    (if around
+        `(call-method ,(first around) (,@(rest around)
+                                       (make-method ,form)))
+        form)))
+
+(defgeneric dmc-test-mc.3a (val)
+  (:method-combination dmc-test-mc.3a))
+
+(defmethod dmc-test-mc.3a ((val number))
+  (+ val (if (next-method-p) (call-next-method) 0)))
+
+(defmethod dmc-test-mc.3a :around ((val number))
+  (+ val (if (next-method-p) (call-next-method) 0)))
+
+(defmethod dmc-test-mc.3a :somethingelse ((val number))
+  (+ val (if (next-method-p) (call-next-method) 0)))
+
+(deftest dmc-test-mc.3a
+    (multiple-value-bind
+          (value error)
+        (ignore-errors (wam-test-mc-b 13))
+      (declare (ignore value))
+      (typep error 'error))
+  T)
 
 (defclass foo-class (standard-class))
 (defmethod mop:validate-superclass ((class foo-class) (superclass standard-object))




More information about the armedbear-cvs mailing list