aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2026-03-08 19:11:13 -0400
committerStefan Monnier2026-03-08 19:11:13 -0400
commit0df94040fcf76bb894cd24f7242fd40aba67bb3f (patch)
treeddb4819c9989f75c675af1f5d1e3ee6ec4b20d66
parenta3dda7e5252f8fff33a60dc455c4a25ea5904edd (diff)
downloademacs-0df94040fcf76bb894cd24f7242fd40aba67bb3f.tar.gz
emacs-0df94040fcf76bb894cd24f7242fd40aba67bb3f.zip
Improve the error API
Define new functions to manipulate error descriptors and add support for `signal` to *re*signal a previous error. * src/eval.c (Fsignal): Make the second arg optional and document the possibility of passing a whole error descriptor to re-signal it. (signal_or_quit): Fix a few corner case issues when DATA is `nil` and ERROR_SYMBOL is an error descriptor. * lisp/subr.el (error-type-p, error--p, error-type, error-data) (error-has-type-p, error-slot-value): New function. * doc/lispref/control.texi (Handling Errors): Prefer "error descriptor" to "error description". Use the new single-arg call to `signal` to re-throw an error. Document `error-type`, `error-data` and `error-slot-value`. (Error Symbols): Document the new functions `error-type-p` and `error-has-type-p`.
-rw-r--r--doc/lispref/control.texi41
-rw-r--r--lisp/subr.el32
-rw-r--r--src/eval.c12
3 files changed, 76 insertions, 9 deletions
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index a7d605cf0a0..3925bdd1b40 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -2447,12 +2447,13 @@ as the overall value.
2447The argument @var{var} is a variable. @code{condition-case} does not 2447The argument @var{var} is a variable. @code{condition-case} does not
2448bind this variable when executing the @var{protected-form}, only when it 2448bind this variable when executing the @var{protected-form}, only when it
2449handles an error. At that time, it binds @var{var} locally to an 2449handles an error. At that time, it binds @var{var} locally to an
2450@dfn{error description}, which is a list giving the particulars of the 2450@dfn{error descriptor}, also sometimes called error description,
2451error. The error description has the form @code{(@var{error-symbol} 2451which is a list giving the particulars of the error.
2452The error descriptor has the form @code{(@var{error-symbol}
2452. @var{data})}. The handler can refer to this list to decide what to 2453. @var{data})}. The handler can refer to this list to decide what to
2453do. For example, if the error is for failure opening a file, the file 2454do. For example, if the error is for failure opening a file, the file
2454name is the second element of @var{data}---the third element of the 2455name is the second element of @var{data}---the third element of the
2455error description. 2456error descriptor.
2456 2457
2457If @var{var} is @code{nil}, that means no variable is bound. Then the 2458If @var{var} is @code{nil}, that means no variable is bound. Then the
2458error symbol and associated data are not available to the handler. 2459error symbol and associated data are not available to the handler.
@@ -2469,15 +2470,31 @@ Sometimes it is necessary to re-throw a signal caught by
2469how to do that: 2470how to do that:
2470 2471
2471@example 2472@example
2472 (signal (car err) (cdr err)) 2473 (signal err)
2473@end example 2474@end example
2474 2475
2475@noindent 2476@noindent
2476where @code{err} is the error description variable, the first argument 2477where @code{err} is the error descriptor variable, the first argument
2477to @code{condition-case} whose error condition you want to re-throw. 2478to @code{condition-case} whose error condition you want to re-throw.
2478@xref{Definition of signal}. 2479@xref{Definition of signal}.
2479@end defspec 2480@end defspec
2480 2481
2482@defun error-type error
2483This function returns the error symbol of the error descriptor @var{error}.
2484@end defun
2485
2486@defun error-data error
2487This function returns the data of the error descriptor @var{error}.
2488@end defun
2489
2490@defun error-slot-value error pos
2491This function returns the value in the field number @var{pos} of the error
2492descriptor @var{error}. The fields are numbered starting with 1. E.g.,
2493for an error of type @code{wrong-type-argument}, @code{(error-slot-value
2494@var{error} 2)} returns the object that failed the type test, and
2495@code{(error-slot-value @var{error} 1)} returns the predicate that failed.
2496@end defun
2497
2481@defun error-message-string error-descriptor 2498@defun error-message-string error-descriptor
2482This function returns the error message string for a given error 2499This function returns the error message string for a given error
2483descriptor. It is useful if you want to handle an error by printing the 2500descriptor. It is useful if you want to handle an error by printing the
@@ -2615,7 +2632,7 @@ Emacs searches all the active @code{condition-case} and
2615specifies one or more of these condition names. When the innermost 2632specifies one or more of these condition names. When the innermost
2616matching handler is one installed by @code{handler-bind}, the 2633matching handler is one installed by @code{handler-bind}, the
2617@var{handler} function is called with a single argument holding the 2634@var{handler} function is called with a single argument holding the
2618error description. 2635error descriptor.
2619 2636
2620Contrary to what happens with @code{condition-case}, @var{handler} is 2637Contrary to what happens with @code{condition-case}, @var{handler} is
2621called in the dynamic context where the error happened. This means it 2638called in the dynamic context where the error happened. This means it
@@ -2799,6 +2816,18 @@ make it possible to categorize errors at various levels of generality
2799when you write an error handler. Using error symbols alone would 2816when you write an error handler. Using error symbols alone would
2800eliminate all but the narrowest level of classification. 2817eliminate all but the narrowest level of classification.
2801 2818
2819@defun error-type-p symbol
2820This function returns non-@code{nil} if @var{symbol} is a valid
2821error condition name.
2822@end defun
2823
2824@defun error-has-type-p error condition
2825This function tests whether @var{condition} is a parent of the error
2826symbol of the error descriptor @var{error}.
2827It returns non-@code{nil} if the type of the error descriptor
2828@var{error} belongs to the condition name @var{condition}.
2829@end defun
2830
2802 @xref{Standard Errors}, for a list of the main error symbols 2831 @xref{Standard Errors}, for a list of the main error symbols
2803and their conditions. 2832and their conditions.
2804 2833
diff --git a/lisp/subr.el b/lisp/subr.el
index 0ad86fd30a1..3cf4e8276d6 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -568,8 +568,40 @@ Defaults to `error'."
568 (cons parent (get parent 'error-conditions))))) 568 (cons parent (get parent 'error-conditions)))))
569 (put name 'error-conditions 569 (put name 'error-conditions
570 (delete-dups (copy-sequence (cons name conditions)))) 570 (delete-dups (copy-sequence (cons name conditions))))
571 ;; FIXME: Make `error-message-string' more flexible, e.g. allow
572 ;; the message to be specified by a `format' string or a function.
571 (when message (put name 'error-message message)))) 573 (when message (put name 'error-message message))))
572 574
575(defun error-type-p (symbol)
576 "Return non-nil if SYMBOL is a condition type."
577 (get symbol 'error-conditions))
578
579(defun error--p (object)
580 "Return non-nil if OBJECT looks like a valid error descriptor."
581 (let ((type (car-safe object)))
582 (and type (symbolp type) (listp (cdr object))
583 (error-type-p type))))
584
585(defalias 'error-type #'car
586 "Return the symbol which represents the type of ERROR.
587\n(fn ERROR)")
588
589(defalias 'error-data #'cdr
590 "Return the slots attached to ERROR, as a list.
591\n(fn ERROR)")
592
593(defun error-has-type-p (error condition)
594 "Return non-nil if ERROR is of type CONDITION (or a subtype of it)."
595 (unless (error--p error)
596 (signal 'wrong-type-argument (list #'error--p error)))
597 (or (eq condition t)
598 (memq condition (get (car error) 'error-conditions))))
599
600(defalias 'error-slot-value #'elt
601 "Access the SLOT of object ERROR.
602Slots are specified by position, and slot 0 is the error symbol.
603\n(fn ERROR SLOT)")
604
573;; We put this here instead of in frame.el so that it's defined even on 605;; We put this here instead of in frame.el so that it's defined even on
574;; systems where frame.el isn't loaded. 606;; systems where frame.el isn't loaded.
575(defun frame-configuration-p (object) 607(defun frame-configuration-p (object)
diff --git a/src/eval.c b/src/eval.c
index 7ca9d761a7e..0b451b2c891 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1871,10 +1871,15 @@ probably_quit (void)
1871 unbind_to (gc_count, Qnil); 1871 unbind_to (gc_count, Qnil);
1872} 1872}
1873 1873
1874DEFUN ("signal", Fsignal, Ssignal, 2, 2, 0, 1874DEFUN ("signal", Fsignal, Ssignal, 1, 2, 0,
1875 doc: /* Signal an error. Args are ERROR-SYMBOL and associated DATA. 1875 doc: /* Signal an error. Args are ERROR-SYMBOL and associated DATA.
1876This function does not return. 1876This function does not return.
1877 1877
1878When signaling a new error, the DATA argument is mandatory.
1879When re-signaling an error to propagate it to further handlers,
1880DATA has to be omitted and the first argument has to be the whole
1881error descriptor.
1882
1878When `noninteractive' is non-nil (in particular, in batch mode), an 1883When `noninteractive' is non-nil (in particular, in batch mode), an
1879unhandled error calls `kill-emacs', which terminates the Emacs 1884unhandled error calls `kill-emacs', which terminates the Emacs
1880session with a non-zero exit code. 1885session with a non-zero exit code.
@@ -1942,13 +1947,14 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool continuable)
1942 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */ 1947 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */
1943 /* FIXME: Here we still "split" the error object 1948 /* FIXME: Here we still "split" the error object
1944 into its error-symbol and its error-data? */ 1949 into its error-symbol and its error-data? */
1945 calln (Vsignal_hook_function, error_symbol, data); 1950 calln (Vsignal_hook_function, real_error_symbol,
1951 NILP (data) && CONSP (error) ? XCDR (error) : data);
1946 unbind_to (count, Qnil); 1952 unbind_to (count, Qnil);
1947 } 1953 }
1948 1954
1949 conditions = Fget (real_error_symbol, Qerror_conditions); 1955 conditions = Fget (real_error_symbol, Qerror_conditions);
1950 if (NILP (conditions)) 1956 if (NILP (conditions))
1951 signal_error ("Invalid error symbol", error_symbol); 1957 signal_error ("Invalid error symbol", real_error_symbol);
1952 1958
1953 /* Remember from where signal was called. Skip over the frame for 1959 /* Remember from where signal was called. Skip over the frame for
1954 `signal' itself. If a frame for `error' follows, skip that, 1960 `signal' itself. If a frame for `error' follows, skip that,