]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.3200: Vim9: hard to guess where a type error is given v8.2.3200
authorBram Moolenaar <Bram@vim.org>
Thu, 22 Jul 2021 12:58:47 +0000 (14:58 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 22 Jul 2021 12:58:47 +0000 (14:58 +0200)
Problem:    Vim9: hard to guess where a type error is given.
Solution:   Add the function name where possible. (closes #8608)

13 files changed:
src/dict.c
src/errors.h
src/eval.c
src/if_py_both.h
src/list.c
src/proto/dict.pro
src/proto/vim9type.pro
src/structs.h
src/testdir/test_vim9_builtin.vim
src/version.c
src/vim9compile.c
src/vim9execute.c
src/vim9type.c

index 8bcf28c72f71e9130dcc5b9c572189dee76fb1a6..080c345bfa71922df7ee263f89978cefd6d2908a 100644 (file)
@@ -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)
index 8655d3f455aa831264fab9fb9cf66a941d798319..281bda66bf58a77533c9ea1c65b81d970a0c1509 100644 (file)
@@ -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[]
index a5c889af87de6715864584ca62feb620ad9b204d..bfe9f613611f45589470ce3d7cb9894d336a4493 100644 (file)
@@ -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)
index 7f38e175b412c997e91fd0d780cbfe3915cb5d82..6d71ac1a28bc86a0a23974df70b3a6aaa8b54e21 100644 (file)
@@ -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;
index 55b9fa0aee466e0cd2ba17e48419de9fd06db97e..c59197b3c4d6aaffdd9f975fa486bc8ececde055 100644 (file)
@@ -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)
index 7789d4c6caf1fa33ed075ba3c9571b1df235b453..5d763853858764c896523a3701563788ac6b9034 100644 (file)
@@ -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);
index a512fa4d557bd688725426388d9f306a96466e2f..559eb5c146172ccc27ac9079a86abe53b4de87f0 100644 (file)
@@ -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);
index 5331183e1f35b58ac45351802819eea51ae74330..265fe0253d637d015f64187c8c29196806525ddf 100644 (file)
@@ -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}
+
index fb9c868ecc571f97b45310ea585e31ddf01a0238..741e74a3b639c5d51851c2faa8e07583f634edd1 100644 (file)
@@ -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()
index cd0f9ec385c279d4c34ba8ec542b59f636d07a1b..02469ed60793f256f51297219b005ca7dee650e8 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3200,
 /**/
     3199,
 /**/
index 8e8ae3f98ed477106ed031b25e3787aa96961528..4f7a0397b70214980199c497760b40ec9913571f 100644 (file)
@@ -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;
index 6cc1fc7e9f7913bcd129a935d1fdecb2e7e53688..33ad788a22f30f65559a77f49dec705d90c41021 100644 (file)
@@ -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;
            }
index c4f3cd504c3f3726152c7a9d51216181118d9ae2..ea50e890300d8cfbcaf04096cd508df307c58caa 100644 (file)
@@ -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)
     {
-       semsg(_(where.wt_variable
-                       ? e_variable_nr_type_mismatch_expected_str_but_got_str
-                       : e_argument_nr_type_mismatch_expected_str_but_got_str),
+       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
+    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;