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 -- Br...@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 ///