changeset 25547:ec4df0b982da v8.2.3310

patch 8.2.3310: Vim9: unpack assignment does not mention source of type error Commit: https://github.com/vim/vim/commit/4270d8b7626ff8a7006f6a09c89bc446a3f89d1e Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 7 16:30:42 2021 +0200 patch 8.2.3310: Vim9: unpack assignment does not mention source of type error Problem: Vim9: unpack assignment does not mention source of type error. Solution: Mention the argument number. (closes https://github.com/vim/vim/issues/8719)
author Bram Moolenaar <Bram@vim.org>
date Sat, 07 Aug 2021 16:45:03 +0200
parents 465989ba8936
children 99ea34936e33
files src/testdir/test_vim9_assign.vim src/testdir/test_vim9_disassemble.vim src/version.c src/vim9compile.c
diffstat 4 files changed, 63 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -414,6 +414,22 @@ def Test_assign_unpack()
     [x, y] = g:values
   END
   CheckDefExecAndScriptFailure(lines, 'E1163: Variable 2: type mismatch, expected string but got number')
+
+  lines =<< trim END
+    var x: number
+    var y: number
+    var z: string
+    [x, y, z] = [1, 2, 3]
+  END
+  CheckDefAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number')
+
+  lines =<< trim END
+    var x: number
+    var y: string
+    var z: string
+    [x, y, z] = [1, '2', 3]
+  END
+  CheckDefExecAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number')
 enddef
 
 def Test_assign_linebreak()
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -441,10 +441,10 @@ def Test_disassemble_list_assign()
         '\d CHECKTYPE list<any> stack\[-1\]\_s*' ..
         '\d CHECKLEN >= 2\_s*' ..
         '\d\+ ITEM 0\_s*' ..
-        '\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
+        '\d\+ CHECKTYPE string stack\[-1\] arg 1\_s*' ..
         '\d\+ STORE $0\_s*' ..
         '\d\+ ITEM 1\_s*' ..
-        '\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
+        '\d\+ CHECKTYPE string stack\[-1\] arg 2\_s*' ..
         '\d\+ STORE $1\_s*' ..
         '\d\+ SLICE 2\_s*' ..
         '\d\+ STORE $2\_s*' ..
--- 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 */
 /**/
+    3310,
+/**/
     3309,
 /**/
     3308,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1039,6 +1039,42 @@ use_typecheck(type_T *actual, type_T *ex
  * If "actual_is_const" is TRUE then the type won't change at runtime, do not
  * generate a TYPECHECK.
  */
+    static int
+need_type_where(
+	type_T	*actual,
+	type_T	*expected,
+	int	offset,
+	where_T	where,
+	cctx_T	*cctx,
+	int	silent,
+	int	actual_is_const)
+{
+    if (expected == &t_bool && actual != &t_bool
+					&& (actual->tt_flags & TTFLAG_BOOL_OK))
+    {
+	// Using "0", "1" or the result of an expression with "&&" or "||" as a
+	// boolean is OK but requires a conversion.
+	generate_2BOOL(cctx, FALSE, offset);
+	return OK;
+    }
+
+    if (check_type(expected, actual, FALSE, where) == OK)
+	return OK;
+
+    // If the actual type can be the expected type add a runtime check.
+    // If it's a constant a runtime check makes no sense.
+    if ((!actual_is_const || actual == &t_any)
+					    && use_typecheck(actual, expected))
+    {
+	generate_TYPECHECK(cctx, expected, offset, where.wt_index);
+	return OK;
+    }
+
+    if (!silent)
+	type_mismatch_where(expected, actual, where);
+    return FAIL;
+}
+
     int
 need_type(
 	type_T	*actual,
@@ -1051,31 +1087,9 @@ need_type(
 {
     where_T where = WHERE_INIT;
 
-    if (expected == &t_bool && actual != &t_bool
-					&& (actual->tt_flags & TTFLAG_BOOL_OK))
-    {
-	// Using "0", "1" or the result of an expression with "&&" or "||" as a
-	// boolean is OK but requires a conversion.
-	generate_2BOOL(cctx, FALSE, offset);
-	return OK;
-    }
-
     where.wt_index = arg_idx;
-    if (check_type(expected, actual, FALSE, where) == OK)
-	return OK;
-
-    // If the actual type can be the expected type add a runtime check.
-    // If it's a constant a runtime check makes no sense.
-    if ((!actual_is_const || actual == &t_any)
-					    && use_typecheck(actual, expected))
-    {
-	generate_TYPECHECK(cctx, expected, offset, arg_idx);
-	return OK;
-    }
-
-    if (!silent)
-	arg_type_mismatch(expected, actual, arg_idx);
-    return FAIL;
+    return need_type_where(actual, expected, offset, where,
+						cctx, silent, actual_is_const);
 }
 
 /*
@@ -7004,14 +7018,17 @@ compile_assignment(char_u *arg, exarg_T 
 		    else if (*op == '=')
 		    {
 			type_T *use_type = lhs.lhs_lvar->lv_type;
+			where_T where = WHERE_INIT;
 
 			// Without operator check type here, otherwise below.
 			// Use the line number of the assignment.
 			SOURCING_LNUM = start_lnum;
+			where.wt_index = var_count > 0 ? var_idx + 1 : 0;
+			where.wt_variable = var_count > 0;
 			if (lhs.lhs_has_index)
 			    use_type = lhs.lhs_member_type;
-			if (need_type(rhs_type, use_type, -1, 0, cctx,
-						      FALSE, is_const) == FAIL)
+			if (need_type_where(rhs_type, use_type, -1, where,
+				    cctx, FALSE, is_const) == FAIL)
 			    goto theend;
 		    }
 		}