changeset 25054:64bef59f11ef v8.2.3064

patch 8.2.3064: Vim9: in script cannot set item in uninitialized list Commit: https://github.com/vim/vim/commit/e65081d1b591f16dc6e380a830d87565c5eb7b03 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jun 27 15:04:05 2021 +0200 patch 8.2.3064: Vim9: in script cannot set item in uninitialized list Problem: Vim9: in script cannot set item in uninitialized list. Solution: When a list is NULL allocate an empty one. (closes https://github.com/vim/vim/issues/8461)
author Bram Moolenaar <Bram@vim.org>
date Sun, 27 Jun 2021 15:15:03 +0200
parents ce8252036ab0
children 960fe9bef317
files src/eval.c src/testdir/test_vim9_assign.vim src/version.c
diffstat 3 files changed, 49 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -932,15 +932,22 @@ get_lval(
 		semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
 	    return NULL;
 	}
-	if (!(lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list != NULL)
-		&& !(lp->ll_tv->v_type == VAR_DICT)
-		&& !(lp->ll_tv->v_type == VAR_BLOB
-					   && lp->ll_tv->vval.v_blob != NULL))
+	if (lp->ll_tv->v_type != VAR_LIST
+		&& lp->ll_tv->v_type != VAR_DICT
+		&& lp->ll_tv->v_type != VAR_BLOB)
 	{
 	    if (!quiet)
 		emsg(_("E689: Can only index a List, Dictionary or Blob"));
 	    return NULL;
 	}
+
+	// a NULL list/blob works like an empty list/blob, allocate one now.
+	if (lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
+	    rettv_list_alloc(lp->ll_tv);
+	else if (lp->ll_tv->v_type == VAR_BLOB
+					     && lp->ll_tv->vval.v_blob == NULL)
+	    rettv_blob_alloc(lp->ll_tv);
+
 	if (lp->ll_range)
 	{
 	    if (!quiet)
@@ -1201,10 +1208,20 @@ get_lval(
 	    lp->ll_li = list_find_index(lp->ll_list, &lp->ll_n1);
 	    if (lp->ll_li == NULL)
 	    {
-		clear_tv(&var2);
-		if (!quiet)
-		    semsg(_(e_listidx), lp->ll_n1);
-		return NULL;
+		// Vim9: Allow for adding an item at the end.
+		if (in_vim9script() && lp->ll_n1 == lp->ll_list->lv_len
+						  && lp->ll_list->lv_lock == 0)
+		{
+		    list_append_number(lp->ll_list, 0);
+		    lp->ll_li = list_find_index(lp->ll_list, &lp->ll_n1);
+		}
+		if (lp->ll_li == NULL)
+		{
+		    clear_tv(&var2);
+		    if (!quiet)
+			semsg(_(e_listidx), lp->ll_n1);
+		    return NULL;
+		}
 	    }
 
 	    if (lp->ll_valtype != NULL)
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -1102,21 +1102,30 @@ def Test_assignment_failure()
 enddef
 
 def Test_assign_list()
-  var l: list<string> = []
-  l[0] = 'value'
-  assert_equal('value', l[0])
+  var lines =<< trim END
+      var l: list<string> = []
+      l[0] = 'value'
+      assert_equal('value', l[0])
+
+      l[1] = 'asdf'
+      assert_equal('value', l[0])
+      assert_equal('asdf', l[1])
+      assert_equal('asdf', l[-1])
+      assert_equal('value', l[-2])
 
-  l[1] = 'asdf'
-  assert_equal('value', l[0])
-  assert_equal('asdf', l[1])
-  assert_equal('asdf', l[-1])
-  assert_equal('value', l[-2])
+      var nrl: list<number> = []
+      for i in range(5)
+        nrl[i] = i
+      endfor
+      assert_equal([0, 1, 2, 3, 4], nrl)
 
-  var nrl: list<number> = []
-  for i in range(5)
-    nrl[i] = i
-  endfor
-  assert_equal([0, 1, 2, 3, 4], nrl)
+      var ul: list<any>
+      ul[0] = 1
+      ul[1] = 2
+      ul[2] = 3
+      assert_equal([1, 2, 3], ul)
+  END
+  CheckDefAndScriptSuccess(lines)
 
   CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1)
   CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1)
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3064,
+/**/
     3063,
 /**/
     3062,