diff src/evalfunc.c @ 26737:10d3105030ab v8.2.3897

patch 8.2.3897: Vim9: second argument of map() and filter() not checked Commit: https://github.com/vim/vim/commit/1802405d71da20dff510690bf14f6da085836125 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Dec 25 21:43:28 2021 +0000 patch 8.2.3897: Vim9: second argument of map() and filter() not checked Problem: Vim9: the second argument of map() and filter() is not checked at compile time. Solution: Add more specific type check for the second argument.
author Bram Moolenaar <Bram@vim.org>
date Sat, 25 Dec 2021 22:45:02 +0100
parents 3aa38eaa5a11
children 59dde78e9436
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -486,6 +486,52 @@ arg_list_or_dict_or_blob_or_string(type_
 }
 
 /*
+ * Check second argument of filter(): func must return a bool.
+ */
+    static int
+arg_filter_func(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_FUNC
+	    && !(type->tt_member->tt_type == VAR_BOOL
+		|| type->tt_member->tt_type == VAR_NUMBER
+		|| type->tt_member->tt_type == VAR_ANY))
+    {
+	arg_type_mismatch(&t_func_bool, type, context->arg_idx + 1);
+	return FAIL;
+    }
+    return OK;
+}
+
+/*
+ * Check second argument of map().
+ */
+    static int
+arg_map_func(type_T *type, argcontext_T *context)
+{
+    if (type->tt_type == VAR_FUNC
+	    && type->tt_member != &t_any
+	    && type->tt_member != &t_unknown)
+    {
+	type_T *expected = NULL;
+
+	if (context->arg_types[0]->tt_type == VAR_LIST
+		|| context->arg_types[0]->tt_type == VAR_DICT)
+	    expected = context->arg_types[0]->tt_member;
+	else if (context->arg_types[0]->tt_type == VAR_STRING
+		|| context->arg_types[0]->tt_type == VAR_BLOB)
+	    expected = &t_number;
+	if (expected != NULL)
+	{
+	    type_T t_func_exp = {VAR_FUNC, -1, 0, TTFLAG_STATIC,
+							       expected, NULL};
+
+	    return check_arg_type(&t_func_exp, type, context);
+	}
+    }
+    return OK;
+}
+
+/*
  * Check "type" is a list of 'any' or a blob or a string.
  */
     static int
@@ -859,7 +905,9 @@ static argcheck_T arg23_insert[] = {arg_
 static argcheck_T arg1_len[] = {arg_len1};
 static argcheck_T arg3_libcall[] = {arg_string, arg_string, arg_string_or_nr};
 static argcheck_T arg14_maparg[] = {arg_string, arg_string, arg_bool, arg_bool};
-static argcheck_T arg2_mapfilter[] = {arg_list_or_dict_or_blob_or_string, NULL};
+static argcheck_T arg2_filter[] = {arg_list_or_dict_or_blob_or_string, arg_filter_func};
+static argcheck_T arg2_map[] = {arg_list_or_dict_or_blob_or_string, arg_map_func};
+static argcheck_T arg2_mapnew[] = {arg_list_or_dict_or_blob_or_string, NULL};
 static argcheck_T arg25_matchadd[] = {arg_string, arg_string, arg_number, arg_number, arg_dict_any};
 static argcheck_T arg25_matchaddpos[] = {arg_string, arg_list_any, arg_number, arg_number, arg_dict_any};
 static argcheck_T arg119_printf[] = {arg_string_or_nr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
@@ -1437,7 +1485,7 @@ static funcentry_T global_functions[] =
 			ret_number_bool,    f_filereadable},
     {"filewritable",	1, 1, FEARG_1,	    arg1_string,
 			ret_number,	    f_filewritable},
-    {"filter",		2, 2, FEARG_1,	    arg2_mapfilter,
+    {"filter",		2, 2, FEARG_1,	    arg2_filter,
 			ret_first_arg,	    f_filter},
     {"finddir",		1, 3, FEARG_1,	    arg3_string_string_number,
 			ret_finddir,	    f_finddir},
@@ -1703,13 +1751,13 @@ static funcentry_T global_functions[] =
 		NULL
 #endif
 			},
-    {"map",		2, 2, FEARG_1,	    arg2_mapfilter,
+    {"map",		2, 2, FEARG_1,	    arg2_map,
 			ret_first_cont,	    f_map},
     {"maparg",		1, 4, FEARG_1,	    arg14_maparg,
 			ret_maparg,	    f_maparg},
     {"mapcheck",	1, 3, FEARG_1,	    arg3_string_string_bool,
 			ret_string,	    f_mapcheck},
-    {"mapnew",		2, 2, FEARG_1,	    arg2_mapfilter,
+    {"mapnew",		2, 2, FEARG_1,	    arg2_mapnew,
 			ret_first_cont,	    f_mapnew},
     {"mapset",		3, 3, FEARG_1,	    arg3_string_bool_dict,
 			ret_void,	    f_mapset},