chiark / gitweb /
doc/concepts.tex: Typeset method rĂ´le names as identifiers.
[sod] / src / method-impl.lisp
index 963f2fef8f12f4c98a7f557323539bdaa1e9453d..e93fb3aa1887e8f5618566e3810037d682bf46d1 100644 (file)
@@ -30,8 +30,7 @@ (cl:in-package #:sod)
 
 (export 'basic-message)
 (defclass basic-message (sod-message)
-  ((argument-tail :type list :reader sod-message-argument-tail)
-   (no-varargs-tail :type list :reader sod-message-no-varargs-tail))
+  ((argument-tail :type list :reader sod-message-argument-tail))
   (:documentation
    "Base class for built-in message classes.
 
@@ -52,9 +51,6 @@ (define-on-demand-slot basic-message argument-tail (message)
                                 (argument-type arg))))
            (c-function-arguments (sod-message-type message)))))
 
-(define-on-demand-slot basic-message no-varargs-tail (message)
-  (reify-variable-argument-tail (sod-message-argument-tail message)))
-
 (defmethod sod-message-method-class
     ((message basic-message) (class sod-class) pset)
   (let ((role (get-property pset :role :keyword nil)))
@@ -156,6 +152,11 @@ (define-on-demand-slot basic-direct-method function-type (method)
                 ("me" (* (class (sod-method-class method))))
                 . method-args))))
 
+(defmethod sod-method-description ((method basic-direct-method))
+  (with-slots (role) method
+    (if role (string-downcase role)
+       "primary")))
+
 (defmethod sod-method-function-name ((method basic-direct-method))
   (with-slots ((class %class) role message) method
     (format nil "~A__~@[~(~A~)_~]method_~A__~A" class role
@@ -248,21 +249,48 @@ (define-on-demand-slot delegating-direct-method function-type (method)
 ;;;--------------------------------------------------------------------------
 ;;; Effective method classes.
 
+(defmethod method-keyword-argument-lists
+    ((method effective-method) direct-methods state)
+  (with-slots (message) method
+    (and (keyword-message-p message)
+        (cons (cons (lambda (arg)
+                      (let ((class (sod-message-class message)))
+                        (info-with-location
+                         message "Type `~A' declared in message ~
+                                  definition in `~A' (here)"
+                         (argument-type arg) class)
+                        (report-inheritance-path state class)))
+                    (c-function-keywords (sod-message-type message)))
+              (mapcar (lambda (m)
+                        (cons (lambda (arg)
+                                (let ((class (sod-method-class m)))
+                                  (info-with-location
+                                   m "Type `~A' declared in ~A direct ~
+                                      method of `~A' (defined here)"
+                                   (argument-type arg)
+                                   (sod-method-description m) class)
+                                  (report-inheritance-path state class)))
+                              (c-function-keywords (sod-method-type m))))
+                      direct-methods)))))
+
 (defmethod shared-initialize :after
     ((method effective-method) slot-names &key direct-methods)
   (declare (ignore slot-names))
 
-  ;; Set the keyword argument list.
-  (with-slots (message keywords) method
-    (setf keywords (and (keyword-message-p message)
-                       (merge-keyword-lists
-                        (mapcar (lambda (m)
-                                  (let ((type (sod-method-type m)))
-                                    (cons (c-function-keywords type)
-                                          (format nil "method for ~A on ~A"
-                                                  message
-                                                  (sod-method-class m)))))
-                                direct-methods))))))
+  ;; Set the keyword argument list.  Blame the class as a whole for mismatch
+  ;; errors, because they're fundamentally a non-local problem about the
+  ;; class construction.
+  (with-slots ((class %class) message keywords) method
+    (setf keywords
+         (merge-keyword-lists
+          (lambda ()
+            (values class
+                    (format nil
+                            "methods for message `~A' ~
+                             applicable to class `~A'"
+                            message class)))
+          (method-keyword-argument-lists method direct-methods
+           (make-inheritance-path-reporter-state class))))))
 
 (export '(basic-effective-method
          effective-method-around-methods effective-method-before-methods
@@ -288,9 +316,9 @@ (defclass basic-effective-method (effective-method)
    using a slot reader method."))
 
 (define-on-demand-slot basic-effective-method basic-argument-names (method)
-  (let ((message (effective-method-message method)))
-    (mapcar #'argument-name
-           (sod-message-no-varargs-tail message))))
+  (let* ((message (effective-method-message method))
+        (raw-tail (sod-message-argument-tail message)))
+    (mapcar #'argument-name (reify-variable-argument-tail raw-tail))))
 
 (defmethod effective-method-function-name ((method effective-method))
   (let* ((class (effective-method-class method))
@@ -658,7 +686,8 @@ (defmethod compute-method-entry-functions ((method basic-effective-method))
               (codegen-push codegen)
               (ensure-var codegen "sod__obj" ilayout-type
                           (make-convert-to-ilayout-inst class
-                                                        head "me"))))
+                                                        head "me"))
+              (deliver-call codegen :void "SOD__IGNORE" "sod__obj")))
           (finish-entry (tail)
             (let* ((head (sod-class-chain-head tail))
                    (role (if parm-n :valist nil))
@@ -789,14 +818,24 @@ (defmethod compute-effective-method-body :around
                    (*keyword-struct-disposition* :local))
               (ensure-var codegen *sod-keywords* (c-type (struct tag)))
               (make-keyword-parser-function codegen method tag set keywords)
+              (emit-insts codegen
+                          (mapcar (lambda (keyword)
+                                    (make-set-inst
+                                     (format nil "~A.~A__suppliedp"
+                                             *sod-keywords*
+                                             (argument-name keyword))
+                                     0))
+                                  keywords))
               (parse-keywords (lambda ()
                                 (call :void name kw-addr ap-addr
                                       *null-pointer* 0)))
               (call-next-method)))))))
 
-(defmethod compute-method-entry-functions
-    ((method simple-effective-method))
-  (if (effective-method-primary-methods method)
+(defmethod effective-method-live-p ((method simple-effective-method))
+  (effective-method-primary-methods method))
+
+(defmethod compute-method-entry-functions :around ((method effective-method))
+  (if (effective-method-live-p method)
       (call-next-method)
       nil))