mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 17:24:23 +00:00
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).
This commit is contained in:
parent
8d241e8840
commit
433b6fc53d
3 changed files with 32 additions and 13 deletions
|
|
@ -762,6 +762,11 @@ arguments, rather than a single list. We say that @code{apply}
|
|||
@dfn{spreads} this list so that each individual element becomes an
|
||||
argument.
|
||||
|
||||
@code{apply} with a single argument is special: the first element of
|
||||
the argument, which must be a non-empty list, is called as a function
|
||||
with the remaining elements as individual arguments. Passing two or
|
||||
more arguments will be faster.
|
||||
|
||||
@code{apply} returns the result of calling @var{function}. As with
|
||||
@code{funcall}, @var{function} must either be a Lisp function or a
|
||||
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
|
|||
(apply 'append '((a b c) nil (x y z) nil))
|
||||
@result{} (a b c x y z)
|
||||
@end group
|
||||
|
||||
@group
|
||||
(apply '(+ 3 4))
|
||||
@result{} 7
|
||||
@end group
|
||||
@end example
|
||||
|
||||
For an interesting example of using @code{apply}, see @ref{Definition
|
||||
|
|
|
|||
|
|
@ -1044,19 +1044,22 @@
|
|||
(defun byte-optimize-apply (form)
|
||||
;; If the last arg is a literal constant, turn this into a funcall.
|
||||
;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...).
|
||||
(let ((fn (nth 1 form))
|
||||
(last (nth (1- (length form)) form))) ; I think this really is fastest
|
||||
(or (if (or (null last)
|
||||
(eq (car-safe last) 'quote))
|
||||
(if (listp (nth 1 last))
|
||||
(let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
|
||||
(nconc (list 'funcall fn) butlast
|
||||
(mapcar (lambda (x) (list 'quote x)) (nth 1 last))))
|
||||
(byte-compile-warn
|
||||
"last arg to apply can't be a literal atom: `%s'"
|
||||
(prin1-to-string last))
|
||||
nil))
|
||||
form)))
|
||||
(if (= (length form) 2)
|
||||
;; single-argument `apply' is not worth optimizing (bug#40968)
|
||||
form
|
||||
(let ((fn (nth 1 form))
|
||||
(last (nth (1- (length form)) form))) ; I think this really is fastest
|
||||
(or (if (or (null last)
|
||||
(eq (car-safe last) 'quote))
|
||||
(if (listp (nth 1 last))
|
||||
(let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
|
||||
(nconc (list 'funcall fn) butlast
|
||||
(mapcar (lambda (x) (list 'quote x)) (nth 1 last))))
|
||||
(byte-compile-warn
|
||||
"last arg to apply can't be a literal atom: `%s'"
|
||||
(prin1-to-string last))
|
||||
nil))
|
||||
form))))
|
||||
|
||||
(put 'funcall 'byte-optimizer #'byte-optimize-funcall)
|
||||
(put 'apply 'byte-optimizer #'byte-optimize-apply)
|
||||
|
|
|
|||
|
|
@ -2371,6 +2371,8 @@ eval_sub (Lisp_Object form)
|
|||
DEFUN ("apply", Fapply, Sapply, 1, MANY, 0,
|
||||
doc: /* Call FUNCTION with our remaining args, using our last arg as list of args.
|
||||
Then return the value FUNCTION returns.
|
||||
With a single argument, call the argument's first element using the
|
||||
other elements as args.
|
||||
Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10.
|
||||
usage: (apply FUNCTION &rest ARGUMENTS) */)
|
||||
(ptrdiff_t nargs, Lisp_Object *args)
|
||||
|
|
@ -2381,6 +2383,10 @@ usage: (apply FUNCTION &rest ARGUMENTS) */)
|
|||
Lisp_Object fun = args[0];
|
||||
USE_SAFE_ALLOCA;
|
||||
|
||||
if (nargs == 1)
|
||||
/* Special case: FUN is really a list of (FUNCTION . ARGS). */
|
||||
return CALLN (Fapply, CAR (fun), CDR (fun));
|
||||
|
||||
ptrdiff_t numargs = list_length (spread_arg);
|
||||
|
||||
if (numargs == 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue