]> granicus.if.org Git - vim/commitdiff
patch 8.2.1479: Vim9: error for list index uses wrong line number v8.2.1479
authorBram Moolenaar <Bram@vim.org>
Tue, 18 Aug 2020 11:41:50 +0000 (13:41 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 18 Aug 2020 11:41:50 +0000 (13:41 +0200)
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().

runtime/doc/testing.txt
src/evalfunc.c
src/globals.h
src/message.c
src/testdir/test_vim9_expr.vim
src/testdir/vim9.vim
src/testing.c
src/version.c
src/vim9execute.c

index 15c5498a5143c7ea82893fd65a9749eded270204..74b705c14edac2cac3a5d9b992eda2694ad457b9 100644 (file)
@@ -291,8 +291,9 @@ assert_exception({error} [, {msg}])                 *assert_exception()*
                        catch
                          call assert_exception('E492:')
                        endtry
-
-assert_fails({cmd} [, {error} [, {msg}]])                      *assert_fails()*
+<
+                                                       *assert_fails()*
+assert_fails({cmd} [, {error} [, {msg} [, {lnum}]]])
                Run {cmd} and add an error message to |v:errors| if it does
                NOT produce an error or when {error} is not found in the
                error message.  Also see |assert-return|.
@@ -311,13 +312,21 @@ assert_fails({cmd} [, {error} [, {msg}]])                 *assert_fails()*
                string for the first error: >
                        assert_fails('cmd', ['', 'E987:'])
 <
+               If {msg} is empty then it is not used.  Do this to get the
+               default message when passing the {lnum} argument.
+
+               When {lnum} is present and not negative, and the {error}
+               argument is present and matches, then this is compared with
+               the line number at which the error was reported. That can be
+               the line number in a function or in a script.
+
                Note that beeping is not considered an error, and some failing
                commands only beep.  Use |assert_beeps()| for those.
 
                Can also be used as a |method|: >
                        GetCmd()->assert_fails('E99:')
 
-assert_false({actual} [, {msg}])                               *assert_false()*
+assert_false({actual} [, {msg}])                       *assert_false()*
                When {actual} is not false an error message is added to
                |v:errors|, like with |assert_equal()|.
                Also see |assert-return|.
index ff814622a88a890c61860671c560712040dd843b..c759afcd2030d0f363a3ffb4de67780f123ce726 100644 (file)
@@ -494,7 +494,7 @@ static funcentry_T global_functions[] =
     {"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},
index d7d1c08f9a80c8d843a9bc1ee5e44bbea8c76284..e883c56f637d25f53a9a02b60feced504b1f703d 100644 (file)
@@ -223,6 +223,7 @@ EXTERN int  emsg_severe INIT(= FALSE);  // use message of next of several
 // 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
index 91b2fe23721b8d8a5b0574f13aba485e8ed062ee..38e695900f8fbe55ce4f92d32a7440c8abb600b1 100644 (file)
@@ -655,7 +655,10 @@ emsg_core(char_u *s)
        }
 
        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);
index ee68537e7cfadd1ce9fa7d332ed5c5ab618fd759..0e6702df291841986e5bc9bf65ec4be2c7c464fa 100644 (file)
@@ -1464,16 +1464,18 @@ def Test_expr7_list()
                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:')
index 448aa3db947231d294126de75121a0040ce200c9..c890b0c699ea09e6b42c1cfe47d2c08e31e59b96 100644 (file)
@@ -9,17 +9,19 @@ func CheckDefSuccess(lines)
 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
 
index 137d5fe9f708ef8e5e3288e8c1e7c12039e4fddf..09718760a8e4b9b12d7a3fd9bba28d06be46794f 100644 (file)
@@ -142,7 +142,10 @@ fill_assert_error(
     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 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
        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 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
            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);
index b17bcd2f3fd626c6a9def4fa2c863e7ac6bac27e..e8eb8521d2bcb1a819da1166325fdca51d054237 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1479,
 /**/
     1478,
 /**/
index 059e768e81d552c92fd6b98ff53688656777d5f3..fe78e8f59ed91c7642d897cf9996a1803a5be2e0 100644 (file)
@@ -2299,6 +2299,7 @@ call_def_function(
 
                    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;