emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 433b6fc: Handle single-argument `apply' consistently (bug#40968)


From: Lars Ingebrigtsen
Subject: master 433b6fc: Handle single-argument `apply' consistently (bug#40968)
Date: Sun, 27 Sep 2020 11:02:37 -0400 (EDT)

branch: master
commit 433b6fc53dc9511077ed3a8c1ad130196dedbb55
Author: Pip Cet <pipcet@gmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    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).
---
 doc/lispref/functions.texi  | 10 ++++++++++
 lisp/emacs-lisp/byte-opt.el | 29 ++++++++++++++++-------------
 src/eval.c                  |  6 ++++++
 3 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 26b212d..e8e2207 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}
 @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
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 8a6c0b9..65e4e44 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -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)
diff --git a/src/eval.c b/src/eval.c
index 5d3c323..c34c118 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]