Subject: Re: bug#7070: `load-time-value' local-vars this-kind and that-one

From: [email-masked]
Date: Sun, 07 Aug 2016 16:42:29 -0400

severity 7070 minor
quit

MON KEY <[email-masked]> writes:

> current through BZR-101480 lisp/cl-macs.el macro `load-time-value' has this
> branch which if unsatisfied is supposed to fset `byte-compile-file-form':
>
>  (and (fboundp 'byte-compile-file-form-defmumble)
>       (boundp 'this-kind) (boundp 'that-one))
>
> However, luckily the above doesn't happen.
>
> The only locations that bind the variables like this are in
> byte-compile-file-form-defmumble' e.g. the local letbound vars
> bytecomp-this-kind' and `bytecomp-that-one'.

[...]

>
> Revision 96701 renamed the `byte-compile-file-form-defmumble's local vars:
>
> `this-kind' -> `bytecomp-this-kind'
> `this-one'  -> `bytecomp-this-one'
> `that-one'  -> `bytecomp-that-one'
> `outbuffer' -> `bytecomp-outbuffer'
>
> Revision 96702 renamed the `load-time-value' local var:
>
> `outbuffer' -> `bytecomp-outbuffer'
>
> but it appears to have left the `this-one' and `this-kind' vars unchanged.

Meanwhile, bytecomp.el has switched to lexical binding, so the names of
this-kind and that-one are irrelevant; they will never be bound.

>
> Unless I am misunderstanding/missing something either:
>
> a) some special magic that happens invisibily when Emacs is dumped and the
>    current constraint is some sort of backward compatibility kludge;
>
> b) the macro never worked correctly;
>
> c) revisions at 96701/96702 created a bug where `load-time-value's can no longer
>    alter via fset the function cell of `byte-compile-file-form' because the
>    following constraint can not be satisfied;
>
> d) the macro never worked correctly and revisions at 96701/96702 created an
>    additional bug;
>
> My money is on d.

I'm not sure about past behaviour, but with current Emacs, the macro
does appear to work correctly.  AFAICT, it's because the condition the
boundp calls are trying to protect against (that the compiler is in the
middle of printing out a function's code) never occurs because the
compiler prints the code of a function in a single shot (perhaps because
it has to run optimizations on the whole function before printing?).  In
other words this macro could be simplified to

    (defmacro cl-load-time-value (form &optional _read-only)
      "Like `progn', but evaluates the body at load time.
    The result of the body appears to the compiler as a quoted constant."
      (declare (debug (form &optional sexp)))
      (if (cl--compiling-file)
          (let* ((temp (cl-gentemp "--cl-load-time--")))
            ;; Assume there are no unclosed parens in
            ;; `byte-compile--outbuffer'.
            (print `(setq ,temp ,form) byte-compile--outbuffer)
            temp)
        `',(eval form)))

And it should probably use `defconst' instead of `setq' to avoid a free
variable warning.

>
> Also, what does the READ-ONLY arg do?
>
> The only possibility I can think of is that it somehow dovetails with the
> :read-only key in defstruct.

It does nothing in Emacs' implementation, perhaps it could use
`purecopy'?  Although that would still do nothing most of the time, so
maybe it's not worth the trouble.

According to cltl (https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node224.html)

  The optional read-only-p argument designates whether the result may
  be considered a read-only constant. If nil (the default), the result
  must be considered ordinary, modifiable data. If t, the result is a
  read-only quantity that may, as appropriate, be copied into
  read-only space and may, as appropriate, be shared with other
  programs. The read-only-p argument is not evaluated and only the
  literal symbols t and nil are permitted.