diff --git a/NEWS.md b/NEWS.md index dfc849654..65f015612 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # vctrs (development version) +* Fixed an issue where `vec_set_*()` used with data frames could accidentally + return an object with the type of the proxy rather than the type of the + original inputs (#1837). + * Fixed a rare `vec_locate_matches()` bug that could occur when using a max/min `filter` (tidyverse/dplyr#6835). diff --git a/src/proxy.c b/src/proxy.c index d7bd89865..b17ea8365 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -215,7 +215,10 @@ r_obj* vec_proxy_order_invoke(r_obj* x, r_obj* method) { static inline r_obj* df_proxy(r_obj* x, enum vctrs_proxy_kind kind) { - x = KEEP(r_clone_referenced(x)); + // Always clone to avoid modifying the original object, even if it is one + // we freshly created in C, because we often work with both the proxy and the + // original object within the same function (#1837) + x = KEEP(r_clone(x)); switch (kind) { case VCTRS_PROXY_KIND_equal: DF_PROXY(vec_proxy_equal); break; diff --git a/tests/testthat/test-set.R b/tests/testthat/test-set.R index 5ad9cc209..7eb47287e 100644 --- a/tests/testthat/test-set.R +++ b/tests/testthat/test-set.R @@ -341,6 +341,20 @@ test_that("works with rcrds", { # common ------------------------------------------------------------------ +test_that("works with package version columns of data frames (#1837)", { + package_frame <- function(x) { + data_frame(version = package_version(x)) + } + + x <- package_frame(c("4.0", "2.0")) + y <- package_frame(c("1.0", "3.0" ,"4.0")) + + expect_identical(vec_set_intersect(x, y), package_frame("4.0")) + expect_identical(vec_set_difference(x, y), package_frame("2.0")) + expect_identical(vec_set_union(x, y), package_frame(c("4.0", "2.0", "1.0", "3.0"))) + expect_identical(vec_set_symmetric_difference(x, y), package_frame(c("2.0", "1.0", "3.0"))) +}) + test_that("errors nicely if common type can't be taken", { expect_snapshot(error = TRUE, { vec_set_intersect(1, "x")