]> granicus.if.org Git - vim/commitdiff
patch 8.2.1465: Vim9: subscript not handled properly v8.2.1465
authorBram Moolenaar <Bram@vim.org>
Sun, 16 Aug 2020 12:48:19 +0000 (14:48 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 16 Aug 2020 12:48:19 +0000 (14:48 +0200)
Problem:    Vim9: subscript not handled properly.
Solution:   Adjust error message.  Remove dead code.  Disallow string to
            number conversion in scripts.

src/errors.h
src/eval.c
src/list.c
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_script.vim
src/typval.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index 3f9607146928c53672cddbd6e416430863fb7cb3..0622042a81c3ff47d037451904ec869a4f37c441 100644 (file)
@@ -228,8 +228,8 @@ EXTERN char e_one_argument_too_many[]
        INIT(= N_("E1106: one argument too many"));
 EXTERN char e_nr_arguments_too_many[]
        INIT(= N_("E1106: %d arguments too many"));
-EXTERN char e_list_dict_or_blob_required[]
-       INIT(= N_("E1107: List, Dict or Blob required"));
+EXTERN char e_string_list_dict_or_blob_required[]
+       INIT(= N_("E1107: String, List, Dict or Blob required"));
 EXTERN char e_item_not_found_str[]
        INIT(= N_("E1108: Item not found: %s"));
 #endif
index 8f685eda47e814312b8a3f5293188a8fb5836244..02b5623fc6c0d7fce708e234ed03ae83436b44d6 100644 (file)
@@ -2142,7 +2142,9 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
        {
            int         error = FALSE;
 
-           if (tv_get_number_chk(rettv, &error) != 0)
+           if (in_vim9script())
+               result = tv2bool(rettv);
+           else if (tv_get_number_chk(rettv, &error) != 0)
                result = TRUE;
            clear_tv(rettv);
            if (error)
index 955272c37bae1fd387c89563891a8cad2502f0da..b09e87f5fd05a50d604e3bdc4929db9c48ef2f98 100644 (file)
@@ -1909,7 +1909,10 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
        int         error = FALSE;
 
        // filter(): when expr is zero remove the item
-       *remp = (tv_get_number_chk(&rettv, &error) == 0);
+       if (in_vim9script())
+           *remp = !tv2bool(&rettv);
+       else
+           *remp = (tv_get_number_chk(&rettv, &error) == 0);
        clear_tv(&rettv);
        // On type error, nothing has been removed; return FAIL to stop the
        // loop.  The error message was given by tv_get_number_chk().
index 6f3cedf902d4202d02a1307063d6ce6e2d4a99f2..720f2307f1f183f3712ef2da73723b71a5b33e99 100644 (file)
@@ -384,12 +384,14 @@ func Test_expr3_fails()
   call CheckDefFailure(["let x = 1&& 2"], msg)
 endfunc
 
+" global variables to use for tests with the "any" type
 let atrue = v:true
 let afalse = v:false
 let anone = v:none
 let anull = v:null
 let anint = 10
-let alsoint = 4
+let theone = 1
+let thefour = 4
 if has('float')
   let afloat = 0.1
 endif
@@ -901,17 +903,17 @@ def Test_expr5()
   assert_equal(66, 60 + 6)
   assert_equal(70, 60 +
                        g:anint)
-  assert_equal(9, g:alsoint
+  assert_equal(9, g:thefour
                        + 5)
-  assert_equal(14, g:alsoint + g:anint)
+  assert_equal(14, g:thefour + g:anint)
   assert_equal([1, 2, 3, 4], [1] + g:alist)
 
   assert_equal(54, 60 - 6)
   assert_equal(50, 60 -
                    g:anint)
-  assert_equal(-1, g:alsoint
+  assert_equal(-1, g:thefour
                        - 5)
-  assert_equal(-6, g:alsoint - g:anint)
+  assert_equal(-6, g:thefour - g:anint)
 
   assert_equal('hello', 'hel' .. 'lo')
   assert_equal('hello 123', 'hello ' ..
@@ -1136,24 +1138,24 @@ endfunc
 def Test_expr6()
   assert_equal(36, 6 * 6)
   assert_equal(24, 6 *
-                       g:alsoint)
-  assert_equal(24, g:alsoint
+                       g:thefour)
+  assert_equal(24, g:thefour
                        * 6)
-  assert_equal(40, g:anint * g:alsoint)
+  assert_equal(40, g:anint * g:thefour)
 
   assert_equal(10, 60 / 6)
   assert_equal(6, 60 /
                        g:anint)
   assert_equal(1, g:anint / 6)
   assert_equal(2, g:anint
-                       / g:alsoint)
+                       / g:thefour)
 
   assert_equal(5, 11 % 6)
   assert_equal(4, g:anint % 6)
   assert_equal(3, 13 %
                        g:anint)
   assert_equal(2, g:anint
-                       % g:alsoint)
+                       % g:thefour)
 
   assert_equal(4, 6 * 4 / 6)
 
@@ -1323,7 +1325,7 @@ let $TESTVAR = 'testvar'
 " type casts
 def Test_expr7t()
   let ls: list<string> = ['a', <string>g:string_empty]
-  let ln: list<number> = [<number>g:anint, <number>g:alsoint]
+  let ln: list<number> = [<number>g:anint, <number>g:thefour]
   let nr = <number>234
   assert_equal(234, nr)
 
@@ -1448,13 +1450,15 @@ def Test_expr7_list()
 
   let mixed: list<any> = [1, 'b', false,]
   assert_equal(g:list_mixed, mixed)
-  assert_equal('b', g:list_mixed[1])
+  assert_equal('b', mixed[1])
 
   echo [1,
        2] [3,
                4]
 
-  call CheckDefExecFailure(["let x = g:anint[3]"], 'E714:')
+  call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
+  call CheckDefExecFailure(["let x = g:anint[3]"], 'E1029:')
+
   call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
 
   call CheckDefFailure(["let x = [1,2,3]"], 'E1069:')
@@ -2136,6 +2140,7 @@ def Test_expr7_list_subscript()
     assert_equal([4], list[4:-1])
     assert_equal([], list[5:-1])
     assert_equal([], list[999:-1])
+    assert_equal([1, 2, 3, 4], list[g:theone:g:thefour])
 
     assert_equal([0, 1, 2, 3], list[0:3])
     assert_equal([0], list[0:0])
@@ -2147,6 +2152,10 @@ def Test_expr7_list_subscript()
   END
   CheckDefSuccess(lines)
   CheckScriptSuccess(['vim9script'] + lines)
+
+  lines = ['let l = [0, 1, 2]', 'echo l[g:astring : g:theone]']
+  CheckDefExecFailure(lines, 'E1029:')
+  CheckScriptFailure(['vim9script'] + lines, 'E1030:')
 enddef
 
 def Test_expr7_subscript_linebreak()
index 832835ec50c3625ccd41468dc7b1bb6374321470..1e265be0d70818356c3364a460fb2cfe2a698e95 100644 (file)
@@ -793,19 +793,20 @@ def Test_try_catch()
   endtry
   assert_equal(99, n)
 
+  # TODO: this will change when index on "any" works
   try
     n = g:astring[3]
-  catch /E714:/
+  catch /E1029:/
     n = 77
   endtry
   assert_equal(77, n)
 
   try
     n = l[g:astring]
-  catch /E39:/
-    n = 77
+  catch /E1029:/
+    n = 88
   endtry
-  assert_equal(77, n)
+  assert_equal(88, n)
 
   try
     n = s:does_not_exist
index e87f91096ef9ab4f737db5fe26a989c2afa627f3..406a193be33a0bb3ad68e4aeb2ffb9b59ea51d37 100644 (file)
@@ -204,6 +204,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
            emsg(_("E703: Using a Funcref as a Number"));
            break;
        case VAR_STRING:
+           if (in_vim9script())
+           {
+               emsg(_(e_using_string_as_number));
+               break;
+           }
            if (varp->vval.v_string != NULL)
                vim_str2nr(varp->vval.v_string, NULL, NULL,
                                            STR2NR_ALL, &n, NULL, 0, FALSE);
@@ -216,6 +221,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
            break;
        case VAR_BOOL:
        case VAR_SPECIAL:
+           if (in_vim9script())
+           {
+               emsg(_("E611: Using a Special as a Number"));
+               break;
+           }
            return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
        case VAR_JOB:
 #ifdef FEAT_JOB_CHANNEL
@@ -1461,9 +1471,10 @@ eval_env_var(char_u **arg, typval_T *rettv, int evaluate)
     linenr_T
 tv_get_lnum(typval_T *argvars)
 {
-    linenr_T   lnum;
+    linenr_T   lnum = 0;
 
-    lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
+    if (argvars[0].v_type != VAR_STRING || !in_vim9script())
+       lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
     if (lnum == 0)  // no valid number, try using arg like line()
     {
        int     fnum;
index 4554fc4bbf650397e1fb2a420d8e259f0a209e5a..7a6fcbfff657ecadbbfcd45d98f9620f440394bb 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1465,
 /**/
     1464,
 /**/
index da44770f3e74b4239fe3d2c6f6228b9baca61e60..cdc63cfe19872d6fb08edc82d4c32fb6bd85214f 100644 (file)
@@ -3067,6 +3067,7 @@ compile_subscript(
        {
            garray_T    *stack = &cctx->ctx_type_stack;
            type_T      **typep;
+           type_T      *valtype;
            vartype_T   vtype;
            int         is_slice = FALSE;
 
@@ -3127,13 +3128,22 @@ compile_subscript(
            typep = ((type_T **)stack->ga_data) + stack->ga_len
                                                          - (is_slice ? 3 : 2);
            vtype = (*typep)->tt_type;
-           if (*typep == &t_any)
+           valtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+           // If the index is a string, the variable must be a Dict.
+           if (*typep == &t_any && valtype == &t_string)
+               vtype = VAR_DICT;
+           if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
            {
-               type_T *valtype = ((type_T **)stack->ga_data)
-                                                          [stack->ga_len - 1];
-               if (valtype == &t_string)
-                   vtype = VAR_DICT;
+               if (need_type(valtype, &t_number, -1, cctx, FALSE) == FAIL)
+                   return FAIL;
+               if (is_slice)
+               {
+                   valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
+                   if (need_type(valtype, &t_number, -2, cctx, FALSE) == FAIL)
+                       return FAIL;
+               }
            }
+
            if (vtype == VAR_DICT)
            {
                if (is_slice)
@@ -3169,6 +3179,10 @@ compile_subscript(
            }
            else if (vtype == VAR_LIST || *typep == &t_any)
            {
+               // TODO: any requires runtime code
+               if (*typep == &t_any && need_type(*typep, &t_list_any,
+                                     is_slice ? -3 : -2, cctx, FALSE) == FAIL)
+                   return FAIL;
                if (is_slice)
                {
                    if (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
@@ -3184,7 +3198,7 @@ compile_subscript(
            }
            else
            {
-               emsg(_(e_list_dict_or_blob_required));
+               emsg(_(e_string_list_dict_or_blob_required));
                return FAIL;
            }
        }
index 5670a7c3c07fd82b5089fe1925b2fb148b08ddd4..02a895ecb7952238f8f65fc252483ac23f06622a 100644 (file)
@@ -2241,33 +2241,13 @@ call_def_function(
                    // string index: string is at stack-2, index at stack-1
                    // string slice: string is at stack-3, first index at
                    // stack-2, second index at stack-1
-                   tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
-                   if (tv->v_type != VAR_STRING)
-                   {
-                       SOURCING_LNUM = iptr->isn_lnum;
-                       emsg(_(e_stringreq));
-                       goto on_error;
-                   }
-
                    if (is_slice)
                    {
                        tv = STACK_TV_BOT(-2);
-                       if (tv->v_type != VAR_NUMBER)
-                       {
-                           SOURCING_LNUM = iptr->isn_lnum;
-                           emsg(_(e_number_exp));
-                           goto on_error;
-                       }
                        n1 = tv->vval.v_number;
                    }
 
                    tv = STACK_TV_BOT(-1);
-                   if (tv->v_type != VAR_NUMBER)
-                   {
-                       SOURCING_LNUM = iptr->isn_lnum;
-                       emsg(_(e_number_exp));
-                       goto on_error;
-                   }
                    n2 = tv->vval.v_number;
 
                    ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
@@ -2296,33 +2276,15 @@ call_def_function(
                    // list slice: list is at stack-3, indexes at stack-2 and
                    // stack-1
                    tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
-                   if (tv->v_type != VAR_LIST)
-                   {
-                       SOURCING_LNUM = iptr->isn_lnum;
-                       emsg(_(e_listreq));
-                       goto on_error;
-                   }
                    list = tv->vval.v_list;
 
                    tv = STACK_TV_BOT(-1);
-                   if (tv->v_type != VAR_NUMBER)
-                   {
-                       SOURCING_LNUM = iptr->isn_lnum;
-                       emsg(_(e_number_exp));
-                       goto on_error;
-                   }
                    n1 = n2 = tv->vval.v_number;
                    clear_tv(tv);
 
                    if (is_slice)
                    {
                        tv = STACK_TV_BOT(-2);
-                       if (tv->v_type != VAR_NUMBER)
-                       {
-                           SOURCING_LNUM = iptr->isn_lnum;
-                           emsg(_(e_number_exp));
-                           goto on_error;
-                       }
                        n1 = tv->vval.v_number;
                        clear_tv(tv);
                    }