Andrea Corallo writes: > branch: master > commit da8b06bd6181bc56fb0f133d17cae7eff44a83e8 > Merge: 2f5c9b31161 64d3100cb59 > Author: Andrea Corallo > Commit: Andrea Corallo > > Merge branch 'lisp-func-type-decls' into 'master' > --- > doc/lispref/functions.texi | 52 ++++++++++++++++++++++++++++++++++ > etc/NEWS | 5 ++++ > lisp/custom.el | 3 +- > lisp/emacs-lisp/byte-run.el | 8 +++++- > lisp/emacs-lisp/comp-common.el | 64 +++++++++++++----------------------------- > lisp/emacs-lisp/comp.el | 24 +++++++++++----- > lisp/emacs-lisp/lisp.el | 3 +- > lisp/emacs-lisp/regexp-opt.el | 3 +- > lisp/env.el | 3 +- > lisp/files.el | 1 + > lisp/help-fns.el | 2 +- > lisp/simple.el | 10 +++++-- > lisp/subr.el | 36 ++++++++++++++++-------- > lisp/window.el | 9 ++++-- > 14 files changed, 147 insertions(+), 76 deletions(-) > > diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi > index c57de08460f..d88f5d05339 100644 > --- a/doc/lispref/functions.texi > +++ b/doc/lispref/functions.texi > @@ -2709,6 +2709,58 @@ native code emitted for the function. In particular, if @var{n} is > @minus{}1, native compilation of the function will emit bytecode > instead of native code for the function. > > +@item (type @var{type}) > +Declare @var{type} to be the type of this function. This is used for > +documentation by @code{describe-function}. Also it can be used by the > +native compiler (@pxref{Native Compilation}) for improving code > +generation and for deriving more precisely the type of other functions > +without type declaration. > + > +@var{type} is a type specifier in the form @w{@code{(function > +(ARG-1-TYPE ... ARG-N-TYPE) RETURN-TYPE)}}. Argument types can be > +interleaved with symbols @code{&optional} and @code{&rest} to match the > +function's arguments (@pxref{Argument List}). > + > +Here's an example of using @code{type} inside @code{declare} to declare > +a function @code{positive-p} that takes an argument of type @var{number} > +and return a @var{boolean}: > + > +@group > +@lisp > +(defun positive-p (x) > + (declare (type (function (number) boolean))) > + (when (> x 0) > + t)) > +@end lisp > +@end group > + > +Similarly this declares a function @code{cons-or-number} that: expects a > +first argument being a @var{cons} or a @var{number}, a second optional > +argument of type @var{string} and return one of the symbols > +@code{is-cons} or @code{is-number}: > + > +@group > +@lisp > +(defun cons-or-number (x &optional err-msg) > + (declare (type (function ((or cons number) &optional string) > + (member is-cons is-number)))) > + (if (consp x) > + 'is-cons > + (if (numberp x) > + 'is-number > + (error (or err-msg "Unexpected input"))))) > +@end lisp > +@end group > + > +More types are described in the Lisp Data Types chapter (@ref{Lisp Data > +Types}). > + > +Declaring a function with an incorrect type produces undefined behavior > +and could lead to unexpected results or might even crash Emacs when code > +is native-compiled and loaded. Note also that when redefining (or > +advising) a type declared function the replacement should respect the > +original signature to avoid undefined behavior. > + > @item no-font-lock-keyword > This is valid for macros only. Macros with this declaration are > highlighted by font-lock (@pxref{Font Lock Mode}) as normal functions, > diff --git a/etc/NEWS b/etc/NEWS > index 4d363d300a8..8477a1eed58 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -1939,6 +1939,11 @@ unibyte string. > > * Lisp Changes in Emacs 30.1 > > ++++ > +** Function type declaration > +It is now possible, using the 'declare' macro, to declare expected types > +of function arguments and return type. > + > ** New types 'closure' and 'interpreted-function'. > 'interpreted-function' is the new type used for interpreted functions, > and 'closure' is the common parent type of 'interpreted-function' > diff --git a/lisp/custom.el b/lisp/custom.el > index a19b14aaf8a..6f2aa18ba1d 100644 > --- a/lisp/custom.el > +++ b/lisp/custom.el > @@ -667,7 +667,8 @@ If NOSET is non-nil, don't bother autoloading LOAD when setting the variable." > A customizable variable is either (i) a variable whose property > list contains a non-nil `standard-value' or `custom-autoload' > property, or (ii) an alias for another customizable variable." > - (declare (side-effect-free t)) > + (declare (type (function (symbol) t)) > + (side-effect-free t)) > (when (symbolp variable) > (setq variable (indirect-variable variable)) > (or (get variable 'standard-value) > diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el > index cc176821026..84cc83f2270 100644 > --- a/lisp/emacs-lisp/byte-run.el > +++ b/lisp/emacs-lisp/byte-run.el > @@ -217,6 +217,11 @@ So far, FUNCTION can only be a symbol, not a lambda expression." > (cadr elem))) > val))))) > > +(defalias 'byte-run--set-function-type > + #'(lambda (f _args &rest val) > + (list 'function-put (list 'quote f) > + ''function-type (list 'quote val)))) > + > ;; Add any new entries to info node `(elisp)Declare Form'. > (defvar defun-declarations-alist > (list > @@ -239,7 +244,8 @@ If `error-free', drop calls even if `byte-compile-delete-errors' is nil.") > (list 'speed #'byte-run--set-speed) > (list 'completion #'byte-run--set-completion) > (list 'modes #'byte-run--set-modes) > - (list 'interactive-args #'byte-run--set-interactive-args)) > + (list 'interactive-args #'byte-run--set-interactive-args) > + (list 'type #'byte-run--set-function-type)) > "List associating function properties to their macro expansion. > Each element of the list takes the form (PROP FUN) where FUN is > a function. For each (PROP . VALUES) in a function's declaration, > diff --git a/lisp/emacs-lisp/comp-common.el b/lisp/emacs-lisp/comp-common.el > index 62fd28f772e..ef40882a98a 100644 > --- a/lisp/emacs-lisp/comp-common.el > +++ b/lisp/emacs-lisp/comp-common.el > @@ -68,7 +68,7 @@ Used to modify the compiler environment." > :risky t > :version "28.1") > > -(defconst comp-known-type-specifiers > +(defconst comp-primitive-type-specifiers > `( > ;; Functions we can trust not to be redefined, or, if redefined, > ;; to expose the same type. The vast majority of these are > @@ -97,7 +97,6 @@ Used to modify the compiler environment." > (assq (function (t list) list)) > (atan (function (number &optional number) float)) > (atom (function (t) boolean)) > - (bignump (function (t) boolean)) > (bobp (function () boolean)) > (bolp (function () boolean)) > (bool-vector-count-consecutive > @@ -107,7 +106,6 @@ Used to modify the compiler environment." > (bool-vector-p (function (t) boolean)) > (bool-vector-subsetp (function (bool-vector bool-vector) boolean)) > (boundp (function (symbol) boolean)) > - (buffer-end (function ((or number marker)) integer)) > (buffer-file-name (function (&optional buffer) (or string null))) > (buffer-list (function (&optional frame) list)) > (buffer-local-variables (function (&optional buffer) list)) > @@ -157,8 +155,6 @@ Used to modify the compiler environment." > (copy-sequence (function (sequence) sequence)) > (copysign (function (float float) float)) > (cos (function (number) float)) > - (count-lines > - (function ((or integer marker) (or integer marker) &optional t) integer)) > (current-buffer (function () buffer)) > (current-global-map (function () cons)) > (current-indentation (function () integer)) > @@ -171,7 +167,6 @@ Used to modify the compiler environment." > (current-time-zone (function (&optional (or number list) > (or symbol string cons integer)) > cons)) > - (custom-variable-p (function (symbol) t)) > (decode-char (function (cons t) (or fixnum null))) > (decode-time (function (&optional (or number list) > (or symbol string cons integer) > @@ -179,7 +174,6 @@ Used to modify the compiler environment." > cons)) > (default-boundp (function (symbol) boolean)) > (default-value (function (symbol) t)) > - (degrees-to-radians (function (number) float)) > (documentation > (function ((or function symbol subr) &optional t) (or null string))) > (downcase (function ((or fixnum string)) (or fixnum string))) > @@ -192,7 +186,6 @@ Used to modify the compiler environment." > (eql (function (t t) boolean)) > (equal (function (t t) boolean)) > (error-message-string (function (list) string)) > - (eventp (function (t) boolean)) > (exp (function (number) float)) > (expt (function (number number) number)) > (fboundp (function (symbol) boolean)) > @@ -207,7 +200,6 @@ Used to modify the compiler environment." > (file-readable-p (function (string) boolean)) > (file-symlink-p (function (string) (or boolean string))) > (file-writable-p (function (string) boolean)) > - (fixnump (function (t) boolean)) > (float (function (number) float)) > (float-time (function (&optional (or number list)) float)) > (floatp (function (t) boolean)) > @@ -230,18 +222,12 @@ Used to modify the compiler environment." > (function (&optional (or buffer string) (or symbol (integer 0 0))) > (or null window))) > (get-file-buffer (function (string) (or null buffer))) > - (get-largest-window (function (&optional t t t) (or window null))) > - (get-lru-window (function (&optional t t t) (or window null))) > - (getenv (function (string &optional frame) (or null string))) > (gethash (function (t hash-table &optional t) t)) > (hash-table-count (function (hash-table) integer)) > (hash-table-p (function (t) boolean)) > (identity (function (t) t)) > - (ignore (function (&rest t) null)) > - (int-to-string (function (number) string)) > (integer-or-marker-p (function (t) boolean)) > (integerp (function (t) boolean)) > - (interactive-p (function () boolean)) > (intern-soft (function ((or string symbol) &optional (or obarray vector)) > symbol)) > (invocation-directory (function () string)) > @@ -250,8 +236,6 @@ Used to modify the compiler environment." > (keymap-parent (function (cons) (or cons null))) > (keymapp (function (t) boolean)) > (keywordp (function (t) boolean)) > - (last (function (list &optional integer) list)) > - (lax-plist-get (function (list t) t)) > (ldexp (function (number integer) float)) > (length (function (t) (integer 0 *))) > (length< (function (sequence fixnum) boolean)) > @@ -265,7 +249,6 @@ Used to modify the compiler environment." > (local-variable-p (function (symbol &optional buffer) boolean)) > (locale-info (function ((member codeset days months paper)) (or null string))) > (log (function (number number) float)) > - (log10 (function (number) float)) > (logand (function (&rest (or integer marker)) integer)) > (logb (function (number) integer)) > (logcount (function (integer) integer)) > @@ -273,7 +256,6 @@ Used to modify the compiler environment." > (lognot (function (integer) integer)) > (logxor (function (&rest (or integer marker)) integer)) > ;; (lsh (function ((integer ,most-negative-fixnum *) integer) integer)) ? > - (lsh (function (integer integer) integer)) > (make-byte-code > (function ((or fixnum list) string vector integer &optional string t > &rest t) > @@ -282,14 +264,12 @@ Used to modify the compiler environment." > (make-marker (function () marker)) > (make-string (function (integer fixnum &optional t) string)) > (make-symbol (function (string) symbol)) > - (mark (function (&optional t) (or integer null))) > (mark-marker (function () marker)) > (marker-buffer (function (marker) (or buffer null))) > (markerp (function (t) boolean)) > (max (function ((or number marker) &rest (or number marker)) number)) > (max-char (function (&optional t) fixnum)) > (member (function (t list) list)) > - (memory-limit (function () integer)) > (memq (function (t list) list)) > (memql (function (t list) list)) > (min (function ((or number marker) &rest (or number marker)) number)) > @@ -298,7 +278,6 @@ Used to modify the compiler environment." > (mod > (function ((or number marker) (or number marker)) > (or (integer 0 *) (float 0 *)))) > - (mouse-movement-p (function (t) boolean)) > (multibyte-char-to-unibyte (function (fixnum) fixnum)) > (natnump (function (t) boolean)) > (next-window (function (&optional window t t) window)) > @@ -310,9 +289,7 @@ Used to modify the compiler environment." > (number-or-marker-p (function (t) boolean)) > (number-to-string (function (number) string)) > (numberp (function (t) boolean)) > - (one-window-p (function (&optional t t) boolean)) > (overlayp (function (t) boolean)) > - (parse-colon-path (function (string) list)) > (plist-get (function (list t &optional t) t)) > (plist-member (function (list t &optional t) list)) > (point (function () integer)) > @@ -325,13 +302,11 @@ Used to modify the compiler environment." > (processp (function (t) boolean)) > (proper-list-p (function (t) (or fixnum null))) > (propertize (function (string &rest t) string)) > - (radians-to-degrees (function (number) float)) > (rassoc (function (t list) list)) > (rassq (function (t list) list)) > (read-from-string (function (string &optional integer integer) cons)) > (recent-keys (function (&optional (or cons null)) vector)) > (recursion-depth (function () integer)) > - (regexp-opt (function (list) string)) > (regexp-quote (function (string) string)) > (region-beginning (function () integer)) > (region-end (function () integer)) > @@ -387,7 +362,6 @@ Used to modify the compiler environment." > (upcase (function ((or fixnum string)) (or fixnum string))) > (user-full-name (function (&optional integer) (or string null))) > (user-login-name (function (&optional integer) (or string null))) > - (user-original-login-name (function (&optional integer) (or string null))) > (user-real-login-name (function () string)) > (user-real-uid (function () integer)) > (user-uid (function () integer)) > @@ -400,13 +374,8 @@ Used to modify the compiler environment." > (window-live-p (function (t) boolean)) > (window-valid-p (function (t) boolean)) > (windowp (function (t) boolean)) > - (zerop (function (number) boolean)) > - ;; Type hints > - (comp-hint-fixnum (function (t) fixnum)) > - (comp-hint-cons (function (t) cons)) > ;; Non returning functions > (throw (function (t t) nil)) > - (error (function (string &rest t) nil)) > (signal (function (symbol t) nil))) > "Alist used for type propagation.") > > @@ -532,22 +501,27 @@ Account for `native-comp-eln-load-path' and `comp-native-version-dir'." > (defun comp-function-type-spec (function) > "Return the type specifier of FUNCTION. > > -This function returns a cons cell whose car is the function > -specifier, and cdr is a symbol, either `inferred' or `know'. > -If the symbol is `inferred', the type specifier is automatically > -inferred from the code itself by the native compiler; if it is > -`know', the type specifier comes from `comp-known-type-specifiers'." > - (let ((kind 'know) > - type-spec ) > - (when-let ((res (assoc function comp-known-type-specifiers))) > +This function returns a cons cell whose car is the function specifier, > +and cdr is a symbol, either `inferred' or `declared'. If the symbol is > +`inferred', the type specifier is automatically inferred from the code > +itself by the native compiler; if it is `declared', the type specifier > +comes from `comp-primitive-type-specifiers' or the function type declaration > +itself." > + (let ((kind 'declared) > + type-spec) > + (when-let ((res (assoc function comp-primitive-type-specifiers))) > + ;; Declared primitive > (setf type-spec (cadr res))) > (let ((f (and (symbolp function) > (symbol-function function)))) > - (when (and f > - (null type-spec) > - (subr-native-elisp-p f)) > - (setf kind 'inferred > - type-spec (subr-type f)))) > + (when (and f (null type-spec)) > + (if-let ((delc-type (function-get function 'function-type))) > + ;; Declared Lisp function > + (setf type-spec (car delc-type)) > + (when (subr-native-elisp-p f) > + ;; Native compiled inferred > + (setf kind 'inferred > + type-spec (subr-type f)))))) > (when type-spec > (cons type-spec kind)))) > > diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el > index 2ec55ed98ee..d7cd6b79c86 100644 > --- a/lisp/emacs-lisp/comp.el > +++ b/lisp/emacs-lisp/comp.el > @@ -179,16 +179,24 @@ For internal use by the test suite only.") > Each function in FUNCTIONS is run after PASS. > Useful to hook into pass checkers.") > > -(defconst comp-known-func-cstr-h > +(defconst comp-primitive-func-cstr-h > (cl-loop > with comp-ctxt = (make-comp-cstr-ctxt) > with h = (make-hash-table :test #'eq) > - for (f type-spec) in comp-known-type-specifiers > + for (f type-spec) in comp-primitive-type-specifiers > for cstr = (comp-type-spec-to-cstr type-spec) > do (puthash f cstr h) > finally return h) > "Hash table function -> `comp-constraint'.") > > +(defun comp--get-function-cstr (function) > + "Given FUNCTION return the corresponding `comp-constraint'." > + (when (symbolp function) > + (let ((f (symbol-function function))) > + (or (gethash f comp-primitive-func-cstr-h) > + (when-let ((res (function-get function 'function-type))) > + (comp-type-spec-to-cstr (car res))))))) > + > ;; Keep it in sync with the `cl-deftype-satisfies' property set in > ;; cl-macs.el. We can't use `cl-deftype-satisfies' directly as the > ;; relation type <-> predicate is not bijective (bug#45576). > @@ -2102,10 +2110,10 @@ TARGET-BB-SYM is the symbol name of the target block." > (when-let ((match > (pcase insn > (`(set ,lhs (,(pred comp--call-op-p) ,f . ,args)) > - (when-let ((cstr-f (gethash f comp-known-func-cstr-h))) > + (when-let ((cstr-f (comp--get-function-cstr f))) > (cl-values f cstr-f lhs args))) > (`(,(pred comp--call-op-p) ,f . ,args) > - (when-let ((cstr-f (gethash f comp-known-func-cstr-h))) > + (when-let ((cstr-f (comp--get-function-cstr f))) > (cl-values f cstr-f nil args)))))) > (cl-multiple-value-bind (f cstr-f lhs args) match > (cl-loop > @@ -2642,7 +2650,7 @@ Fold the call in case." > (comp-cstr-imm-vld-p (car args))) > (setf f (comp-cstr-imm (car args)) > args (cdr args))) > - (when-let ((cstr-f (gethash f comp-known-func-cstr-h))) > + (when-let ((cstr-f (comp--get-function-cstr f))) > (let ((cstr (comp-cstr-f-ret cstr-f))) > (when (comp-cstr-empty-p cstr) > ;; Store it to be rewritten as non local exit. > @@ -3301,11 +3309,13 @@ Prepare every function for final compilation and drive the C back-end." > ;; are assumed just to be true. Use with extreme caution... > > (defun comp-hint-fixnum (x) > - (declare (gv-setter (lambda (val) `(setf ,x ,val)))) > + (declare (type (function (t) fixnum)) > + (gv-setter (lambda (val) `(setf ,x ,val)))) > x) > > (defun comp-hint-cons (x) > - (declare (gv-setter (lambda (val) `(setf ,x ,val)))) > + (declare (type (function (t) cons)) > + (gv-setter (lambda (val) `(setf ,x ,val)))) > x) > > > diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el > index 7e6db51b1d5..9edc11ad132 100644 > --- a/lisp/emacs-lisp/lisp.el > +++ b/lisp/emacs-lisp/lisp.el > @@ -534,7 +534,8 @@ major mode's decisions about context.") > "Return the \"far end\" position of the buffer, in direction ARG. > If ARG is positive, that's the end of the buffer. > Otherwise, that's the beginning of the buffer." > - (declare (side-effect-free error-free)) > + (declare (type (function ((or number marker)) integer)) > + (side-effect-free error-free)) > (if (> arg 0) (point-max) (point-min))) > > (defun end-of-defun (&optional arg interactive) > diff --git a/lisp/emacs-lisp/regexp-opt.el b/lisp/emacs-lisp/regexp-opt.el > index 59c1b7d8e10..f23343a34c6 100644 > --- a/lisp/emacs-lisp/regexp-opt.el > +++ b/lisp/emacs-lisp/regexp-opt.el > @@ -130,7 +130,8 @@ usually more efficient than that of a simplified version: > (concat (car parens) > (mapconcat \\='regexp-quote strings \"\\\\|\") > (cdr parens))))" > - (declare (pure t) (side-effect-free t)) > + (declare (type (function (list &optional t) string)) > + (pure t) (side-effect-free t)) > (save-match-data > ;; Recurse on the sorted list. > (let* ((max-lisp-eval-depth 10000) > diff --git a/lisp/env.el b/lisp/env.el > index e0a8df8476c..7d0c7dd0126 100644 > --- a/lisp/env.el > +++ b/lisp/env.el > @@ -207,7 +207,8 @@ parameter. > Otherwise, this function searches `process-environment' for > VARIABLE. If it is not found there, then it continues the search > in the environment list of the selected frame." > - (declare (side-effect-free t)) > + (declare (type (function (string &optional frame) (or null string))) > + (side-effect-free t)) > (interactive (list (read-envvar-name "Get environment variable: " t))) > (let ((value (getenv-internal (if (multibyte-string-p variable) > (encode-coding-string > diff --git a/lisp/files.el b/lisp/files.el > index b7ebb727c72..c24e48e3db2 100644 > --- a/lisp/files.el > +++ b/lisp/files.el > @@ -862,6 +862,7 @@ GNU and Unix systems). Substitute environment variables into the > resulting list of directory names. For an empty path element (i.e., > a leading or trailing separator, or two adjacent separators), return > nil (meaning `default-directory') as the associated list element." > + (declare (type (function (string) list))) > (when (stringp search-path) > (let ((spath (substitute-env-vars search-path)) > (double-slash-special-p > diff --git a/lisp/help-fns.el b/lisp/help-fns.el > index 9bf2f61aee6..182b22549b5 100644 > --- a/lisp/help-fns.el > +++ b/lisp/help-fns.el > @@ -732,7 +732,7 @@ the C sources, too." > (insert (format > (if (eq kind 'inferred) > "\nInferred type: %s\n" > - "\nType: %s\n") > + "\nDeclared type: %s\n") > type-spec)))) > (fill-region fill-begin (point)) > high-doc))))) > diff --git a/lisp/simple.el b/lisp/simple.el > index be64f3574e0..a459f6ecfd2 100644 > --- a/lisp/simple.el > +++ b/lisp/simple.el > @@ -1762,7 +1762,9 @@ not at the start of a line. > > When IGNORE-INVISIBLE-LINES is non-nil, invisible lines are not > included in the count." > - (declare (side-effect-free t)) > + (declare (type (function ((or integer marker) (or integer marker) &optional t) > + integer)) > + (side-effect-free t)) > (save-excursion > (save-restriction > (narrow-to-region start end) > @@ -6882,7 +6884,8 @@ is active, and returns an integer or nil in the usual way. > > If you are using this in an editing command, you are most likely making > a mistake; see the documentation of `set-mark'." > - (declare (side-effect-free t)) > + (declare (type (function (&optional t) (or integer null))) > + (side-effect-free t)) > (if (or force (not transient-mark-mode) mark-active mark-even-if-inactive) > (marker-position (mark-marker)) > (signal 'mark-inactive nil))) > @@ -11163,7 +11166,8 @@ killed." > > (defun lax-plist-get (plist prop) > "Extract a value from a property list, comparing with `equal'." > - (declare (pure t) (side-effect-free t) (obsolete plist-get "29.1")) > + (declare (type (function (list t) t)) > + (pure t) (side-effect-free t) (obsolete plist-get "29.1")) > (plist-get plist prop #'equal)) > > (defun lax-plist-put (plist prop val) > diff --git a/lisp/subr.el b/lisp/subr.el > index 352ecc315ef..92d1e50ab2c 100644 > --- a/lisp/subr.el > +++ b/lisp/subr.el > @@ -451,7 +451,8 @@ This function accepts any number of arguments in ARGUMENTS. > Also see `always'." > ;; Not declared `side-effect-free' because we don't want calls to it > ;; elided; see `byte-compile-ignore'. > - (declare (pure t) (completion ignore)) > + (declare (type (function (&rest t) null)) > + (pure t) (completion ignore)) > (interactive) > nil) > > @@ -480,7 +481,8 @@ for the sake of consistency. > > To alter the look of the displayed error messages, you can use > the `command-error-function' variable." > - (declare (advertised-calling-convention (string &rest args) "23.1")) > + (declare (type (function (string &rest t) nil)) > + (advertised-calling-convention (string &rest args) "23.1")) > (signal 'error (list (apply #'format-message args)))) > > (defun user-error (format &rest args) > @@ -545,19 +547,22 @@ was called." > "Return t if NUMBER is zero." > ;; Used to be in C, but it's pointless since (= 0 n) is faster anyway because > ;; = has a byte-code. > - (declare (pure t) (side-effect-free t) > + (declare (type (function (number) boolean)) > + (pure t) (side-effect-free t) > (compiler-macro (lambda (_) `(= 0 ,number)))) > (= 0 number)) > > (defun fixnump (object) > "Return t if OBJECT is a fixnum." > - (declare (side-effect-free error-free)) > + (declare (type (function (t) boolean)) > + (side-effect-free error-free)) > (and (integerp object) > (<= most-negative-fixnum object most-positive-fixnum))) > > (defun bignump (object) > "Return t if OBJECT is a bignum." > - (declare (side-effect-free error-free)) > + (declare (type (function (t) boolean)) > + (side-effect-free error-free)) > (and (integerp object) (not (fixnump object)))) > > (defun lsh (value count) > @@ -570,7 +575,8 @@ Most uses of this function turn out to be mistakes. We recommend > to use `ash' instead, unless COUNT could ever be negative, and > if, when COUNT is negative, your program really needs the special > treatment of negative COUNT provided by this function." > - (declare (compiler-macro > + (declare (type (function (integer integer) integer)) > + (compiler-macro > (lambda (form) > (macroexp-warn-and-return > (format-message "avoid `lsh'; use `ash' instead") > @@ -748,7 +754,8 @@ treatment of negative COUNT provided by this function." > If LIST is nil, return nil. > If N is non-nil, return the Nth-to-last link of LIST. > If N is bigger than the length of LIST, return LIST." > - (declare (pure t) (side-effect-free t)) ; pure up to mutation > + (declare (type (function (list &optional integer) list)) > + (pure t) (side-effect-free t)) ; pure up to mutation > (if n > (and (>= n 0) > (let ((m (safe-length list))) > @@ -1585,7 +1592,8 @@ See also `current-global-map'.") > > (defun eventp (object) > "Return non-nil if OBJECT is an input event or event object." > - (declare (pure t) (side-effect-free error-free)) > + (declare (type (function (t) boolean)) > + (pure t) (side-effect-free error-free)) > (or (integerp object) > (and (if (consp object) > (setq object (car object)) > @@ -1652,7 +1660,8 @@ in the current Emacs session, then this function may return nil." > > (defsubst mouse-movement-p (object) > "Return non-nil if OBJECT is a mouse movement event." > - (declare (side-effect-free error-free)) > + (declare (type (function (t) boolean)) > + (side-effect-free error-free)) > (eq (car-safe object) 'mouse-movement)) > > (defun mouse-event-p (object) > @@ -1961,7 +1970,8 @@ be a list of the form returned by `event-start' and `event-end'." > > (defun log10 (x) > "Return (log X 10), the log base 10 of X." > - (declare (side-effect-free t) (obsolete log "24.4")) > + (declare (type (function (number) float)) > + (side-effect-free t) (obsolete log "24.4")) > (log x 10)) > > (set-advertised-calling-convention > @@ -3245,7 +3255,8 @@ It can be retrieved with `(process-get PROCESS PROPNAME)'." > > (defun memory-limit () > "Return an estimate of Emacs virtual memory usage, divided by 1024." > - (declare (side-effect-free error-free)) > + (declare (type (function () integer)) > + (side-effect-free error-free)) > (let ((default-directory temporary-file-directory)) > (or (cdr (assq 'vsize (process-attributes (emacs-pid)))) 0))) > > @@ -6467,7 +6478,8 @@ To test whether a function can be called interactively, use > `commandp'." > ;; Kept around for now. See discussion at: > ;; https://lists.gnu.org/r/emacs-devel/2020-08/msg00564.html > - (declare (obsolete called-interactively-p "23.2") > + (declare (type (function () boolean)) > + (obsolete called-interactively-p "23.2") > (side-effect-free error-free)) > (called-interactively-p 'interactive)) > > diff --git a/lisp/window.el b/lisp/window.el > index cdc6f690bab..639090752be 100644 > --- a/lisp/window.el > +++ b/lisp/window.el > @@ -2515,7 +2515,8 @@ have special meanings: > > Any other value of ALL-FRAMES means consider all windows on the > selected frame and no others." > - (declare (side-effect-free error-free)) > + (declare (type (function (&optional t t t) (or window null))) > + (side-effect-free error-free)) > (let ((windows (window-list-1 nil 'nomini all-frames)) > best-window best-time second-best-window second-best-time time) > (dolist (window windows) > @@ -2594,7 +2595,8 @@ have special meanings: > > Any other value of ALL-FRAMES means consider all windows on the > selected frame and no others." > - (declare (side-effect-free error-free)) > + (declare (type (function (&optional t t t) (or window null))) > + (side-effect-free error-free)) > (let ((best-size 0) > best-window size) > (dolist (window (window-list-1 nil 'nomini all-frames)) > @@ -4089,7 +4091,8 @@ with a special meaning are: > > Anything else means consider all windows on the selected frame > and no others." > - (declare (side-effect-free error-free)) > + (declare (type (function (&optional t t) boolean)) > + (side-effect-free error-free)) > (let ((base-window (selected-window))) > (if (and nomini (eq base-window (minibuffer-window))) > (setq base-window (next-window base-window)))