mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.3200: Vim9: hard to guess where a type error is given
Problem: Vim9: hard to guess where a type error is given. Solution: Add the function name where possible. (closes #8608)
This commit is contained in:
@@ -1073,7 +1073,7 @@ failret:
|
||||
* Otherwise duplicate keys are ignored ("action" is "keep").
|
||||
*/
|
||||
void
|
||||
dict_extend(dict_T *d1, dict_T *d2, char_u *action)
|
||||
dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name)
|
||||
{
|
||||
dictitem_T *di1;
|
||||
hashitem_T *hi2;
|
||||
@@ -1106,8 +1106,8 @@ dict_extend(dict_T *d1, dict_T *d2, char_u *action)
|
||||
}
|
||||
|
||||
if (type != NULL
|
||||
&& check_typval_arg_type(type, &HI2DI(hi2)->di_tv, 0)
|
||||
== FAIL)
|
||||
&& check_typval_arg_type(type, &HI2DI(hi2)->di_tv,
|
||||
func_name, 0) == FAIL)
|
||||
break;
|
||||
|
||||
if (di1 == NULL)
|
||||
|
@@ -192,8 +192,12 @@ EXTERN char e_name_too_long_str[]
|
||||
INIT(= N_("E1011: Name too long: %s"));
|
||||
EXTERN char e_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1012: Type mismatch; expected %s but got %s"));
|
||||
EXTERN char e_type_mismatch_expected_str_but_got_str_in_str[]
|
||||
INIT(= N_("E1012: Type mismatch; expected %s but got %s in %s"));
|
||||
EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1013: Argument %d: type mismatch, expected %s but got %s"));
|
||||
EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str_in_str[]
|
||||
INIT(= N_("E1013: Argument %d: type mismatch, expected %s but got %s in %s"));
|
||||
EXTERN char e_invalid_key_str[]
|
||||
INIT(= N_("E1014: Invalid key: %s"));
|
||||
EXTERN char e_name_expected_str[]
|
||||
@@ -494,6 +498,8 @@ EXTERN char e_register_name_must_be_one_char_str[]
|
||||
INIT(= N_("E1162: Register name must be one character: %s"));
|
||||
EXTERN char e_variable_nr_type_mismatch_expected_str_but_got_str[]
|
||||
INIT(= N_("E1163: Variable %d: type mismatch, expected %s but got %s"));
|
||||
EXTERN char e_variable_nr_type_mismatch_expected_str_but_got_str_in_str[]
|
||||
INIT(= N_("E1163: Variable %d: type mismatch, expected %s but got %s in %s"));
|
||||
EXTERN char e_vim9cmd_must_be_followed_by_command[]
|
||||
INIT(= N_("E1164: vim9cmd must be followed by a command"));
|
||||
EXTERN char e_cannot_use_range_with_assignment_str[]
|
||||
|
@@ -1365,8 +1365,8 @@ set_var_lval(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lp->ll_type != NULL
|
||||
&& check_typval_arg_type(lp->ll_type, rettv, 0) == FAIL)
|
||||
if (lp->ll_type != NULL && check_typval_arg_type(lp->ll_type, rettv,
|
||||
NULL, 0) == FAIL)
|
||||
return;
|
||||
set_var_const(lp->ll_name, lp->ll_type, rettv, copy,
|
||||
flags, var_idx);
|
||||
@@ -1450,7 +1450,8 @@ set_var_lval(
|
||||
}
|
||||
|
||||
if (lp->ll_valtype != NULL
|
||||
&& check_typval_arg_type(lp->ll_valtype, rettv, 0) == FAIL)
|
||||
&& check_typval_arg_type(lp->ll_valtype, rettv,
|
||||
NULL, 0) == FAIL)
|
||||
return;
|
||||
|
||||
if (lp->ll_newkey != NULL)
|
||||
|
@@ -2043,7 +2043,7 @@ DictionaryUpdate(DictionaryObject *self, PyObject *args, PyObject *kwargs)
|
||||
return NULL;
|
||||
|
||||
VimTryStart();
|
||||
dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force");
|
||||
dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force", NULL);
|
||||
clear_tv(&tv);
|
||||
if (VimTryEnd())
|
||||
return NULL;
|
||||
|
31
src/list.c
31
src/list.c
@@ -605,7 +605,8 @@ list_append_tv(list_T *l, typval_T *tv)
|
||||
listitem_T *li;
|
||||
|
||||
if (l->lv_type != NULL && l->lv_type->tt_member != NULL
|
||||
&& check_typval_arg_type(l->lv_type->tt_member, tv, 0) == FAIL)
|
||||
&& check_typval_arg_type(l->lv_type->tt_member, tv,
|
||||
NULL, 0) == FAIL)
|
||||
return FAIL;
|
||||
li = listitem_alloc();
|
||||
if (li == NULL)
|
||||
@@ -722,7 +723,8 @@ list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
|
||||
listitem_T *ni;
|
||||
|
||||
if (l->lv_type != NULL && l->lv_type->tt_member != NULL
|
||||
&& check_typval_arg_type(l->lv_type->tt_member, tv, 0) == FAIL)
|
||||
&& check_typval_arg_type(l->lv_type->tt_member, tv,
|
||||
NULL, 0) == FAIL)
|
||||
return FAIL;
|
||||
ni = listitem_alloc();
|
||||
if (ni == NULL)
|
||||
@@ -2085,9 +2087,9 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||
blob_T *b = NULL;
|
||||
int rem;
|
||||
int todo;
|
||||
char_u *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()"
|
||||
char *func_name = filtermap == FILTERMAP_MAP ? "map()"
|
||||
: filtermap == FILTERMAP_MAPNEW ? "mapnew()"
|
||||
: "filter()");
|
||||
: "filter()";
|
||||
char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP
|
||||
? N_("map() argument")
|
||||
: filtermap == FILTERMAP_MAPNEW
|
||||
@@ -2144,7 +2146,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||
}
|
||||
else
|
||||
{
|
||||
semsg(_(e_listdictblobarg), ermsg);
|
||||
semsg(_(e_listdictblobarg), func_name);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
@@ -2210,7 +2212,8 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||
if (filtermap == FILTERMAP_MAP)
|
||||
{
|
||||
if (type != NULL && check_typval_arg_type(
|
||||
type->tt_member, &newtv, 0) == FAIL)
|
||||
type->tt_member, &newtv,
|
||||
func_name, 0) == FAIL)
|
||||
{
|
||||
clear_tv(&newtv);
|
||||
break;
|
||||
@@ -2345,7 +2348,8 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||
{
|
||||
if (filtermap == FILTERMAP_MAP && type != NULL
|
||||
&& check_typval_arg_type(
|
||||
type->tt_member, &newtv, 0) == FAIL)
|
||||
type->tt_member, &newtv,
|
||||
func_name, 0) == FAIL)
|
||||
{
|
||||
clear_tv(&newtv);
|
||||
break;
|
||||
@@ -2389,7 +2393,7 @@ filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||
if (filtermap == FILTERMAP_MAP)
|
||||
{
|
||||
if (type != NULL && check_typval_arg_type(
|
||||
type->tt_member, &newtv, 0) == FAIL)
|
||||
type->tt_member, &newtv, func_name, 0) == FAIL)
|
||||
{
|
||||
clear_tv(&newtv);
|
||||
break;
|
||||
@@ -2627,6 +2631,7 @@ extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
|
||||
{
|
||||
type_T *type = NULL;
|
||||
garray_T type_list;
|
||||
char *func_name = is_new ? "extendnew()" : "extend()";
|
||||
|
||||
if (!is_new && in_vim9script())
|
||||
{
|
||||
@@ -2680,7 +2685,7 @@ extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
|
||||
else
|
||||
item = NULL;
|
||||
if (type != NULL && check_typval_arg_type(
|
||||
type, &argvars[1], 2) == FAIL)
|
||||
type, &argvars[1], func_name, 2) == FAIL)
|
||||
goto theend;
|
||||
list_extend(l1, l2, item);
|
||||
|
||||
@@ -2737,10 +2742,10 @@ extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
|
||||
else
|
||||
action = (char_u *)"force";
|
||||
|
||||
if (type != NULL && check_typval_arg_type(
|
||||
type, &argvars[1], 2) == FAIL)
|
||||
if (type != NULL && check_typval_arg_type(type, &argvars[1],
|
||||
func_name, 2) == FAIL)
|
||||
goto theend;
|
||||
dict_extend(d1, d2, action);
|
||||
dict_extend(d1, d2, action, func_name);
|
||||
|
||||
if (is_new)
|
||||
{
|
||||
@@ -2753,7 +2758,7 @@ extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new)
|
||||
}
|
||||
}
|
||||
else
|
||||
semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
|
||||
semsg(_(e_listdictarg), func_name);
|
||||
|
||||
theend:
|
||||
if (type != NULL)
|
||||
|
@@ -37,7 +37,7 @@ char_u *dict2string(typval_T *tv, int copyID, int restore_copyID);
|
||||
char_u *skip_literal_key(char_u *key);
|
||||
char_u *get_literal_key(char_u **arg);
|
||||
int eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal);
|
||||
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
|
||||
void dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name);
|
||||
dictitem_T *dict_lookup(hashitem_T *hi);
|
||||
int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
|
||||
void f_items(typval_T *argvars, typval_T *rettv);
|
||||
|
@@ -11,7 +11,7 @@ int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
|
||||
int need_convert_to_bool(type_T *type, typval_T *tv);
|
||||
type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int do_member);
|
||||
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
|
||||
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx);
|
||||
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
|
||||
int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
|
||||
void type_mismatch(type_T *expected, type_T *actual);
|
||||
void arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx);
|
||||
|
@@ -4438,7 +4438,10 @@ typedef enum {
|
||||
|
||||
// Struct used to pass to error messages about where the error happened.
|
||||
typedef struct {
|
||||
char *wt_func_name; // function name or NULL
|
||||
char wt_index; // argument or variable index, 0 means unknown
|
||||
char wt_variable; // "variable" when TRUE, "argument" otherwise
|
||||
} where_T;
|
||||
|
||||
#define WHERE_INIT {NULL, 0, 0}
|
||||
|
||||
|
@@ -795,6 +795,8 @@ def Test_extend_arg_types()
|
||||
|
||||
CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
|
||||
CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any>')
|
||||
|
||||
CheckScriptFailure(['vim9script', 'extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any> in extend()')
|
||||
enddef
|
||||
|
||||
func g:ExtendDict(d)
|
||||
@@ -1741,19 +1743,19 @@ def Test_map_item_type()
|
||||
var l: list<number> = [0]
|
||||
echo map(l, (_, v) => [])
|
||||
END
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown> in map()', 2)
|
||||
|
||||
lines =<< trim END
|
||||
var l: list<number> = range(2)
|
||||
echo map(l, (_, v) => [])
|
||||
END
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown> in map()', 2)
|
||||
|
||||
lines =<< trim END
|
||||
var d: dict<number> = {key: 0}
|
||||
echo map(d, (_, v) => [])
|
||||
END
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 2)
|
||||
CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown> in map()', 2)
|
||||
enddef
|
||||
|
||||
def Test_maparg()
|
||||
|
@@ -755,6 +755,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
3200,
|
||||
/**/
|
||||
3199,
|
||||
/**/
|
||||
|
@@ -1033,7 +1033,7 @@ need_type(
|
||||
int silent,
|
||||
int actual_is_const)
|
||||
{
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
if (expected == &t_bool && actual != &t_bool
|
||||
&& (actual->tt_flags & TTFLAG_BOOL_OK))
|
||||
@@ -1045,7 +1045,6 @@ need_type(
|
||||
}
|
||||
|
||||
where.wt_index = arg_idx;
|
||||
where.wt_variable = FALSE;
|
||||
if (check_type(expected, actual, FALSE, where) == OK)
|
||||
return OK;
|
||||
|
||||
@@ -2804,10 +2803,8 @@ check_ppconst_bool(ppconst_T *ppconst)
|
||||
if (ppconst->pp_used > 0)
|
||||
{
|
||||
typval_T *tv = &ppconst->pp_tv[ppconst->pp_used - 1];
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
where.wt_index = 0;
|
||||
where.wt_variable = FALSE;
|
||||
return check_typval_type(&t_bool, tv, where);
|
||||
}
|
||||
return OK;
|
||||
@@ -4822,12 +4819,10 @@ compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
type_T *actual;
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
generate_ppconst(cctx, ppconst);
|
||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
where.wt_index = 0;
|
||||
where.wt_variable = FALSE;
|
||||
if (check_type(want_type, actual, FALSE, where) == FAIL)
|
||||
{
|
||||
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||
@@ -7975,7 +7970,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
||||
int vimvaridx = -1;
|
||||
type_T *type = &t_any;
|
||||
type_T *lhs_type = &t_any;
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
p = skip_var_one(arg, FALSE);
|
||||
varlen = p - arg;
|
||||
@@ -9325,7 +9320,7 @@ compile_def_function(
|
||||
garray_T *stack = &cctx.ctx_type_stack;
|
||||
type_T *val_type;
|
||||
int arg_idx = first_def_arg + i;
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
int r;
|
||||
int jump_instr_idx = instr->ga_len;
|
||||
isn_T *isn;
|
||||
@@ -9348,7 +9343,6 @@ compile_def_function(
|
||||
// specified type.
|
||||
val_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||
where.wt_index = arg_idx + 1;
|
||||
where.wt_variable = FALSE;
|
||||
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
|
||||
{
|
||||
did_set_arg_type = TRUE;
|
||||
|
@@ -730,15 +730,18 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx)
|
||||
int idx;
|
||||
int did_emsg_before = did_emsg;
|
||||
ectx_T *prev_ectx = current_ectx;
|
||||
char *save_func_name = ectx->ec_where.wt_func_name;
|
||||
|
||||
if (call_prepare(argcount, argvars, ectx) == FAIL)
|
||||
return FAIL;
|
||||
ectx->ec_where.wt_func_name = internal_func_name(func_idx);
|
||||
|
||||
// Call the builtin function. Set "current_ectx" so that when it
|
||||
// recursively invokes call_def_function() a closure context can be set.
|
||||
current_ectx = ectx;
|
||||
call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
|
||||
current_ectx = prev_ectx;
|
||||
ectx->ec_where.wt_func_name = save_func_name;
|
||||
|
||||
// Clear the arguments.
|
||||
for (idx = 0; idx < argcount; ++idx)
|
||||
@@ -907,7 +910,7 @@ call_by_name(
|
||||
else if (ufunc->uf_va_type != NULL)
|
||||
type = ufunc->uf_va_type->tt_member;
|
||||
if (type != NULL && check_typval_arg_type(type,
|
||||
&argv[i], i + 1) == FAIL)
|
||||
&argv[i], NULL, i + 1) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
@@ -4535,7 +4538,8 @@ call_def_function(
|
||||
{
|
||||
if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
|
||||
&& check_typval_arg_type(
|
||||
ufunc->uf_arg_types[idx], &argv[idx], idx + 1) == FAIL)
|
||||
ufunc->uf_arg_types[idx], &argv[idx],
|
||||
NULL, idx + 1) == FAIL)
|
||||
goto failed_early;
|
||||
copy_tv(&argv[idx], STACK_TV_BOT(0));
|
||||
}
|
||||
@@ -4567,7 +4571,7 @@ call_def_function(
|
||||
for (idx = 0; idx < vararg_count; ++idx)
|
||||
{
|
||||
if (check_typval_arg_type(expected, &li->li_tv,
|
||||
argc + idx + 1) == FAIL)
|
||||
NULL, argc + idx + 1) == FAIL)
|
||||
goto failed_early;
|
||||
li = li->li_next;
|
||||
}
|
||||
|
@@ -428,12 +428,16 @@ typval2type_vimvar(typval_T *tv, garray_T *type_gap)
|
||||
}
|
||||
|
||||
int
|
||||
check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx)
|
||||
check_typval_arg_type(
|
||||
type_T *expected,
|
||||
typval_T *actual_tv,
|
||||
char *func_name,
|
||||
int arg_idx)
|
||||
{
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
where.wt_index = arg_idx;
|
||||
where.wt_variable = FALSE;
|
||||
where.wt_func_name = func_name;
|
||||
return check_typval_type(expected, actual_tv, where);
|
||||
}
|
||||
|
||||
@@ -465,10 +469,9 @@ type_mismatch(type_T *expected, type_T *actual)
|
||||
void
|
||||
arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx)
|
||||
{
|
||||
where_T where;
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
where.wt_index = arg_idx;
|
||||
where.wt_variable = FALSE;
|
||||
type_mismatch_where(expected, actual, where);
|
||||
}
|
||||
|
||||
@@ -481,14 +484,23 @@ type_mismatch_where(type_T *expected, type_T *actual, where_T where)
|
||||
|
||||
if (where.wt_index > 0)
|
||||
{
|
||||
if (where.wt_func_name == NULL)
|
||||
semsg(_(where.wt_variable
|
||||
? e_variable_nr_type_mismatch_expected_str_but_got_str
|
||||
: e_argument_nr_type_mismatch_expected_str_but_got_str),
|
||||
where.wt_index, typename1, typename2);
|
||||
}
|
||||
else
|
||||
semsg(_(where.wt_variable
|
||||
? e_variable_nr_type_mismatch_expected_str_but_got_str_in_str
|
||||
: e_argument_nr_type_mismatch_expected_str_but_got_str_in_str),
|
||||
where.wt_index, typename1, typename2, where.wt_func_name);
|
||||
}
|
||||
else if (where.wt_func_name == NULL)
|
||||
semsg(_(e_type_mismatch_expected_str_but_got_str),
|
||||
typename1, typename2);
|
||||
else
|
||||
semsg(_(e_type_mismatch_expected_str_but_got_str_in_str),
|
||||
typename1, typename2, where.wt_func_name);
|
||||
vim_free(tofree1);
|
||||
vim_free(tofree2);
|
||||
}
|
||||
@@ -604,7 +616,7 @@ check_argument_types(
|
||||
expected = type->tt_args[type->tt_argcount - 1]->tt_member;
|
||||
else
|
||||
expected = type->tt_args[i];
|
||||
if (check_typval_arg_type(expected, &argvars[i], i + 1) == FAIL)
|
||||
if (check_typval_arg_type(expected, &argvars[i], NULL, i + 1) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
|
Reference in New Issue
Block a user