Subject: Re: byte-compile-let: reversing the order of evaluation of the clauses CAN make a difference.

From: Stefan Monnier <[email-masked]>
Date: Sat, 11 Nov 2023 23:52:38 -0500

> In lisp/emacs-lisp/bytecomp.el (byte-compile-let), when the following
> form (from jit-lock--debug-fontify):
>
>                           (let
>                               ((beg pos)
>                                 (end (setq pos
>                                                (next-single-property-change
>                                                 pos 'fontified
>                                                 nil (point-max)))))
>                             (put-text-property beg end 'fontified nil)
>                             (jit-lock-fontify-now beg end))
>
> gets byte compiled, the order of evaluating BEG and END gets reversed so
> that END gets evaluated first.

Sounds like a bug.  Do you have some recipe to reproduce it?
I looked at the bytecode but it's a bit hard to tell what's going on
there, since the var names are lost along the way.

> The comment in byte-compile-let:
>
>       ;; Bind the variables.
>       ;; For `let', do it in reverse order, because it makes no
>       ;; semantic difference, but it is a lot more efficient since the
>       ;; values are now in reverse order on the stack.
>
> , is not true.  It can make a semantic difference.  So doing the binding
> in reverse order is a bug.

Note that this is talking about the actual binding operations, which is
separate from the computation of the values that are to be given.
What this is saying is that

    (let ((X1 E1)
          (X2 E2))
      ...)

can be compiled to

    <compute E1>
    <compute E2>
    varbind X2
    varbind X1

since computing E pushes it value on the stack, so after the two
"compute" we have the values of E1 and E2 on the stack and we can pop
them in reverse order.  And indeed it should make no difference if we
do the `varbind X1` before or after `varbind X2` as long as they get
the right value and as long as we don't compute anything which depends
on those vars in-between.

        Stefan