]> granicus.if.org Git - vim/commitdiff
patch 8.2.4662: no error for using out of range list index v8.2.4662
authorBram Moolenaar <Bram@vim.org>
Fri, 1 Apr 2022 14:26:58 +0000 (15:26 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 1 Apr 2022 14:26:58 +0000 (15:26 +0100)
Problem:    No error for using out of range list index.
Solution:   Check list index at script level like in compiled function.
            (closes #10051)

src/eval.c
src/evalvars.c
src/list.c
src/proto/list.pro
src/testdir/test_vim9_assign.vim
src/version.c
src/vim.h
src/vim9execute.c

index 0d24f768885571a11dd1b63ca51034a90efa8696..2cde6421618362f859a20417d5ff40a715779f23 100644 (file)
@@ -1311,7 +1311,8 @@ get_lval(
 
            lp->ll_dict = NULL;
            lp->ll_list = lp->ll_tv->vval.v_list;
-           lp->ll_li = check_range_index_one(lp->ll_list, &lp->ll_n1, quiet);
+           lp->ll_li = check_range_index_one(lp->ll_list, &lp->ll_n1,
+                                    (flags & GLV_ASSIGN_WITH_OP) == 0, quiet);
            if (lp->ll_li == NULL)
            {
                clear_tv(&var2);
index 202ada1914f84477e700056d4cf11ed3bebae0d9..dd70427d32f31407de265f49d95a1dfa03983cc7 100644 (file)
@@ -1647,13 +1647,15 @@ ex_let_one(
     {
        lval_T  lv;
        char_u  *p;
+       int     lval_flags = (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
+                                                            ? GLV_NO_DECL : 0;
+       if (op != NULL && *op != '=')
+           lval_flags |= GLV_ASSIGN_WITH_OP;
 
        // ":let var = expr": Set internal variable.
        // ":let var: type = expr": Set internal variable with type.
        // ":let {expr} = expr": Idem, name made with curly braces
-       p = get_lval(arg, tv, &lv, FALSE, FALSE,
-               (flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
-                                          ? GLV_NO_DECL : 0, FNE_CHECK_START);
+       p = get_lval(arg, tv, &lv, FALSE, FALSE, lval_flags, FNE_CHECK_START);
        if (p != NULL && lv.ll_name != NULL)
        {
            if (endchars != NULL && vim_strchr(endchars,
index 666fb5ad61011e378d709afa51cb294316b00935..50bf3afc0f524bdfeb6a087b3760fca12959447a 100644 (file)
@@ -760,18 +760,20 @@ list_insert(list_T *l, listitem_T *ni, listitem_T *item)
 
 /*
  * Get the list item in "l" with index "n1".  "n1" is adjusted if needed.
- * In Vim9, it is at the end of the list, add an item.
+ * In Vim9, it is at the end of the list, add an item if "can_append" is TRUE.
  * Return NULL if there is no such item.
  */
     listitem_T *
-check_range_index_one(list_T *l, long *n1, int quiet)
+check_range_index_one(list_T *l, long *n1, int can_append, int quiet)
 {
-    listitem_T *li = list_find_index(l, n1);
+    long       orig_n1 = *n1;
+    listitem_T *li = list_find_index(l, n1);
 
     if (li == NULL)
     {
        // Vim9: Allow for adding an item at the end.
-       if (in_vim9script() && *n1 == l->lv_len && l->lv_lock == 0)
+       if (can_append && in_vim9script()
+                                       && *n1 == l->lv_len && l->lv_lock == 0)
        {
            list_append_number(l, 0);
            li = list_find_index(l, n1);
@@ -779,7 +781,7 @@ check_range_index_one(list_T *l, long *n1, int quiet)
        if (li == NULL)
        {
            if (!quiet)
-               semsg(_(e_list_index_out_of_range_nr), *n1);
+               semsg(_(e_list_index_out_of_range_nr), orig_n1);
            return NULL;
        }
     }
index 468775e59ad92861a8c441353484b6727288ba88..3f77f04d15d3832b54ddf8aed5b0ba033052da7a 100644 (file)
@@ -30,7 +30,7 @@ int list_append_string(list_T *l, char_u *str, int len);
 int list_append_number(list_T *l, varnumber_T n);
 int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
 void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
-listitem_T *check_range_index_one(list_T *l, long *n1, int quiet);
+listitem_T *check_range_index_one(list_T *l, long *n1, int can_append, int quiet);
 int check_range_index_two(list_T *l, long *n1, listitem_T *li1, long *n2, int quiet);
 int list_assign_range(list_T *dest, list_T *src, long idx1_arg, long idx2, int empty_idx2, char_u *op, char_u *varname);
 void f_flatten(typval_T *argvars, typval_T *rettv);
index 0a25ca4a7ee23b7202921f56e253fe1319033a91..57d205ceef3bddf1b9896b1b54c28c14c0a81e02 100644 (file)
@@ -288,6 +288,12 @@ def Test_assign_concat()
     s ..= {a: 2}
   END
   v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2)
+
+  lines =<< trim END
+      var ls: list<string> = []
+      ls[-1] ..= 'foo'
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E684: list index out of range: -1', 2)
 enddef
 
 def Test_assign_register()
index 95a0f0e0cfe1da2acf254bfb188c3329fc87ca66..d3be7a85362e7a6b26ebcfe5116ba99d28f93429 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4662,
 /**/
     4661,
 /**/
index bff49be34ca908e3aa9f428836185edae98fa72b..23771fbcf05a034eee0af437d492f9b5bdd1ab1c 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2632,6 +2632,7 @@ typedef enum {
 #define TFN_NO_DECL    0x20    // only used for GLV_NO_DECL
 #define TFN_COMPILING  0x40    // only used for GLV_COMPILING
 #define TFN_NEW_FUNC   0x80    // defining a new function
+#define TFN_ASSIGN_WITH_OP     0x100   // only for GLV_ASSIGN_WITH_OP
 
 // Values for get_lval() flags argument:
 #define GLV_QUIET      TFN_QUIET       // no error messages
@@ -2639,6 +2640,7 @@ typedef enum {
 #define GLV_READ_ONLY  TFN_READ_ONLY   // will not change the var
 #define GLV_NO_DECL    TFN_NO_DECL     // assignment without :var or :let
 #define GLV_COMPILING  TFN_COMPILING   // variable may be defined later
+#define GLV_ASSIGN_WITH_OP TFN_ASSIGN_WITH_OP // assignment with operator
 
 #define DO_NOT_FREE_CNT 99999  // refcount for dict or list that should not
                                // be freed.
index a1710407a83d66c2b979c01396ea3774e5d95757..a6789b5999d052b62f61463850709c9f4ba85d94 100644 (file)
@@ -1988,7 +1988,7 @@ execute_storerange(isn_T *iptr, ectx_T *ectx)
        else
            n2 = (long)tv_get_number_chk(tv_idx2, NULL);
 
-       li1 = check_range_index_one(tv_dest->vval.v_list, &n1, FALSE);
+       li1 = check_range_index_one(tv_dest->vval.v_list, &n1, TRUE, FALSE);
        if (li1 == NULL)
            status = FAIL;
        else