pub unsafe fn try_eval_with_handlers(
expr: SEXP,
env: SEXP,
) -> Result<SEXP, REvalError>Expand description
Evaluate expr in env in the caller’s R context, as
eval_with_handlers does, but return an R error as Err instead of
letting it unwind.
The caller’s withCallingHandlers(), suppressWarnings() and
suppressMessages() see the evaluation’s warnings, messages and other
conditions; one they muffle returns here and the evaluation goes on. A
condition of class error is caught at the evaluation, by an exiting
handler (R_tryCatchError), and comes back as Err(REvalError)
built as RCall::eval builds it: R’s condition, with its message (no
Error in prefix, no Calls: line), call and classes. The Rust code
decides what to raise (REvalError::reraise_class).
Any other exit (an exiting handler of the caller’s tryCatch(), such as
tryCatch(warning = ), invokeRestart(), an interrupt) leaves as under
eval_with_handlers: it stops at this function’s own R_UnwindProtect
frame and goes on as a Rust unwind, the frames up to the #[miniextendr]
boundary drop their values, and the boundary hands the exit back to R.
The error handler is the innermost one, so a handler of the caller’s for
errors (withCallingHandlers(error = ), tryCatch(error = )) does not see
an error the evaluation raises. An error raised by a handler of the
caller’s, as in withCallingHandlers(warning = function(w) stop("no")),
is not the evaluation’s: R runs that handler outside the evaluation’s
handlers, so the error unwinds to the caller as raised.
The evaluation runs inside R’s tryCatch(), as under RCall::eval: an
error raised at the top of expr (stop() called directly, not from a
function) has no call, and code at the top of expr
that inspects the call stack (sys.call()) sees the tryCatch() frames.
The rules of eval_with_handlers for the unwind hold here too: don’t
catch it with std::panic::catch_unwind on its way to the boundary, and
don’t call this from a Drop implementation.
§Safety
- R’s main thread, inside a miniextendr boundary: a
#[miniextendr]function body, awith_r_unwind_protectclosure, an ALTREP callback with ther_unwindorrust_unwindguard (notunsafe, which catches nothing), a connection callback, awith_r_threadclosure. exprandenvstay rooted for the call;envis an environment.
§Returns
Ok(SEXP)with the value, unprotected: protect it before the next allocation.Err(REvalError)with R’s error condition.