aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPip Cet2020-09-27 16:59:00 +0200
committerLars Ingebrigtsen2020-09-27 16:59:00 +0200
commit433b6fc53dc9511077ed3a8c1ad130196dedbb55 (patch)
treeef369ccea800d0ab2e00cb189bacefa2e9426efa
parent8d241e8840fdb02dcfce52425626dd8f2125e51a (diff)
downloademacs-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.texi10
-rw-r--r--lisp/emacs-lisp/byte-opt.el29
-rw-r--r--src/eval.c6
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
763argument. 763argument.
764 764
765@code{apply} with a single argument is special: the first element of
766the argument, which must be a non-empty list, is called as a function
767with the remaining elements as individual arguments. Passing two or
768more 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
767primitive function; special forms and macros do not make sense in 772primitive 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
794For an interesting example of using @code{apply}, see @ref{Definition 804For 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)
2371DEFUN ("apply", Fapply, Sapply, 1, MANY, 0, 2371DEFUN ("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.
2373Then return the value FUNCTION returns. 2373Then return the value FUNCTION returns.
2374With a single argument, call the argument's first element using the
2375other elements as args.
2374Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10. 2376Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10.
2375usage: (apply FUNCTION &rest ARGUMENTS) */) 2377usage: (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)