diff options
| author | Stefan Monnier | 2023-04-02 17:45:58 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2023-04-02 17:45:58 -0400 |
| commit | 5223762e02ac84eee984cd1f7a17865766cdad9a (patch) | |
| tree | 379f3431cbf74fc73afc5fe89314bc98d1db762b | |
| parent | 00144fa287eb168c1ba8e411e43fe13b9d2732ac (diff) | |
| download | emacs-5223762e02ac84eee984cd1f7a17865766cdad9a.tar.gz emacs-5223762e02ac84eee984cd1f7a17865766cdad9a.zip | |
src/eval.c: Fix bug#62419
Yup, almost 40 years after ELisp first combined them, buffer-local
and let bindings still don't work quite right :-(
The "automatically buffer-local if set" semantics should follow the
principle that it becomes buffer-local iff the var's current binding
refers to the top-level/global/non-let binding.
* src/eval.c (let_shadows_buffer_binding_p): Disregard non-global
let-bindings.
* test/src/eval-tests.el (eval-test--bug62419): New test.
| -rw-r--r-- | src/eval.c | 3 | ||||
| -rw-r--r-- | test/src/eval-tests.el | 19 |
2 files changed, 21 insertions, 1 deletions
diff --git a/src/eval.c b/src/eval.c index eb40c953f96..1a4d3ad0307 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -3400,7 +3400,7 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode, | |||
| 3400 | return object; | 3400 | return object; |
| 3401 | } | 3401 | } |
| 3402 | 3402 | ||
| 3403 | /* Return true if SYMBOL currently has a let-binding | 3403 | /* Return true if SYMBOL's default currently has a let-binding |
| 3404 | which was made in the buffer that is now current. */ | 3404 | which was made in the buffer that is now current. */ |
| 3405 | 3405 | ||
| 3406 | bool | 3406 | bool |
| @@ -3415,6 +3415,7 @@ let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol) | |||
| 3415 | struct Lisp_Symbol *let_bound_symbol = XSYMBOL (specpdl_symbol (p)); | 3415 | struct Lisp_Symbol *let_bound_symbol = XSYMBOL (specpdl_symbol (p)); |
| 3416 | eassert (let_bound_symbol->u.s.redirect != SYMBOL_VARALIAS); | 3416 | eassert (let_bound_symbol->u.s.redirect != SYMBOL_VARALIAS); |
| 3417 | if (symbol == let_bound_symbol | 3417 | if (symbol == let_bound_symbol |
| 3418 | && p->kind != SPECPDL_LET_LOCAL /* bug#62419 */ | ||
| 3418 | && EQ (specpdl_where (p), buf)) | 3419 | && EQ (specpdl_where (p), buf)) |
| 3419 | return 1; | 3420 | return 1; |
| 3420 | } | 3421 | } |
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el index 1e7edca3bac..e0a27439ba2 100644 --- a/test/src/eval-tests.el +++ b/test/src/eval-tests.el | |||
| @@ -247,4 +247,23 @@ expressions works for identifiers starting with period." | |||
| 247 | (should (equal (string-trim (buffer-string)) | 247 | (should (equal (string-trim (buffer-string)) |
| 248 | expected-messages)))))))) | 248 | expected-messages)))))))) |
| 249 | 249 | ||
| 250 | (defvar-local eval-test--local-var 'global) | ||
| 251 | |||
| 252 | (ert-deftest eval-test--bug62419 () | ||
| 253 | (with-temp-buffer | ||
| 254 | (setq eval-test--local-var 'first-local) | ||
| 255 | (let ((eval-test--local-var t)) | ||
| 256 | (kill-local-variable 'eval-test--local-var) | ||
| 257 | (setq eval-test--local-var 'second-local) | ||
| 258 | (should (eq eval-test--local-var 'second-local))) | ||
| 259 | ;; FIXME: It's not completely clear if exiting the above `let' | ||
| 260 | ;; should restore the buffer-local binding to `first-local' | ||
| 261 | ;; (i.e. reset the value of the second buffer-local binding to the | ||
| 262 | ;; first's initial value) or should do nothing (on the principle that | ||
| 263 | ;; the first buffer-local binding doesn't exists any more so there's | ||
| 264 | ;; nothing to restore). I think both semantics make sense. | ||
| 265 | ;;(should (eq eval-test--local-var 'first-local)) | ||
| 266 | ) | ||
| 267 | (should (eq eval-test--local-var 'global))) | ||
| 268 | |||
| 250 | ;;; eval-tests.el ends here | 269 | ;;; eval-tests.el ends here |