Package: emacs;
Reported by: Jonas Bernoulli <jonas <at> bernoul.li>
Date: Wed, 2 Apr 2025 16:01:01 UTC
Severity: normal
Message #8 received at 77464 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Jonas Bernoulli <jonas <at> bernoul.li>, Stefan Monnier <monnier <at> iro.umontreal.ca> Cc: 77464 <at> debbugs.gnu.org Subject: Re: bug#77464: X is already defined as something else than a generic function Date: Sun, 13 Apr 2025 11:17:05 +0300
> Date: Wed, 02 Apr 2025 17:59:53 +0200 > From: Jonas Bernoulli via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org> > > Hello, > > Users of my packages occasionally report such errors but I was never > able to reproduce. What is strange is that X always was a function that > was definitely not defined as "something else than a generic function" > anywhere in my code, or even just in past versions of my code, and users > were not able to find anything in their configuration or third-party > packages either. > > Actually I have seen this issue myself a few times, but it was always > when I badly messed up something else and by the time I had fixed that, > the "something other" issue was also gone. In hindsight it is obvious > that I should sooner have investigated the "something other" issue > without first fixing the seemingly unrelated issue. > > Now that I have finally done that, I also managed to come of with a > reproducer. > > 1. Create a file "demo.el" with contents: > > (require 'eieio) > (defclass demo-class () ()) > (cl-defmethod demo-function ((obj demo-class)) obj) > > (error "something else goes wrong here") > (provide 'demo) > > 2. Optionally apply this patch to Emacs: > > diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el > @@ -193,8 +193,8 @@ cl-generic-ensure-function > (autoloadp (symbol-function name)) > (and (functionp name) generic) > noerror) > - (error "%s is already defined as something else than a generic function" > - origname)) > + (error "%s [%s] is already defined as something else than a generic function" > + origname (symbol-function name))) > (if generic > (cl-assert (eq name (cl--generic-name generic))) > (setf (cl--generic name) (setq generic (cl--generic-make name)))) > @@ -645,7 +645,9 @@ cl-generic-define-method > ;; is still valid (e.g. still empty method cache)? > (gfun (cl--generic-make-function generic))) > (unless (symbol-function sym) > - (defalias sym 'dummy)) ;Record definition into load-history. > + (defalias sym 'dummy) ;Record definition into load-history. > + (when (eq sym 'demo-function) > + (message "First defalias: %s" (symbol-function 'demo-function)))) > (cl-pushnew `(cl-defmethod . ,(cl--generic-load-hist-format > (cl--generic-name generic) > qualifiers specializers)) > @@ -659,7 +661,9 @@ cl-generic-define-method > (set-advertised-calling-convention gfun old-adv-cc nil)) > ;; But do use `defalias', so that it interacts properly with nadvice, > ;; e.g. for tracing/debug-on-entry. > - (defalias sym gfun))))) > + (defalias sym gfun) > + (when (eq sym 'demo-function) > + (message "Second defalias: %s" (symbol-function 'demo-function))))))) > > (defvar cl--generic-dispatchers (make-hash-table :test #'equal)) > > 3. Paste this into a buffer and adjust the load-path: > > (add-to-list 'load-path "/path/to/demo") > > (message "Load attempt one... [%s]" (symbol-function 'demo-function)) > (with-demoted-errors "Trigger: %S" > (require 'demo)) > (message "Load attempt one...done") > (message "Load attempt two... [%s]" (symbol-function 'demo-function)) > (require 'demo) > (message "Load attempt two...done") > > 4. Evaluate that buffer, you'll get this output: > > Load attempt one... [nil] > First defalias: dummy > Second defalias: #[...] > Trigger: (error "something else goes wrong here") > Load attempt one...done > Load attempt two... [dummy] > cl-generic-ensure-function: demo-function [dummy] is already defined \ > as something else than a generic function > > > cl-generic-define-method first sets (symbol-function 'demo-function) > to 'dummy, and then it successfully sets it to something else. The > debug statements helped confirm that both defalias calls are actually > successful, i.e., the problem isn't that something in between these > calls ends up calling cl-generic-ensure-function. > > Then, after this function has returned, something else goes wrong (in > this reproducer intentionally). We can then observe that the value of > (symbol-function 'demo-function) somehow goes back to being 'dummy. > (I couldn't find anything else in Emacs that sets a symbol-function to > 'dummy.) > > The first (require 'demo) failed because the (here intentional) error > occurred before the provide form was reached. Once a second attempt to > require the same library is made, the cl-defmethod fails because the > encountered 'dummy is "something else than a generic function". > > (Also, isn't it "something OTHER than a generic function"?) Stefan, any comments or suggestions?
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.