diff options
| author | Pip Cet | 2020-09-27 16:59:00 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2020-09-27 16:59:00 +0200 |
| commit | 433b6fc53dc9511077ed3a8c1ad130196dedbb55 (patch) | |
| tree | ef369ccea800d0ab2e00cb189bacefa2e9426efa | |
| parent | 8d241e8840fdb02dcfce52425626dd8f2125e51a (diff) | |
| download | emacs-433b6fc53dc9511077ed3a8c1ad130196dedbb55.tar.gz emacs-433b6fc53dc9511077ed3a8c1ad130196dedbb55.zip | |
Handle single-argument `apply' consistently (bug#40968)
* src/eval.c (Fapply): Handle (apply nil) without crashing.
Document single-argument form.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-apply): Don't attempt
to optimize single-argument apply.
* doc/lispref/functions.texi (Calling Functions): Document
single-argument apply. Provide example (bug#40968).
| -rw-r--r-- | doc/lispref/functions.texi | 10 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 29 | ||||
| -rw-r--r-- | src/eval.c | 6 |
3 files changed, 32 insertions, 13 deletions
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 26b212d05eb..e8e22078d9b 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi | |||
| @@ -762,6 +762,11 @@ arguments, rather than a single list. We say that @code{apply} | |||
| 762 | @dfn{spreads} this list so that each individual element becomes an | 762 | @dfn{spreads} this list so that each individual element becomes an |
| 763 | argument. | 763 | argument. |
| 764 | 764 | ||
| 765 | @code{apply} with a single argument is special: the first element of | ||
| 766 | the argument, which must be a non-empty list, is called as a function | ||
| 767 | with the remaining elements as individual arguments. Passing two or | ||
| 768 | more arguments will be faster. | ||
| 769 | |||
| 765 | @code{apply} returns the result of calling @var{function}. As with | 770 | @code{apply} returns the result of calling @var{function}. As with |
| 766 | @code{funcall}, @var{function} must either be a Lisp function or a | 771 | @code{funcall}, @var{function} must either be a Lisp function or a |
| 767 | primitive function; special forms and macros do not make sense in | 772 | primitive function; special forms and macros do not make sense in |
| @@ -789,6 +794,11 @@ primitive function; special forms and macros do not make sense in | |||
| 789 | (apply 'append '((a b c) nil (x y z) nil)) | 794 | (apply 'append '((a b c) nil (x y z) nil)) |
| 790 | @result{} (a b c x y z) | 795 | @result{} (a b c x y z) |
| 791 | @end group | 796 | @end group |
| 797 | |||
| 798 | @group | ||
| 799 | (apply '(+ 3 4)) | ||
| 800 | @result{} 7 | ||
| 801 | @end group | ||
| 792 | @end example | 802 | @end example |
| 793 | 803 | ||
| 794 | For an interesting example of using @code{apply}, see @ref{Definition | 804 | For an interesting example of using @code{apply}, see @ref{Definition |
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 8a6c0b9a7fa..65e4e446266 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -1044,19 +1044,22 @@ | |||
| 1044 | (defun byte-optimize-apply (form) | 1044 | (defun byte-optimize-apply (form) |
| 1045 | ;; If the last arg is a literal constant, turn this into a funcall. | 1045 | ;; If the last arg is a literal constant, turn this into a funcall. |
| 1046 | ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...). | 1046 | ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...). |
| 1047 | (let ((fn (nth 1 form)) | 1047 | (if (= (length form) 2) |
| 1048 | (last (nth (1- (length form)) form))) ; I think this really is fastest | 1048 | ;; single-argument `apply' is not worth optimizing (bug#40968) |
| 1049 | (or (if (or (null last) | 1049 | form |
| 1050 | (eq (car-safe last) 'quote)) | 1050 | (let ((fn (nth 1 form)) |
| 1051 | (if (listp (nth 1 last)) | 1051 | (last (nth (1- (length form)) form))) ; I think this really is fastest |
| 1052 | (let ((butlast (nreverse (cdr (reverse (cdr (cdr form))))))) | 1052 | (or (if (or (null last) |
| 1053 | (nconc (list 'funcall fn) butlast | 1053 | (eq (car-safe last) 'quote)) |
| 1054 | (mapcar (lambda (x) (list 'quote x)) (nth 1 last)))) | 1054 | (if (listp (nth 1 last)) |
| 1055 | (byte-compile-warn | 1055 | (let ((butlast (nreverse (cdr (reverse (cdr (cdr form))))))) |
| 1056 | "last arg to apply can't be a literal atom: `%s'" | 1056 | (nconc (list 'funcall fn) butlast |
| 1057 | (prin1-to-string last)) | 1057 | (mapcar (lambda (x) (list 'quote x)) (nth 1 last)))) |
| 1058 | nil)) | 1058 | (byte-compile-warn |
| 1059 | form))) | 1059 | "last arg to apply can't be a literal atom: `%s'" |
| 1060 | (prin1-to-string last)) | ||
| 1061 | nil)) | ||
| 1062 | form)))) | ||
| 1060 | 1063 | ||
| 1061 | (put 'funcall 'byte-optimizer #'byte-optimize-funcall) | 1064 | (put 'funcall 'byte-optimizer #'byte-optimize-funcall) |
| 1062 | (put 'apply 'byte-optimizer #'byte-optimize-apply) | 1065 | (put 'apply 'byte-optimizer #'byte-optimize-apply) |
diff --git a/src/eval.c b/src/eval.c index 5d3c32326db..c34c11828c5 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -2371,6 +2371,8 @@ eval_sub (Lisp_Object form) | |||
| 2371 | DEFUN ("apply", Fapply, Sapply, 1, MANY, 0, | 2371 | DEFUN ("apply", Fapply, Sapply, 1, MANY, 0, |
| 2372 | doc: /* Call FUNCTION with our remaining args, using our last arg as list of args. | 2372 | doc: /* Call FUNCTION with our remaining args, using our last arg as list of args. |
| 2373 | Then return the value FUNCTION returns. | 2373 | Then return the value FUNCTION returns. |
| 2374 | With a single argument, call the argument's first element using the | ||
| 2375 | other elements as args. | ||
| 2374 | Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10. | 2376 | Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10. |
| 2375 | usage: (apply FUNCTION &rest ARGUMENTS) */) | 2377 | usage: (apply FUNCTION &rest ARGUMENTS) */) |
| 2376 | (ptrdiff_t nargs, Lisp_Object *args) | 2378 | (ptrdiff_t nargs, Lisp_Object *args) |
| @@ -2381,6 +2383,10 @@ usage: (apply FUNCTION &rest ARGUMENTS) */) | |||
| 2381 | Lisp_Object fun = args[0]; | 2383 | Lisp_Object fun = args[0]; |
| 2382 | USE_SAFE_ALLOCA; | 2384 | USE_SAFE_ALLOCA; |
| 2383 | 2385 | ||
| 2386 | if (nargs == 1) | ||
| 2387 | /* Special case: FUN is really a list of (FUNCTION . ARGS). */ | ||
| 2388 | return CALLN (Fapply, CAR (fun), CDR (fun)); | ||
| 2389 | |||
| 2384 | ptrdiff_t numargs = list_length (spread_arg); | 2390 | ptrdiff_t numargs = list_length (spread_arg); |
| 2385 | 2391 | ||
| 2386 | if (numargs == 0) | 2392 | if (numargs == 0) |