Skip to content

Commit 1a5003b

Browse files
Exclude '..1' from up-a-level search (#7128)
* Exclude '..1' from up-a-level search * slightly simplify (?) regex * Revert "slightly simplify (?) regex" This reverts commit 74a54ef. * new test belying the "simplification" in prev. commit * another one * i guess these should all work (?) * local() avoid scope spillover * remove the failing test
1 parent b92ac52 commit 1a5003b

File tree

3 files changed

+47
-13
lines changed

3 files changed

+47
-13
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@
111111
112112
18. `fwrite` now allows `dec` to be the same as `sep` for edge cases where only one will be written, e.g. 0-row or 1-column tables. [#7227](https://github.com/Rdatatable/data.table/issues/7227). Thanks @MichaelChirico for the report and @venom1204 for the fix.
113113
114+
19. Ellipsis elements like `..1` are correctly excluded when searching for variables in "up-a-level" syntax inside `[`, [#5460](https://github.com/Rdatatable/data.table/issues/5460). Thanks @ggrothendieck for the report and @MichaelChirico for the fix.
115+
114116
### NOTES
115117
116118
1. The following in-progress deprecations have proceeded:

R/data.table.R

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ replace_dot_alias = function(e) {
264264
if (!missing(j)) {
265265
jsub = replace_dot_alias(jsub)
266266
root = root_name(jsub)
267-
av = all.vars(jsub)
267+
# exclude '..1' etc. for #5460
268+
av = grepv("^[.][.](?:[.]|[0-9]+)$", all.vars(jsub), invert=TRUE)
268269
all..names = FALSE
269270
if ((.is_withFALSE_range(jsub, x, root, av)) ||
270271
(root %chin% c("-","!") && jsub[[2L]] %iscall% '(' && jsub[[2L]][[2L]] %iscall% ':') || ## x[, !(V8:V10)]
@@ -1297,8 +1298,8 @@ replace_dot_alias = function(e) {
12971298
SDenv = new.env(parent=parent.frame())
12981299

12991300
syms = all.vars(jsub)
1300-
syms = syms[ startsWith(syms, "..") ]
1301-
syms = syms[ substr(syms, 3L, 3L) != "." ] # exclude ellipsis
1301+
syms = syms[startsWith(syms, "..")]
1302+
syms = grepv("^[.][.](?:[.]|[0-9]+)$", syms, invert=TRUE) # exclude ellipsis and '..n' ellipsis elements
13021303
for (sym in syms) {
13031304
if (sym %chin% names_x) {
13041305
# if "..x" exists as column name, use column, for backwards compatibility; e.g. package socialmixr in rev dep checks #2779

inst/tests/tests.Rraw

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21568,16 +21568,16 @@ test(2333, as.expression(data.table(a = 1))[["a"]], 1)
2156821568

2156921569
# regression test for hexdigits subscript overrun (uint8_t wraps over 255, unsigned overflow is well defined in c)
2157021570
local({
21571-
f = tempfile()
21572-
on.exit(unlink(f))
21573-
# the line is likely invalid in current encoding, so disable any translation, #7209
21574-
# test.data.table() sets options(encoding="UTF-8"), so go the long way around.
21575-
ff = file(f, encoding = "")
21576-
tryCatch(
21577-
writeLines(c('a', rep('0x1.ffffp0', 10000L), `Encoding<-`('0x1.ff\x9fp0', 'bytes'), rep('0x1.ffffp0', 20000L)), ff),
21578-
finally = close(ff)
21579-
)
21580-
test(2334, names(fread(f)), "a")
21571+
f = tempfile()
21572+
on.exit(unlink(f))
21573+
# the line is likely invalid in current encoding, so disable any translation, #7209
21574+
# test.data.table() sets options(encoding="UTF-8"), so go the long way around.
21575+
ff = file(f, encoding = "")
21576+
tryCatch(
21577+
writeLines(c('a', rep('0x1.ffffp0', 10000L), `Encoding<-`('0x1.ff\x9fp0', 'bytes'), rep('0x1.ffffp0', 20000L)), ff),
21578+
finally = close(ff)
21579+
)
21580+
test(2334, names(fread(f)), "a")
2158121581
})
2158221582

2158321583
# Tests for new isoyear() helper (complement to isoweek) #7154
@@ -21624,3 +21624,34 @@ local({
2162421624
test(2338.9, {fwrite(dd, f, forceDecimal=FALSE); fread(f)}, di)
2162521625
})
2162621626

21627+
# '..1' is ...elt(1), not a variable named '1', when doing "up-a-level" search (#5460)
21628+
DT = data.table(a=1.0)
21629+
sqrt_dot_sym = function(...) sqrt(..1)
21630+
test(2339.01, lapply(DT, function(...) sqrt(..1)), list(a=1.0))
21631+
test(2339.02, lapply(DT, sqrt_dot_sym), list(a=1.0))
21632+
test(2339.03, DT[, lapply(.SD, function(...) sqrt(..1))], data.table(a=1.0))
21633+
test(2339.04, DT[, lapply(.SD, sqrt_dot_sym)], data.table(a=1.0))
21634+
sqrt_elt_sym = function(...) sqrt(...elt(1))
21635+
# TODO(R>=3.5.0): run this unconditionally
21636+
if (!inherits(tryCatch(sqrt_elt_sym(1), error=identity), "error")) {
21637+
test(2339.05, lapply(DT, sqrt_elt_sym), list(a=1.0))
21638+
test(2339.06, lapply(DT, function(...) sqrt(...elt(1L))), list(a=1.0))
21639+
test(2339.07, DT[, lapply(.SD, sqrt_elt_sym)], data.table(a=1.0))
21640+
test(2339.08, DT[, lapply(.SD, function(...) sqrt(...elt(1L)))], data.table(a=1.0))
21641+
}
21642+
# edge case of weird, though technically valid, names:
21643+
# _not_ '..N' style and distinct from '...'
21644+
# `123`='a'; DT[, ..123] doesn't work, but that's fine & easy to work around
21645+
DT = data.table(a = 4L)
21646+
local({
21647+
`.123` = 'a'
21648+
test(2339.09, DT[, ...123], DT)
21649+
})
21650+
local({
21651+
..123 = 'a'
21652+
test(2339.10, DT[, ....123], DT)
21653+
})
21654+
local({
21655+
...123 = 'a'
21656+
test(2339.11, DT[, .....123], DT)
21657+
})

0 commit comments

Comments
 (0)