Skip to content

Commit 70250fb

Browse files
committed
patch 8.2.2365: Vim9: no check for map() changing item type at script level
Problem: Vim9: no check for map() changing item type at script level. Solution: Check the new value type.
1 parent f898f7c commit 70250fb

4 files changed

Lines changed: 80 additions & 29 deletions

File tree

src/list.c

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,10 +1985,18 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
19851985
: N_("filter() argument"));
19861986
int save_did_emsg;
19871987
int idx = 0;
1988+
type_T *type = NULL;
1989+
garray_T type_list;
19881990

19891991
// map() and filter() return the first argument, also on failure.
19901992
if (filtermap != FILTERMAP_MAPNEW)
19911993
copy_tv(&argvars[0], rettv);
1994+
if (filtermap == FILTERMAP_MAP && in_vim9script())
1995+
{
1996+
// Check that map() does not change the type of the dict.
1997+
ga_init2(&type_list, sizeof(type_T *), 10);
1998+
type = typval2type(argvars, &type_list);
1999+
}
19922000

19932001
if (argvars[0].v_type == VAR_BLOB)
19942002
{
@@ -1998,7 +2006,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
19982006
rettv->vval.v_blob = NULL;
19992007
}
20002008
if ((b = argvars[0].vval.v_blob) == NULL)
2001-
return;
2009+
goto theend;
20022010
}
20032011
else if (argvars[0].v_type == VAR_LIST)
20042012
{
@@ -2010,7 +2018,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
20102018
if ((l = argvars[0].vval.v_list) == NULL
20112019
|| (filtermap == FILTERMAP_FILTER
20122020
&& value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
2013-
return;
2021+
goto theend;
20142022
}
20152023
else if (argvars[0].v_type == VAR_DICT)
20162024
{
@@ -2022,12 +2030,12 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
20222030
if ((d = argvars[0].vval.v_dict) == NULL
20232031
|| (filtermap == FILTERMAP_FILTER
20242032
&& value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
2025-
return;
2033+
goto theend;
20262034
}
20272035
else
20282036
{
20292037
semsg(_(e_listdictblobarg), ermsg);
2030-
return;
2038+
goto theend;
20312039
}
20322040

20332041
expr = &argvars[1];
@@ -2055,7 +2063,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
20552063
if (filtermap == FILTERMAP_MAPNEW)
20562064
{
20572065
if (rettv_dict_alloc(rettv) == FAIL)
2058-
return;
2066+
goto theend;
20592067
d_ret = rettv->vval.v_dict;
20602068
}
20612069

@@ -2090,6 +2098,12 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
20902098
}
20912099
if (filtermap == FILTERMAP_MAP)
20922100
{
2101+
if (type != NULL && check_typval_type(type->tt_member,
2102+
&newtv, 0) == FAIL)
2103+
{
2104+
clear_tv(&newtv);
2105+
break;
2106+
}
20932107
// map(): replace the dict item value
20942108
clear_tv(&di->di_tv);
20952109
newtv.v_lock = 0;
@@ -2126,7 +2140,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
21262140
if (filtermap == FILTERMAP_MAPNEW)
21272141
{
21282142
if (blob_copy(b, rettv) == FAIL)
2129-
return;
2143+
goto theend;
21302144
b_ret = rettv->vval.v_blob;
21312145
}
21322146

@@ -2175,7 +2189,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
21752189
if (filtermap == FILTERMAP_MAPNEW)
21762190
{
21772191
if (rettv_list_alloc(rettv) == FAIL)
2178-
return;
2192+
goto theend;
21792193
l_ret = rettv->vval.v_list;
21802194
}
21812195
// set_vim_var_nr() doesn't set the type
@@ -2218,6 +2232,13 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
22182232
}
22192233
if (filtermap != FILTERMAP_FILTER)
22202234
{
2235+
if (filtermap == FILTERMAP_MAP && type != NULL
2236+
&& check_typval_type(type->tt_member,
2237+
&newtv, 0) == FAIL)
2238+
{
2239+
clear_tv(&newtv);
2240+
break;
2241+
}
22212242
// map(), mapnew(): always append the new value to the
22222243
// list
22232244
if (list_append_tv_move(filtermap == FILTERMAP_MAP
@@ -2256,6 +2277,12 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
22562277
}
22572278
if (filtermap == FILTERMAP_MAP)
22582279
{
2280+
if (type != NULL && check_typval_type(type->tt_member,
2281+
&newtv, 0) == FAIL)
2282+
{
2283+
clear_tv(&newtv);
2284+
break;
2285+
}
22592286
// map(): replace the list item value
22602287
clear_tv(&li->li_tv);
22612288
newtv.v_lock = 0;
@@ -2281,6 +2308,10 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
22812308

22822309
did_emsg |= save_did_emsg;
22832310
}
2311+
2312+
theend:
2313+
if (type != NULL)
2314+
clear_type_list(&type_list);
22842315
}
22852316

22862317
/*

src/testdir/test_vim9_assign.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ def Test_var_list_dict_type()
13511351
var ll: list<number>
13521352
ll = [1, 2, 3]->map('"one"')
13531353
END
1354-
CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>')
1354+
CheckDefExecFailure(lines, 'E1012: Type mismatch; expected number but got string')
13551355
enddef
13561356

13571357
def Test_cannot_use_let()

src/testdir/test_vim9_builtin.vim

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -331,27 +331,6 @@ def Wrong_dict_key_type(items: list<number>): list<number>
331331
return filter(items, (_, val) => get({[val]: 1}, 'x'))
332332
enddef
333333

334-
def Test_map_function_arg()
335-
var lines =<< trim END
336-
def MapOne(i: number, v: string): string
337-
return i .. ':' .. v
338-
enddef
339-
var l = ['a', 'b', 'c']
340-
map(l, MapOne)
341-
assert_equal(['0:a', '1:b', '2:c'], l)
342-
END
343-
CheckDefAndScriptSuccess(lines)
344-
enddef
345-
346-
def Test_map_item_type()
347-
var lines =<< trim END
348-
var l = ['a', 'b', 'c']
349-
map(l, (k, v) => k .. '/' .. v )
350-
assert_equal(['0/a', '1/b', '2/c'], l)
351-
END
352-
CheckDefAndScriptSuccess(lines)
353-
enddef
354-
355334
def Test_filereadable()
356335
assert_false(filereadable(""))
357336
assert_false(filereadable(test_null_string()))
@@ -584,6 +563,45 @@ def SID(): number
584563
->str2nr()
585564
enddef
586565

566+
def Test_map_function_arg()
567+
var lines =<< trim END
568+
def MapOne(i: number, v: string): string
569+
return i .. ':' .. v
570+
enddef
571+
var l = ['a', 'b', 'c']
572+
map(l, MapOne)
573+
assert_equal(['0:a', '1:b', '2:c'], l)
574+
END
575+
CheckDefAndScriptSuccess(lines)
576+
enddef
577+
578+
def Test_map_item_type()
579+
var lines =<< trim END
580+
var l = ['a', 'b', 'c']
581+
map(l, (k, v) => k .. '/' .. v )
582+
assert_equal(['0/a', '1/b', '2/c'], l)
583+
END
584+
CheckDefAndScriptSuccess(lines)
585+
586+
lines =<< trim END
587+
var l: list<number> = [0]
588+
echo map(l, (_, v) => [])
589+
END
590+
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
591+
592+
lines =<< trim END
593+
var l: list<number> = range(2)
594+
echo map(l, (_, v) => [])
595+
END
596+
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
597+
598+
lines =<< trim END
599+
var d: dict<number> = {key: 0}
600+
echo map(d, (_, v) => [])
601+
END
602+
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
603+
enddef
604+
587605
def Test_maparg()
588606
var lnum = str2nr(expand('<sflnum>'))
589607
map foo bar

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2365,
753755
/**/
754756
2364,
755757
/**/

0 commit comments

Comments
 (0)