Subject: bug#68113: Wrong error message triggered in cl--generic-standard-method-combination

From: Stefan Monnier <[email-masked]>
Date: Fri, 29 Dec 2023 12:24:36 -0500

Hi Alan,

> In my development version of Emacs (based on the master branch) I get a
> backtrace with the error message being:
>
>     Error: wrong-type-argument (symbolp mets-by-qual)
>
> This occurs during the execution of cl-generic-combine-methods, whose
> code starts:
>
> (defun cl--generic-standard-method-combination (generic methods)
>   (let ((mets-by-qual ()))
>     (dolist (method methods)
>       (let ((qualifiers (cl-method-qualifiers method)))
>         (if (eq (car qualifiers) :extra) (setq qualifiers (cddr qualifiers)))
>         (unless (member qualifiers '(() (:after) (:before) (:around)))
>           (error "Unsupported qualifiers in function %S: %S"
>                  (cl--generic-name generic) qualifiers))
>         (push method (alist-get (car qualifiers) mets-by-qual))))
>
> It is the last line that is signalling the error.  The pertinent line
> from the backtrace which is the expansion of that last line reads:
>
>     (let* ((k (car qualifiers)) (p (assq k mets-by-qual)) (v (cons method (cdr p)))) (progn (if p (setcdr p v) (progn (signal 'wrong-type-argument (list 'symbolp 'mets-by-qual)))) v))
>
> ..  The error is, in actual fact, the failure to find an entry for (car
> qualifiers) in the alist mets-by-qual.  The error message given is
> rubbish and more than a little misleading.  mets-by-qual is clearly a
> symbol.

[ Side note: not finding an entry for (car qualifiers) in the above code
  is perfectly normal (it's the most common case, even).  The code only
  finds such an entry when there are several applicable methods (and
  they have the same set of qualifiers).  ]

Hmm... the error occurs during macroexpansion, because the
macroexpansion of the `push` above should be (and is, normally):

    ELISP> (macroexpand '(push method (alist-get (car qualifiers) mets-by-qual)))
    (let*
        ((k (car qualifiers)) (p (assq k mets-by-qual))
         (v (cons method (cdr p))))
      (progn
        (if p (setcdr p v)
          (setq mets-by-qual (cons (setq p (cons k v)) mets-by-qual)))
        v))
    
    ELISP>

I don't know why you're not getting that expansion, and I don't know
either why you're getting that

    (signal 'wrong-type-argument (list 'symbolp 'mets-by-qual))

AFAICT this weird code is likely generated by `gv-delay-error` but
according to `grep` it's only used in `map-elt` so I can't see why it's
showing up here.

I'd start debugging this with something like `M-x trace-function RET
gv-get RET` and `M-x debug-on-entry RET gv-delay-error RET`.
[ Tho, presumably you're seeing this during the bootstrap, so you'll
  probably want to add `message/debug` calls in the code instead.  ]

        Stefan