0

While working on developing a fork of inf-ruby such as to use EIEIO and cl-generic in an approach, I've discovered what appears to be a bug in cl-generic.el.

I'm testing this presently with GNU Emacs 29.0.50 on FreeBSD 13.1 amd64. This Emacs build was produced with the nativecomp option under the FreeBSD editors/emacs-devel port, in a build from about a week ago.

The shortest test case that I've been able to develop is as follows:

(require 'eieio)
(require 'cl-generic)

(defclass a ()
  ())

(defclass b (a)
  ())

(cl-defgeneric frob (obj)
  (:method ((obj a))
    (list :a obj))
  (:method ((obj b))
    (append (when (cl-next-method-p)
              (cl-call-next-method))
            (list :b))))

The following method call then results in an error that might serve to illustrate the bug, to some extent:

(frob (b))

This calls the frob generic function on a new instance of the class b. The following is shown in the Emacs debuger after that method call:

Debugger entered--Lisp error: (void-variable cl--nmp)
  (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append (if (funcall cl--nmp) (progn (funcall cl--cnm))) (list :b)))) cl--nmp cl--cnm cl--args)
  (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm (or args cl--args))))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append (if (funcall cl--nmp) (progn ...)) (list :b)))) cl--nmp cl--cnm cl--args))
  (lambda (&rest cl--args) "\n\n(fn OBJ)" (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm ...)))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append ... ...))) cl--nmp cl--cnm cl--args)))(#<b b-208546b1e>)
  apply((lambda (&rest cl--args) "\n\n(fn OBJ)" (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm ...)))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append ... ...))) cl--nmp cl--cnm cl--args))) #<b b-208546b1e> nil)
  frob(#<b b-208546b1e>)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  command-execute(eval-last-sexp)

This appears to be occurring from something in how the method-call dispatch is handled for the initial method call onto the frob function. That method call would use both cl-next-method-p and cl-call-next-method, ostensibly.

To my nearest estimation, the symbols showing up as unbound there might be supposed to be bound with a function produced in some code defined in cl-generic.el (this file is a part of Emacs)

In trying to develop a workaround for this, short of any ostensible patching on cl-generic.el, I've discovered that the following code fails similarly.

(require 'cl-extra)

(cl-defgeneric nextfrob (obj)
  (:method ((obj a))
    (list :a obj))
  (:method ((obj b))
    (append (when (cl-next-method-p)
              (cl-call-next-method))
            (list :b))))

  (defun make-one-lambda (genfunc mtd next)
    (cl-generic-call-method
     genfunc mtd
     (when next (make-one-lambda genfunc (car next) (cdr next)))))

  (cl-defgeneric cl-generic-combine-methods ((genfunc (eql (cl--generic 'nextfrob)))
                                             methods)
    (let (last)
      (cl-maplist (lambda (next)
                    (let ((nextlm (make-one-lambda genfunc (car next) (cdr next))))
                      (setq last (funcall nextlm last))))
                  methods)
      (if last
          (funcall last)
        (error "no methods? for %S" genfunc)))
    )

  (nextfrob (b))

There, I'd tried to develop a workaround in defining a method specializing cl-generic-combine-methods such as to be called only for the nextfrob generic function.

The error that occurs there occurs only once. If evaluating the form (nextfrob (b)) a second time, then a second error may occur, such that may appear to be related to a methodology for method caching for optimized method dispatch in cl-generic.el.

What the debugger displays for the first error in that second section of code:

Debugger entered--Lisp error: (void-variable cl--nmp)
  (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append (if (funcall cl--nmp) (progn (funcall cl--cnm))) (list :b)))) cl--nmp cl--cnm cl--args)
  (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm (or args cl--args))))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append (if (funcall cl--nmp) (progn ...)) (list :b)))) cl--nmp cl--cnm cl--args))
  (lambda (&rest cl--args) "\n\n(fn OBJ)" (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm ...)))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append ... ...))) cl--nmp cl--cnm cl--args)))(nil)
  funcall((lambda (&rest cl--args) "\n\n(fn OBJ)" (let ((cl--cnm #'(lambda (&rest args) (apply cl--nm ...)))) (apply #'(lambda (cl--nmp cl--cnm obj) (progn (append ... ...))) cl--nmp cl--cnm cl--args))) nil)
  (setq last (funcall nextlm last))
  (let ((nextlm (make-one-lambda genfunc (car next) (cdr next)))) (setq last (funcall nextlm last)))
  (lambda (next) (let ((nextlm (make-one-lambda genfunc (car next) (cdr next)))) (setq last (funcall nextlm last))))((#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl-maplist((lambda (next) (let ((nextlm (make-one-lambda genfunc (car next) (cdr next)))) (setq last (funcall nextlm last)))) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  (let (last) (cl-maplist #'(lambda (next) (let ((nextlm (make-one-lambda genfunc ... ...))) (setq last (funcall nextlm last)))) methods) (if last (funcall last) (error "no methods? for %S" genfunc)))
  (progn (let (last) (cl-maplist #'(lambda (next) (let ((nextlm ...)) (setq last (funcall nextlm last)))) methods) (if last (funcall last) (error "no methods? for %S" genfunc))))
  (lambda (genfunc methods) (progn (let (last) (cl-maplist #'(lambda (next) (let ... ...)) methods) (if last (funcall last) (error "no methods? for %S" genfunc)))))(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  apply((lambda (genfunc methods) (progn (let (last) (cl-maplist #'(lambda (next) (let ... ...)) methods) (if last (funcall last) (error "no methods? for %S" genfunc))))) #s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl-generic-combine-methods(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl--generic-build-combined-method(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl--generic-make-next-function(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) nil (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl--generic-cache-miss(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) 0 nil (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) Sure it might seem like a high goal.(let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) (b a eieio-default-superclass t))
  nextfrob(#<b b-20409cf9a>)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  command-execute(eval-last-sexp)

If evaluating (nextfrob (b)) again, the second error may appear to be related to the failure in the initial method call in this bit of hacking:

Debugger entered--Lisp error: (cl--generic-cyclic-definition nextfrob)
  signal(cl--generic-cyclic-definition (nextfrob))
  cl--generic-build-combined-method(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl--generic-make-next-function(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) nil (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))))
  cl--generic-cache-miss(#s(cl--generic :name nextfrob :dispatches ((0 #s(cl--generic-generalizer :name eieio--generic-generalizer :priority 50 :tagcode-function cl--generic-struct-tag :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x1bd3ac213fac4a61>)) #s(cl--generic-generalizer :name cl--generic-t-generalizer :priority 0 :tagcode-function #f(compiled-function (name &rest _) #<bytecode -0x1cba4f13a96764e4>) :specializers-function #f(compiled-function (tag &rest _) #<bytecode -0x2b626d08469105e>)))) :method-table (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp ...)) #'(lambda ... "\n\n(fn OBJ)" ...)))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) :options nil) 0 nil (#s(cl--generic-method :specializers (b) :qualifiers nil :call-con curried :function (lambda (cl--nm) (let ((cl--nmp (if ... ... ...))) #'(lambda (&rest cl--args) "\n\n(fn OBJ)" (let ... ...))))) #s(cl--generic-method :specializers (a) :qualifiers nil :call-con nil :function (lambda (obj) (progn (list :a obj))))) (b a eieio-default-superclass t))
  nextfrob(#<b b-2098153ca>)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  command-execute(eval-last-sexp)

If it was possible to use next-method-p/call-next-method here, then it may serve to simplify some aspects of an API design, e.g for a method that could be applied in appending a list of shell command arguments for some specialized class of an interactive Ruby command, given a list of shell command arguments produced by a next method on the same generic function.

With that bug occurring in this usage of both cl-next-method-p and cl-call-next-method, that does not appear to be possible.

If it may be possible to develop any workaround for it, but I don't believe a re-implementation of cl-generic.el was initially in scope for this simple project.

I've not yet tried testing this in an Emacs build without the nativecomp option. It's only an offhand guess if that could even affect it, or if the bug might occur even then.

Holding to the adage that there may be an inverse relation between the depth of a bug and the number of people aware of the bug, I thought it might help to present this to an n+1 set of eyes, so.

To my own impression, there is quite a lot going on in cl-generic.el with regards to definition and dispatch with anonymous lambdas - some of whose arguments are created with make-symbol (it's not gensym) - and otherwise.

Maybe I can develop some kind of a workaround in my own code, to not reach this bug with it. tbt, even that seems a little bit difficult to figure out right now, if there could be any methodology that would not use `cl-call-next-method' and still retain the set of class, generic function, and method definitions in the unabridged codebase.

Are there any guesses on how to approach this for deconstructing the bug, ostensibly patching it, and/or developing any working implementation of cl-next-method-p/cl-call-next-method?

Update:

I believe this can be approached in using lexically-let/lexically-let* to establish a lexical binding for some of the variables created with make-symbol in the affected anonymous lambda forms, such that those variables would need to be accessible in any more closely encapsulated anonymous lambda forms, as created for the method dispatch in cl-generic.el. The Emacs Wiki has an example and a discussion of Emacs Lisp's lexically-let

To patch the lambda forms created for dispatching to the affected methods of this frob function, the following seems to work out:


  (defmacro with-symbols (names &rest forms)
    `(let ,(mapcar (lambda (name)
                   (let ((s (make-symbol
                             (concat "%" (symbol-name name)))))
                     `(,name (quote ,s))))
                 names)
     ,@forms)

  (funcall
   (funcall
    (with-symbols (cl--nm cl--nmp cl--nnm cl--cnm cl--args)

      `(lambda (,cl--nm)
         (lexical-let* ((,cl--nm ,cl--nm)
                        (,cl--nmp
                        (if (cl--generic-isnot-nnm-p ,cl--nm)
                            #'always #'ignore)))
           #'(lambda (&rest ,cl--args) "..."
               (lexical-let ((,cl--nmp ,cl--nmp)
                             (,cl--cnm
                              #'(lambda (&rest args)
                                  (apply ,cl--nm (or args ,cl--args)))))
                 (apply #'(lambda (,cl--nmp ,cl--cnm obj)
                            (progn
                              (append (if (funcall ,cl--nmp)
                                          (progn (funcall ,cl--cnm)))
                                      (list :b))))
                        ;; ,cl--nmp was unbound here
                        ,cl--nmp ,cl--cnm ,cl--args))))))
    (lambda (it) (list it (b))))
   :a)

This would return a value approximately equivalent to the expected return value for the frob method specialized on the class b

This is patching the anonymous lambda forms accessible and called with the following, such that would initially err as similar to the previous

  (funcall (funcall (cl--generic-method-function
                     (car (cl--generic-method-table (cl--generic 'frob))))
                    (lambda (it) (list it (b))))
           :a)

Though it may not seem particularly succinct, I believe I may have an idea for a working patch by now.

Second Update

The lexical-let macro from cl.el works out for a patch when cl-generic.el is evaluated from source (patch). That particular patch needs update, however, to ensure that cl.el is available in the compilation environment for cl-generic.el.

It seems that it may not be possible to use that macro from cl.el in cl-generic.el when building Emacs from source.

After adding (eval-when-compile (require 'cl)) to the patched file then testing the subsequent patch under a local port build for emacs, the build fails.

Loading /wrkdirs/usr/ports/editors/emacs-devel/work-full/emacs-4cba465/lisp/emacs-lisp/cl-generic.el (source)...
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")

Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Eager macro-expansion failure: (file-missing "Cannot open load file" "No such file or directory" "cl")
Cannot open load file: No such file or directory, cl

Error: file-missing ("Cannot open load file" "No such file or directory" "cl")
  gmake[3]: *** [Makefile:924: bootstrap-emacs.pdmp] Error 255
gmake[3]: Leaving directory '/wrkdirs/usr/ports/editors/emacs-devel/work-full/emacs-4cba465/src'
gmake[2]: *** [Makefile:469: src] Error 2
gmake[2]: *** Waiting for unfinished jobs....
gmake[3]: Leaving directory '/wrkdirs/usr/ports/editors/emacs-devel/work-full/emacs-4cba465/doc/lispref'
gmake[2]: Leaving directory '/wrkdirs/usr/ports/editors/emacs-devel/work-full/emacs-4cba465'
===> Compilation failed unexpectedly.
Try to set MAKE_JOBS_UNSAFE=yes and rebuild before reporting the failure to
the maintainer.
*** Error code 1

Stop.
make[1]: stopped in /usr/ports/editors/emacs-devel

Perhaps that would be too early in the Emacs build process to evaluate the unabridged cl.el.

So, I'll take a look at the macro definition for lexically-let in cl.el, will update under a new patch branch for this

Known Workaround:

Simpler than the ostensible patch, it would seem that the Emacs Lisp variable lexical-binding may be bound to a non-nil value in any source file that defines a cl-defmethod method using either cl-next-method-p or cl-call-next-method

This is accomplished in cl-generic.el itself, using such as the following in the first line of the file (excerpt)

;;; cl-generic.el --- CLOS-style generic functions for Elisp  -*- lexical-binding: t; -*-

Perhaps this is the simplest workaround, to ensure that lexical-binding has a non-nil value in any source file ostensibly using either or both of those special calls i.e cl-next-method-p or cl-call-next-method within a cl-defmethod form in the same source file.

2
  • 2
    If you've found a bug in Emacs then M-x report-emacs-bug
    – phils
    Jun 1, 2022 at 12:01
  • I might try to check out the source code and test out a patch for it, will try to take a look at what bug tracker report-emacs-bug would use (iirc is it gnats?). Good to have any idea of short of signing up for another mailing list, lol.
    – Sean Champ
    Jun 1, 2022 at 16:12

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.