mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.1931: Vim9: arguments of extend() not checked at compile time
Problem: Vim9: arguments of extend() not checked at compile time. Solution: Add argument type checking for extend().
This commit is contained in:
@@ -276,6 +276,9 @@ typedef struct {
|
|||||||
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
|
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
|
||||||
typedef int (*argcheck_T)(type_T *, argcontext_T *);
|
typedef int (*argcheck_T)(type_T *, argcontext_T *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a float or a number.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
arg_float_or_nr(type_T *type, argcontext_T *context)
|
arg_float_or_nr(type_T *type, argcontext_T *context)
|
||||||
{
|
{
|
||||||
@@ -286,12 +289,27 @@ arg_float_or_nr(type_T *type, argcontext_T *context)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a number.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
arg_number(type_T *type, argcontext_T *context)
|
arg_number(type_T *type, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_type(&t_number, type, TRUE, context->arg_idx + 1);
|
return check_type(&t_number, type, TRUE, context->arg_idx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a string.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_string(type_T *type, argcontext_T *context)
|
||||||
|
{
|
||||||
|
return check_type(&t_string, type, TRUE, context->arg_idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a list or a blob.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_or_blob(type_T *type, argcontext_T *context)
|
arg_list_or_blob(type_T *type, argcontext_T *context)
|
||||||
{
|
{
|
||||||
@@ -303,7 +321,32 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the type is an item of the list or blob of the previous arg.
|
* Check "type" is a list or a dict.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_list_or_dict(type_T *type, argcontext_T *context)
|
||||||
|
{
|
||||||
|
if (type->tt_type == VAR_ANY
|
||||||
|
|| type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
|
||||||
|
return OK;
|
||||||
|
arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is the same type as the previous argument
|
||||||
|
* Must not be used for the first argcheck_T entry.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_same_as_prev(type_T *type, argcontext_T *context)
|
||||||
|
{
|
||||||
|
type_T *prev_type = context->arg_types[context->arg_idx - 1];
|
||||||
|
|
||||||
|
return check_type(prev_type, type, TRUE, context->arg_idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is an item of the list or blob of the previous arg.
|
||||||
* Must not be used for the first argcheck_T entry.
|
* Must not be used for the first argcheck_T entry.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@@ -323,10 +366,28 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
|
|||||||
return check_type(expected, type, TRUE, context->arg_idx + 1);
|
return check_type(expected, type, TRUE, context->arg_idx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" which is the third argument of extend().
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_extend3(type_T *type, argcontext_T *context)
|
||||||
|
{
|
||||||
|
type_T *first_type = context->arg_types[context->arg_idx - 2];
|
||||||
|
|
||||||
|
if (first_type->tt_type == VAR_LIST)
|
||||||
|
return arg_number(type, context);
|
||||||
|
if (first_type->tt_type == VAR_DICT)
|
||||||
|
return arg_string(type, context);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lists of functions that check the argument types of a builtin function.
|
* Lists of functions that check the argument types of a builtin function.
|
||||||
*/
|
*/
|
||||||
argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
|
argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
|
||||||
|
argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
|
||||||
|
argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
|
||||||
argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
|
argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -567,7 +628,7 @@ static funcentry_T global_functions[] =
|
|||||||
ret_any, FLOAT_FUNC(f_abs)},
|
ret_any, FLOAT_FUNC(f_abs)},
|
||||||
{"acos", 1, 1, FEARG_1, NULL,
|
{"acos", 1, 1, FEARG_1, NULL,
|
||||||
ret_float, FLOAT_FUNC(f_acos)},
|
ret_float, FLOAT_FUNC(f_acos)},
|
||||||
{"add", 2, 2, FEARG_1, NULL,
|
{"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */,
|
||||||
ret_first_arg, f_add},
|
ret_first_arg, f_add},
|
||||||
{"and", 2, 2, FEARG_1, NULL,
|
{"and", 2, 2, FEARG_1, NULL,
|
||||||
ret_number, f_and},
|
ret_number, f_and},
|
||||||
@@ -793,7 +854,7 @@ static funcentry_T global_functions[] =
|
|||||||
ret_any, f_expand},
|
ret_any, f_expand},
|
||||||
{"expandcmd", 1, 1, FEARG_1, NULL,
|
{"expandcmd", 1, 1, FEARG_1, NULL,
|
||||||
ret_string, f_expandcmd},
|
ret_string, f_expandcmd},
|
||||||
{"extend", 2, 3, FEARG_1, NULL,
|
{"extend", 2, 3, FEARG_1, arg23_extend,
|
||||||
ret_first_arg, f_extend},
|
ret_first_arg, f_extend},
|
||||||
{"feedkeys", 1, 2, FEARG_1, NULL,
|
{"feedkeys", 1, 2, FEARG_1, NULL,
|
||||||
ret_void, f_feedkeys},
|
ret_void, f_feedkeys},
|
||||||
|
@@ -191,6 +191,24 @@ def Test_expand()
|
|||||||
close
|
close
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_extend_arg_types()
|
||||||
|
assert_equal([1, 2, 3], extend([1, 2], [3]))
|
||||||
|
assert_equal([3, 1, 2], extend([1, 2], [3], 0))
|
||||||
|
assert_equal([1, 3, 2], extend([1, 2], [3], 1))
|
||||||
|
|
||||||
|
assert_equal(#{a: 1, b: 2, c: 3}, extend(#{a: 1, b: 2}, #{c: 3}))
|
||||||
|
assert_equal(#{a: 1, b: 4}, extend(#{a: 1, b: 2}, #{b: 4}))
|
||||||
|
assert_equal(#{a: 1, b: 2}, extend(#{a: 1, b: 2}, #{b: 4}, 'keep'))
|
||||||
|
|
||||||
|
CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, expected list<number> but got number')
|
||||||
|
CheckDefFailure(['extend([1, 2], ["x"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
|
||||||
|
CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
|
||||||
|
|
||||||
|
CheckDefFailure(['extend(#{a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
|
||||||
|
CheckDefFailure(['extend(#{a: 1}, #{b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
|
||||||
|
CheckDefFailure(['extend(#{a: 1}, #{b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_extend_return_type()
|
def Test_extend_return_type()
|
||||||
var l = extend([1, 2], [3])
|
var l = extend([1, 2], [3])
|
||||||
var res = 0
|
var res = 0
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1931,
|
||||||
/**/
|
/**/
|
||||||
1930,
|
1930,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user