On Emacs 24.3.1/CentOS, when I try load subr-x
, this error appears:
compat--require: Invalid function: if-let
Reproduction steps from emacs -q
:
;; -*- lexical-binding: t; -*-
(require 'package)
(package-initialize)
;; For unknown reasons I can't reach the official elpa.gnu.org on CentOS 7 container
(setq package-archives '(("gnu" . "http://1.15.88.122/gnu/")))
(package-refresh-contents)
(unless (package-installed-p 'nadvice) (package-install 'nadvice))
(unless (package-installed-p 'compat) (package-install 'compat))
(require 'nadvice)
(require 'compat)
(require 'subr-x)
Backtrace:
Debugger entered--Lisp error: (invalid-function if-let)
if-let()
funcall(if-let)
(let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--)))
(while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))
(let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--)))))
(let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))))
(let ((entry (assq feature after-load-alist))) (let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--)))))))
(if (eq feature (quote subr-x)) (let ((entry (assq feature after-load-alist))) (let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form ...)) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))))) (apply oldfun feature args))
Looks like it's related to this:
(compat-advise require (feature &rest args)
"Allow for Emacs 24.x to require the inexistent FEATURE subr-x."
;; As the compatibility advise around `require` is more a hack than
;; of of actual value, the highlighting is suppressed.
:no-highlight t
(if (eq feature 'subr-x)
(let ((entry (assq feature after-load-alist)))
(let ((load-file-name nil))
(dolist (form (cdr entry))
(funcall (eval form t)))))
(apply oldfun feature args)))
Inspecting after-load-alist
:
(subr-x
(if load-file-name
(let ((fun (make-symbol "eval-after-load-helper")))
(fset fun `(lambda (file)
(if (not (equal file ',load-file-name))
nil
(remove-hook 'after-load-functions ',fun)
,'(funcall '(closure (t) nil
(funcall
'(closure (t) nil
(defalias 'if-let #'compat--if-let))))))))
(add-hook 'after-load-functions fun))
(funcall '(closure (t) nil
(funcall
'(closure (t) nil
(defalias 'if-let #'compat--if-let)))))))
(funcall '(closure (t) nil (funcall '(closure (t) nil (defalias 'if-let #'compat--if-let)))))
=> if-let
(eval form t)
=>if-let
(funcall 'if-let)
=> Error!
It seems to be fixed if I change (funcall (eval form t))
to (eval form t)
only.
"~daanturo" outgoing@sr.ht writes:
On Emacs 24.3.1/CentOS, when I try load
subr-x
, this error appears:compat--require: Invalid function: if-let
That is an unusual error message...
Reproduction steps from
emacs -q
:;; -*- lexical-binding: t; -*- (require 'package) (package-initialize) ;; For unknown reasons I can't reach the official elpa.gnu.org on CentOS 7 container (setq package-archives '(("gnu" . "http://1.15.88.122/gnu/"))) (package-refresh-contents) (unless (package-installed-p 'nadvice) (package-install 'nadvice)) (unless (package-installed-p 'compat) (package-install 'compat)) (require 'nadvice) (require 'compat) (require 'subr-x)This looks fine. Is the mirror up to date?
Backtrace:
Debugger entered--Lisp error: (invalid-function if-let) if-let() funcall(if-let) (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--)))) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))) (let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--)))))) (let ((entry (assq feature after-load-alist))) (let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form (car --dolist-tail--))) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))))) (if (eq feature (quote subr-x)) (let ((entry (assq feature after-load-alist))) (let ((load-file-name nil)) (let ((--dolist-tail-- (cdr entry))) (while --dolist-tail-- (let ((form ...)) (funcall (eval form t)) (setq --dolist-tail-- (cdr --dolist-tail--))))))) (apply oldfun feature args))
Looks like it's related to this:
(compat-advise require (feature &rest args) "Allow for Emacs 24.x to require the inexistent FEATURE subr-x." ;; As the compatibility advise around `require` is more a hack than ;; of of actual value, the highlighting is suppressed. :no-highlight t (if (eq feature 'subr-x) (let ((entry (assq feature after-load-alist))) (let ((load-file-name nil)) (dolist (form (cdr entry)) (funcall (eval form t))))) (apply oldfun feature args)))Inspecting
after-load-alist
:(subr-x (if load-file-name (let ((fun (make-symbol "eval-after-load-helper"))) (fset fun `(lambda (file) (if (not (equal file ',load-file-name)) nil (remove-hook 'after-load-functions ',fun) ,'(funcall '(closure (t) nil (funcall '(closure (t) nil (defalias 'if-let #'compat--if-let)))))))) (add-hook 'after-load-functions fun)) (funcall '(closure (t) nil (funcall '(closure (t) nil (defalias 'if-let #'compat--if-let)))))))(funcall '(closure (t) nil (funcall '(closure (t) nil (defalias 'if-let #'compat--if-let))))) => if-let (eval form t) =>if-let (funcall 'if-let) => Error!It seems to be fixed if I change
(funcall (eval form t))
to(eval form t)
only.I will have to take some time to take a look at what could be going wrong here. I suspect this might be an issue in compat-macs.el and code being generated when defining if-let... Could you macro-expand the definition the definition in compat-25.el for me to see if it is doing anything unusual?
Could you macro-expand the definition the definition in compat-25.el for me to see if it is doing anything unusual?
(if (and t (not (fboundp 'if-let))) (progn (defmacro if-let (spec then &rest else) "[Compatibility macro for `if-let']\n\n:realname" compat--if-let :feature 'subr-x (declare (indent 2) (debug ([&or (symbolp form) (&rest [&or symbolp (symbolp form) (form)])] body))) (when (and (<= (length spec) 2) (not (listp (car spec)))) (setq spec (list spec))) `(compat--if-let* ,spec ,then ,(macroexp-progn else)))))The mentioned mirror was from https://elpamirror.emacs-china.org/ , although I don't live in China.
"~daanturo" outgoing@sr.ht writes:
Could you macro-expand the definition the definition in compat-25.el for me to see if it is doing anything unusual?
(if (and t (not (fboundp 'if-let))) (progn (defmacro if-let (spec then &rest else) "[Compatibility macro for `if-let']\n\n:realname" compat--if-let :feature 'subr-x (declare (indent 2) (debug ([&or (symbolp form) (&rest [&or symbolp (symbolp form) (form)])] body))) (when (and (<= (length spec) 2) (not (listp (car spec)))) (setq spec (list spec))) `(compat--if-let* ,spec ,then ,(macroexp-progn else)))))This seems fine, what about if-let*? That is being used here (because the two macros are related), and all the "heavy lifting" is done in that macro.
Note the
eval-after-load 'subr-x
part, it will be called by therequire
advice.(funcall (eval `(funcall ',(lambda nil (defalias 'if-let* #'compat--if-let*))) t))
Invalid function: if-let*
: looks like the error withif-let
.
The expanded macro for
if-let*
as mentioned above (I forgot to include it):(progn (defmacro compat--if-let* (varlist then &rest else) "[Compatibility macro for `if-let*']\n\nBind variables according to VARLIST and evaluate THEN or ELSE.\nThis is like `if-let' but doesn't handle a VARLIST of the form\n(SYMBOL SOMETHING) specially." (declare (indent 2) (debug ((&rest [&or symbolp (symbolp form) (form)]) body))) (let ((empty (make-symbol "s")) (last t) list) (dolist (var varlist) (push `(,(if (cdr var) (car var) empty) (and ,last ,(or (cadr var) (car var)))) list) (when (or (cdr var) (consp (car var))) (setq last (caar list)))) `(let* ,(nreverse list) (if ,(caar list) ,then ,@else)))) (when (and t (not (fboundp 'if-let*))) (eval-after-load 'subr-x `(funcall ',(lambda nil (defalias 'if-let* #'compat--if-let*))))))
"~daanturo" outgoing@sr.ht writes:
Note the
eval-after-load 'subr-x
part, it will be called by therequire
advice.(funcall (eval `(funcall ',(lambda nil (defalias 'if-let* #'compat--if-let*))) t))
Invalid function: if-let*
: looks like the error withif-let
.The background for what is happening here is to be found in https://nullprogram.com/blog/2018/02/22/ (as referenced in `compat--generate-default').
What this indicates to me is that the advice on require might be mistaken in the assumptions it makes on the structure of `after-load-alist' -- at least how it used to look like on Emacs 24.3.
You mentioned having a fix that appeared to work on your system, right? Could you formalise that into a patch?