Patch 8.2.2362

4 views
Skip to first unread message

Bram Moolenaar

unread,
Jan 16, 2021, 10:07:36 AM1/16/21
to vim...@googlegroups.com

Patch 8.2.2362
Problem: Vim9: check of builtin function argument type is incomplete.
Solution: Use need_type() instead of check_arg_type().
Files: src/vim9compile.c, src/proto/vim9compile.pro, src/evalfunc.c,
src/proto/evalfunc.pro, src/vim9type.c, src/proto/vim9type.pro,
src/testdir/test_vim9_builtin.vim


*** ../vim-8.2.2361/src/vim9compile.c 2021-01-14 20:35:46.254002151 +0100
--- src/vim9compile.c 2021-01-16 15:56:19.864363365 +0100
***************
*** 878,888 ****
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
* generate a TYPECHECK.
*/
! static int
need_type(
type_T *actual,
type_T *expected,
int offset,
cctx_T *cctx,
int silent,
int actual_is_const)
--- 878,889 ----
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
* generate a TYPECHECK.
*/
! int
need_type(
type_T *actual,
type_T *expected,
int offset,
+ int arg_idx,
cctx_T *cctx,
int silent,
int actual_is_const)
***************
*** 896,902 ****
return OK;
}

! if (check_type(expected, actual, FALSE, 0) == OK)
return OK;

// If the actual type can be the expected type add a runtime check.
--- 897,903 ----
return OK;
}

! if (check_type(expected, actual, FALSE, arg_idx) == OK)
return OK;

// If the actual type can be the expected type add a runtime check.
***************
*** 908,914 ****
}

if (!silent)
! type_mismatch(expected, actual);
return FAIL;
}

--- 909,915 ----
}

if (!silent)
! arg_type_mismatch(expected, actual, arg_idx);
return FAIL;
}

***************
*** 931,937 ****
// This requires a runtime type check.
return generate_COND2BOOL(cctx);

! return need_type(type, &t_bool, -1, cctx, FALSE, FALSE);
}

