summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2024-06-08 17:34:30 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2024-06-08 17:34:56 -0400
commite9a0256a556622474bcbb015f88d790666db2cc9 (patch)
tree614c7612fe09bf0f5de1231ca6741213d31b8f3b /lisp/emacs-lisp
parent15f515c7a37f29117ff123821265a760ff0d040d (diff)
downloademacs-e9a0256a556622474bcbb015f88d790666db2cc9.tar.gz
emacs-e9a0256a556622474bcbb015f88d790666db2cc9.tar.bz2
emacs-e9a0256a556622474bcbb015f88d790666db2cc9.zip
(pcase--app-subst-match): Try and fix performance regression (bug#71398)
* lisp/emacs-lisp/pcase.el (pcase--app-subst-match): Optimize matches against (quote VAL). * test/lisp/emacs-lisp/pcase-tests.el (pcase-tests-quote-optimization): Add new test case.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/pcase.el33
1 files changed, 28 insertions, 5 deletions
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 69353daf7d0..5a7f3995311 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -857,13 +857,36 @@ A and B can be one of:
(or (keywordp upat) (integerp upat) (stringp upat)))
(defun pcase--app-subst-match (match sym fun nsym)
+ "Refine MATCH knowing that NSYM = (funcall FUN SYM)."
(cond
((eq (car-safe match) 'match)
- (if (and (eq sym (cadr match))
- (eq 'app (car-safe (cddr match)))
- (equal fun (nth 1 (cddr match))))
- (pcase--match nsym (nth 2 (cddr match)))
- match))
+ (cond
+ ((not (eq sym (cadr match))) match)
+ ((and (eq 'app (car-safe (cddr match)))
+ (equal fun (nth 1 (cddr match))))
+ ;; MATCH is (match SYM app FUN UPAT), so we can refine it to refer to
+ ;; NSYM rather than re-compute (funcall FUN SYM).
+ (pcase--match nsym (nth 2 (cddr match))))
+ ((eq 'quote (car-safe (cddr match)))
+ ;; MATCH is (match SYM quote VAL), so we can decompose it into
+ ;; (match NSYM quote (funcall FUN VAL)) plus a check that
+ ;; the part of VAL not included in (funcall FUN VAL) still
+ ;; result is SYM matching (quote VAL). (bug#71398)
+ (condition-case nil
+ `(and (match ,nsym . ',(funcall fun (nth 3 match)))
+ ;; FIXME: "the part of VAL not included in (funcall FUN VAL)"
+ ;; is hard to define for arbitrary FUN. We do it only when
+ ;; FUN is `c[ad]r', and for the rest we just preserve
+ ;; the original `match' which is not optimal but safe.
+ ,(if (and (memq fun '(car cdr car-safe cdr-safe))
+ (consp (nth 3 match)))
+ (let ((otherfun (if (memq fun '(car car-safe))
+ #'cdr-safe #'car-safe)))
+ `(match ,(cadr match) app ,otherfun
+ ',(funcall otherfun (nth 3 match))))
+ match))
+ (error match)))
+ (t match)))
((memq (car-safe match) '(or and))
`(,(car match)
,@(mapcar (lambda (match)