Skip to main content

try_eval_with_handlers

Function try_eval_with_handlers 

Source
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

As eval_with_handlers:

  • R’s main thread, inside a miniextendr boundary: a #[miniextendr] function body, a with_r_unwind_protect closure, an ALTREP callback with the r_unwind or rust_unwind guard (not unsafe, which catches nothing), a connection callback, a with_r_thread closure.
  • expr and env stay rooted for the call; env is an environment.

§Returns

  • Ok(SEXP) with the value, unprotected: protect it before the next allocation.
  • Err(REvalError) with R’s error condition.