"~daanturo" outgoing@sr.ht writes:
Thank you for your quick implementation.
Although I noticed that the original function is an interactive command for but for compat, it has been added without its interactive spec, was this intended?
Yes, Compat doesn't intend to provide any user-facing functionality.
Comment by ~daanturo on ~pkal/compat
Thank you for your quick implementation.
Although I notice that the original function is an interactive command but for compat, it has been added without the interactive spec, was this intended?
"~daanturo" outgoing@sr.ht writes:
Defined in Emacs 27.
Added in 6b7a3513dc9dce2e59ef8e11f73f2a011ea1ffeb.
Ticket created by ~daanturo on ~pkal/compat
Defined in Emacs 27.
"~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?
Comment by ~daanturo on ~pkal/compat
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*))))))
Comment by ~daanturo on ~pkal/compat
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
.
"~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.
Comment by ~daanturo on ~pkal/compat
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:
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?