Skip to content

Commit 619ca73

Browse files
improve error message for nested assignment (#6484)
* improve error message for nested assignment * new test case (will fail) * working now * improve error message for nested assignment * need jj-1 (call itself is 1->offset) * fix test to be applicable here * Catch partially-named nested usage too * consistent local naming * move NEWS * Use a helper to reduce repetition
1 parent 6a2bf2e commit 619ca73

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ rowwiseDT(
7979

8080
6. `set()` and `:=` now provide some extra guidance for common incorrect approaches to assigning `NULL` to some rows of a list column. The correct way is to put `list(list(NULL))` on the RHS of `:=` (or `.(.(NULL))` for short). Thanks to @MichaelChirico for the suggestion and @Nj221102 for the implementation.
8181

82+
7. Improved the error message when trying to write code like `DT[, ":="(a := b, c := d)]` (which should be `DT[, ":="(a = b, c = d)]`), [#5296](https://github.com/Rdatatable/data.table/issues/5296). Thanks @MichaelChirico for the suggestion & fix.
83+
8284
# data.table [v1.16.0](https://github.com/Rdatatable/data.table/milestone/30) (25 August 2024)
8385

8486
## BREAKING CHANGES

R/data.table.R

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,10 @@ replace_dot_alias = function(e) {
11111111
if (is.null(names(jsub))) {
11121112
# regular LHS:=RHS usage, or `:=`(...) with no named arguments (an error)
11131113
# `:=`(LHS,RHS) is valid though, but more because can't see how to detect that, than desire
1114-
if (length(jsub)!=3L) stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named.", if (root == "let") "let" else "`:=`")
1114+
this_call = if (root == "let") "let" else "`:=`"
1115+
.check_nested_walrus(jsub, 2:length(jsub), this_call)
1116+
if (length(jsub) != 3L)
1117+
stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named.", this_call)
11151118
lhs = jsub[[2L]]
11161119
jsub = jsub[[3L]]
11171120
if (is.name(lhs)) {
@@ -1131,11 +1134,12 @@ replace_dot_alias = function(e) {
11311134
if (!all(named_idx <- nzchar(lhs))) {
11321135
# friendly error for common case: trailing terminal comma
11331136
n_lhs = length(lhs)
1134-
root_name <- if (root == "let") "let" else "`:=`"
1137+
this_call <- if (root == "let") "let" else "`:=`"
1138+
.check_nested_walrus(jsub, which(!named_idx)+1L, this_call)
11351139
if (!named_idx[n_lhs] && all(named_idx[-n_lhs])) {
1136-
stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named, but the last argument has no name. Did you forget a trailing comma?", root_name)
1140+
stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named, but the last argument has no name. Did you forget a trailing comma?", this_call)
11371141
} else {
1138-
stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named, but these arguments lack names: %s.", root_name, brackify(which(!named_idx)))
1142+
stopf("In %s(col1=val1, col2=val2, ...) form, all arguments must be named, but these arguments lack names: %s.", this_call, brackify(which(!named_idx)))
11391143
}
11401144
}
11411145
names(jsub)=""
@@ -3144,6 +3148,11 @@ is_constantish = function(q, check_singleton=FALSE) {
31443148
q
31453149
}
31463150

3151+
.check_nested_walrus = function(e, check_entries, call_name) {
3152+
for (jj in check_entries) if (e[[jj]] %iscall% ":=")
3153+
stopf("It looks like you re-used `:=` in argument %d a functional assignment call -- use `=` instead: %s(col1=val1, col2=val2, ...)", jj-1L, call_name)
3154+
}
3155+
31473156
.prepareFastSubset = function(isub, x, enclos, notjoin, verbose = FALSE){
31483157
## helper that decides, whether a fast binary search can be performed, if i is a call
31493158
## For details on the supported queries, see \code{\link{datatable-optimize}}

inst/tests/tests.Rraw

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19227,3 +19227,13 @@ if (test_bit64) {
1922719227
dt = data.table(a=1:2, b=expression(1,2))
1922819228
test(2289.1, dt[1,], data.table(a=1L, b=expression(1)))
1922919229
test(2289.2, dt[,b,a], dt)
19230+
19231+
# error message improvement, #5296
19232+
DT = data.table(a = 1)
19233+
test(2290.1, DT[, `:=`(a := 2)], error="It looks like you re-used `:=`")
19234+
# special case where length(jsub) == 3 that would have failed later
19235+
test(2290.2, DT[, `:=`(a := 2, c := 3)], error="It looks like you re-used `:=` in argument 1")
19236+
# NB: _not_ a = 2, because that means partially-named --> not currently covered
19237+
test(2290.3, DT[, `:=`(a, c := 3)], error="It looks like you re-used `:=` in argument 2")
19238+
# partially-named `:=`(...) --> different branch, same error
19239+
test(2290.4, DT[, `:=`(a = 2, c := 3)], error="It looks like you re-used `:=` in argument 2")

0 commit comments

Comments
 (0)