Skip to content

Commit a8772b2

Browse files
committed
Fix array() reshape source and dim handling
- Ensure Fortran RESHAPE() receives an array-valued SOURCE; expand scalar-fill constructors (integer/double/logical) to the required element count. - Derive SHAPE from r2dims()+dims2f() so dim can be supplied as an AST literal vector. - Add regression tests covering both cases.
1 parent b6e46aa commit a8772b2

2 files changed

Lines changed: 58 additions & 13 deletions

File tree

R/r2f-constructors.R

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,29 +85,52 @@ r2f_handlers[["array"]] <- function(args, scope = NULL, ...) {
8585
}
8686

8787
out <- r2f(args$data, scope, ...)
88+
target_dims <- r2dims(args$dim, scope)
8889
if (!passes_as_scalar(out@value)) {
8990
# R semantics: `array()` flattens its input (dropping dim) then reshapes.
9091
# We implement this as `reshape()`; recycling is not supported here.
91-
dim_vec <- r2f(args$dim, scope, ...)
92-
if (
93-
is.null(dim_vec@value) ||
94-
!(dim_vec@value@mode %in% c("integer", "double"))
95-
) {
96-
stop("array(dim=) must be an integer/numeric value", call. = FALSE)
92+
dims_f <- dims2f(target_dims, scope)
93+
if (!nzchar(dims_f)) {
94+
dims_f <- "1"
9795
}
98-
shape <- if (passes_as_scalar(dim_vec@value)) {
99-
glue("[int({dim_vec})]")
100-
} else if (dim_vec@value@rank == 1L) {
101-
glue("int({dim_vec})")
96+
if (grepl(":", dims_f, fixed = TRUE)) {
97+
stop("array(dim=) must be known", call. = FALSE)
98+
}
99+
shape <- glue("int([{dims_f}])")
100+
101+
data_r <- args$data
102+
is_fill_constructor <-
103+
is.call(data_r) &&
104+
is.symbol(data_r[[1L]]) &&
105+
as.character(data_r[[1L]]) %in%
106+
c(
107+
"logical",
108+
"integer",
109+
"double",
110+
"numeric"
111+
)
112+
113+
source <- if (is_fill_constructor) {
114+
dims_terms <- strsplit(dims_f, ",\\s*")[[1L]]
115+
n_expr <- if (length(dims_terms) == 1L) {
116+
dims_terms[[1L]]
117+
} else {
118+
glue("({paste(dims_terms, collapse = ' * ')})")
119+
}
120+
i <- scope@get_unique_var("integer")
121+
glue("[({out}, {i}=1, int({n_expr}))]")
102122
} else {
103-
stop("array(dim=) must be a scalar or 1-d vector", call. = FALSE)
123+
# RESHAPE() requires `SOURCE` to be an array expression; array constructors
124+
# flatten array-valued expressions (which matches R's array() semantics).
125+
glue("[{out}]")
104126
}
105-
out <- Fortran(glue("reshape({out}, {shape})"), out@value)
127+
128+
out <- Fortran(glue("reshape({source}, {shape})"), out@value)
106129
}
107130

108131
out@value <- Variable(
109132
mode = out@value@mode,
110-
dims = r2dims(args$dim, scope)
133+
dims = target_dims
111134
)
112135
out
113136
}

tests/testthat/test-array-reshape.R

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,25 @@ test_that("array() reshape accepts scalar dims", {
3333
x <- sample(1:10, 24, replace = TRUE)
3434
expect_quick_identical(fn, list(x))
3535
})
36+
37+
test_that("array() reshape works when data is scalar-emitted (e.g. integer(n))", {
38+
fn <- function() {
39+
# `integer(3)` currently lowers to scalar `0` with a non-scalar value shape.
40+
# The array() reshape path must produce valid Fortran anyway.
41+
array(integer(3L), dim = c(1L, 3L))
42+
}
43+
44+
expect_quick_identical(fn, list())
45+
})
46+
47+
test_that("array() reshape accepts literal dim vectors in the AST", {
48+
dim_const <- c(2L, 3L, 4L)
49+
fn <- eval(bquote(function(x) {
50+
declare(type(x = integer(2L, 3L, 4L)))
51+
array(as.double(x), dim = .(dim_const))
52+
}))
53+
54+
set.seed(1)
55+
x <- array(sample(1:10, 24, replace = TRUE), dim = c(2L, 3L, 4L))
56+
expect_quick_identical(fn, list(x))
57+
})

0 commit comments

Comments
 (0)