Patch 8.2.2325
Problem:    Vim9: crash if map() changes the item type.
Solution:   Check that the item type is still OK. (closes #7652)
            Fix problem with mapnew() on range list.
Files:      src/evalfunc.c, src/proto/evalfunc.pro, src/vim9compile.c,
            src/list.c, src/testdir/test_vim9_builtin.vim,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_func.vim


*** ../vim-8.2.2324/src/evalfunc.c      2021-01-10 20:22:20.763926913 +0100
--- src/evalfunc.c      2021-01-10 21:52:46.893315360 +0100
***************
*** 1930,1935 ****
--- 1930,1944 ----
  }
  
  /*
+  * Return TRUE if "idx" is for the map() function.
+  */
+     int
+ internal_func_is_map(int idx)
+ {
+     return global_functions[idx].f_func == f_map;
+ }
+ 
+ /*
   * Check the argument count to use for internal function "idx".
   * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
   * first argument, 2 if method base is second argument, etc.  9 if method base
*** ../vim-8.2.2324/src/proto/evalfunc.pro      2020-11-08 12:49:43.120372854 
+0100
--- src/proto/evalfunc.pro      2021-01-10 21:52:50.661305593 +0100
***************
*** 6,11 ****
--- 6,12 ----
  char *internal_func_name(int idx);
  int internal_func_check_arg_types(type_T **types, int idx, int argcount);
  type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
+ int internal_func_is_map(int idx);
  int check_internal_func(int idx, int argcount);
  int call_internal_func(char_u *name, int argcount, typval_T *argvars, 
typval_T *rettv);
  void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv);
*** ../vim-8.2.2324/src/vim9compile.c   2021-01-10 19:23:23.352958354 +0100
--- src/vim9compile.c   2021-01-10 21:53:21.017226887 +0100
***************
*** 1592,1597 ****
--- 1592,1598 ----
      garray_T  *stack = &cctx->ctx_type_stack;
      int               argoff;
      type_T    **argtypes = NULL;
+     type_T    *maptype = NULL;
  
      RETURN_OK_IF_SKIP(cctx);
      argoff = check_internal_func(func_idx, argcount);
***************
*** 1612,1617 ****
--- 1613,1620 ----
        argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
        if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
            return FAIL;
+       if (internal_func_is_map(func_idx))
+           maptype = *argtypes;
      }
  
      if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
***************
*** 1627,1632 ****
--- 1630,1640 ----
                          internal_func_ret_type(func_idx, argcount, argtypes);
      ++stack->ga_len;
  
+     if (maptype != NULL && maptype->tt_member != NULL
+                                              && maptype->tt_member != &t_any)
+       // Check that map() didn't change the item types.
+       generate_TYPECHECK(cctx, maptype, -1);
+ 
      return OK;
  }
  
*** ../vim-8.2.2324/src/list.c  2021-01-09 13:20:32.200472552 +0100
--- src/list.c  2021-01-10 22:33:58.382050386 +0100
***************
*** 2188,2197 ****
                int             stride = l->lv_u.nonmat.lv_stride;
  
                // List from range(): loop over the numbers
!               l->lv_first = NULL;
!               l->lv_u.mat.lv_last = NULL;
!               l->lv_len = 0;
!               l->lv_u.mat.lv_idx_item = NULL;
  
                for (idx = 0; idx < len; ++idx)
                {
--- 2188,2200 ----
                int             stride = l->lv_u.nonmat.lv_stride;
  
                // List from range(): loop over the numbers
!               if (filtermap != FILTERMAP_MAPNEW)
!               {
!                   l->lv_first = NULL;
!                   l->lv_u.mat.lv_last = NULL;
!                   l->lv_len = 0;
!                   l->lv_u.mat.lv_idx_item = NULL;
!               }
  
                for (idx = 0; idx < len; ++idx)
                {
*** ../vim-8.2.2324/src/testdir/test_vim9_builtin.vim   2021-01-07 
20:23:29.842515296 +0100
--- src/testdir/test_vim9_builtin.vim   2021-01-10 22:01:52.191433608 +0100
***************
*** 231,237 ****
    assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, s:string_keep))
  
    var res: list<dict<any>>
!   extend(res, map([1, 2], (_, v) => ({})))
    assert_equal([{}, {}], res)
  
    CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, 
expected list<number> but got number')
--- 231,237 ----
    assert_equal({a: 1, b: 2}, extend({a: 1, b: 2}, {b: 4}, s:string_keep))
  
    var res: list<dict<any>>
!   extend(res, mapnew([1, 2], (_, v) => ({})))
    assert_equal([{}, {}], res)
  
    CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, 
expected list<number> but got number')
***************
*** 320,325 ****
--- 320,334 ----
    CheckDefAndScriptSuccess(lines)
  enddef
  
+ def Test_map_item_type()
+   var lines =<< trim END
+       var l = ['a', 'b', 'c']
+       map(l, (k, v) => k .. '/' .. v )
+       assert_equal(['0/a', '1/b', '2/c'], l)
+   END
+   CheckDefAndScriptSuccess(lines)
+ enddef
+ 
  def Test_filereadable()
    assert_false(filereadable(""))
    assert_false(filereadable(test_null_string()))
***************
*** 728,734 ****
  
  def Test_submatch()
    var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
!   var Rep = () => range(10)->map((_, v) => submatch(v, true))->string()
    var actual = substitute('A123456789', pat, Rep, '')
    var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], 
['7'], ['8'], ['9']]"
    actual->assert_equal(expected)
--- 737,743 ----
  
  def Test_submatch()
    var pat = 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)'
!   var Rep = () => range(10)->mapnew((_, v) => submatch(v, true))->string()
    var actual = substitute('A123456789', pat, Rep, '')
    var expected = "[['A123456789'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], 
['7'], ['8'], ['9']]"
    actual->assert_equal(expected)
*** ../vim-8.2.2324/src/testdir/test_vim9_expr.vim      2021-01-10 
19:23:23.352958354 +0100
--- src/testdir/test_vim9_expr.vim      2021-01-10 22:42:25.212899527 +0100
***************
*** 1859,1868 ****
  
        # line continuation inside lambda with "cond ? expr : expr" works
        var ll = range(3)
!       map(ll, (k, v) => v % 2 ? {
                  ['111']: 111 } : {}
              )
!       assert_equal([{}, {111: 111}, {}], ll)
  
        ll = range(3)
        map(ll, (k, v) => v == 8 || v
--- 1859,1868 ----
  
        # line continuation inside lambda with "cond ? expr : expr" works
        var ll = range(3)
!       var dll = mapnew(ll, (k, v) => v % 2 ? {
                  ['111']: 111 } : {}
              )
!       assert_equal([{}, {111: 111}, {}], dll)
  
        ll = range(3)
        map(ll, (k, v) => v == 8 || v
***************
*** 1946,1955 ****
  
        # line continuation inside lambda with "cond ? expr : expr" works
        var ll = range(3)
!       map(ll, (k, v) => v % 2 ? {
                  ['111']: 111 } : {}
              )
!       assert_equal([{}, {111: 111}, {}], ll)
  
        ll = range(3)
        map(ll, (k, v) => v == 8 || v
--- 1946,1955 ----
  
        # line continuation inside lambda with "cond ? expr : expr" works
        var ll = range(3)
!       var dll = mapnew(ll, (k, v) => v % 2 ? {
                  ['111']: 111 } : {}
              )
!       assert_equal([{}, {111: 111}, {}], dll)
  
        ll = range(3)
        map(ll, (k, v) => v == 8 || v
***************
*** 2964,2988 ****
    var range = range(
                3)
    var l = range
!       ->map('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
!       ->map('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range # comment
!       ->map('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
  
!       ->map('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
        # comment
!       ->map('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    assert_equal('1', l[
--- 2964,2988 ----
    var range = range(
                3)
    var l = range
!       ->mapnew('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
!       ->mapnew('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range # comment
!       ->mapnew('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
  
!       ->mapnew('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    l = range
        # comment
!       ->mapnew('string(v:key)')
    assert_equal(['0', '1', '2'], l)
  
    assert_equal('1', l[
*** ../vim-8.2.2324/src/testdir/test_vim9_func.vim      2021-01-10 
18:33:08.011683523 +0100
--- src/testdir/test_vim9_func.vim      2021-01-10 22:39:30.681313837 +0100
***************
*** 1763,1769 ****
  
  def Shadowed(): list<number>
    var FuncList: list<func: number> = [() => 42]
!   return FuncList->map((_, Shadowed) => Shadowed())
  enddef
  
  def Test_lambda_arg_shadows_func()
--- 1763,1769 ----
  
  def Shadowed(): list<number>
    var FuncList: list<func: number> = [() => 42]
!   return FuncList->mapnew((_, Shadowed) => Shadowed())
  enddef
  
  def Test_lambda_arg_shadows_func()
***************
*** 1792,1798 ****
  
  def Line_continuation_in_lambda(): list<string>
    var x = range(97, 100)
!       ->map((_, v) => nr2char(v)
            ->toupper())
        ->reverse()
    return x
--- 1792,1798 ----
  
  def Line_continuation_in_lambda(): list<string>
    var x = range(97, 100)
!       ->mapnew((_, v) => nr2char(v)
            ->toupper())
        ->reverse()
    return x
***************
*** 1908,1914 ****
  enddef
  
  def TreeWalk(dir: string): list<any>
!   return readdir(dir)->map((_, val) =>
              fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
                 ? {[val]: TreeWalk(dir .. '/' .. val)}
                 : val
--- 1908,1914 ----
  enddef
  
  def TreeWalk(dir: string): list<any>
!   return readdir(dir)->mapnew((_, val) =>
              fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
                 ? {[val]: TreeWalk(dir .. '/' .. val)}
                 : val
*** ../vim-8.2.2324/src/version.c       2021-01-10 20:22:20.767926906 +0100
--- src/version.c       2021-01-10 21:40:02.739257436 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2325,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
122. You ask if the Netaholics Anonymous t-shirt you ordered can be
     sent to you via e-mail.

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202101102143.10ALhFiP459405%40masaka.moolenaar.net.

Raspunde prin e-mail lui