aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2023-04-02 17:45:58 -0400
committerStefan Monnier2023-04-02 17:45:58 -0400
commit5223762e02ac84eee984cd1f7a17865766cdad9a (patch)
tree379f3431cbf74fc73afc5fe89314bc98d1db762b
parent00144fa287eb168c1ba8e411e43fe13b9d2732ac (diff)
downloademacs-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.c3
-rw-r--r--test/src/eval-tests.el19
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
3406bool 3406bool
@@ -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