aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2020-05-10 19:07:45 -0400
committerStefan Monnier2020-05-10 19:07:45 -0400
commita218c9861573b5ec4979ff2662f5c0343397e3ff (patch)
tree679088862b2b911365767f01cc1e8edabe3ec2c9
parent7f7a8fbfd707ee51858a9bee53cff560a0e5b3c0 (diff)
downloademacs-a218c9861573b5ec4979ff2662f5c0343397e3ff.tar.gz
emacs-a218c9861573b5ec4979ff2662f5c0343397e3ff.zip
* lisp/emacs-lisp/pcase.el: Don't bind unused vars in branches
(pcase--fgrep): Change calling convention to take bindings rather than just variables. (pcase--funcall, pcase--eval): Adjust to this new calling convention. (pcase--expand): Use `pcase--fgrep` to bind only the vars that are used.
-rw-r--r--lisp/emacs-lisp/pcase.el47
1 files changed, 27 insertions, 20 deletions
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 36b93fa7ac5..4b7689ad42c 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -344,7 +344,8 @@ of the elements of LIST is performed as if by `pcase-let'.
344 (seen '()) 344 (seen '())
345 (codegen 345 (codegen
346 (lambda (code vars) 346 (lambda (code vars)
347 (let ((prev (assq code seen))) 347 (let ((vars (pcase--fgrep vars code))
348 (prev (assq code seen)))
348 (if (not prev) 349 (if (not prev)
349 (let ((res (pcase-codegen code vars))) 350 (let ((res (pcase-codegen code vars)))
350 (push (list code vars res) seen) 351 (push (list code vars res) seen)
@@ -398,7 +399,10 @@ of the elements of LIST is performed as if by `pcase-let'.
398 (if (pcase--small-branch-p (cdr case)) 399 (if (pcase--small-branch-p (cdr case))
399 ;; Don't bother sharing multiple 400 ;; Don't bother sharing multiple
400 ;; occurrences of this leaf since it's small. 401 ;; occurrences of this leaf since it's small.
401 #'pcase-codegen codegen) 402 (lambda (code vars)
403 (pcase-codegen code
404 (pcase--fgrep vars code)))
405 codegen)
402 (cdr case) 406 (cdr case)
403 vars)))) 407 vars))))
404 cases)))) 408 cases))))
@@ -687,14 +691,17 @@ MATCH is the pattern that needs to be matched, of the form:
687 '(nil . :pcase--fail) 691 '(nil . :pcase--fail)
688 '(:pcase--fail . nil)))))) 692 '(:pcase--fail . nil))))))
689 693
690(defun pcase--fgrep (vars sexp) 694(defun pcase--fgrep (bindings sexp)
691 "Check which of the symbols VARS appear in SEXP." 695 "Return those of the BINDINGS which might be used in SEXP."
692 (let ((res '())) 696 (let ((res '()))
693 (while (consp sexp) 697 (while (and (consp sexp) bindings)
694 (dolist (var (pcase--fgrep vars (pop sexp))) 698 (dolist (binding (pcase--fgrep bindings (pop sexp)))
695 (unless (memq var res) (push var res)))) 699 (push binding res)
696 (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) 700 (setq bindings (remove binding bindings))))
697 res)) 701 (let ((tmp (assq sexp bindings)))
702 (if tmp
703 (cons tmp res)
704 res))))
698 705
699(defun pcase--self-quoting-p (upat) 706(defun pcase--self-quoting-p (upat)
700 (or (keywordp upat) (integerp upat) (stringp upat))) 707 (or (keywordp upat) (integerp upat) (stringp upat)))
@@ -734,13 +741,11 @@ MATCH is the pattern that needs to be matched, of the form:
734 "Build a function call to FUN with arg ARG." 741 "Build a function call to FUN with arg ARG."
735 (if (symbolp fun) 742 (if (symbolp fun)
736 `(,fun ,arg) 743 `(,fun ,arg)
737 (let* (;; `vs' is an upper bound on the vars we need. 744 (let* (;; `env' is an upper bound on the bindings we need.
738 (vs (pcase--fgrep (mapcar #'car vars) fun)) 745 (env (mapcar (lambda (x) (list (car x) (cdr x)))
739 (env (mapcar (lambda (var) 746 (pcase--fgrep vars fun)))
740 (list var (cdr (assq var vars))))
741 vs))
742 (call (progn 747 (call (progn
743 (when (memq arg vs) 748 (when (assq arg env)
744 ;; `arg' is shadowed by `env'. 749 ;; `arg' is shadowed by `env'.
745 (let ((newsym (gensym "x"))) 750 (let ((newsym (gensym "x")))
746 (push (list newsym arg) env) 751 (push (list newsym arg) env)
@@ -748,7 +753,7 @@ MATCH is the pattern that needs to be matched, of the form:
748 (if (functionp fun) 753 (if (functionp fun)
749 `(funcall #',fun ,arg) 754 `(funcall #',fun ,arg)
750 `(,@fun ,arg))))) 755 `(,@fun ,arg)))))
751 (if (null vs) 756 (if (null env)
752 call 757 call
753 ;; Let's not replace `vars' in `fun' since it's 758 ;; Let's not replace `vars' in `fun' since it's
754 ;; too difficult to do it right, instead just 759 ;; too difficult to do it right, instead just
@@ -759,10 +764,12 @@ MATCH is the pattern that needs to be matched, of the form:
759 "Build an expression that will evaluate EXP." 764 "Build an expression that will evaluate EXP."
760 (let* ((found (assq exp vars))) 765 (let* ((found (assq exp vars)))
761 (if found (cdr found) 766 (if found (cdr found)
762 (let* ((vs (pcase--fgrep (mapcar #'car vars) exp)) 767 (let* ((env (pcase--fgrep vars exp)))
763 (env (mapcar (lambda (v) (list v (cdr (assq v vars)))) 768 (if env
764 vs))) 769 (macroexp-let* (mapcar (lambda (x) (list (car x) (cdr x)))
765 (if env (macroexp-let* env exp) exp))))) 770 env)
771 exp)
772 exp)))))
766 773
767;; It's very tempting to use `pcase' below, tho obviously, it'd create 774;; It's very tempting to use `pcase' below, tho obviously, it'd create
768;; bootstrapping problems. 775;; bootstrapping problems.