Patch 8.2.1466
Problem:    Vim9: cannot index or slice a variable with type "any".
Solution:   Add runtime index and slice.
Files:      src/eval.c, src/proto/eval.pro, src/vim9compile.c,
            src/vim9execute.c, src/vim9.h, src/errors.h, src/list.c,
            src/testdir/test_vim9_expr.vim,
            src/testdir/test_vim9_disassemble.vim,
            src/testdir/test_vim9_script.vim


*** ../vim-8.2.1465/src/eval.c  2020-08-16 14:48:14.377965877 +0200
--- src/eval.c  2020-08-16 17:07:16.209603356 +0200
***************
*** 20,27 ****
  # include <float.h>
  #endif
  
- static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
- 
  #define NAMESPACE_CHAR        (char_u *)"abglstvw"
  
  /*
--- 20,25 ----
***************
*** 928,934 ****
                if (lp->ll_tv->v_type == VAR_DICT)
                {
                    if (!quiet)
!                       emsg(_(e_dictrange));
                    clear_tv(&var1);
                    return NULL;
                }
--- 926,932 ----
                if (lp->ll_tv->v_type == VAR_DICT)
                {
                    if (!quiet)
!                       emsg(_(e_cannot_slice_dictionary));
                    clear_tv(&var1);
                    return NULL;
                }
***************
*** 3549,3595 ****
                                      && (evalarg->eval_flags & EVAL_EVALUATE);
      int               empty1 = FALSE, empty2 = FALSE;
      typval_T  var1, var2;
-     long      i;
-     long      n1, n2 = 0;
-     long      len = -1;
      int               range = FALSE;
-     char_u    *s;
      char_u    *key = NULL;
  
!     switch (rettv->v_type)
!     {
!       case VAR_FUNC:
!       case VAR_PARTIAL:
!           if (verbose)
!               emsg(_("E695: Cannot index a Funcref"));
!           return FAIL;
!       case VAR_FLOAT:
! #ifdef FEAT_FLOAT
!           if (verbose)
!               emsg(_(e_float_as_string));
!           return FAIL;
! #endif
!       case VAR_BOOL:
!       case VAR_SPECIAL:
!       case VAR_JOB:
!       case VAR_CHANNEL:
!           if (verbose)
!               emsg(_("E909: Cannot index a special variable"));
!           return FAIL;
!       case VAR_UNKNOWN:
!       case VAR_ANY:
!       case VAR_VOID:
!           if (evaluate)
!               return FAIL;
!           // FALLTHROUGH
! 
!       case VAR_STRING:
!       case VAR_NUMBER:
!       case VAR_LIST:
!       case VAR_DICT:
!       case VAR_BLOB:
!           break;
!     }
  
      init_tv(&var1);
      init_tv(&var2);
--- 3547,3558 ----
                                      && (evalarg->eval_flags & EVAL_EVALUATE);
      int               empty1 = FALSE, empty2 = FALSE;
      typval_T  var1, var2;
      int               range = FALSE;
      char_u    *key = NULL;
+     int               keylen = -1;
  
!     if (check_can_index(rettv, evaluate, verbose) == FAIL)
!       return FAIL;
  
      init_tv(&var1);
      init_tv(&var2);
***************
*** 3599,3609 ****
         * dict.name
         */
        key = *arg + 1;
!       for (len = 0; eval_isdictc(key[len]); ++len)
            ;
!       if (len == 0)
            return FAIL;
