diff --git a/r/R/as-array.R b/r/R/as-array.R index d3aa5ee9a..c45fdf241 100644 --- a/r/R/as-array.R +++ b/r/R/as-array.R @@ -257,7 +257,7 @@ as_nanoarrow_array.list <- function(x, ..., schema = NULL) { array <- nanoarrow_array_init(schema) - child <- unlist(x, recursive = FALSE, use.names = FALSE) + child <- do.call(c, x) if (is.null(child)) { child_array <- as_nanoarrow_array.vctrs_unspecified(logical(), schema = na_na()) } else { diff --git a/r/src/materialize_int64.h b/r/src/materialize_int64.h index ad83671e5..086a7505d 100644 --- a/r/src/materialize_int64.h +++ b/r/src/materialize_int64.h @@ -49,7 +49,7 @@ static inline int nanoarrow_materialize_int64(struct ArrayViewSlice* src, break; case NANOARROW_TYPE_INT64: memcpy(result + dst->offset, - src->array_view->buffer_views[1].data.as_int32 + raw_src_offset, + src->array_view->buffer_views[1].data.as_int64 + raw_src_offset, dst->length * sizeof(int64_t)); // Set any nulls to NA_INTEGER64 diff --git a/r/tests/testthat/test-as-array.R b/r/tests/testthat/test-as-array.R index 6157bf551..7c301e0b5 100644 --- a/r/tests/testthat/test-as-array.R +++ b/r/tests/testthat/test-as-array.R @@ -824,6 +824,29 @@ test_that("as_nanoarrow_array() works for list(integer()) -> na_list(na_int32()) expect_identical(array$children[[1]]$length, 10L) }) +test_that("as_nanoarrow_array() works for list(integer64()) -> na_list(na_int64())", { + # GH932: unlist() silently strips the integer64 class from list elements, + # reinterpreting the underlying int64 bit pattern as a double and corrupting + # values before the child array is even built. + skip_if_not_installed("bit64") + + big <- bit64::as.integer64(c("9223372036854775295", "2")) + x <- list(big, bit64::as.integer64("3")) + array <- as_nanoarrow_array(x, schema = na_list(na_int64())) + + expect_identical(infer_nanoarrow_schema(array)$format, "+l") + expect_identical(array$length, 2L) + expect_identical(array$null_count, 0L) + expect_identical(infer_nanoarrow_schema(array$children[[1]])$format, "l") + expect_identical(array$children[[1]]$length, 3L) + + to <- vctrs::new_list_of(list(), ptype = bit64::integer64()) + expect_identical( + convert_array(array, to), + vctrs::new_list_of(list(big, bit64::as.integer64("3")), ptype = bit64::integer64()) + ) +}) + test_that("as_nanoarrow_array() works for unspecified() -> na_na()", { skip_if_not_installed("vctrs") diff --git a/r/tests/testthat/test-convert-array.R b/r/tests/testthat/test-convert-array.R index 8ceca779f..deedb7e38 100644 --- a/r/tests/testthat/test-convert-array.R +++ b/r/tests/testthat/test-convert-array.R @@ -744,6 +744,24 @@ test_that("convert to vector works for valid integer64()", { ) }) +test_that("convert to vector works for int64 with a nonzero offset", { + # GH932: the int64 materializer read from buffer_views[1].data.as_int32 + # (i.e., with int32-sized pointer arithmetic) instead of as_int64, so any + # slice with a nonzero starting offset (e.g., a list child sliced per-row) + # read from the wrong memory location. + skip_if_not_installed("bit64") + + vals <- bit64::as.integer64(c("9223372036854775295", "2", "3")) + array <- as_nanoarrow_array(vals, schema = na_int64()) + + sliced <- nanoarrow_array_modify(array, list(offset = 1L, length = 2L)) + + expect_identical( + convert_array(sliced, bit64::integer64()), + vals[2:3] + ) +}) + test_that("convert to vector works for null -> integer64()", { skip_if_not_installed("bit64")