Skip to content

check_number_*() not catching -Inf < min, max < Inf (standalone-types-check.R) #1861

@tjmahr

Description

@tjmahr

-Inf, Inf are not checked against min/max boundaries.

check_number_decimal(-Inf, min = 0, allow_infinite = TRUE)
check_number_decimal(+Inf, max = 0, allow_infinite = TRUE)

Reprex:

library(rlang)
.standalone_types_check_dot_call <- .Call

IS_NUMBER_true <- 0
IS_NUMBER_false <- 1
IS_NUMBER_oob <- 2

check_number_decimal <- function(
    x,
    ...,
    min = NULL,
    max = NULL,
    allow_infinite = TRUE,
    allow_na = FALSE,
    allow_null = FALSE,
    arg = caller_arg(x),
    call = caller_env()
) {
  if (missing(x)) {
    exit_code <- IS_NUMBER_false
  } else if (
    0 ==
    (exit_code <- .standalone_types_check_dot_call(
      ffi_standalone_check_number_1.0.7,
      x,
      allow_decimal = TRUE,
      min,
      max,
      allow_infinite,
      allow_na,
      allow_null
    ))
  ) {
    return(invisible(NULL))
  }
  
  .stop_not_number(
    x,
    ...,
    exit_code = exit_code,
    allow_decimal = TRUE,
    min = min,
    max = max,
    allow_na = allow_na,
    allow_null = allow_null,
    arg = arg,
    call = call
  )
}

check_number_whole <- function(
    x,
    ...,
    min = NULL,
    max = NULL,
    allow_infinite = FALSE,
    allow_na = FALSE,
    allow_null = FALSE,
    arg = caller_arg(x),
    call = caller_env()
) {
  if (missing(x)) {
    exit_code <- IS_NUMBER_false
  } else if (
    0 ==
    (exit_code <- .standalone_types_check_dot_call(
      ffi_standalone_check_number_1.0.7,
      x,
      allow_decimal = FALSE,
      min,
      max,
      allow_infinite,
      allow_na,
      allow_null
    ))
  ) {
    return(invisible(NULL))
  }
  
  .stop_not_number(
    x,
    ...,
    exit_code = exit_code,
    allow_decimal = FALSE,
    min = min,
    max = max,
    allow_na = allow_na,
    allow_null = allow_null,
    arg = arg,
    call = call
  )
}

.stop_not_number <- function(
    x,
    ...,
    exit_code,
    allow_decimal,
    min,
    max,
    allow_na,
    allow_null,
    arg,
    call
) {
  if (allow_decimal) {
    what <- "a number"
  } else {
    what <- "a whole number"
  }
  
  if (exit_code == IS_NUMBER_oob) {
    min <- min %||% -Inf
    max <- max %||% Inf
    
    if (min > -Inf && max < Inf) {
      what <- sprintf("%s between %s and %s", what, min, max)
    } else if (x < min) {
      what <- sprintf("%s larger than or equal to %s", what, min)
    } else if (x > max) {
      what <- sprintf("%s smaller than or equal to %s", what, max)
    } else {
      abort("Unexpected state in OOB check", .internal = TRUE)
    }
  }
  
  stop_input_type(
    x,
    what,
    ...,
    allow_na = allow_na,
    allow_null = allow_null,
    arg = arg,
    call = call
  )
}


# should pass / passes
check_number_decimal(2, min = 0)
check_number_decimal(-Inf, min = NULL, allow_infinite = TRUE)
check_number_decimal(+Inf, max = NULL, allow_infinite = TRUE)

# should fail / fails
check_number_decimal(-2, min = 0)
#> Error in `stop_input_type()`:
#> ! could not find function "stop_input_type"

# should fail / passes
check_number_decimal(-Inf, min = 0, allow_infinite = TRUE)
check_number_decimal(+Inf, max = 0, allow_infinite = TRUE)

Created on 2026-01-15 with reprex v2.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions