vim-patch:8.2.1890: Vim9: strange error for subtracting from a list

Problem:    Vim9: strange error for subtracting from a list.
Solution:   Check getting a number, not a string. (closes vim/vim#7167)

081db1a66d

Cherry-pick eval_addblob() and eval_addlist() from patch 8.2.0149.

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-02-28 15:05:40 +08:00
parent befb47f2e1
commit 99faac8644

View File

@ -2556,6 +2556,39 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
return OK;
}
/// Make a copy of blob "tv1" and append blob "tv2".
static void eval_addblob(typval_T *tv1, typval_T *tv2)
{
const blob_T *const b1 = tv1->vval.v_blob;
const blob_T *const b2 = tv2->vval.v_blob;
blob_T *const b = tv_blob_alloc();
for (int i = 0; i < tv_blob_len(b1); i++) {
ga_append(&b->bv_ga, tv_blob_get(b1, i));
}
for (int i = 0; i < tv_blob_len(b2); i++) {
ga_append(&b->bv_ga, tv_blob_get(b2, i));
}
tv_clear(tv1);
tv_blob_set_ret(tv1, b);
}
/// Make a copy of list "tv1" and append list "tv2".
static int eval_addlist(typval_T *tv1, typval_T *tv2)
{
typval_T var3;
// Concatenate Lists.
if (tv_list_concat(tv1->vval.v_list, tv2->vval.v_list, &var3) == FAIL) {
tv_clear(tv1);
tv_clear(tv2);
return FAIL;
}
tv_clear(tv1);
*tv1 = var3;
return OK;
}
/// Handle fourth level expression:
/// + number addition, concatenation of list or blob
/// - number subtraction
@ -2569,7 +2602,6 @@ static int eval4(char **arg, typval_T *rettv, int evaluate)
static int eval5(char **arg, typval_T *rettv, int evaluate)
{
typval_T var2;
typval_T var3;
varnumber_T n1, n2;
float_T f1 = 0, f2 = 0;
char *p;
@ -2587,7 +2619,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
}
if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB))
&& (op == '.' || rettv->v_type != VAR_FLOAT)) {
&& (op == '.' || rettv->v_type != VAR_FLOAT) && evaluate) {
// For "list + ...", an illegal use of the first operand as
// a number cannot be determined before evaluating the 2nd
// operand: if this is also a list, all is ok.
@ -2595,7 +2627,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
// we know that the first operand needs to be a string or number
// without evaluating the 2nd operand. So check before to avoid
// side effects after an error.
if (evaluate && !tv_check_str(rettv)) {
if ((op == '.' && !tv_check_str(rettv)) || (op != '.' && !tv_check_num(rettv))) {
tv_clear(rettv);
return FAIL;
}
@ -2628,32 +2660,12 @@ static int eval5(char **arg, typval_T *rettv, int evaluate)
tv_clear(rettv);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = p;
} else if (op == '+' && rettv->v_type == VAR_BLOB
&& var2.v_type == VAR_BLOB) {
const blob_T *const b1 = rettv->vval.v_blob;
const blob_T *const b2 = var2.vval.v_blob;
blob_T *const b = tv_blob_alloc();
for (int i = 0; i < tv_blob_len(b1); i++) {
ga_append(&b->bv_ga, tv_blob_get(b1, i));
}
for (int i = 0; i < tv_blob_len(b2); i++) {
ga_append(&b->bv_ga, tv_blob_get(b2, i));
}
tv_clear(rettv);
tv_blob_set_ret(rettv, b);
} else if (op == '+' && rettv->v_type == VAR_LIST
&& var2.v_type == VAR_LIST) {
// Concatenate Lists.
if (tv_list_concat(rettv->vval.v_list, var2.vval.v_list, &var3)
== FAIL) {
tv_clear(rettv);
tv_clear(&var2);
} else if (op == '+' && rettv->v_type == VAR_BLOB && var2.v_type == VAR_BLOB) {
eval_addblob(rettv, &var2);
} else if (op == '+' && rettv->v_type == VAR_LIST && var2.v_type == VAR_LIST) {
if (eval_addlist(rettv, &var2) == FAIL) {
return FAIL;
}
tv_clear(rettv);
*rettv = var3;
} else {
bool error = false;