changeset 23800:57f0e3fd7c05 v8.2.2441

patch 8.2.2441: Vim9: extend() does not give an error for a type mismatch Commit: https://github.com/vim/vim/commit/c03f5c677a1fba99d2379550ccf2391eaa43e2ac Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 31 17:48:30 2021 +0100 patch 8.2.2441: Vim9: extend() does not give an error for a type mismatch Problem: Vim9: extend() does not give an error for a type mismatch. Solution: Check the type of the second argument. (closes https://github.com/vim/vim/issues/7760)
author Bram Moolenaar <Bram@vim.org>
date Sun, 31 Jan 2021 18:00:04 +0100
parents 0a69ae7387d9
children e3163b68805d
files src/list.c src/testdir/test_vim9_builtin.vim src/version.c
diffstat 3 files changed, 46 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/list.c
+++ b/src/list.c
@@ -2493,6 +2493,16 @@ f_count(typval_T *argvars, typval_T *ret
     static void
 extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
 {
+    type_T	*type = NULL;
+    garray_T	type_list;
+
+    if (!is_new && in_vim9script())
+    {
+	// Check that map() does not change the type of the dict.
+	ga_init2(&type_list, sizeof(type_T *), 10);
+	type = typval2type(argvars, &type_list);
+    }
+
     if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
     {
 	list_T		*l1, *l2;
@@ -2504,7 +2514,7 @@ extend(typval_T *argvars, typval_T *rett
 	if (l1 == NULL)
 	{
 	    emsg(_(e_cannot_extend_null_list));
-	    return;
+	    goto theend;
 	}
 	l2 = argvars[1].vval.v_list;
 	if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE))
@@ -2514,14 +2524,14 @@ extend(typval_T *argvars, typval_T *rett
 	    {
 		l1 = list_copy(l1, FALSE, get_copyID());
 		if (l1 == NULL)
-		    return;
+		    goto theend;
 	    }
 
 	    if (argvars[2].v_type != VAR_UNKNOWN)
 	    {
 		before = (long)tv_get_number_chk(&argvars[2], &error);
 		if (error)
-		    return;		// type error; errmsg already given
+		    goto theend;	// type error; errmsg already given
 
 		if (before == l1->lv_len)
 		    item = NULL;
@@ -2531,12 +2541,14 @@ extend(typval_T *argvars, typval_T *rett
 		    if (item == NULL)
 		    {
 			semsg(_(e_listidx), before);
-			return;
+			goto theend;
 		    }
 		}
 	    }
 	    else
 		item = NULL;
+	    if (type != NULL && check_typval_type(type, &argvars[1], 2) == FAIL)
+		goto theend;
 	    list_extend(l1, l2, item);
 
 	    if (is_new)
@@ -2559,7 +2571,7 @@ extend(typval_T *argvars, typval_T *rett
 	if (d1 == NULL)
 	{
 	    emsg(_(e_cannot_extend_null_dict));
-	    return;
+	    goto theend;
 	}
 	d2 = argvars[1].vval.v_dict;
 	if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE))
@@ -2569,7 +2581,7 @@ extend(typval_T *argvars, typval_T *rett
 	    {
 		d1 = dict_copy(d1, FALSE, get_copyID());
 		if (d1 == NULL)
-		    return;
+		    goto theend;
 	    }
 
 	    // Check the third argument.
@@ -2579,19 +2591,21 @@ extend(typval_T *argvars, typval_T *rett
 
 		action = tv_get_string_chk(&argvars[2]);
 		if (action == NULL)
-		    return;		// type error; errmsg already given
+		    goto theend;	// type error; errmsg already given
 		for (i = 0; i < 3; ++i)
 		    if (STRCMP(action, av[i]) == 0)
 			break;
 		if (i == 3)
 		{
 		    semsg(_(e_invarg2), action);
-		    return;
+		    goto theend;
 		}
 	    }
 	    else
 		action = (char_u *)"force";
 
+	    if (type != NULL && check_typval_type(type, &argvars[1], 2) == FAIL)
+		goto theend;
 	    dict_extend(d1, d2, action);
 
 	    if (is_new)
@@ -2606,6 +2620,10 @@ extend(typval_T *argvars, typval_T *rett
     }
     else
 	semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
+
+theend:
+    if (type != NULL)
+	clear_type_list(&type_list);
 }
 
 /*
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -240,19 +240,24 @@ def Test_expand()
 enddef
 
 def Test_extend_arg_types()
-  assert_equal([1, 2, 3], extend([1, 2], [3]))
-  assert_equal([3, 1, 2], extend([1, 2], [3], 0))
-  assert_equal([1, 3, 2], extend([1, 2], [3], 1))
-  assert_equal([1, 3, 2], extend([1, 2], [3], s:number_one))
+  g:number_one = 1
+  g:string_keep = 'keep'
+  var lines =<< trim END
+      assert_equal([1, 2, 3], extend([1, 2], [3]))
+      assert_equal([3, 1, 2], extend([1, 2], [3], 0))
+      assert_equal([1, 3, 2], extend([1, 2], [3], 1))
+      assert_equal([1, 3, 2], extend([1, 2], [3], g:number_one))
 
-  assert_equal({a: 1, b: 2, c: 3}, extend({a: 1, b: 2}, {c: 3}))
-  assert_equal({a: 1, b: 4}, extend({a: 1, b: 2}, {b: 4}))
-  assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, 'keep'))
-  assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, s:string_keep))
+      assert_equal({a: 1, b: 2, c: 3}, extend({a: 1, b: 2}, {c: 3}))
+      assert_equal({a: 1, b: 4}, extend({a: 1, b: 2}, {b: 4}))
+      assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, 'keep'))
+      assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, g:string_keep))
 
-  var res: list<dict<any>>
-  extend(res, mapnew([1, 2], (_, v) => ({})))
-  assert_equal([{}, {}], res)
+      var res: list<dict<any>>
+      extend(res, mapnew([1, 2], (_, v) => ({})))
+      assert_equal([{}, {}], res)
+  END
+  CheckDefAndScriptSuccess(lines)
 
   CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, expected list<number> but got number')
   CheckDefFailure(['extend([1, 2], ["x"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
@@ -300,8 +305,7 @@ def Test_extend_dict_item_type()
        var d: dict<number> = {a: 1}
        extend(d, {b: 'x'})
   END
-  CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 2)
-  CheckScriptFailure(['vim9script'] + lines, 'E1012:', 3)
+  CheckDefAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 2)
 
   lines =<< trim END
        var d: dict<number> = {a: 1}
@@ -326,8 +330,7 @@ def Test_extend_list_item_type()
        var l: list<number> = [1]
        extend(l, ['x'])
   END
-  CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 2)
-  CheckScriptFailure(['vim9script'] + lines, 'E1012:', 3)
+  CheckDefAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 2)
 
   lines =<< trim END
        var l: list<number> = [1]
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2441,
+/**/
     2440,
 /**/
     2439,