]> git.eshelyaron.com Git - emacs.git/commitdiff
Don't rewrite `set` to `setq` of lexical variables
authorMattias Engdegård <mattiase@acm.org>
Thu, 22 Sep 2022 12:15:56 +0000 (14:15 +0200)
committerMattias Engdegård <mattiase@acm.org>
Thu, 22 Sep 2022 12:54:15 +0000 (14:54 +0200)
Only perform the rewrite

   (set 'VAR X) -> (setq VAR X)

for dynamic variables, as `set` isn't supposed to affect
lexical vars (and never does so when interpreted).

* lisp/emacs-lisp/byte-opt.el (byte-optimize-set):
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--xx): New.
(bytecomp-tests--test-cases): Add test cases.
* test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el:
Remove obsolete test.

lisp/emacs-lisp/byte-opt.el
test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el [deleted file]
test/lisp/emacs-lisp/bytecomp-tests.el

index 0d5f8c26eb2d0999a91909ab649ddcb6cbe94ba1..4ef9cb0a1e4aca1310ef7738e73b93c342e16411 100644 (file)
@@ -1531,15 +1531,16 @@ See Info node `(elisp) Integer Basics'."
 
 (put 'set 'byte-optimizer #'byte-optimize-set)
 (defun byte-optimize-set (form)
-  (let ((var (car-safe (cdr-safe form))))
-    (cond
-     ((and (eq (car-safe var) 'quote) (consp (cdr var)))
-      `(setq ,(cadr var) ,@(cddr form)))
-     ((and (eq (car-safe var) 'make-local-variable)
-          (eq (car-safe (setq var (car-safe (cdr var)))) 'quote)
-          (consp (cdr var)))
-      `(progn ,(cadr form) (setq ,(cadr var) ,@(cddr form))))
-     (t form))))
+  (pcase (cdr form)
+    ;; Make sure we only turn `set' into `setq' for dynamic variables.
+    (`((quote ,(and var (guard (and (symbolp var)
+                                    (not (macroexp--const-symbol-p var))
+                                    (not (assq var byte-optimize--lexvars))))))
+       ,newval)
+     `(setq ,var ,newval))
+    (`(,(and ml `(make-local-variable ,(and v `(quote ,_)))) ,newval)
+     `(progn ,ml (,(car form) ,v ,newval)))
+    (_ form)))
 \f
 ;; enumerating those functions which need not be called if the returned
 ;; value is not used.  That is, something like
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el
deleted file mode 100644 (file)
index 0c76c4d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-;;; -*- lexical-binding: t -*-
-(defun foo ()
-  (set '(a) nil))
index 1ca44dc7a488a0aa85b2e0bb9737ab2adbcf06d8..e7c308213e4e85a645518095fce3b9675deb7b59 100644 (file)
@@ -59,6 +59,8 @@ inner loops respectively."
        (setq i (1- i)))
      res))
 
+(defvar bytecomp-tests--xx nil)
+
 (defconst bytecomp-tests--test-cases
   '(
     ;; some functional tests
@@ -692,6 +694,16 @@ inner loops respectively."
            (f (lambda ()
                 (let ((y x)) (list y 3 y)))))
       (funcall f))
+
+    ;; Test rewriting of `set' to `setq' (only done on dynamic variables).
+    (let ((xx 1)) (set 'xx 2) xx)
+    (let ((bytecomp-tests--xx 1))
+      (set 'bytecomp-tests--xx 2)
+      bytecomp-tests--xx)
+    (let ((aaa 1)) (set (make-local-variable 'aaa) 2) aaa)
+    (let ((bytecomp-tests--xx 1))
+      (set (make-local-variable 'bytecomp-tests--xx) 2)
+      bytecomp-tests--xx)
     )
   "List of expressions for cross-testing interpreted and compiled code.")
 
@@ -953,9 +965,6 @@ byte-compiled.  Run with dynamic binding."
 (bytecomp--define-warning-file-test "warn-variable-set-constant.el"
                             "attempt to set constant")
 
-(bytecomp--define-warning-file-test "warn-variable-set-nonvariable.el"
-                            "variable reference to nonvariable")
-
 (bytecomp--define-warning-file-test "warn-variable-setq-nonvariable.el"
                             "attempt to set non-variable")