diff options
| author | Noam Postavsky | 2018-06-12 18:41:46 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2018-06-19 20:02:16 -0400 |
| commit | e292c0973cf7a92819d312ea8a828b67e6adf1ab (patch) | |
| tree | 5ae59aef028cd644b87d6d4d8909972515a2a3b4 | |
| parent | 36737705b451ad4c765baa5789e3ceb752ee07a3 (diff) | |
| download | emacs-e292c0973cf7a92819d312ea8a828b67e6adf1ab.tar.gz emacs-e292c0973cf7a92819d312ea8a828b67e6adf1ab.zip | |
Fix #'fun handling inside `labels' (Bug#31792)
* lisp/emacs-lisp/cl.el (labels): Apply the equivalent of the
cl-labels change from 2015-01-16 "* lisp/emacs-lisp/cl-macs.el: Fix
last change".
* test/lisp/emacs-lisp/cl-tests.el (labels-function-quoting): New
test.
* lisp/emacs-lisp/cl-macs.el (cl-flet, cl-labels): Improve docstring,
link to relevant manual page.
* doc/misc/cl.texi (Function Bindings): Don't imply that function
cells of symbols are modified by cl-flet. Don't claim that cl-flet or
cl-labels affect references of the form (quote FUNC).
| -rw-r--r-- | doc/misc/cl.texi | 23 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 17 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl.el | 7 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-tests.el | 35 |
4 files changed, 62 insertions, 20 deletions
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index bf85b00e937..553b935b1ef 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi | |||
| @@ -1299,17 +1299,18 @@ These forms make @code{let}-like bindings to functions instead | |||
| 1299 | of variables. | 1299 | of variables. |
| 1300 | 1300 | ||
| 1301 | @defmac cl-flet (bindings@dots{}) forms@dots{} | 1301 | @defmac cl-flet (bindings@dots{}) forms@dots{} |
| 1302 | This form establishes @code{let}-style bindings on the function | 1302 | This form establishes @code{let}-style bindings for functions rather |
| 1303 | cells of symbols rather than on the value cells. Each @var{binding} | 1303 | than values. Each @var{binding} must be a list of the form |
| 1304 | must be a list of the form @samp{(@var{name} @var{arglist} | 1304 | @samp{(@var{name} @var{arglist} @var{body}@dots{})}. Within |
| 1305 | @var{forms}@dots{})}, which defines a function exactly as if | 1305 | @var{forms}, any reference to the function @var{name} uses the local |
| 1306 | it were a @code{cl-defun} form. The function @var{name} is defined | 1306 | definition instead of the global one. |
| 1307 | accordingly but only within the body of the @code{cl-flet}, hiding any external | 1307 | |
| 1308 | definition if applicable. | 1308 | A ``reference'' to a function name is either a call to that function, |
| 1309 | or a use of its name quoted by @code{function} to be passed on to, | ||
| 1310 | say, @code{mapcar}. | ||
| 1309 | 1311 | ||
| 1310 | The bindings are lexical in scope. This means that all references to | 1312 | The bindings are lexical in scope. This means that all references to |
| 1311 | the named functions must appear physically within the body of the | 1313 | the named functions must appear physically within @var{forms}. |
| 1312 | @code{cl-flet} form. | ||
| 1313 | 1314 | ||
| 1314 | Functions defined by @code{cl-flet} may use the full Common Lisp | 1315 | Functions defined by @code{cl-flet} may use the full Common Lisp |
| 1315 | argument notation supported by @code{cl-defun}; also, the function | 1316 | argument notation supported by @code{cl-defun}; also, the function |
| @@ -1336,10 +1337,6 @@ functions must appear physically within the body of the | |||
| 1336 | the functions themselves. Thus, @code{cl-labels} can define | 1337 | the functions themselves. Thus, @code{cl-labels} can define |
| 1337 | local recursive functions, or mutually-recursive sets of functions. | 1338 | local recursive functions, or mutually-recursive sets of functions. |
| 1338 | 1339 | ||
| 1339 | A ``reference'' to a function name is either a call to that | ||
| 1340 | function, or a use of its name quoted by @code{quote} or | ||
| 1341 | @code{function} to be passed on to, say, @code{mapcar}. | ||
| 1342 | |||
| 1343 | Note that the @file{cl.el} version of this macro behaves slightly | 1340 | Note that the @file{cl.el} version of this macro behaves slightly |
| 1344 | differently. @xref{Obsolete Macros}. | 1341 | differently. @xref{Obsolete Macros}. |
| 1345 | @end defmac | 1342 | @end defmac |
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 9c47ceae18e..0854e665b9b 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el | |||
| @@ -1964,13 +1964,16 @@ a `let' form, except that the list of symbols can be computed at run-time." | |||
| 1964 | ;;;###autoload | 1964 | ;;;###autoload |
| 1965 | (defmacro cl-flet (bindings &rest body) | 1965 | (defmacro cl-flet (bindings &rest body) |
| 1966 | "Make local function definitions. | 1966 | "Make local function definitions. |
| 1967 | Like `cl-labels' but the definitions are not recursive. | 1967 | Each definition can take the form (FUNC EXP) where |
| 1968 | Each binding can take the form (FUNC EXP) where | ||
| 1969 | FUNC is the function name, and EXP is an expression that returns the | 1968 | FUNC is the function name, and EXP is an expression that returns the |
| 1970 | function value to which it should be bound, or it can take the more common | 1969 | function value to which it should be bound, or it can take the more common |
| 1971 | form \(FUNC ARGLIST BODY...) which is a shorthand | 1970 | form \(FUNC ARGLIST BODY...) which is a shorthand |
| 1972 | for (FUNC (lambda ARGLIST BODY)). | 1971 | for (FUNC (lambda ARGLIST BODY)). |
| 1973 | 1972 | ||
| 1973 | FUNC is defined only within FORM, not BODY, so you can't write | ||
| 1974 | recursive function definitions. Use `cl-labels' for that. See | ||
| 1975 | info node `(cl) Function Bindings' for details. | ||
| 1976 | |||
| 1974 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" | 1977 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" |
| 1975 | (declare (indent 1) (debug ((&rest (cl-defun)) cl-declarations body))) | 1978 | (declare (indent 1) (debug ((&rest (cl-defun)) cl-declarations body))) |
| 1976 | (let ((binds ()) (newenv macroexpand-all-environment)) | 1979 | (let ((binds ()) (newenv macroexpand-all-environment)) |
| @@ -2012,9 +2015,13 @@ Like `cl-flet' but the definitions can refer to previous ones. | |||
| 2012 | 2015 | ||
| 2013 | ;;;###autoload | 2016 | ;;;###autoload |
| 2014 | (defmacro cl-labels (bindings &rest body) | 2017 | (defmacro cl-labels (bindings &rest body) |
| 2015 | "Make temporary function bindings. | 2018 | "Make local (recursive) function definitions. |
| 2016 | The bindings can be recursive and the scoping is lexical, but capturing them | 2019 | Each definition can take the form (FUNC ARGLIST BODY...) where |
| 2017 | in closures will only work if `lexical-binding' is in use. | 2020 | FUNC is the function name, ARGLIST its arguments, and BODY the |
| 2021 | forms of the function body. FUNC is defined in any BODY, as well | ||
| 2022 | as FORM, so you can write recursive and mutually recursive | ||
| 2023 | function definitions. See info node `(cl) Function Bindings' for | ||
| 2024 | details. | ||
| 2018 | 2025 | ||
| 2019 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" | 2026 | \(fn ((FUNC ARGLIST BODY...) ...) FORM...)" |
| 2020 | (declare (indent 1) (debug cl-flet)) | 2027 | (declare (indent 1) (debug cl-flet)) |
diff --git a/lisp/emacs-lisp/cl.el b/lisp/emacs-lisp/cl.el index d53c8e0bbcf..f6643158d2d 100644 --- a/lisp/emacs-lisp/cl.el +++ b/lisp/emacs-lisp/cl.el | |||
| @@ -466,9 +466,12 @@ rather than relying on `lexical-binding'." | |||
| 466 | (push var sets) | 466 | (push var sets) |
| 467 | (push (cons (car binding) | 467 | (push (cons (car binding) |
| 468 | `(lambda (&rest cl-labels-args) | 468 | `(lambda (&rest cl-labels-args) |
| 469 | (cl-list* 'funcall ',var | 469 | (if (eq (car cl-labels-args) cl--labels-magic) |
| 470 | cl-labels-args))) | 470 | (list cl--labels-magic ',var) |
| 471 | (cl-list* 'funcall ',var cl-labels-args)))) | ||
| 471 | newenv))) | 472 | newenv))) |
| 473 | ;; `lexical-let' adds `cl--function-convert' (which calls | ||
| 474 | ;; `cl--labels-convert') as a macroexpander for `function'. | ||
| 472 | (macroexpand-all `(lexical-let ,vars (setq ,@sets) ,@body) newenv))) | 475 | (macroexpand-all `(lexical-let ,vars (setq ,@sets) ,@body) newenv))) |
| 473 | 476 | ||
| 474 | ;; Generalized variables are provided by gv.el, but some details are | 477 | ;; Generalized variables are provided by gv.el, but some details are |
diff --git a/test/lisp/emacs-lisp/cl-tests.el b/test/lisp/emacs-lisp/cl-tests.el new file mode 100644 index 00000000000..b673822cd9a --- /dev/null +++ b/test/lisp/emacs-lisp/cl-tests.el | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | ;;; cl-tests.el --- tests for emacs-lisp/cl.el -*- lexical-binding:t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2018 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | ;; This program is free software: you can redistribute it and/or | ||
| 8 | ;; modify it under the terms of the GNU General Public License as | ||
| 9 | ;; published by the Free Software Foundation, either version 3 of the | ||
| 10 | ;; License, or (at your option) any later version. | ||
| 11 | ;; | ||
| 12 | ;; This program is distributed in the hope that it will be useful, but | ||
| 13 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | ;; General Public License for more details. | ||
| 16 | ;; | ||
| 17 | ;; You should have received a copy of the GNU General Public License | ||
| 18 | ;; along with this program. If not, see `https://www.gnu.org/licenses/'. | ||
| 19 | |||
| 20 | ;;; Commentary: | ||
| 21 | |||
| 22 | ;;; Code: | ||
| 23 | |||
| 24 | (require 'cl) | ||
| 25 | (require 'ert) | ||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | (ert-deftest labels-function-quoting () | ||
| 30 | "Test that #'foo does the right thing in `labels'." ; Bug#31792. | ||
| 31 | (should (eq (funcall (labels ((foo () t)) | ||
| 32 | #'foo)) | ||
| 33 | t))) | ||
| 34 | |||
| 35 | ;;; cl-tests.el ends here | ||