Subject: bug#47272: 27.1; cl-progv binds variables in wrong order

From: Toby Cubitt <[email-masked]>
Date: Sat, 20 Mar 2021 00:27:03 +0000

The following

(cl-progv (test test) (1 2)
  test)

evaluates to 1. It should evaluate to 2.

The docstring states that cl-progv "much like a let form", and

(let ((test 1) (test 2))
 test)

evaluates to 2.

This bug in cl-progv breaks org agenda settings in
org-agenda-custom-commands, by preventing local variable settings in
agenda blocks from overriding variable settings in the overall agenda
command. (Broken since commit 129c33dddfa80202f23756ad5b513acdc036591c
in the org-mode repo, which switched the agenda varable setting code in
org-agenda to use cl-progv.)

Fixed implementation of cl-progv:

(defmacro cl-progv (symbols values &rest body)
  "Bind SYMBOLS to VALUES dynamically in BODY.
The forms SYMBOLS and VALUES are evaluated, and must evaluate to lists.
Each symbol in the first list is bound to the corresponding value in the
second list (or to nil if VALUES is shorter than SYMBOLS); then the
BODY forms are executed and their result is returned.  This is much like
a `let' form, except that the list of symbols can be computed at run-time."
  (declare (indent 2) (debug (form form body)))
  (let ((bodyfun (make-symbol "body"))
        (binds (make-symbol "binds"))
        (syms (make-symbol "syms"))
        (vals (make-symbol "vals")))
    `(progn
       (let* ((,syms ,symbols)
              (,vals ,values)
              (,bodyfun (lambda () ,@body))
              (,binds ()))
         (while ,syms
           (push (list (pop ,syms) (list 'quote (pop ,vals))) ,binds))
	 (setq ,binds (nreverse ,binds))
         (eval (list 'let ,binds (list 'funcall (list 'quote ,bodyfun))))))))

--
Dr T. S. Cubitt
Reader (Associate Professor) in Quantum Information
Royal Society University Research Fellow
Department of Computer Science
University College London

email: [email-masked]
web:   www.dr-qubit.org