diff options
| author | Stefan Monnier | 2012-05-29 10:28:02 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-05-29 10:28:02 -0400 |
| commit | 6876a58db34b81e411293b5ee8d161aa451fd767 (patch) | |
| tree | b1cc081fe4c2b62f737018f19c016b95ff5a9e99 | |
| parent | 46b7967e4d98570501f5e75ba7460fa4c79e4617 (diff) | |
| download | emacs-6876a58db34b81e411293b5ee8d161aa451fd767.tar.gz emacs-6876a58db34b81e411293b5ee8d161aa451fd767.zip | |
Fix minor corner case bugs in byte compilation and pcase.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand): Don't re-preprocess
functions from byte-compile-function-environment.
* lisp/emacs-lisp/bytecomp.el (byte-compile-constp): Treat #'v as a constant.
(byte-compile-close-variables): Bind byte-compile--outbuffer here...
(byte-compile-from-buffer): ...rather than here.
* lisp/emacs-lisp/pcase.el (pcase--expand): Accept different sets of vars in
different alternative patterns.
(pcase-codegen): Be more careful to preserve identity.
(pcase--u1): Don't forget to mark vars as used.
| -rw-r--r-- | lisp/ChangeLog | 14 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 12 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 75 | ||||
| -rw-r--r-- | lisp/emacs-lisp/pcase.el | 15 |
4 files changed, 71 insertions, 45 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index fbb398335d8..83d3f3e4677 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,17 @@ | |||
| 1 | 2012-05-29 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/pcase.el (pcase--expand): Accept different sets of vars in | ||
| 4 | different alternative patterns. | ||
| 5 | (pcase-codegen): Be more careful to preserve identity. | ||
| 6 | (pcase--u1): Don't forget to mark vars as used. | ||
| 7 | |||
| 8 | * emacs-lisp/bytecomp.el (byte-compile-constp): Treat #'v as a constant. | ||
| 9 | (byte-compile-close-variables): Bind byte-compile--outbuffer here... | ||
| 10 | (byte-compile-from-buffer): ...rather than here. | ||
| 11 | |||
| 12 | * emacs-lisp/byte-opt.el (byte-compile-inline-expand): Don't re-preprocess | ||
| 13 | functions from byte-compile-function-environment. | ||
| 14 | |||
| 1 | 2012-05-29 Troels Nielsen <bn.troels@gmail.com> | 15 | 2012-05-29 Troels Nielsen <bn.troels@gmail.com> |
| 2 | 16 | ||
| 3 | * window.el (window-deletable-p): Avoid deleting the root window | 17 | * window.el (window-deletable-p): Avoid deleting the root window |
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 3b324a09659..9dd475f2a51 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -288,10 +288,14 @@ | |||
| 288 | (push `(,(car binding) ',(cdr binding)) renv))) | 288 | (push `(,(car binding) ',(cdr binding)) renv))) |
| 289 | ((eq binding t)) | 289 | ((eq binding t)) |
| 290 | (t (push `(defvar ,binding) body)))) | 290 | (t (push `(defvar ,binding) body)))) |
| 291 | (let ((newfn (byte-compile-preprocess | 291 | (let ((newfn (if (eq fn localfn) |
| 292 | (if (null renv) | 292 | ;; If `fn' is from the same file, it has already |
| 293 | `(lambda ,args ,@body) | 293 | ;; been preprocessed! |
| 294 | `(lambda ,args (let ,(nreverse renv) ,@body)))))) | 294 | `(function ,fn) |
| 295 | (byte-compile-preprocess | ||
| 296 | (if (null renv) | ||
| 297 | `(lambda ,args ,@body) | ||
| 298 | `(lambda ,args (let ,(nreverse renv) ,@body))))))) | ||
| 295 | (if (eq (car-safe newfn) 'function) | 299 | (if (eq (car-safe newfn) 'function) |
| 296 | (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form))) | 300 | (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form))) |
| 297 | (byte-compile-log-warning | 301 | (byte-compile-log-warning |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 91db288feef..2518d8359c3 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -1478,40 +1478,46 @@ symbol itself." | |||
| 1478 | 1478 | ||
| 1479 | (defmacro byte-compile-constp (form) | 1479 | (defmacro byte-compile-constp (form) |
| 1480 | "Return non-nil if FORM is a constant." | 1480 | "Return non-nil if FORM is a constant." |
| 1481 | `(cond ((consp ,form) (eq (car ,form) 'quote)) | 1481 | `(cond ((consp ,form) (or (eq (car ,form) 'quote) |
| 1482 | (and (eq (car ,form) 'function) | ||
| 1483 | (symbolp (cadr ,form))))) | ||
| 1482 | ((not (symbolp ,form))) | 1484 | ((not (symbolp ,form))) |
| 1483 | ((byte-compile-const-symbol-p ,form)))) | 1485 | ((byte-compile-const-symbol-p ,form)))) |
| 1484 | 1486 | ||
| 1487 | ;; Dynamically bound in byte-compile-from-buffer. | ||
| 1488 | ;; NB also used in cl.el and cl-macs.el. | ||
| 1489 | (defvar byte-compile--outbuffer) | ||
| 1490 | |||
| 1485 | (defmacro byte-compile-close-variables (&rest body) | 1491 | (defmacro byte-compile-close-variables (&rest body) |
| 1486 | (declare (debug t)) | 1492 | (declare (debug t)) |
| 1487 | (cons 'let | 1493 | `(let (;; |
| 1488 | (cons '(;; | 1494 | ;; Close over these variables to encapsulate the |
| 1489 | ;; Close over these variables to encapsulate the | 1495 | ;; compilation state |
| 1490 | ;; compilation state | 1496 | ;; |
| 1491 | ;; | 1497 | (byte-compile-macro-environment |
| 1492 | (byte-compile-macro-environment | 1498 | ;; Copy it because the compiler may patch into the |
| 1493 | ;; Copy it because the compiler may patch into the | 1499 | ;; macroenvironment. |
| 1494 | ;; macroenvironment. | 1500 | (copy-alist byte-compile-initial-macro-environment)) |
| 1495 | (copy-alist byte-compile-initial-macro-environment)) | 1501 | (byte-compile--outbuffer nil) |
| 1496 | (byte-compile-function-environment nil) | 1502 | (byte-compile-function-environment nil) |
| 1497 | (byte-compile-bound-variables nil) | 1503 | (byte-compile-bound-variables nil) |
| 1498 | (byte-compile-const-variables nil) | 1504 | (byte-compile-const-variables nil) |
| 1499 | (byte-compile-free-references nil) | 1505 | (byte-compile-free-references nil) |
| 1500 | (byte-compile-free-assignments nil) | 1506 | (byte-compile-free-assignments nil) |
| 1501 | ;; | 1507 | ;; |
| 1502 | ;; Close over these variables so that `byte-compiler-options' | 1508 | ;; Close over these variables so that `byte-compiler-options' |
| 1503 | ;; can change them on a per-file basis. | 1509 | ;; can change them on a per-file basis. |
| 1504 | ;; | 1510 | ;; |
| 1505 | (byte-compile-verbose byte-compile-verbose) | 1511 | (byte-compile-verbose byte-compile-verbose) |
| 1506 | (byte-optimize byte-optimize) | 1512 | (byte-optimize byte-optimize) |
| 1507 | (byte-compile-dynamic byte-compile-dynamic) | 1513 | (byte-compile-dynamic byte-compile-dynamic) |
| 1508 | (byte-compile-dynamic-docstrings | 1514 | (byte-compile-dynamic-docstrings |
| 1509 | byte-compile-dynamic-docstrings) | 1515 | byte-compile-dynamic-docstrings) |
| 1510 | ;; (byte-compile-generate-emacs19-bytecodes | 1516 | ;; (byte-compile-generate-emacs19-bytecodes |
| 1511 | ;; byte-compile-generate-emacs19-bytecodes) | 1517 | ;; byte-compile-generate-emacs19-bytecodes) |
| 1512 | (byte-compile-warnings byte-compile-warnings) | 1518 | (byte-compile-warnings byte-compile-warnings) |
| 1513 | ) | 1519 | ) |
| 1514 | body))) | 1520 | ,@body)) |
| 1515 | 1521 | ||
| 1516 | (defmacro displaying-byte-compile-warnings (&rest body) | 1522 | (defmacro displaying-byte-compile-warnings (&rest body) |
| 1517 | (declare (debug t)) | 1523 | (declare (debug t)) |
| @@ -1852,13 +1858,8 @@ With argument ARG, insert value in current buffer after the form." | |||
| 1852 | (insert "\n")) | 1858 | (insert "\n")) |
| 1853 | ((message "%s" (prin1-to-string value))))))) | 1859 | ((message "%s" (prin1-to-string value))))))) |
| 1854 | 1860 | ||
| 1855 | ;; Dynamically bound in byte-compile-from-buffer. | ||
| 1856 | ;; NB also used in cl.el and cl-macs.el. | ||
| 1857 | (defvar byte-compile--outbuffer) | ||
| 1858 | |||
| 1859 | (defun byte-compile-from-buffer (inbuffer) | 1861 | (defun byte-compile-from-buffer (inbuffer) |
| 1860 | (let (byte-compile--outbuffer | 1862 | (let ((byte-compile-current-buffer inbuffer) |
| 1861 | (byte-compile-current-buffer inbuffer) | ||
| 1862 | (byte-compile-read-position nil) | 1863 | (byte-compile-read-position nil) |
| 1863 | (byte-compile-last-position nil) | 1864 | (byte-compile-last-position nil) |
| 1864 | ;; Prevent truncation of flonums and lists as we read and print them | 1865 | ;; Prevent truncation of flonums and lists as we read and print them |
| @@ -1930,8 +1931,8 @@ and will be removed soon. See (elisp)Backquote in the manual.")) | |||
| 1930 | ;; if the buffer contains multibyte characters. | 1931 | ;; if the buffer contains multibyte characters. |
| 1931 | (and byte-compile-current-file | 1932 | (and byte-compile-current-file |
| 1932 | (with-current-buffer byte-compile--outbuffer | 1933 | (with-current-buffer byte-compile--outbuffer |
| 1933 | (byte-compile-fix-header byte-compile-current-file))))) | 1934 | (byte-compile-fix-header byte-compile-current-file)))) |
| 1934 | byte-compile--outbuffer)) | 1935 | byte-compile--outbuffer))) |
| 1935 | 1936 | ||
| 1936 | (defun byte-compile-fix-header (filename) | 1937 | (defun byte-compile-fix-header (filename) |
| 1937 | "If the current buffer has any multibyte characters, insert a version test." | 1938 | "If the current buffer has any multibyte characters, insert a version test." |
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 363c0965c3e..9f98b30adae 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el | |||
| @@ -206,9 +206,12 @@ of the form (UPAT EXP)." | |||
| 206 | (setq vars (delq v vars)) | 206 | (setq vars (delq v vars)) |
| 207 | (cdr v))) | 207 | (cdr v))) |
| 208 | prevvars))) | 208 | prevvars))) |
| 209 | (when vars ;New additional vars. | 209 | ;; If some of `vars' were not found in `prevvars', that's |
| 210 | (error "The vars %s are only bound in some paths" | 210 | ;; OK it just means those vars aren't present in all |
| 211 | (mapcar #'car vars))) | 211 | ;; branches, so they can be used within the pattern |
| 212 | ;; (e.g. by a `guard/let/pred') but not in the branch. | ||
| 213 | ;; FIXME: But if some of `prevvars' are not in `vars' we | ||
| 214 | ;; should remove them from `prevvars'! | ||
| 212 | `(funcall ,res ,@args))))))) | 215 | `(funcall ,res ,@args))))))) |
| 213 | (main | 216 | (main |
| 214 | (pcase--u | 217 | (pcase--u |
| @@ -225,7 +228,10 @@ of the form (UPAT EXP)." | |||
| 225 | (pcase--let* defs main)))) | 228 | (pcase--let* defs main)))) |
| 226 | 229 | ||
| 227 | (defun pcase-codegen (code vars) | 230 | (defun pcase-codegen (code vars) |
| 228 | `(let* ,(mapcar (lambda (b) (list (car b) (cdr b))) vars) | 231 | ;; Don't use let*, otherwise pcase--let* may merge it with some surrounding |
| 232 | ;; let* which might prevent the setcar/setcdr in pcase--expand's fancy | ||
| 233 | ;; codegen from later metamorphosing this let into a funcall. | ||
| 234 | `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars) | ||
| 229 | ,@code)) | 235 | ,@code)) |
| 230 | 236 | ||
| 231 | (defun pcase--small-branch-p (code) | 237 | (defun pcase--small-branch-p (code) |
| @@ -619,6 +625,7 @@ Otherwise, it defers to REST which is a list of branches of the form | |||
| 619 | sym (apply-partially #'pcase--split-member elems) rest)) | 625 | sym (apply-partially #'pcase--split-member elems) rest)) |
| 620 | (then-rest (car splitrest)) | 626 | (then-rest (car splitrest)) |
| 621 | (else-rest (cdr splitrest))) | 627 | (else-rest (cdr splitrest))) |
| 628 | (put sym 'pcase-used t) | ||
| 622 | (pcase--if `(,(if memq-fine #'memq #'member) ,sym ',elems) | 629 | (pcase--if `(,(if memq-fine #'memq #'member) ,sym ',elems) |
| 623 | (pcase--u1 matches code vars then-rest) | 630 | (pcase--u1 matches code vars then-rest) |
| 624 | (pcase--u else-rest))) | 631 | (pcase--u else-rest))) |