!       *arg = skipwhite(key + len);
      }
      else
      {
--- 3562,3572 ----
         * dict.name
         */
        key = *arg + 1;
!       for (keylen = 0; eval_isdictc(key[keylen]); ++keylen)
            ;
!       if (keylen == 0)
            return FAIL;
!       *arg = skipwhite(key + keylen);
      }
      else
      {
***************
*** 3666,3714 ****
  
      if (evaluate)
      {
!       n1 = 0;
!       if (!empty1 && rettv->v_type != VAR_DICT)
!       {
!           n1 = tv_get_number(&var1);
            clear_tv(&var1);
-       }
        if (range)
!       {
!           if (empty2)
!               n2 = -1;
!           else
            {
!               n2 = tv_get_number(&var2);
!               clear_tv(&var2);
            }
!       }
  
!       switch (rettv->v_type)
        {
!           case VAR_UNKNOWN:
!           case VAR_ANY:
!           case VAR_VOID:
!           case VAR_FUNC:
!           case VAR_PARTIAL:
!           case VAR_FLOAT:
!           case VAR_BOOL:
!           case VAR_SPECIAL:
!           case VAR_JOB:
!           case VAR_CHANNEL:
!               break; // not evaluating, skipping over subscript
  
-           case VAR_NUMBER:
-           case VAR_STRING:
-               s = tv_get_string(rettv);
                len = (long)STRLEN(s);
                if (in_vim9script())
                {
!                   if (range)
                        s = string_slice(s, n1, n2);
                    else
                        s = char_from_string(s, n1);
                }
!               else if (range)
                {
                    // The resulting variable is a substring.  If the indexes
                    // are out of range the result is empty.
--- 3629,3760 ----
  
      if (evaluate)
      {
!       int res = eval_index_inner(rettv, range,
!               empty1 ? NULL : &var1, empty2 ? NULL : &var2,
!               key, keylen, verbose);
!       if (!empty1)
            clear_tv(&var1);
        if (range)
!           clear_tv(&var2);
!       return res;
!     }
!     return OK;
! }
! 
! /*
!  * Check if "rettv" can have an [index] or [sli:ce]
!  */
!     int
! check_can_index(typval_T *rettv, int evaluate, int verbose)
! {
!     switch (rettv->v_type)
!     {
!       case VAR_FUNC:
!       case VAR_PARTIAL:
!           if (verbose)
!               emsg(_("E695: Cannot index a Funcref"));
!           return FAIL;
!       case VAR_FLOAT:
! #ifdef FEAT_FLOAT
!           if (verbose)
!               emsg(_(e_float_as_string));
!           return FAIL;
! #endif
!       case VAR_BOOL:
!       case VAR_SPECIAL:
!       case VAR_JOB:
!       case VAR_CHANNEL:
!           if (verbose)
!               emsg(_(e_cannot_index_special_variable));
!           return FAIL;
!       case VAR_UNKNOWN:
!       case VAR_ANY:
!       case VAR_VOID:
!           if (evaluate)
            {
!               emsg(_(e_cannot_index_special_variable));
!               return FAIL;
            }
!           // FALLTHROUGH
  
!       case VAR_STRING:
!       case VAR_LIST:
!       case VAR_DICT:
!       case VAR_BLOB:
!           break;
!       case VAR_NUMBER:
!           if (in_vim9script())
!               emsg(_(e_cannot_index_number));
!           break;
!     }
!     return OK;
! }
! 
! /*
!  * Apply index or range to "rettv".
!  * "var1" is the first index, NULL for [:expr].
!  * "var2" is the second index, NULL for [expr] and [expr: ]
!  * Alternatively, "key" is not NULL, then key[keylen] is the dict index.
!  */
!     int
! eval_index_inner(
!       typval_T    *rettv,
!       int         is_range,
!       typval_T    *var1,
!       typval_T    *var2,
!       char_u      *key,
!       int         keylen,
!       int         verbose)
! {
!     long      n1, n2 = 0;
!     long      len;
! 
!     n1 = 0;
!     if (var1 != NULL && rettv->v_type != VAR_DICT)
!       n1 = tv_get_number(var1);
! 
!     if (is_range)
!     {
!       if (rettv->v_type == VAR_DICT)
        {
!           if (verbose)
!               emsg(_(e_cannot_slice_dictionary));
!           return FAIL;
!       }
!       if (var2 == NULL)
!           n2 = -1;
!       else
!           n2 = tv_get_number(var2);
!     }
! 
!     switch (rettv->v_type)
!     {
!       case VAR_UNKNOWN:
!       case VAR_ANY:
!       case VAR_VOID:
!       case VAR_FUNC:
!       case VAR_PARTIAL:
!       case VAR_FLOAT:
!       case VAR_BOOL:
!       case VAR_SPECIAL:
!       case VAR_JOB:
!       case VAR_CHANNEL:
!           break; // not evaluating, skipping over subscript
! 
!       case VAR_NUMBER:
!       case VAR_STRING:
!           {
!               char_u  *s = tv_get_string(rettv);
  
                len = (long)STRLEN(s);
                if (in_vim9script())
                {
!                   if (is_range)
                        s = string_slice(s, n1, n2);
                    else
                        s = char_from_string(s, n1);
                }
!               else if (is_range)
                {
                    // The resulting variable is a substring.  If the indexes
                    // are out of range the result is empty.
***************
*** 3740,3858 ****
                clear_tv(rettv);
                rettv->v_type = VAR_STRING;
                rettv->vval.v_string = s;
!               break;
  
!           case VAR_BLOB:
!               len = blob_len(rettv->vval.v_blob);
!               if (range)
                {
!                   // The resulting variable is a sub-blob.  If the indexes
!                   // are out of range the result is empty.
                    if (n1 < 0)
!                   {
!                       n1 = len + n1;
!                       if (n1 < 0)
!                           n1 = 0;
!                   }
!                   if (n2 < 0)
!                       n2 = len + n2;
!                   else if (n2 >= len)
!                       n2 = len - 1;
!                   if (n1 >= len || n2 < 0 || n1 > n2)
!                   {
!                       clear_tv(rettv);
!                       rettv->v_type = VAR_BLOB;
!                       rettv->vval.v_blob = NULL;
!                   }
!                   else
!                   {
!                       blob_T  *blob = blob_alloc();
! 
!                       if (blob != NULL)
!                       {
!                           if (ga_grow(&blob->bv_ga, n2 - n1 + 1) == FAIL)
!                           {
!                               blob_free(blob);
!                               return FAIL;
!                           }
!                           blob->bv_ga.ga_len = n2 - n1 + 1;
!                           for (i = n1; i <= n2; i++)
!                               blob_set(blob, i - n1,
!                                             blob_get(rettv->vval.v_blob, i));
! 
!                           clear_tv(rettv);
!                           rettv_blob_set(rettv, blob);
!                       }
!                   }
                }
                else
                {
!                   // The resulting variable is a byte value.
!                   // If the index is too big or negative that is an error.
!                   if (n1 < 0)
!                       n1 = len + n1;
!                   if (n1 < len && n1 >= 0)
                    {
!                       int v = blob_get(rettv->vval.v_blob, n1);
  
                        clear_tv(rettv);
!                       rettv->v_type = VAR_NUMBER;
!                       rettv->vval.v_number = v;
                    }
-                   else
-                       semsg(_(e_blobidx), n1);
                }
!               break;
! 
!           case VAR_LIST:
!               if (empty1)
!                   n1 = 0;
!               if (empty2)
!                   n2 = -1;
!               if (list_slice_or_index(rettv->vval.v_list,
!                                       range, n1, n2, rettv, verbose) == FAIL)
!                   return FAIL;
!               break;
! 
!           case VAR_DICT:
!               if (range)
                {
!                   if (verbose)
!                       emsg(_(e_dictrange));
!                   if (len == -1)
!                       clear_tv(&var1);
!                   return FAIL;
                }
!               {
!                   dictitem_T  *item;
  
!                   if (len == -1)
!                   {
!                       key = tv_get_string_chk(&var1);
!                       if (key == NULL)
!                       {
!                           clear_tv(&var1);
!                           return FAIL;
!                       }
!                   }
  
!                   item = dict_find(rettv->vval.v_dict, key, (int)len);
  
!                   if (item == NULL && verbose)
!                       semsg(_(e_dictkey), key);
!                   if (len == -1)
!                       clear_tv(&var1);
!                   if (item == NULL)
                        return FAIL;
- 
-                   copy_tv(&item->di_tv, &var1);
-                   clear_tv(rettv);
-                   *rettv = var1;
                }
-               break;
-       }
-     }
  
      return OK;
  }
  
--- 3786,3892 ----
                clear_tv(rettv);
                rettv->v_type = VAR_STRING;
                rettv->vval.v_string = s;
!           }
!           break;
  
!       case VAR_BLOB:
!           len = blob_len(rettv->vval.v_blob);
!           if (is_range)
!           {
!               // The resulting variable is a sub-blob.  If the indexes
!               // are out of range the result is empty.
!               if (n1 < 0)
                {
!                   n1 = len + n1;
                    if (n1 < 0)
!                       n1 = 0;
!               }
!               if (n2 < 0)
!                   n2 = len + n2;
!               else if (n2 >= len)
!                   n2 = len - 1;
!               if (n1 >= len || n2 < 0 || n1 > n2)
!               {
!                   clear_tv(rettv);
!                   rettv->v_type = VAR_BLOB;
!                   rettv->vval.v_blob = NULL;
                }
                else
                {
!                   blob_T  *blob = blob_alloc();
!                   long    i;
! 
!                   if (blob != NULL)
                    {
!                       if (ga_grow(&blob->bv_ga, n2 - n1 + 1) == FAIL)
!                       {
!                           blob_free(blob);
!                           return FAIL;
!                       }
!                       blob->bv_ga.ga_len = n2 - n1 + 1;
!                       for (i = n1; i <= n2; i++)
!                           blob_set(blob, i - n1,
!                                         blob_get(rettv->vval.v_blob, i));
  
                        clear_tv(rettv);
!                       rettv_blob_set(rettv, blob);
                    }
                }
!           }
!           else
!           {
!               // The resulting variable is a byte value.
!               // If the index is too big or negative that is an error.
!               if (n1 < 0)
!                   n1 = len + n1;
!               if (n1 < len && n1 >= 0)
                {
!                   int v = blob_get(rettv->vval.v_blob, n1);
! 
!                   clear_tv(rettv);
!                   rettv->v_type = VAR_NUMBER;
!                   rettv->vval.v_number = v;
                }
!               else
!                   semsg(_(e_blobidx), n1);
!           }
!           break;
  
!       case VAR_LIST:
!           if (var1 == NULL)
!               n1 = 0;
!           if (var2 == NULL)
!               n2 = -1;
!           if (list_slice_or_index(rettv->vval.v_list,
!                                   is_range, n1, n2, rettv, verbose) == FAIL)
!               return FAIL;
!           break;
  
!       case VAR_DICT:
!           {
!               dictitem_T      *item;
!               typval_T        tmp;
  
!               if (key == NULL)
!               {
!                   key = tv_get_string_chk(var1);
!                   if (key == NULL)
                        return FAIL;
                }
  
+               item = dict_find(rettv->vval.v_dict, key, (int)keylen);
+ 
+               if (item == NULL && verbose)
+                   semsg(_(e_dictkey), key);
+               if (item == NULL)
+                   return FAIL;
+ 
+               copy_tv(&item->di_tv, &tmp);
+               clear_tv(rettv);
+               *rettv = tmp;
+           }
+           break;
+     }
      return OK;
  }
  
***************
*** 5292,5300 ****
   * "str_len".
   * If going over the end return "str_len".
   * If "idx" is negative count from the end, -1 is the last character.
!  * When going over the start return zero.
   */
!     static size_t
  char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
  {
      varnumber_T nchar = idx;
--- 5326,5334 ----
   * "str_len".
   * If going over the end return "str_len".
   * If "idx" is negative count from the end, -1 is the last character.
!  * When going over the start return -1.
   */
!     static long
  char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
  {
      varnumber_T nchar = idx;
***************
*** 5317,5324 ****
            nbyte -= mb_head_off(str, str + nbyte);
            ++nchar;
        }
      }
!     return nbyte;
  }
  
  /*
--- 5351,5360 ----
            nbyte -= mb_head_off(str, str + nbyte);
            ++nchar;
        }
+       if (nchar < 0)
+           return -1;
      }
!     return (long)nbyte;
  }
  
  /*
***************
*** 5328,5351 ****
      char_u *
  string_slice(char_u *str, varnumber_T first, varnumber_T last)
  {
!     size_t        start_byte, end_byte;
!     size_t        slen;
  
      if (str == NULL)
        return NULL;
      slen = STRLEN(str);
      start_byte = char_idx2byte(str, slen, first);
      if (last == -1)
        end_byte = slen;
      else
      {
        end_byte = char_idx2byte(str, slen, last);
!       if (end_byte < slen)
            // end index is inclusive
            end_byte += MB_CPTR2LEN(str + end_byte);
      }
  
!     if (start_byte >= slen || end_byte <= start_byte)
        return NULL;
      return vim_strnsave(str + start_byte, end_byte - start_byte);
  }
--- 5364,5389 ----
      char_u *
  string_slice(char_u *str, varnumber_T first, varnumber_T last)
  {
!     long      start_byte, end_byte;
!     size_t    slen;
  
      if (str == NULL)
        return NULL;
      slen = STRLEN(str);
      start_byte = char_idx2byte(str, slen, first);
+     if (start_byte < 0)
+       start_byte = 0; // first index very negative: use zero
      if (last == -1)
        end_byte = slen;
      else
      {
        end_byte = char_idx2byte(str, slen, last);
!       if (end_byte >= 0 && end_byte < (long)slen)
            // end index is inclusive
            end_byte += MB_CPTR2LEN(str + end_byte);
      }
  
!     if (start_byte >= (long)slen || end_byte <= start_byte)
        return NULL;
      return vim_strnsave(str + start_byte, end_byte - start_byte);
  }
*** ../vim-8.2.1465/src/proto/eval.pro  2020-08-15 21:09:03.281675788 +0200
--- src/proto/eval.pro  2020-08-16 15:48:47.286790791 +0200
***************
*** 37,42 ****
--- 37,44 ----
  int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
  void eval_addblob(typval_T *tv1, typval_T *tv2);
  int eval_addlist(typval_T *tv1, typval_T *tv2);
+ int check_can_index(typval_T *rettv, int evaluate, int verbose);
+ int eval_index_inner(typval_T *rettv, int is_range, typval_T *var1, typval_T 
*var2, char_u *key, int keylen, int verbose);
  char_u *partial_name(partial_T *pt);
  void partial_unref(partial_T *pt);
  int get_copyID(void);
*** ../vim-8.2.1465/src/vim9compile.c   2020-08-16 14:48:14.377965877 +0200
--- src/vim9compile.c   2020-08-16 15:42:15.249579900 +0200
***************
*** 3179,3198 ****
            }
            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)
                        return FAIL;
                }
                else
                {
                    if ((*typep)->tt_type == VAR_LIST)
                        *typep = (*typep)->tt_member;
!                   if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
                        return FAIL;
                }
            }
--- 3179,3198 ----
            }
            else if (vtype == VAR_LIST || *typep == &t_any)
            {
                if (is_slice)
                {
!                   if (generate_instr_drop(cctx,
!                            vtype == VAR_LIST ?  ISN_LISTSLICE : ISN_ANYSLICE,
!                                                                   2) == FAIL)
                        return FAIL;
                }
                else
                {
                    if ((*typep)->tt_type == VAR_LIST)
                        *typep = (*typep)->tt_member;
!                   if (generate_instr_drop(cctx,
!                            vtype == VAR_LIST ?  ISN_LISTINDEX : ISN_ANYINDEX,
!                                                                   1) == FAIL)
                        return FAIL;
                }
            }
***************
*** 7085,7095 ****
        case ISN_2STRING_ANY:
        case ISN_ADDBLOB:
        case ISN_ADDLIST:
        case ISN_BCALL:
        case ISN_CATCH:
        case ISN_CHECKNR:
        case ISN_CHECKTYPE:
-       case ISN_CHECKLEN:
        case ISN_COMPAREANY:
        case ISN_COMPAREBLOB:
        case ISN_COMPAREBOOL:
--- 7085,7097 ----
        case ISN_2STRING_ANY:
        case ISN_ADDBLOB:
        case ISN_ADDLIST:
+       case ISN_ANYINDEX:
+       case ISN_ANYSLICE:
        case ISN_BCALL:
        case ISN_CATCH:
+       case ISN_CHECKLEN:
        case ISN_CHECKNR:
        case ISN_CHECKTYPE:
        case ISN_COMPAREANY:
        case ISN_COMPAREBLOB:
        case ISN_COMPAREBOOL:
***************
*** 7102,7108 ****
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
        case ISN_DCALL:
-       case ISN_SHUFFLE:
        case ISN_DROP:
        case ISN_ECHO:
        case ISN_ECHOERR:
--- 7104,7109 ----
***************
*** 7111,7124 ****
        case ISN_EXECCONCAT:
        case ISN_EXECUTE:
        case ISN_FOR:
-       case ISN_LISTINDEX:
-       case ISN_LISTSLICE:
-       case ISN_STRINDEX:
-       case ISN_STRSLICE:
        case ISN_GETITEM:
-       case ISN_SLICE:
-       case ISN_MEMBER:
        case ISN_JUMP:
        case ISN_LOAD:
        case ISN_LOADBDICT:
        case ISN_LOADGDICT:
--- 7112,7121 ----
        case ISN_EXECCONCAT:
        case ISN_EXECUTE:
        case ISN_FOR:
        case ISN_GETITEM:
        case ISN_JUMP:
+       case ISN_LISTINDEX:
+       case ISN_LISTSLICE:
        case ISN_LOAD:
        case ISN_LOADBDICT:
        case ISN_LOADGDICT:
***************
*** 7128,7154 ****
        case ISN_LOADTDICT:
        case ISN_LOADV:
        case ISN_LOADWDICT:
        case ISN_NEGATENR:
        case ISN_NEWDICT:
        case ISN_NEWLIST:
-       case ISN_OPNR:
-       case ISN_OPFLOAT:
        case ISN_OPANY:
        case ISN_PCALL:
        case ISN_PCALL_END:
        case ISN_PUSHF:
        case ISN_PUSHNR:
-       case ISN_PUSHBOOL:
        case ISN_PUSHSPEC:
        case ISN_RETURN:
        case ISN_STORE:
!       case ISN_STOREOUTER:
!       case ISN_STOREV:
        case ISN_STORENR:
        case ISN_STOREREG:
        case ISN_STORESCRIPT:
!       case ISN_STOREDICT:
!       case ISN_STORELIST:
        case ISN_THROW:
        case ISN_TRY:
            // nothing allocated
--- 7125,7156 ----
        case ISN_LOADTDICT:
        case ISN_LOADV:
        case ISN_LOADWDICT:
+       case ISN_MEMBER:
        case ISN_NEGATENR:
        case ISN_NEWDICT:
        case ISN_NEWLIST:
        case ISN_OPANY:
+       case ISN_OPFLOAT:
+       case ISN_OPNR:
        case ISN_PCALL:
        case ISN_PCALL_END:
+       case ISN_PUSHBOOL:
        case ISN_PUSHF:
        case ISN_PUSHNR:
        case ISN_PUSHSPEC:
        case ISN_RETURN:
+       case ISN_SHUFFLE:
+       case ISN_SLICE:
        case ISN_STORE:
!       case ISN_STOREDICT:
!       case ISN_STORELIST:
        case ISN_STORENR:
+       case ISN_STOREOUTER:
        case ISN_STOREREG:
        case ISN_STORESCRIPT:
!       case ISN_STOREV:
!       case ISN_STRINDEX:
!       case ISN_STRSLICE:
        case ISN_THROW:
        case ISN_TRY:
            // nothing allocated
*** ../vim-8.2.1465/src/vim9execute.c   2020-08-16 14:48:14.377965877 +0200
--- src/vim9execute.c   2020-08-16 16:04:41.218107159 +0200
***************
*** 2297,2302 ****
--- 2297,2328 ----
                }
                break;
  
+           case ISN_ANYINDEX:
+           case ISN_ANYSLICE:
+               {
+                   int         is_slice = iptr->isn_type == ISN_ANYSLICE;
+                   typval_T    *var1, *var2;
+                   int         res;
+ 
+                   // index: composite is at stack-2, index at stack-1
+                   // slice: composite is at stack-3, indexes at stack-2 and
+                   // stack-1
+                   tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
+                   if (check_can_index(tv, TRUE, TRUE) == FAIL)
+                       goto on_error;
+                   var1 = is_slice ? STACK_TV_BOT(-2) : STACK_TV_BOT(-1);
+                   var2 = is_slice ? STACK_TV_BOT(-1) : NULL;
+                   res = eval_index_inner(tv, is_slice,
+                                                  var1, var2, NULL, -1, TRUE);
+                   clear_tv(var1);
+                   if (is_slice)
+                       clear_tv(var2);
+                   ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
+                   if (res == FAIL)
+                       goto on_error;
+               }
+               break;
+ 
            case ISN_SLICE:
                {
                    list_T      *list;
***************
*** 3133,3138 ****
--- 3159,3166 ----
            case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
            case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
            case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
+           case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
+           case ISN_ANYSLICE: smsg("%4d ANYSLICE", current); break;
            case ISN_SLICE: smsg("%4d SLICE %lld",
                                         current, iptr->isn_arg.number); break;
            case ISN_GETITEM: smsg("%4d ITEM %lld",
*** ../vim-8.2.1465/src/vim9.h  2020-08-15 22:14:49.051890442 +0200
--- src/vim9.h  2020-08-16 15:39:00.006999100 +0200
***************
*** 120,125 ****
--- 120,127 ----
      ISN_STRSLICE,   // [expr:expr] string slice
      ISN_LISTINDEX,  // [expr] list index
      ISN_LISTSLICE,  // [expr:expr] list slice
+     ISN_ANYINDEX,   // [expr] runtime index
+     ISN_ANYSLICE,   // [expr:expr] runtime slice
      ISN_SLICE,            // drop isn_arg.number items from start of list
      ISN_GETITEM,    // push list item, isn_arg.number is the index
      ISN_MEMBER,           // dict[member]
*** ../vim-8.2.1465/src/errors.h        2020-08-16 14:48:14.377965877 +0200
--- src/errors.h        2020-08-16 17:11:34.235680579 +0200
***************
*** 21,26 ****
--- 21,30 ----
  #ifdef FEAT_EVAL
  EXTERN char e_invalid_command_str[]
        INIT(= N_("E476: Invalid command: %s"));
+ EXTERN char e_cannot_slice_dictionary[]
+       INIT(= N_("E719: cannot slice a Dictionary"));
+ EXTERN char e_cannot_index_special_variable[]
+       INIT(= N_("E909: Cannot index a special variable"));
  EXTERN char e_missing_let_str[]
        INIT(= N_("E1100: Missing :let: %s"));
  EXTERN char e_variable_not_found_str[]
***************
*** 69,77 ****
        INIT(= N_("E1021: const requires a value"));
  EXTERN char e_type_or_initialization_required[]
        INIT(= N_("E1022: type or initialization required"));
! EXTERN char e_cannot_slice_dictionary[]
!       INIT(= N_("E1023: cannot slice a dictionary"));
! // E1024 unused
  EXTERN char e_using_rcurly_outside_if_block_scope[]
        INIT(= N_("E1025: using } outside of a block scope"));
  EXTERN char e_missing_rcurly[]
--- 73,81 ----
        INIT(= N_("E1021: const requires a value"));
  EXTERN char e_type_or_initialization_required[]
        INIT(= N_("E1022: type or initialization required"));
! // E1023 unused
! EXTERN char e_using_number_as_string[]
!       INIT(= N_("E1024: Using a Number as a String"));
  EXTERN char e_using_rcurly_outside_if_block_scope[]
        INIT(= N_("E1025: using } outside of a block scope"));
  EXTERN char e_missing_rcurly[]
***************
*** 146,152 ****
        INIT(= N_("E1060: expected dot after name: %s"));
  EXTERN char e_cannot_find_function_str[]
        INIT(= N_("E1061: Cannot find function %s"));
! // E1062 unused
  EXTERN char e_type_mismatch_for_v_variable[]
        INIT(= N_("E1063: type mismatch for v: variable"));
  // E1064 unused
--- 150,157 ----
        INIT(= N_("E1060: expected dot after name: %s"));
  EXTERN char e_cannot_find_function_str[]
        INIT(= N_("E1061: Cannot find function %s"));
! EXTERN char e_cannot_index_number[]
!       INIT(= N_("E1062: Cannot index a Number"));
  EXTERN char e_type_mismatch_for_v_variable[]
        INIT(= N_("E1063: type mismatch for v: variable"));
  // E1064 unused
*** ../vim-8.2.1465/src/list.c  2020-08-16 14:48:14.377965877 +0200
--- src/list.c  2020-08-16 16:57:40.625890389 +0200
***************
*** 914,920 ****
                semsg(_(e_listidx), n1);
            return FAIL;
        }
!       n1 = len;
      }
      if (range)
      {
--- 914,920 ----
                semsg(_(e_listidx), n1);
            return FAIL;
        }
!       n1 = n1 < 0 ? 0 : len;
      }
      if (range)
      {
*** ../vim-8.2.1465/src/testdir/test_vim9_expr.vim      2020-08-16 
14:48:14.377965877 +0200
--- src/testdir/test_vim9_expr.vim      2020-08-16 17:13:50.022669179 +0200
***************
*** 1457,1463 ****
                4]
  
    call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
!   call CheckDefExecFailure(["let x = g:anint[3]"], 'E1029:')
  
    call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
  
--- 1457,1463 ----
                4]
  
    call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
!   call CheckDefExecFailure(["let x = g:anint[3]"], 'E1062:')
  
    call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
  
***************
*** 1768,1776 ****
    call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 
'E1029: Expected dict but got list')
  enddef
  
! def Test_expr_index()
!   # getting the one member should clear the list only after getting the item
!   assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
  enddef
  
  def Test_expr_member_vim9script()
--- 1768,1858 ----
    call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 
'E1029: Expected dict but got list')
  enddef
  
! def Test_expr7_any_index_slice()
!   let lines =<< trim END
!     # getting the one member should clear the list only after getting the item
!     assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
! 
!     # string is permissive, index out of range accepted
!     g:teststring = 'abcdef'
!     assert_equal('b', g:teststring[1])
!     assert_equal('', g:teststring[-1])
!     assert_equal('', g:teststring[99])
! 
!     assert_equal('b', g:teststring[1:1])
!     assert_equal('bcdef', g:teststring[1:])
!     assert_equal('abcd', g:teststring[:3])
!     assert_equal('cdef', g:teststring[-4:])
!     assert_equal('abcdef', g:teststring[-9:])
!     assert_equal('abcd', g:teststring[:-3])
!     assert_equal('', g:teststring[:-9])
! 
!     # blob index cannot be out of range
!     g:testblob = 0z01ab
!     assert_equal(0x01, g:testblob[0])
!     assert_equal(0xab, g:testblob[1])
!     assert_equal(0xab, g:testblob[-1])
!     assert_equal(0x01, g:testblob[-2])
! 
!     # blob slice accepts out of range
!     assert_equal(0z01ab, g:testblob[0:1])
!     assert_equal(0z01, g:testblob[0:0])
!     assert_equal(0z01, g:testblob[-2:-2])
!     assert_equal(0zab, g:testblob[1:1])
!     assert_equal(0zab, g:testblob[-1:-1])
!     assert_equal(0z, g:testblob[2:2])
!     assert_equal(0z, g:testblob[0:-3])
! 
!     # list index cannot be out of range
!     g:testlist = [0, 1, 2, 3]
!     assert_equal(0, g:testlist[0])
!     assert_equal(1, g:testlist[1])
!     assert_equal(3, g:testlist[3])
!     assert_equal(3, g:testlist[-1])
!     assert_equal(0, g:testlist[-4])
!     assert_equal(1, g:testlist[g:theone])
! 
!     # list slice accepts out of range
!     assert_equal([0], g:testlist[0:0])
!     assert_equal([3], g:testlist[3:3])
!     assert_equal([0, 1], g:testlist[0:1])
!     assert_equal([0, 1, 2, 3], g:testlist[0:3])
!     assert_equal([0, 1, 2, 3], g:testlist[0:9])
!     assert_equal([], g:testlist[-1:1])
!     assert_equal([1], g:testlist[-3:1])
!     assert_equal([0, 1], g:testlist[-4:1])
!     assert_equal([0, 1], g:testlist[-9:1])
!     assert_equal([1, 2, 3], g:testlist[1:-1])
!     assert_equal([1], g:testlist[1:-3])
!     assert_equal([], g:testlist[1:-4])
!     assert_equal([], g:testlist[1:-9])
! 
!     g:testdict = #{a: 1, b: 2}
!     assert_equal(1, g:testdict['a'])
!     assert_equal(2, g:testdict['b'])
!   END
! 
!   CheckDefSuccess(lines)
!   CheckScriptSuccess(['vim9script'] + lines)
! 
!   CheckDefExecFailure(['echo g:testblob[2]'], 'E979:')
!   CheckScriptFailure(['vim9script', 'echo g:testblob[2]'], 'E979:')
!   CheckDefExecFailure(['echo g:testblob[-3]'], 'E979:')
!   CheckScriptFailure(['vim9script', 'echo g:testblob[-3]'], 'E979:')
! 
!   CheckDefExecFailure(['echo g:testlist[4]'], 'E684:')
!   CheckScriptFailure(['vim9script', 'echo g:testlist[4]'], 'E684:')
!   CheckDefExecFailure(['echo g:testlist[-5]'], 'E684:')
!   CheckScriptFailure(['vim9script', 'echo g:testlist[-5]'], 'E684:')
! 
!   CheckDefExecFailure(['echo g:testdict["a":"b"]'], 'E719:')
!   CheckScriptFailure(['vim9script', 'echo g:testdict["a":"b"]'], 'E719:')
!   CheckDefExecFailure(['echo g:testdict[1]'], 'E716:')
!   CheckScriptFailure(['vim9script', 'echo g:testdict[1]'], 'E716:')
! 
!   unlet g:teststring
!   unlet g:testblob
!   unlet g:testlist
  enddef
  
  def Test_expr_member_vim9script()
*** ../vim-8.2.1465/src/testdir/test_vim9_disassemble.vim       2020-08-15 
22:14:49.055890417 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-08-16 17:31:10.234924598 
+0200
***************
*** 1091,1096 ****
--- 1091,1140 ----
    call assert_equal(1, DictMember())
  enddef
  
+ let somelist = [1, 2, 3, 4, 5]
+ def AnyIndex(): number
+   let res = g:somelist[2]
+   return res
+ enddef
+ 
+ def Test_disassemble_any_index()
+   let instr = execute('disassemble AnyIndex')
+   assert_match('AnyIndex\_s*' ..
+         'let res = g:somelist\[2\]\_s*' ..
+         '\d LOADG g:somelist\_s*' ..
+         '\d PUSHNR 2\_s*' ..
+         '\d ANYINDEX\_s*' ..
+         '\d STORE $0\_s*' ..
+         'return res\_s*' ..
+         '\d LOAD $0\_s*' ..
+         '\d CHECKTYPE number stack\[-1\]\_s*' ..
+         '\d RETURN',
+         instr)
+   assert_equal(3, AnyIndex())
+ enddef
+ 
+ def AnySlice(): list<number>
+   let res = g:somelist[1:3]
+   return res
+ enddef
+ 
+ def Test_disassemble_any_slice()
+   let instr = execute('disassemble AnySlice')
+   assert_match('AnySlice\_s*' ..
+         'let res = g:somelist\[1:3\]\_s*' ..
+         '\d LOADG g:somelist\_s*' ..
+         '\d PUSHNR 1\_s*' ..
+         '\d PUSHNR 3\_s*' ..
+         '\d ANYSLICE\_s*' ..
+         '\d STORE $0\_s*' ..
+         'return res\_s*' ..
+         '\d LOAD $0\_s*' ..
+         '\d CHECKTYPE list stack\[-1\]\_s*' ..
+         '\d RETURN',
+         instr)
+   assert_equal([2, 3, 4], AnySlice())
+ enddef
+ 
  def NegateNumber(): number
    let nr = 9
    let plus = +nr
*** ../vim-8.2.1465/src/testdir/test_vim9_script.vim    2020-08-16 
14:48:14.377965877 +0200
--- src/testdir/test_vim9_script.vim    2020-08-16 17:19:57.395933434 +0200
***************
*** 793,800 ****
    endtry
    assert_equal(99, n)
  
-   # TODO: this will change when index on "any" works
    try
      n = g:astring[3]
    catch /E1029:/
      n = 77
--- 793,800 ----
    endtry
    assert_equal(99, n)
  
    try
+     # string slice returns a string, not a number
      n = g:astring[3]
    catch /E1029:/
      n = 77
*** ../vim-8.2.1465/src/version.c       2020-08-16 14:48:14.377965877 +0200
--- src/version.c       2020-08-16 15:23:40.374474610 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1466,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
217. Your sex life has drastically improved...so what if it's only cyber-sex!

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202008161533.07GFXxqx600579%40masaka.moolenaar.net.

Raspunde prin e-mail lui