diff options
| author | Stefan Monnier | 2020-05-10 19:07:45 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2020-05-10 19:07:45 -0400 |
| commit | a218c9861573b5ec4979ff2662f5c0343397e3ff (patch) | |
| tree | 679088862b2b911365767f01cc1e8edabe3ec2c9 | |
| parent | 7f7a8fbfd707ee51858a9bee53cff560a0e5b3c0 (diff) | |
| download | emacs-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.el | 47 |
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. |