Subject: bug#65797: 29.0.92; func-arity should not return (0 . many) with apply-partially

From: Joseph Turner <[email-masked]>
Date: Thu, 07 Sep 2023 21:40:28 -0700

Stefan Monnier <[email-masked]> writes:

> - Replace `&optional arg` with `&rest args` and pass those args via
>   `apply`, so the number of args passed doesn't depend on the function
>   but on the caller.

I like this idea. See patch.

> - Always pass both args to the function (i.e. as documented in the
>   docstring).

This isn't backwards compatible, is it?

Joseph

>From 5abc2ff47b0c61baecaddd615d7f2783fe8f9c0e Mon Sep 17 00:00:00 2001
From: Joseph Turner <[email-masked]>
Date: Thu, 7 Sep 2023 21:27:01 -0700
Subject: [PATCH] Don't use func-arity in buffer-match-p

* lisp/subr.el (buffer-match-p): Use &rest args instead of &optional
arg so that the number of args passed doesn't depend on the function
but on the caller. (Bug#65797)
(match-buffers): Use &rest args instead of &optional arg to match
function signature of buffer-match-p.
* doc/lispref/buffers.texi (Buffer List): Update documentation to say
ARGS instead of ARG.
---
 doc/lispref/buffers.texi | 23 ++++++++++-------------
 lisp/subr.el             | 17 ++++++++---------
 2 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi
index 86c47ae7310..fa29afd2697 100644
--- a/doc/lispref/buffers.texi
+++ b/doc/lispref/buffers.texi
@@ -957,11 +957,11 @@ with a @code{nil} @var{norecord} argument since this may lead to
 infinite recursion.
 @end defvar
 
-@defun buffer-match-p condition buffer-or-name &optional arg
+@defun buffer-match-p condition buffer-or-name &rest args
 This function checks if a buffer designated by @code{buffer-or-name}
-satisfies the specified @code{condition}.  Optional third argument
-@var{arg} is passed to the predicate function in @var{condition}.  A
-valid @var{condition} can be one of the following:
+satisfies the specified @code{condition}.  Remaining arguments
+@var{args} are passed using @code{apply} to the predicate function in
+@var{condition}.  A valid @var{condition} can be one of the following:
 @itemize @bullet{}
 @item
 A string, interpreted as a regular expression.  The buffer
@@ -969,23 +969,20 @@ satisfies the condition if the regular expression matches the buffer
 name.
 @item
 A predicate function, which should return non-@code{nil} if the buffer
-matches.  If the function expects one argument, it is called with
-@var{buffer-or-name} as the argument; if it expects 2 arguments, the
-first argument is @var{buffer-or-name} and the second is @var{arg}
-(or @code{nil} if @var{arg} is omitted).
+matches.
 @item
 A cons-cell @code{(@var{oper} . @var{expr})} where @var{oper} is one
 of
 @table @code
 @item (not @var{cond})
 Satisfied if @var{cond} doesn't satisfy @code{buffer-match-p} with
-the same buffer and @code{arg}.
+the same buffer and @code{args}.
 @item (or @var{conds}@dots{})
 Satisfied if @emph{any} condition in @var{conds} satisfies
-@code{buffer-match-p}, with the same buffer and @code{arg}.
+@code{buffer-match-p}, with the same buffer and @code{args}.
 @item (and @var{conds}@dots{})
 Satisfied if @emph{all} the conditions in @var{conds} satisfy
-@code{buffer-match-p}, with the same buffer and @code{arg}.
+@code{buffer-match-p}, with the same buffer and @code{args}.
 @item derived-mode
 Satisfied if the buffer's major mode derives from @var{expr}.
 @item major-mode
@@ -998,14 +995,14 @@ string) or @code{(and)} (empty conjunction).
 @end itemize
 @end defun
 
-@defun match-buffers condition &optional buffer-list arg
+@defun match-buffers condition &optional buffer-list &rest args
 This function returns a list of all buffers that satisfy the
 @code{condition}.  If no buffers match, the function returns
 @code{nil}.  The argument @var{condition} is as defined in
 @code{buffer-match-p} above.  By default, all the buffers are
 considered, but this can be restricted via the optional argument
 @code{buffer-list}, which should be a list of buffers to consider.
-Optional third argument @var{arg} will be passed to @var{condition} in
+Remaining arguments @var{args} will be passed to @var{condition} in
 the same way as @code{buffer-match-p} does.
 @end defun
 
diff --git a/lisp/subr.el b/lisp/subr.el
index ce23a699624..87f08c669d4 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -7079,14 +7079,15 @@ lines."
             (setq start (length string)))))
       (nreverse lines))))
 
-(defun buffer-match-p (condition buffer-or-name &optional arg)
+(defun buffer-match-p (condition buffer-or-name &rest args)
   "Return non-nil if BUFFER-OR-NAME matches CONDITION.
 CONDITION is either:
 - the symbol t, to always match,
 - the symbol nil, which never matches,
 - a regular expression, to match a buffer name,
-- a predicate function that takes BUFFER-OR-NAME and ARG as
-  arguments, and returns non-nil if the buffer matches,
+- a predicate function that takes BUFFER-OR-NAME as its first
+  argument and remaining arguments ARGS, and returns non-nil if
+  the buffer matches,
 - a cons-cell, where the car describes how to interpret the cdr.
   The car can be one of the following:
   * `derived-mode': the buffer matches if the buffer's major mode
@@ -7110,9 +7111,7 @@ CONDITION is either:
                       ((pred stringp)
                        (string-match-p condition (buffer-name buffer)))
                       ((pred functionp)
-                       (if (eq 1 (cdr (func-arity condition)))
-                           (funcall condition buffer-or-name)
-                         (funcall condition buffer-or-name arg)))
+                       (apply condition buffer-or-name args))
                       (`(major-mode . ,mode)
                        (eq
                         (buffer-local-value 'major-mode buffer)
@@ -7134,17 +7133,17 @@ CONDITION is either:
                 (throw 'match t)))))))
     (funcall match (list condition))))
 
-(defun match-buffers (condition &optional buffers arg)
+(defun match-buffers (condition &optional buffers &rest args)
   "Return a list of buffers that match CONDITION, or nil if none match.
 See `buffer-match-p' for various supported CONDITIONs.
 By default all buffers are checked, but the optional
 argument BUFFERS can restrict that: its value should be
 an explicit list of buffers to check.
-Optional argument ARG is passed to `buffer-match-p', for
+Remaining arguments ARGS are passed to `buffer-match-p', for
 predicate conditions in CONDITION."
   (let (bufs)
     (dolist (buf (or buffers (buffer-list)))
-      (when (buffer-match-p condition (get-buffer buf) arg)
+      (when (buffer-match-p condition (get-buffer buf) args)
         (push buf bufs)))
     bufs))
 
-- 
2.41.0