/*
--- 932,938 ----
// This requires a runtime type check.
return generate_COND2BOOL(cctx);

! return need_type(type, &t_bool, -1, 0, cctx, FALSE, FALSE);
}

/*
***************
*** 1613,1619 ****
{
// Check the types of the arguments.
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;
--- 1614,1621 ----
{
// Check the types of the arguments.
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
! if (internal_func_check_arg_types(argtypes, func_idx, argcount,
! cctx) == FAIL)
return FAIL;
if (internal_func_is_map(func_idx))
maptype = *argtypes;
***************
*** 1656,1662 ****
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
expected = list_type->tt_member;
! if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL)
return FAIL;

if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
--- 1658,1664 ----
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
expected = list_type->tt_member;
! if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;

if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
***************
*** 1678,1684 ****

// Caller already checked that blob_type is a blob.
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
! if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
return FAIL;

if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
--- 1680,1686 ----

// Caller already checked that blob_type is a blob.
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
! if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;

if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
***************
*** 1733,1739 ****
else
expected = ufunc->uf_va_type->tt_member;
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
! if (need_type(actual, expected, -argcount + i, cctx,
TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
--- 1735,1741 ----
else
expected = ufunc->uf_va_type->tt_member;
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
! if (need_type(actual, expected, -argcount + i, 0, cctx,
TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
***************
*** 1850,1856 ****
type->tt_argcount - 1]->tt_member;
else
expected = type->tt_args[i];
! if (need_type(actual, expected, offset,
cctx, TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
--- 1852,1858 ----
type->tt_argcount - 1]->tt_member;
else
expected = type->tt_args[i];
! if (need_type(actual, expected, offset, 0,
cctx, TRUE, FALSE) == FAIL)
{
arg_type_mismatch(expected, actual, i + 1);
***************
*** 3135,3141 ****
{
type_T *keytype = ((type_T **)stack->ga_data)
[stack->ga_len - 1];
! if (need_type(keytype, &t_string, -1, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
--- 3137,3143 ----
{
type_T *keytype = ((type_T **)stack->ga_data)
[stack->ga_len - 1];
! if (need_type(keytype, &t_string, -1, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
***************
*** 3808,3820 ****
vtype = VAR_DICT;
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
{
! if (need_type(valtype, &t_number, -1, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
if (is_slice)
{
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
! if (need_type(valtype, &t_number, -2, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
--- 3810,3822 ----
vtype = VAR_DICT;
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
{
! if (need_type(valtype, &t_number, -1, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
if (is_slice)
{
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
! if (need_type(valtype, &t_number, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
***************
*** 3836,3842 ****
}
else
{
! if (need_type(*typep, &t_dict_any, -2, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
*typep = &t_any;
--- 3838,3844 ----
}
else
{
! if (need_type(*typep, &t_dict_any, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
*typep = &t_any;
***************
*** 4235,4241 ****
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (check_type(want_type, actual, FALSE, 0) == FAIL)
{
! if (need_type(actual, want_type, -1, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
}
--- 4237,4243 ----
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (check_type(want_type, actual, FALSE, 0) == FAIL)
{
! if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
}
***************
*** 4917,4923 ****
return NULL;
}
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
! cctx, FALSE, FALSE) == FAIL)
return NULL;
}
}
--- 4919,4925 ----
return NULL;
}
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
! 0, cctx, FALSE, FALSE) == FAIL)
return NULL;
}
}
***************
*** 5831,5837 ****
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
// now we can properly check the type
if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
! && need_type(rhs_type, lhs->lhs_type->tt_member, -2, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
--- 5833,5839 ----
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
// now we can properly check the type
if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
! && need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
}
***************
*** 5976,5982 ****
emsg(_(e_cannot_use_void_value));
goto theend;
}
! if (need_type(stacktype, &t_list_any, -1, cctx,
FALSE, FALSE) == FAIL)
goto theend;
// TODO: check the length of a constant list here
--- 5978,5984 ----
emsg(_(e_cannot_use_void_value));
goto theend;
}
! if (need_type(stacktype, &t_list_any, -1, 0, cctx,
FALSE, FALSE) == FAIL)
goto theend;
// TODO: check the length of a constant list here
***************
*** 6123,6135 ****
// without operator check type here, otherwise below
if (lhs.lhs_has_index)
use_type = lhs.lhs_member_type;
! if (need_type(rhs_type, use_type, -1, cctx,
FALSE, is_const) == FAIL)
goto theend;
}
}
else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
! -1, cctx, FALSE, FALSE) == FAIL)
goto theend;
}
else if (cmdidx == CMD_final)
--- 6125,6137 ----
// without operator check type here, otherwise below
if (lhs.lhs_has_index)
use_type = lhs.lhs_member_type;
! if (need_type(rhs_type, use_type, -1, 0, cctx,
FALSE, is_const) == FAIL)
goto theend;
}
}
else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
! -1, 0, cctx, FALSE, FALSE) == FAIL)
goto theend;
}
else if (cmdidx == CMD_final)
***************
*** 6216,6222 ****
// If variable is float operation with number is OK.
!(expected == &t_float && stacktype == &t_number) &&
#endif
! need_type(stacktype, expected, -1, cctx,
FALSE, FALSE) == FAIL)
goto theend;

--- 6218,6224 ----
// If variable is float operation with number is OK.
!(expected == &t_float && stacktype == &t_number) &&
#endif
! need_type(stacktype, expected, -1, 0, cctx,
FALSE, FALSE) == FAIL)
goto theend;

***************
*** 6925,6931 ****
// Now that we know the type of "var", check that it is a list, now or at
// runtime.
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
! if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL)
{
drop_scope(cctx);
return NULL;
--- 6927,6933 ----
// Now that we know the type of "var", check that it is a list, now or at
// runtime.
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
! if (need_type(vartype, &t_list_any, -1, 0, cctx, FALSE, FALSE) == FAIL)
{
drop_scope(cctx);
return NULL;
*** ../vim-8.2.2361/src/proto/vim9compile.pro 2021-01-09 15:45:20.353451132 +0100
--- src/proto/vim9compile.pro 2021-01-16 15:41:13.938984124 +0100
***************
*** 2,7 ****
--- 2,8 ----
int check_defined(char_u *p, size_t len, cctx_T *cctx);
int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
int use_typecheck(type_T *actual, type_T *expected);
+ int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx);
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
*** ../vim-8.2.2361/src/evalfunc.c 2021-01-13 21:46:53.832589880 +0100
--- src/evalfunc.c 2021-01-16 15:59:15.951901386 +0100
***************
*** 275,280 ****
--- 275,281 ----
int arg_count; // actual argument count
type_T **arg_types; // list of argument types
int arg_idx; // current argument index (first arg is zero)
+ cctx_T *arg_cctx;
} argcontext_T;

// A function to check one argument type. The first argument is the type to
***************
*** 283,288 ****
--- 284,305 ----
typedef int (*argcheck_T)(type_T *, argcontext_T *);

/*
+ * Call need_type() to check an argument type.
+ */
+ static int
+ check_arg_type(
+ type_T *expected,
+ type_T *actual,
+ argcontext_T *context)
+ {
+ // TODO: would be useful to know if "actual" is a constant and pass it to
+ // need_type() to get a compile time error if possible.
+ return need_type(actual, expected,
+ context->arg_idx - context->arg_count, context->arg_idx + 1,
+ context->arg_cctx, FALSE, FALSE);
+ }
+
+ /*
* Check "type" is a float or a number.
*/
static int
***************
*** 301,307 ****
static int
arg_number(type_T *type, argcontext_T *context)
{
! return check_arg_type(&t_number, type, context->arg_idx + 1);
}

