[R-pkg-devel] tryCatch() doesn't capture errors due to && or || with R CMD check --as-cran

Etienne Bacher et|enne@b@cher @end|ng |rom protonm@||@com
Thu Sep 1 15:55:15 CEST 2022


Dear all, 

Calling && or || with LHS or (if evaluated) RHS of length greater than one gives an error in the devel version of R and a warning since R 4.2.0. With R 4.2.1, I can capture this warning with tryCatch(). However, R CMD check with R-devel fails because of this new behavior, meaning that tryCatch() doesn't work. For example, take this function:

foo <- function() {
  tryCatch(
    if (c(TRUE, TRUE) || c(TRUE, TRUE)) 1,
    warning = function(w) {
      print(w)
      NULL
    },
    error = function(e) {
      print(e)
      NULL
    }
  )
}

With R 4.2.1, this correctly gives a warning and returns NULL when I run this locally:
> foo()
<simpleWarning in c(TRUE, TRUE) || c(TRUE, TRUE): 'length(x) = 2 > 1' in coercion to 'logical(1)'>
NULL

And if I change the environment variables to return an error instead of the warning, it correctly gives an error and returns NULL:
> Sys.setenv(
    `_R_CHECK_LENGTH_1_CONDITION_` = "true",
    `_R_CHECK_LENGTH_1_LOGIC2_` = "true"
)
>foo()
<simpleError in c(TRUE, TRUE) || c(TRUE, TRUE): 'length(x) = 2 > 1' in coercion to 'logical(1)'>
NULL

This behavior is expected. But if I put this function in a package, add a test for it, and run R CMD check "." --as-cran (or rcmdcheck::rcmdcheck(args = "--as-cran")), then I get an error that I paste at the end of this email because it's quite long. I thought that tryCatch() would capture this error, even when using R CMD check with R-devel, but this is not the case. Is this an expected behavior or a bug?

If you want to reproduce this error, I made a tiny package here: https://github.com/etiennebacher/testpackage. You can simply clone the repo and run R CMD check on it. 

If it matters, I'm using R 4.2.1 on Windows 10.

Thanks in advance,

Etienne


 ----------- FAILURE REPORT -------------- 
 --- failure: length > 1 in coercion to logical ---
 --- srcref --- 
: 
 --- package (from environment) --- 
compiler
 --- call from context --- 
do.call(ffun, args)
 --- call from argument --- 
.Primitive("||")(c(TRUE, TRUE), c(TRUE, TRUE))
 --- R stacktrace ---
where 1: do.call(ffun, args)
where 2: mode(e)
where 3: mode(e) %in% constModes
where 4: checkConst(do.call(ffun, args))
where 5: doTryCatch(return(expr), name, parentenv, handler)
where 6: tryCatchOne(expr, names, parentenv, handlers[[1L]])
where 7: tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
where 8: doTryCatch(return(expr), name, parentenv, handler)
where 9: tryCatchOne(tryCatchList(expr, names[-nh], parentenv, handlers[-nh]), 
    names[nh], parentenv, handlers[[nh]])
where 10: tryCatchList(expr, classes, parentenv, handlers)
where 11: tryCatch(checkConst(do.call(ffun, args)), error = function(e) NULL, 
    warning = function(w) NULL)
where 12: constantFoldCall(e, cntxt)
where 13: constantFold(test, cntxt, loc = cb$savecurloc())
where 14: h(e, cb, cntxt)
where 15: tryInline(call, cb, cntxt)
where 16: cmpCall(e, cb, cntxt)
where 17: cmp(e, cb, cntxt, setloc = FALSE)
where 18: genCode(a, pcntxt, loc = cb$savecurloc())
where 19: cb$putconst(genCode(a, pcntxt, loc = cb$savecurloc()))
where 20: cmpCallArgs(args, cb, cntxt, nse)
where 21: cmpCallSymFun(fun, args, call, cb, cntxt)
where 22: cmpCall(e, cb, cntxt)
where 23: cmp(subexp, cb, cntxt, setloc = FALSE)
where 24: h(e, cb, cntxt)
where 25: tryInline(call, cb, cntxt)
where 26: cmpCall(e, cb, cntxt)
where 27: cmp(e, cb, cntxt, setloc = FALSE)
where 28: genCode(body(f), ncntxt, loc = loc)
where 29: cmpfun(f)
where 30: doTryCatch(return(expr), name, parentenv, handler)
where 31: tryCatchOne(expr, names, parentenv, handlers[[1L]])
where 32: tryCatchList(expr, classes, parentenv, handlers)
where 33: tryCatch(cmpfun(f), error = function(e) {
    notifyCompilerError(paste(e$message, "at", deparse(e$call)))
    f
})
where 34: compiler:::tryCmpfun(function () 
{
    tryCatch(if (c(TRUE, TRUE) || c(TRUE, TRUE)) 
        1, warning = function(w) {
        print(w)
        NULL
    }, error = function(e) {
        print(e)
        NULL
    })
})
where 35: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress, 
    envhook)
where 36: makeLazyLoadDB(ns, dbbase, compress = compress, set.install.dir = set.install.dir)
where 37: code2LazyLoadDB(package, lib.loc = lib.loc, keep.source = keep.source, 
    keep.parse.data = keep.parse.data, compress = compress, set.install.dir = set.install.dir)
where 38: tools:::makeLazyLoading("testpackage", "C:/Users/etienne/AppData/Local/Temp/Rtmp8QXtOL/file41b43ee61605/testpackage.Rcheck/00LOCK-TESTPA~1/00new", 
    keep.source = FALSE, keep.parse.data = FALSE, set.install.dir = "C:/Users/etienne/AppData/Local/Temp/Rtmp8QXtOL/file41b43ee61605/testpackage.Rcheck/testpackage")

 --- value of length: 2 type: logical ---
[1] TRUE TRUE
 --- function from context --- 
function (what, args, quote = FALSE, envir = parent.frame()) 
{
    if (!is.list(args)) 
        stop("second argument must be a list")
    if (quote) 
        args <- lapply(args, enquote)
    .Internal(do.call(what, args, envir))
}
<bytecode: 0x0000021b0a155e20>
<environment: namespace:base>
 --- function search by body ---
Function do.call in namespace base has this body.
 ----------- END OF FAILURE REPORT -------------- 
Fatal error: length > 1 in coercion to logical



More information about the R-package-devel mailing list