Skip to content

Commit 9b6bfcd

Browse files
Ensure we vec_ptype_finalise() when we treat vec_ptype2() like a "common" ptype computation (#2107)
* Adding finalise ptype before casting parameters * Fix protection issues * Finalize `ptype` in `vec_if_else()` * Finalize `ptype` in interval functions * Delay `ptype` finalization in `vec_recode_values()` Until after `default` has been included, then we `vec_ptype_finalize()` on the way out * Header is already included --------- Co-authored-by: Davis Vaughan <davis@posit.co>
1 parent e192e75 commit 9b6bfcd

File tree

6 files changed

+75
-24
lines changed

6 files changed

+75
-24
lines changed

src/dictionary.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -396,23 +396,37 @@ SEXP vec_match_params(SEXP needles,
396396
struct vctrs_arg* haystack_arg,
397397
struct r_lazy call) {
398398
int nprot = 0;
399+
399400
int _;
400-
SEXP type = vec_ptype2_params(needles, haystack,
401-
needles_arg, haystack_arg,
402-
call,
403-
&_);
401+
SEXP type = vec_ptype2_params(
402+
needles,
403+
haystack,
404+
needles_arg,
405+
haystack_arg,
406+
call,
407+
&_
408+
);
404409
PROTECT_N(type, &nprot);
410+
type = PROTECT_N(vec_ptype_finalise(type), &nprot);
405411

406-
needles = vec_cast_params(needles, type,
407-
needles_arg, vec_args.empty,
408-
call,
409-
S3_FALLBACK_false);
412+
needles = vec_cast_params(
413+
needles,
414+
type,
415+
needles_arg,
416+
vec_args.empty,
417+
call,
418+
S3_FALLBACK_false
419+
);
410420
PROTECT_N(needles, &nprot);
411421

412-
haystack = vec_cast_params(haystack, type,
413-
haystack_arg, vec_args.empty,
414-
call,
415-
S3_FALLBACK_false);
422+
haystack = vec_cast_params(
423+
haystack,
424+
type,
425+
haystack_arg,
426+
vec_args.empty,
427+
call,
428+
S3_FALLBACK_false
429+
);
416430
PROTECT_N(haystack, &nprot);
417431

418432
needles = PROTECT_N(vec_proxy_equal(needles), &nprot);
@@ -559,7 +573,6 @@ SEXP vec_in(
559573
int nprot = 0;
560574

561575
int _;
562-
563576
SEXP type = vec_ptype2_params(
564577
needles,
565578
haystack,
@@ -569,6 +582,7 @@ SEXP vec_in(
569582
&_
570583
);
571584
PROTECT_N(type, &nprot);
585+
type = PROTECT_N(vec_ptype_finalise(type), &nprot);
572586

573587
needles = vec_cast_params(
574588
needles,

src/if-else.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,9 @@ r_obj* ptype_finalize(
588588
);
589589
}
590590

591+
// Finalize on the way out
592+
ptype = vec_ptype_finalise(ptype);
593+
591594
FREE(n_prot);
592595
return ptype;
593596
}

src/interval.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ r_obj* vec_interval_group_info(r_obj* start,
8282
&_
8383
);
8484
KEEP_N(ptype, &n_prot);
85+
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
8586

8687
start = vec_cast_params(
8788
start,
@@ -324,6 +325,7 @@ r_obj* vec_interval_complement(r_obj* start,
324325
&_
325326
);
326327
KEEP_N(ptype, &n_prot);
328+
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
327329

328330
start = vec_cast_params(
329331
start,
@@ -733,6 +735,7 @@ r_obj* vec_interval_locate_containers(r_obj* start, r_obj* end) {
733735
&_
734736
);
735737
KEEP_N(ptype, &n_prot);
738+
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
736739

737740
start = vec_cast_params(
738741
start,

src/match.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ r_obj* vec_locate_matches(r_obj* needles,
154154
error_call,
155155
&_
156156
), &n_prot);
157+
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
157158

158159
needles = KEEP_N(vec_cast_params(
159160
needles,

src/recode.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -771,28 +771,35 @@ r_obj* ptype_finalize(
771771
}
772772

773773
// Otherwise `ptype` is `NULL`, and we determine it from `to` and `default`
774+
r_keep_loc ptype_pi;
775+
KEEP_HERE(ptype, &ptype_pi);
774776

775777
if (to_as_list_of_vectors) {
776778
// Use only `to` and `p_to_arg` first for best errors
777-
ptype = KEEP(vec_ptype_common(
779+
// Not finalising `ptype` yet in case we need to incorporate `default`!
780+
ptype = vec_ptype_common(
778781
to,
779782
r_null,
780-
PTYPE_FINALISE_DEFAULT,
783+
PTYPE_FINALISE_false,
781784
S3_FALLBACK_DEFAULT,
782785
p_to_arg,
783786
error_call
784-
));
787+
);
788+
KEEP_AT(ptype, ptype_pi);
785789

786790
// Now incorporate `default` and `p_default_arg`
787791
int _;
788-
ptype = KEEP(vec_ptype2_params(default_, ptype, p_default_arg, vec_args.empty, error_call, &_));
789-
790-
FREE(2);
792+
ptype = vec_ptype2_params(default_, ptype, p_default_arg, vec_args.empty, error_call, &_);
793+
KEEP_AT(ptype, ptype_pi);
791794
} else {
792795
int _;
793-
ptype = KEEP(vec_ptype2_params(to, default_, p_to_arg, p_default_arg, error_call, &_));
794-
FREE(1);
796+
ptype = vec_ptype2_params(to, default_, p_to_arg, p_default_arg, error_call, &_);
797+
KEEP_AT(ptype, ptype_pi);
795798
}
796799

800+
// Finalize on the way out
801+
ptype = vec_ptype_finalise(ptype);
802+
803+
FREE(1);
797804
return ptype;
798805
}

tests/testthat/test-recode.R

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,7 @@ test_that("proof that `ptype` finalization is important", {
460460
to <- FALSE
461461

462462
# If no `ptype` finalization happened, then `ptype = x` would result in
463-
# `unspecified` being the output type and these would error. `list_combine()`
464-
# now does `ptype` finalization when an explicit `ptype` is provided, so this
465-
# works.
463+
# `unspecified` being the output type and these would error
466464
expect_identical(
467465
vec_recode_values(x, from = from, to = to, default = x, ptype = x),
468466
c(FALSE, FALSE)
@@ -473,6 +471,31 @@ test_that("proof that `ptype` finalization is important", {
473471
)
474472
})
475473

474+
test_that("common `ptype` of `to` isn't finalized until `default` has been included", {
475+
# If the common type of `to` is finalized early, we get `logical`, which can't
476+
# combine with `default`'s `character` type
477+
expect_identical(
478+
vec_recode_values(
479+
x = "a",
480+
from = "a",
481+
to = list(NA),
482+
default = "x",
483+
to_as_list_of_vectors = TRUE
484+
),
485+
NA_character_
486+
)
487+
expect_identical(
488+
vec_recode_values(
489+
x = "a",
490+
from = "b",
491+
to = list(NA),
492+
default = "x",
493+
to_as_list_of_vectors = TRUE
494+
),
495+
"x"
496+
)
497+
})
498+
476499
test_that("extraneous `to` attributes don't end up on the final output", {
477500
x <- c(1, 2, 3)
478501

0 commit comments

Comments
 (0)