/*
--- 318,324 ----
static int
arg_number(type_T *type, argcontext_T *context)
{
! return check_arg_type(&t_number, type, context);
}

/*
***************
*** 310,316 ****
static int
arg_string(type_T *type, argcontext_T *context)
{
! return check_arg_type(&t_string, type, context->arg_idx + 1);
}

/*
--- 327,333 ----
static int
arg_string(type_T *type, argcontext_T *context)
{
! return check_arg_type(&t_string, type, context);
}

/*
***************
*** 348,354 ****
{
type_T *prev_type = context->arg_types[context->arg_idx - 1];

! return check_arg_type(prev_type, type, context->arg_idx + 1);
}

/*
--- 365,371 ----
{
type_T *prev_type = context->arg_types[context->arg_idx - 1];

! return check_arg_type(prev_type, type, context);
}

/*
***************
*** 362,368 ****
type_T *prev_type = context->arg_types[context->arg_idx - 1];

if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
! return check_arg_type(prev_type, type, context->arg_idx + 1);
return OK;
}

--- 379,385 ----
type_T *prev_type = context->arg_types[context->arg_idx - 1];

if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
! return check_arg_type(prev_type, type, context);
return OK;
}

***************
*** 384,390 ****
// probably VAR_ANY, can't check
return OK;

! return check_arg_type(expected, type, context->arg_idx + 1);
}

/*
--- 401,407 ----
// probably VAR_ANY, can't check
return OK;

! return check_arg_type(expected, type, context);
}

/*
***************
*** 1931,1937 ****
* Return FAIL and gives an error message when a type is wrong.
*/
int
! internal_func_check_arg_types(type_T **types, int idx, int argcount)
{
argcheck_T *argchecks = global_functions[idx].f_argcheck;
int i;
--- 1948,1958 ----
* Return FAIL and gives an error message when a type is wrong.
*/
int
! internal_func_check_arg_types(
! type_T **types,
! int idx,
! int argcount,
! cctx_T *cctx)
{
argcheck_T *argchecks = global_functions[idx].f_argcheck;
int i;
***************
*** 1942,1947 ****
--- 1963,1969 ----

context.arg_count = argcount;
context.arg_types = types;
+ context.arg_cctx = cctx;
for (i = 0; i < argcount; ++i)
if (argchecks[i] != NULL)
{
*** ../vim-8.2.2361/src/proto/evalfunc.pro 2021-01-10 22:42:46.916847071 +0100
--- src/proto/evalfunc.pro 2021-01-16 15:48:51.973585991 +0100
***************
*** 4,10 ****
int find_internal_func(char_u *name);
int has_internal_func(char_u *name);
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);
--- 4,10 ----
int find_internal_func(char_u *name);
int has_internal_func(char_u *name);
char *internal_func_name(int idx);
! int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx);
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);
*** ../vim-8.2.2361/src/vim9type.c 2021-01-12 21:48:55.879131998 +0100
--- src/vim9type.c 2021-01-16 15:55:18.936525110 +0100
***************
*** 514,538 ****
}

/*
- * Like check_type() but also allow for a runtime type check. E.g. "any" can be
- * used for "number".
- */
- int
- check_arg_type(type_T *expected, type_T *actual, int argidx)
- {
- if (check_type(expected, actual, FALSE, 0) == OK
- || use_typecheck(actual, expected))
- return OK;
- // TODO: should generate a TYPECHECK instruction.
- return check_type(expected, actual, TRUE, argidx);
- }
-
- /*
* Check that the arguments of "type" match "argvars[argcount]".
* Return OK/FAIL.
*/
int
! check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u *name)
{
int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
int i;
--- 514,528 ----
}

/*
* Check that the arguments of "type" match "argvars[argcount]".
* Return OK/FAIL.
*/
int
! check_argument_types(
! type_T *type,
! typval_T *argvars,
! int argcount,
! char_u *name)
{
int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
int i;
*** ../vim-8.2.2361/src/proto/vim9type.pro 2021-01-12 21:48:55.879131998 +0100
--- src/proto/vim9type.pro 2021-01-16 15:48:56.185574013 +0100
***************
*** 15,21 ****
void type_mismatch(type_T *expected, type_T *actual);
void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
int check_type(type_T *expected, type_T *actual, int give_msg, int argidx);
- int check_arg_type(type_T *expected, type_T *actual, int argidx);
int check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u *name);
char_u *skip_type(char_u *start, int optional);
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
--- 15,20 ----
*** ../vim-8.2.2361/src/testdir/test_vim9_builtin.vim 2021-01-13 21:46:53.832589880 +0100
--- src/testdir/test_vim9_builtin.vim 2021-01-16 16:04:27.403098215 +0100
***************
*** 241,246 ****
--- 241,249 ----
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')
+
+ CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
+ CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1012: Type mismatch; expected list<number> but got list<any>')
enddef

def Test_extendnew()
*** ../vim-8.2.2361/src/version.c 2021-01-16 14:34:42.219758927 +0100
--- src/version.c 2021-01-16 15:34:23.844532727 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2362,
/**/

--
hundred-and-one symptoms of being an internet addict:
164. You got out to buy software, instead of going out for a beer.

/// 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 ///
Reply all
Reply to author
Forward
0 new messages