From: Bram Moolenaar Date: Mon, 5 Apr 2021 18:51:00 +0000 (+0200) Subject: patch 8.2.2722: Vim9: crash when using LHS with double index X-Git-Tag: v8.2.2722 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b9c0cd897ab4ad54f514187e89719c0241393f8b;p=vim patch 8.2.2722: Vim9: crash when using LHS with double index Problem: Vim9: crash when using LHS with double index. Solution: Handle lhs_dest which is "dest_expr". (closes #8068) Fix confusing error message for missing dict item. --- diff --git a/src/eval.c b/src/eval.c index d49264997..05b658442 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1474,7 +1474,7 @@ set_var_lval( { if (op != NULL && *op != '=') { - semsg(_(e_letwrong), op); + semsg(_(e_dictkey), lp->ll_newkey); return; } diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 4e37efb28..4e78b5d5b 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1146,6 +1146,12 @@ def Test_assign_dict_with_op() assert_equal(2, dn.a) dn.a %= 6 assert_equal(2, dn.a) + + var dd: dict>> + dd.a = {} + dd.a.b = [0] + dd.a.b += [1] + assert_equal({a: {b: [0, 1]}}, dd) END CheckDefAndScriptSuccess(lines) enddef @@ -1187,6 +1193,13 @@ def Test_assign_with_op_fails() s[1] ..= 'x' END CheckDefAndScriptFailure2(lines, 'E1141:', 'E689:', 2) + + lines =<< trim END + var dd: dict>> + dd.a = {} + dd.a.b += [1] + END + CheckDefExecAndScriptFailure(lines, 'E716:', 3) enddef def Test_assign_lambda() diff --git a/src/version.c b/src/version.c index 331ccdbad..807ef10b8 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2722, /**/ 2721, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 678a98528..6ff00f7d4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6093,6 +6093,48 @@ compile_assign_index( return r; } +/* + * For a LHS with an index, load the variable to be indexed. + */ + static int +compile_load_lhs( + lhs_T *lhs, + char_u *var_start, + type_T *rhs_type, + cctx_T *cctx) +{ + if (lhs->lhs_dest == dest_expr) + { + size_t varlen = lhs->lhs_varlen; + int c = var_start[varlen]; + char_u *p = var_start; + garray_T *stack = &cctx->ctx_type_stack; + + // Evaluate "ll[expr]" of "ll[expr][idx]" + var_start[varlen] = NUL; + if (compile_expr0(&p, cctx) == OK && p != var_start + varlen) + { + // this should not happen + emsg(_(e_missbrac)); + return FAIL; + } + var_start[varlen] = c; + + lhs->lhs_type = stack->ga_len == 0 ? &t_void + : ((type_T **)stack->ga_data)[stack->ga_len - 1]; + // now we can properly check the type + if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL + && rhs_type != &t_void + && need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx, + FALSE, FALSE) == FAIL) + return FAIL; + } + else + generate_loadvar(cctx, lhs->lhs_dest, lhs->lhs_name, + lhs->lhs_lvar, lhs->lhs_type); + return OK; +} + /* * Assignment to a list or dict member, or ":unlet" for the item, using the * information in "lhs". @@ -6106,9 +6148,7 @@ compile_assign_unlet( type_T *rhs_type, cctx_T *cctx) { - char_u *p; vartype_T dest_type; - size_t varlen = lhs->lhs_varlen; garray_T *stack = &cctx->ctx_type_stack; int range = FALSE; @@ -6147,32 +6187,8 @@ compile_assign_unlet( // - index // - for [a : b] second index // - variable - if (lhs->lhs_dest == dest_expr) - { - int c = var_start[varlen]; - - // Evaluate "ll[expr]" of "ll[expr][idx]" - p = var_start; - var_start[varlen] = NUL; - if (compile_expr0(&p, cctx) == OK && p != var_start + varlen) - { - // this should not happen - emsg(_(e_missbrac)); - return FAIL; - } - var_start[varlen] = c; - - lhs->lhs_type = stack->ga_len == 0 ? &t_void - : ((type_T **)stack->ga_data)[stack->ga_len - 1]; - // now we can properly check the type - if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void - && need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx, - FALSE, FALSE) == FAIL) - return FAIL; - } - else - generate_loadvar(cctx, lhs->lhs_dest, lhs->lhs_name, - lhs->lhs_lvar, lhs->lhs_type); + if (compile_load_lhs(lhs, var_start, rhs_type, cctx) == FAIL) + return FAIL; if (dest_type == VAR_LIST || dest_type == VAR_DICT || dest_type == VAR_ANY) { @@ -6384,8 +6400,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) // for "+=", "*=", "..=" etc. first load the current value if (*op != '=') { - generate_loadvar(cctx, lhs.lhs_dest, lhs.lhs_name, - lhs.lhs_lvar, lhs.lhs_type); + compile_load_lhs(&lhs, var_start, NULL, cctx); if (lhs.lhs_has_index) {