patch 8.2.1479: Vim9: error for list index uses wrong line number

Problem:    Vim9: error for list index uses wrong line number.
Solution:   Set source line number. (closes #6724)  Add a way to assert the
            line number of the error with assert_fails().
diff --git a/src/evalfunc.c b/src/evalfunc.c
index ff81462..c759afc 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -494,7 +494,7 @@
     {"assert_equal",	2, 3, FEARG_2,	  ret_number,	f_assert_equal},
     {"assert_equalfile", 2, 3, FEARG_1,	  ret_number,	f_assert_equalfile},
     {"assert_exception", 1, 2, 0,	  ret_number,	f_assert_exception},
-    {"assert_fails",	1, 3, FEARG_1,	  ret_number,	f_assert_fails},
+    {"assert_fails",	1, 4, FEARG_1,	  ret_number,	f_assert_fails},
     {"assert_false",	1, 2, FEARG_1,	  ret_number,	f_assert_false},
     {"assert_inrange",	3, 4, FEARG_3,	  ret_number,	f_assert_inrange},
     {"assert_match",	2, 3, FEARG_2,	  ret_number,	f_assert_match},
diff --git a/src/globals.h b/src/globals.h
index d7d1c08..e883c56 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -223,6 +223,7 @@
 // used by assert_fails()
 EXTERN int	emsg_assert_fails_used INIT(= FALSE);
 EXTERN char_u	*emsg_assert_fails_msg INIT(= NULL);
+EXTERN long	emsg_assert_fails_lnum INIT(= 0);
 
 EXTERN int	did_endif INIT(= FALSE);    // just had ":endif"
 #endif
diff --git a/src/message.c b/src/message.c
index 91b2fe2..38e6959 100644
--- a/src/message.c
+++ b/src/message.c
@@ -655,7 +655,10 @@
 	}
 
 	if (emsg_assert_fails_used && emsg_assert_fails_msg == NULL)
+	{
 	    emsg_assert_fails_msg = vim_strsave(s);
+	    emsg_assert_fails_lnum = SOURCING_LNUM;
+	}
 
 	// set "v:errmsg", also when using ":silent! cmd"
 	set_vim_var_string(VV_ERRMSG, s, -1);
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index ee68537..0e6702d 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -1464,16 +1464,18 @@
 		4]
 
   call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
-  call CheckDefExecFailure(["let x = g:anint[3]"], 'E1062:')
+  call CheckDefExecFailure(["let x = g:anint[3]"], 'E1062:', 1)
 
   call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
 
   call CheckDefFailure(["let x = [1,2,3]"], 'E1069:')
   call CheckDefFailure(["let x = [1 ,2, 3]"], 'E1068:')
 
-  call CheckDefExecFailure(["let x = g:list_mixed['xx']"], 'E1029:')
+  call CheckDefExecFailure(["echo 1", "let x = [][0]", "echo 3"], 'E684:', 2)
+
+  call CheckDefExecFailure(["let x = g:list_mixed['xx']"], 'E1029:', 1)
   call CheckDefFailure(["let x = g:list_mixed["], 'E1097:')
-  call CheckDefFailure(["let x = g:list_mixed[0"], 'E1097:')
+  call CheckDefFailure(["let x = g:list_mixed[0"], 'E1097:', 1)
   call CheckDefExecFailure(["let x = g:list_empty[3]"], 'E684:')
   call CheckDefFailure(["let l: list<number> = [234, 'x']"], 'E1012:')
   call CheckDefFailure(["let l: list<number> = ['x', 234]"], 'E1012:')
diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim
index 448aa3d..c890b0c 100644
--- a/src/testdir/vim9.vim
+++ b/src/testdir/vim9.vim
@@ -9,17 +9,19 @@
 endfunc
 
 " Check that "lines" inside ":def" results in an "error" message.
-func CheckDefFailure(lines, error)
+" If "lnum" is given check that the error is reported for this line.
+func CheckDefFailure(lines, error, lnum = -1)
   call writefile(['def Func()'] + a:lines + ['enddef', 'defcompile'], 'Xdef')
-  call assert_fails('so Xdef', a:error, a:lines)
+  call assert_fails('so Xdef', a:error, a:lines, a:lnum)
   call delete('Xdef')
 endfunc
 
 " Check that "lines" inside ":def" results in an "error" message when executed.
-func CheckDefExecFailure(lines, error)
+" If "lnum" is given check that the error is reported for this line.
+func CheckDefExecFailure(lines, error, lnum = -1)
   call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
   so Xdef
-  call assert_fails('call Func()', a:error, a:lines)
+  call assert_fails('call Func()', a:error, a:lines, a:lnum)
   call delete('Xdef')
 endfunc
 
diff --git a/src/testing.c b/src/testing.c
index 137d5fe..0971876 100644
--- a/src/testing.c
+++ b/src/testing.c
@@ -142,7 +142,10 @@
     int		did_copy = FALSE;
     int		omitted = 0;
 
-    if (opt_msg_tv->v_type != VAR_UNKNOWN)
+    if (opt_msg_tv->v_type != VAR_UNKNOWN
+	    && !(opt_msg_tv->v_type == VAR_STRING
+		&& (opt_msg_tv->vval.v_string == NULL
+		    || *opt_msg_tv->vval.v_string == NUL)))
     {
 	ga_concat(gap, echo_string(opt_msg_tv, &tofree, numbuf, 0));
 	vim_free(tofree);
@@ -570,6 +573,7 @@
 	char_u	buf[NUMBUFLEN];
 	char_u	*expected;
 	int	error_found = FALSE;
+	int	lnum_error_found = FALSE;
 	char_u	*actual = emsg_assert_fails_msg == NULL ? (char_u *)"[unknown]"
 						       : emsg_assert_fails_msg;
 
@@ -611,14 +615,31 @@
 	    goto theend;
 	}
 
+	if (!error_found && argvars[3].v_type == VAR_NUMBER
+		&& argvars[3].vval.v_number >= 0
+		&& argvars[3].vval.v_number != emsg_assert_fails_lnum)
+	{
+	    error_found = TRUE;
+	    lnum_error_found = TRUE;
+	}
+
 	if (error_found)
 	{
 	    typval_T actual_tv;
 
 	    prepare_assert_error(&ga);
-	    actual_tv.v_type = VAR_STRING;
-	    actual_tv.vval.v_string = actual;
-	    fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
+	    if (lnum_error_found)
+	    {
+		actual_tv.v_type = VAR_NUMBER;
+		actual_tv.vval.v_number = emsg_assert_fails_lnum;
+	    }
+	    else
+	    {
+		actual_tv.v_type = VAR_STRING;
+		actual_tv.vval.v_string = actual;
+	    }
+	    fill_assert_error(&ga, &argvars[2], NULL,
+		    &argvars[lnum_error_found ? 3 : 1],
 						     &actual_tv, ASSERT_OTHER);
 	    ga_concat(&ga, (char_u *)": ");
 	    assert_append_cmd_or_arg(&ga, argvars, cmd);
diff --git a/src/version.c b/src/version.c
index b17bcd2..e8eb852 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1479,
+/**/
     1478,
 /**/
     1477,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 059e768..fe78e8f 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2299,6 +2299,7 @@
 
 		    ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
 		    tv = STACK_TV_BOT(-1);
+		    SOURCING_LNUM = iptr->isn_lnum;
 		    if (list_slice_or_index(list, is_slice, n1, n2, tv, TRUE)
 								       == FAIL)
 			goto on_error;