summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2021-07-29 15:35:55 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2021-07-30 09:54:30 +0200
commit52a55e11deb7822c67a8d7e6f2544b8f41d25a4e (patch)
tree0054a11e914e09d5dc775a6c07585c73c1cf0e35 /lisp/emacs-lisp
parentab9c06449df4c4c58d586573003de419199cc1be (diff)
Optimise let and let* whose body is constant or the last variable
Simplify (let ((X1 E1) ... (Xn En)) Xn) => (progn E1 ... En) and (let* ((X1 E1) ... (Xn En)) Xn) => (let* ((X1 E1) ... (Xn-1 En-1)) En) and similarly the case where the body is a constant, extending a previous optimisation that only applied to the constant nil. This reduces the number of bound variables, shortens the code, and enables further optimisations. * lisp/emacs-lisp/byte-opt.el (byte-optimize-letX): Rewrite using `pcase` and add the aforementioned transformations. * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases): Add test cases.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/byte-opt.el37
1 files changed, 25 insertions, 12 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index c9dfa69aeb2..d444d7006eb 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1250,18 +1250,31 @@ See Info node `(elisp) Integer Basics'."
(put 'let 'byte-optimizer #'byte-optimize-letX)
(put 'let* 'byte-optimizer #'byte-optimize-letX)
(defun byte-optimize-letX (form)
- (cond ((null (nth 1 form))
- ;; No bindings
- (cons 'progn (cdr (cdr form))))
- ((or (nth 2 form) (nthcdr 3 form))
- form)
- ;; The body is nil
- ((eq (car form) 'let)
- (append '(progn) (mapcar 'car-safe (mapcar 'cdr-safe (nth 1 form)))
- '(nil)))
- (t
- (let ((binds (reverse (nth 1 form))))
- (list 'let* (reverse (cdr binds)) (nth 1 (car binds)) nil)))))
+ (pcase form
+ ;; No bindings.
+ (`(,_ () . ,body)
+ `(progn . ,body))
+
+ ;; Body is empty or just contains a constant.
+ (`(,head ,bindings . ,(or '() `(,(and const (pred macroexp-const-p)))))
+ (if (eq head 'let)
+ `(progn ,@(mapcar (lambda (binding)
+ (and (consp binding) (cadr binding)))
+ bindings)
+ ,const)
+ `(let* ,(butlast bindings) ,(cadar (last bindings)) ,const)))
+
+ ;; Body is last variable.
+ (`(,head ,bindings ,(and var (pred symbolp) (pred (not keywordp))
+ (pred (not booleanp))
+ (guard (eq var (caar (last bindings))))))
+ (if (eq head 'let)
+ `(progn ,@(mapcar (lambda (binding)
+ (and (consp binding) (cadr binding)))
+ bindings))
+ `(let* ,(butlast bindings) ,(cadar (last bindings)))))
+
+ (_ form)))
(put 'nth 'byte-optimizer #'byte-optimize-nth)