bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#62419: 28.2; Elisp let-bound buffer-local variable and kill-local-va


From: Matthew Malcomson
Subject: bug#62419: 28.2; Elisp let-bound buffer-local variable and kill-local-variable
Date: Fri, 24 Mar 2023 13:37:57 +0000

Hello,

I’m inlining some elisp which has behaviour I find unintuitive.
To view the bug I would run each top-level form with C-x C-e in turn in an 
elisp buffer.
This behaviour may be expected — the manual mentions something related — but I 
believe this is an unintended edge-case.
N.b. the use of `auto-fill-function’ is just for a variable which turns 
buffer-local when set, not as anything related to this particular symbol.
FWIW I believe this behaviour to be the root cause of 
https://github.com/joaotavora/yasnippet/issues/919 (which was closed due to not 
being able to reproduce it).

—————
;; Ensure that `auto-fill-function' has a buffer-local version and a global
;; version.
(setq auto-fill-function 'local-symbol)
(describe-variable 'auto-fill-function)
;; `auto-fill-function' is let-bound in the buffer scope
(let ((auto-fill-function 'temp-symbol))
  ;; Now there is no buffer-local variable for `auto-fill-function', but the
  ;; `let' unwrapping info is still there.
  (kill-local-variable 'auto-fill-function)
  ;; Since the check in the emacs source is
  ;; a) Is there a buffer-local variable.
  ;; b) Is there a let-binding shadowing the current variable.
  ;; Then this `setq' sets the *global* variable.
  (setq auto-fill-function 'other-symbol))
;; Exiting the `let' has special handling to avoid resetting a local variable
;; when the local variable was `let' bound, which means that overall the `setq'
;; set the global variable and the `let' has been lost.
(describe-variable 'auto-fill-function)
—————


I think the final state after having done the above should be:
1) Global value has not changed.
2) Local value has not changed.

While the observed state after the above is:
1) Global value has been set to `other-symbol'.
2) Local value has been removed.

- The `setq` inside the `let` sets the *global* value rather than creating a 
buffer-local variable.
- The `let` on the buffer-local version of the variable is lost.

The manual for `make-variable-buffer-local` — in `(elisp) Creating 
Buffer-Local` — does mention that if a variable is in a `let` binding then a 
`setq` does not create a buffer-local version.
That said, I’m guessing the intention of this behaviour is so a `let` binding 
on a global variable is modified rather than bypassed by a `setq`.
I’d suggest that is not relevant to the above code since the use of 
`kill-local-variable` means the `let` is effectively lost already (e.g. it does 
not get “reset” on an unwind).

I’m attaching the source code hack that I’ve started using to work around this.
I’m not proposing this as a change, just including it for extra context about 
the cause.
I *believe* that the form of the C code around here looks like the special case 
of a forwarded variable not having a buffer-local value but having a 
buffer-local `let` binding could easily have been an oversight rather than 
intention.
(N.b. for this hack I guessed the meanings of the `let` enum values).

Attachment: emacs-patch.diff
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]