To: vim_dev@googlegroups.com Subject: Patch 8.2.3200 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3200 Problem: Vim9: hard to guess where a type error is given. Solution: Add the function name where possible. (closes #8608) Files: src/dict.c, src/proto/dict.pro, src/eval.c, src/list.c, src/vim9compile.c, src/vim9execute.c, src/structs.h, src/vim9type.c, src/proto/vim9type.pro, src/if_py_both.h, src/errors.h, src/testdir/test_vim9_builtin.vim *** ../vim-8.2.3199/src/dict.c 2021-07-20 17:51:48.239744107 +0200 --- src/dict.c 2021-07-22 14:08:37.316706384 +0200 *************** *** 1073,1079 **** * Otherwise duplicate keys are ignored ("action" is "keep"). */ void ! dict_extend(dict_T *d1, dict_T *d2, char_u *action) { dictitem_T *di1; hashitem_T *hi2; --- 1073,1079 ---- * Otherwise duplicate keys are ignored ("action" is "keep"). */ void ! dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name) { dictitem_T *di1; hashitem_T *hi2; *************** *** 1106,1113 **** } if (type != NULL ! && check_typval_arg_type(type, &HI2DI(hi2)->di_tv, 0) ! == FAIL) break; if (di1 == NULL) --- 1106,1113 ---- } if (type != NULL ! && check_typval_arg_type(type, &HI2DI(hi2)->di_tv, ! func_name, 0) == FAIL) break; if (di1 == NULL) *** ../vim-8.2.3199/src/proto/dict.pro 2021-06-01 21:21:51.918500942 +0200 --- src/proto/dict.pro 2021-07-22 14:08:44.704689196 +0200 *************** *** 37,43 **** 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); 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); --- 37,43 ---- 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, 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); *** ../vim-8.2.3199/src/eval.c 2021-07-20 17:51:48.243744105 +0200 --- src/eval.c 2021-07-22 13:37:52.565374186 +0200 *************** *** 1365,1372 **** } else { ! if (lp->ll_type != NULL ! && check_typval_arg_type(lp->ll_type, rettv, 0) == FAIL) return; set_var_const(lp->ll_name, lp->ll_type, rettv, copy, flags, var_idx); --- 1365,1372 ---- } else { ! 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,1456 **** } if (lp->ll_valtype != NULL ! && check_typval_arg_type(lp->ll_valtype, rettv, 0) == FAIL) return; if (lp->ll_newkey != NULL) --- 1450,1457 ---- } if (lp->ll_valtype != NULL ! && check_typval_arg_type(lp->ll_valtype, rettv, ! NULL, 0) == FAIL) return; if (lp->ll_newkey != NULL) *** ../vim-8.2.3199/src/list.c 2021-07-20 21:07:32.964058857 +0200 --- src/list.c 2021-07-22 14:15:11.587800542 +0200 *************** *** 605,611 **** 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) return FAIL; li = listitem_alloc(); if (li == NULL) --- 605,612 ---- listitem_T *li; if (l->lv_type != NULL && l->lv_type->tt_member != NULL ! && check_typval_arg_type(l->lv_type->tt_member, tv, ! NULL, 0) == FAIL) return FAIL; li = listitem_alloc(); if (li == NULL) *************** *** 722,728 **** 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) return FAIL; ni = listitem_alloc(); if (ni == NULL) --- 723,730 ---- listitem_T *ni; if (l->lv_type != NULL && l->lv_type->tt_member != NULL ! && check_typval_arg_type(l->lv_type->tt_member, tv, ! NULL, 0) == FAIL) return FAIL; ni = listitem_alloc(); if (ni == NULL) *************** *** 2085,2093 **** blob_T *b = NULL; int rem; int todo; ! char_u *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()" : filtermap == FILTERMAP_MAPNEW ? "mapnew()" ! : "filter()"); char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP ? N_("map() argument") : filtermap == FILTERMAP_MAPNEW --- 2087,2095 ---- blob_T *b = NULL; int rem; int todo; ! char *func_name = filtermap == FILTERMAP_MAP ? "map()" : filtermap == FILTERMAP_MAPNEW ? "mapnew()" ! : "filter()"; char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP ? N_("map() argument") : filtermap == FILTERMAP_MAPNEW *************** *** 2144,2150 **** } else { ! semsg(_(e_listdictblobarg), ermsg); goto theend; } --- 2146,2152 ---- } else { ! semsg(_(e_listdictblobarg), func_name); goto theend; } *************** *** 2210,2216 **** if (filtermap == FILTERMAP_MAP) { if (type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, 0) == FAIL) { clear_tv(&newtv); break; --- 2212,2219 ---- if (filtermap == FILTERMAP_MAP) { if (type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, ! func_name, 0) == FAIL) { clear_tv(&newtv); break; *************** *** 2345,2351 **** { if (filtermap == FILTERMAP_MAP && type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, 0) == FAIL) { clear_tv(&newtv); break; --- 2348,2355 ---- { if (filtermap == FILTERMAP_MAP && type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, ! func_name, 0) == FAIL) { clear_tv(&newtv); break; *************** *** 2389,2395 **** if (filtermap == FILTERMAP_MAP) { if (type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, 0) == FAIL) { clear_tv(&newtv); break; --- 2393,2399 ---- if (filtermap == FILTERMAP_MAP) { if (type != NULL && check_typval_arg_type( ! type->tt_member, &newtv, func_name, 0) == FAIL) { clear_tv(&newtv); break; *************** *** 2627,2632 **** --- 2631,2637 ---- { type_T *type = NULL; garray_T type_list; + char *func_name = is_new ? "extendnew()" : "extend()"; if (!is_new && in_vim9script()) { *************** *** 2680,2686 **** else item = NULL; if (type != NULL && check_typval_arg_type( ! type, &argvars[1], 2) == FAIL) goto theend; list_extend(l1, l2, item); --- 2685,2691 ---- else item = NULL; if (type != NULL && check_typval_arg_type( ! type, &argvars[1], func_name, 2) == FAIL) goto theend; list_extend(l1, l2, item); *************** *** 2737,2746 **** else action = (char_u *)"force"; ! if (type != NULL && check_typval_arg_type( ! type, &argvars[1], 2) == FAIL) goto theend; ! dict_extend(d1, d2, action); if (is_new) { --- 2742,2751 ---- else action = (char_u *)"force"; ! if (type != NULL && check_typval_arg_type(type, &argvars[1], ! func_name, 2) == FAIL) goto theend; ! dict_extend(d1, d2, action, func_name); if (is_new) { *************** *** 2753,2759 **** } } else ! semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()"); theend: if (type != NULL) --- 2758,2764 ---- } } else ! semsg(_(e_listdictarg), func_name); theend: if (type != NULL) *** ../vim-8.2.3199/src/vim9compile.c 2021-07-21 22:20:30.066401728 +0200 --- src/vim9compile.c 2021-07-22 14:39:39.116569041 +0200 *************** *** 1033,1039 **** int silent, int actual_is_const) { ! where_T where; if (expected == &t_bool && actual != &t_bool && (actual->tt_flags & TTFLAG_BOOL_OK)) --- 1033,1039 ---- int silent, int actual_is_const) { ! where_T where = WHERE_INIT; if (expected == &t_bool && actual != &t_bool && (actual->tt_flags & TTFLAG_BOOL_OK)) *************** *** 1045,1051 **** } where.wt_index = arg_idx; - where.wt_variable = FALSE; if (check_type(expected, actual, FALSE, where) == OK) return OK; --- 1045,1050 ---- *************** *** 2804,2813 **** if (ppconst->pp_used > 0) { typval_T *tv = &ppconst->pp_tv[ppconst->pp_used - 1]; ! where_T where; - where.wt_index = 0; - where.wt_variable = FALSE; return check_typval_type(&t_bool, tv, where); } return OK; --- 2803,2810 ---- if (ppconst->pp_used > 0) { typval_T *tv = &ppconst->pp_tv[ppconst->pp_used - 1]; ! where_T where = WHERE_INIT; return check_typval_type(&t_bool, tv, where); } return OK; *************** *** 4822,4833 **** { garray_T *stack = &cctx->ctx_type_stack; type_T *actual; ! where_T where; 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) --- 4819,4828 ---- { garray_T *stack = &cctx->ctx_type_stack; type_T *actual; ! where_T where = WHERE_INIT; generate_ppconst(cctx, ppconst); actual = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (check_type(want_type, actual, FALSE, where) == FAIL) { if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL) *************** *** 7975,7981 **** int vimvaridx = -1; type_T *type = &t_any; type_T *lhs_type = &t_any; ! where_T where; p = skip_var_one(arg, FALSE); varlen = p - arg; --- 7970,7976 ---- int vimvaridx = -1; type_T *type = &t_any; type_T *lhs_type = &t_any; ! where_T where = WHERE_INIT; p = skip_var_one(arg, FALSE); varlen = p - arg; *************** *** 9325,9331 **** garray_T *stack = &cctx.ctx_type_stack; type_T *val_type; int arg_idx = first_def_arg + i; ! where_T where; int r; int jump_instr_idx = instr->ga_len; isn_T *isn; --- 9320,9326 ---- garray_T *stack = &cctx.ctx_type_stack; type_T *val_type; int arg_idx = first_def_arg + i; ! where_T where = WHERE_INIT; int r; int jump_instr_idx = instr->ga_len; isn_T *isn; *************** *** 9348,9354 **** // 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; --- 9343,9348 ---- *** ../vim-8.2.3199/src/vim9execute.c 2021-07-22 12:26:09.486596831 +0200 --- src/vim9execute.c 2021-07-22 14:55:27.330414520 +0200 *************** *** 730,744 **** --- 730,747 ---- 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,913 **** 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) return FAIL; } } --- 910,916 ---- else if (ufunc->uf_va_type != NULL) type = ufunc->uf_va_type->tt_member; if (type != NULL && check_typval_arg_type(type, ! &argv[i], NULL, i + 1) == FAIL) return FAIL; } } *************** *** 4535,4541 **** { 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) goto failed_early; copy_tv(&argv[idx], STACK_TV_BOT(0)); } --- 4538,4545 ---- { if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len && check_typval_arg_type( ! ufunc->uf_arg_types[idx], &argv[idx], ! NULL, idx + 1) == FAIL) goto failed_early; copy_tv(&argv[idx], STACK_TV_BOT(0)); } *************** *** 4567,4573 **** for (idx = 0; idx < vararg_count; ++idx) { if (check_typval_arg_type(expected, &li->li_tv, ! argc + idx + 1) == FAIL) goto failed_early; li = li->li_next; } --- 4571,4577 ---- for (idx = 0; idx < vararg_count; ++idx) { if (check_typval_arg_type(expected, &li->li_tv, ! NULL, argc + idx + 1) == FAIL) goto failed_early; li = li->li_next; } *** ../vim-8.2.3199/src/structs.h 2021-07-14 20:00:24.545690127 +0200 --- src/structs.h 2021-07-22 14:38:12.816763524 +0200 *************** *** 4438,4444 **** --- 4438,4447 ---- // 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} + *** ../vim-8.2.3199/src/vim9type.c 2021-07-09 19:53:51.590271249 +0200 --- src/vim9type.c 2021-07-22 14:40:51.648405458 +0200 *************** *** 428,439 **** } int ! check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx) { ! where_T where; where.wt_index = arg_idx; ! where.wt_variable = FALSE; return check_typval_type(expected, actual_tv, where); } --- 428,443 ---- } int ! check_typval_arg_type( ! type_T *expected, ! typval_T *actual_tv, ! char *func_name, ! int arg_idx) { ! where_T where = WHERE_INIT; where.wt_index = arg_idx; ! where.wt_func_name = func_name; return check_typval_type(expected, actual_tv, where); } *************** *** 465,474 **** void arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx) { ! where_T where; where.wt_index = arg_idx; - where.wt_variable = FALSE; type_mismatch_where(expected, actual, where); } --- 469,477 ---- void arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx) { ! where_T where = WHERE_INIT; where.wt_index = arg_idx; type_mismatch_where(expected, actual, where); } *************** *** 481,494 **** 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), where.wt_index, typename1, typename2); } ! else semsg(_(e_type_mismatch_expected_str_but_got_str), typename1, typename2); vim_free(tofree1); vim_free(tofree2); } --- 484,506 ---- 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,610 **** 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) return FAIL; } return OK; --- 616,622 ---- expected = type->tt_args[type->tt_argcount - 1]->tt_member; else expected = type->tt_args[i]; ! if (check_typval_arg_type(expected, &argvars[i], NULL, i + 1) == FAIL) return FAIL; } return OK; *** ../vim-8.2.3199/src/proto/vim9type.pro 2021-04-13 20:53:09.846201149 +0200 --- src/proto/vim9type.pro 2021-07-22 13:41:55.296776135 +0200 *************** *** 11,17 **** 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_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); --- 11,17 ---- 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, 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); *** ../vim-8.2.3199/src/if_py_both.h 2021-05-07 17:55:51.975584414 +0200 --- src/if_py_both.h 2021-07-22 14:07:35.288850851 +0200 *************** *** 2043,2049 **** return NULL; VimTryStart(); ! dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force"); clear_tv(&tv); if (VimTryEnd()) return NULL; --- 2043,2049 ---- return NULL; VimTryStart(); ! dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force", NULL); clear_tv(&tv); if (VimTryEnd()) return NULL; *** ../vim-8.2.3199/src/errors.h 2021-07-21 22:20:30.058401746 +0200 --- src/errors.h 2021-07-22 14:14:20.359911414 +0200 *************** *** 192,199 **** --- 192,203 ---- 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,499 **** --- 498,505 ---- 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[] *** ../vim-8.2.3199/src/testdir/test_vim9_builtin.vim 2021-07-21 19:09:06.248680063 +0200 --- src/testdir/test_vim9_builtin.vim 2021-07-22 14:56:25.954280782 +0200 *************** *** 795,800 **** --- 795,802 ---- CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list but got list') CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') + + CheckScriptFailure(['vim9script', 'extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list in extend()') enddef func g:ExtendDict(d) *************** *** 1741,1759 **** var l: list = [0] echo map(l, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list', 2) lines =<< trim END var l: list = range(2) echo map(l, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list', 2) lines =<< trim END var d: dict = {key: 0} echo map(d, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list', 2) enddef def Test_maparg() --- 1743,1761 ---- var l: list = [0] echo map(l, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list in map()', 2) lines =<< trim END var l: list = range(2) echo map(l, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list in map()', 2) lines =<< trim END var d: dict = {key: 0} echo map(d, (_, v) => []) END ! CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list in map()', 2) enddef def Test_maparg() *** ../vim-8.2.3199/src/version.c 2021-07-22 12:26:09.486596831 +0200 --- src/version.c 2021-07-22 14:58:16.502028765 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3200, /**/ -- hundred-and-one symptoms of being an internet addict: 203. You're an active member of more than 20 newsgroups. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///