To: vim_dev@googlegroups.com Subject: Patch 8.2.4231 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4231 Problem: Vim9: map() gives type error when type was not declared. Solution: Only check the type when it was declared, like extend() does. (closes #9635) Files: src/list.c, src/evalfunc.c, src/vim9instr.c, src/testdir/test_vim9_builtin.vim, src/testdir/test_vim9_assign.vim *** ../vim-8.2.4230/src/list.c 2022-01-08 16:19:18.505639885 +0000 --- src/list.c 2022-01-27 15:35:42.761597288 +0000 *************** *** 580,594 **** { // empty list l->lv_first = item; - l->lv_u.mat.lv_last = item; item->li_prev = NULL; } else { l->lv_u.mat.lv_last->li_next = item; item->li_prev = l->lv_u.mat.lv_last; - l->lv_u.mat.lv_last = item; } ++l->lv_len; item->li_next = NULL; } --- 580,593 ---- { // empty list l->lv_first = item; item->li_prev = NULL; } else { l->lv_u.mat.lv_last->li_next = item; item->li_prev = l->lv_u.mat.lv_last; } + l->lv_u.mat.lv_last = item; ++l->lv_len; item->li_next = NULL; } *************** *** 2362,2369 **** tv.v_lock = 0; tv.vval.v_number = val; set_vim_var_nr(VV_KEY, idx); ! if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) ! == FAIL) break; if (did_emsg) { --- 2361,2367 ---- tv.v_lock = 0; tv.vval.v_number = val; set_vim_var_nr(VV_KEY, idx); ! if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL) break; if (did_emsg) { *************** *** 2461,2467 **** : N_("filter() argument")); int save_did_emsg; type_T *type = NULL; - garray_T type_list; // map() and filter() return the first argument, also on failure. if (filtermap != FILTERMAP_MAPNEW && argvars[0].v_type != VAR_STRING) --- 2459,2464 ---- *************** *** 2474,2482 **** if (filtermap == FILTERMAP_MAP && in_vim9script()) { ! // Check that map() does not change the type of the dict. ! ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, get_copyID(), &type_list, TVTT_DO_MEMBER); } if (argvars[0].v_type != VAR_BLOB --- 2471,2483 ---- if (filtermap == FILTERMAP_MAP && in_vim9script()) { ! // Check that map() does not change the declared type of the list or ! // dict. ! if (argvars[0].v_type == VAR_DICT && argvars[0].vval.v_dict != NULL) ! type = argvars[0].vval.v_dict->dv_type; ! else if (argvars[0].v_type == VAR_LIST ! && argvars[0].vval.v_list != NULL) ! type = argvars[0].vval.v_list->lv_type; } if (argvars[0].v_type != VAR_BLOB *************** *** 2489,2498 **** goto theend; } - expr = &argvars[1]; // On type errors, the preceding call has already displayed an error // message. Avoid a misleading error message for an empty string that // was not passed as argument. if (expr->v_type != VAR_UNKNOWN) { typval_T save_val; --- 2490,2499 ---- goto theend; } // On type errors, the preceding call has already displayed an error // message. Avoid a misleading error message for an empty string that // was not passed as argument. + expr = &argvars[1]; if (expr->v_type != VAR_UNKNOWN) { typval_T save_val; *************** *** 2525,2532 **** } theend: - if (type != NULL) - clear_type_list(&type_list); } /* --- 2526,2531 ---- *** ../vim-8.2.4230/src/evalfunc.c 2022-01-27 13:16:54.328078845 +0000 --- src/evalfunc.c 2022-01-27 16:16:45.417594878 +0000 *************** *** 530,550 **** if (type->tt_type == VAR_FUNC) { ! if (type->tt_member != &t_any ! && type->tt_member != &t_unknown) { type_T *expected = NULL; if (context->arg_types[0].type_curr->tt_type == VAR_LIST || context->arg_types[0].type_curr->tt_type == VAR_DICT) ! expected = context->arg_types[0].type_curr->tt_member; else if (context->arg_types[0].type_curr->tt_type == VAR_STRING) expected = &t_string; else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB) expected = &t_number; if (expected != NULL) { ! type_T t_func_exp = {VAR_FUNC, -1, 0, TTFLAG_STATIC, NULL, NULL}; t_func_exp.tt_member = expected; return check_arg_type(&t_func_exp, type, context); --- 530,559 ---- if (type->tt_type == VAR_FUNC) { ! if (type->tt_member != &t_any && type->tt_member != &t_unknown) { type_T *expected = NULL; if (context->arg_types[0].type_curr->tt_type == VAR_LIST || context->arg_types[0].type_curr->tt_type == VAR_DICT) ! { ! // Use the declared type, so that an error is given if a ! // declared list changes type, but not if a constant list ! // changes type. ! if (context->arg_types[0].type_decl->tt_type == VAR_LIST ! || context->arg_types[0].type_decl->tt_type == VAR_DICT) ! expected = context->arg_types[0].type_decl->tt_member; ! else ! expected = context->arg_types[0].type_curr->tt_member; ! } else if (context->arg_types[0].type_curr->tt_type == VAR_STRING) expected = &t_string; else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB) expected = &t_number; if (expected != NULL) { ! type_T t_func_exp = {VAR_FUNC, -1, 0, TTFLAG_STATIC, ! NULL, NULL}; t_func_exp.tt_member = expected; return check_arg_type(&t_func_exp, type, context); *** ../vim-8.2.4230/src/vim9instr.c 2022-01-25 15:51:52.430855187 +0000 --- src/vim9instr.c 2022-01-27 16:22:14.032604969 +0000 *************** *** 1331,1340 **** if (push_type_stack(cctx, type) == FAIL) return FAIL; ! if (maptype != NULL && maptype[0].type_curr->tt_member != NULL ! && maptype[0].type_curr->tt_member != &t_any) // Check that map() didn't change the item types. ! generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1); return OK; } --- 1331,1340 ---- if (push_type_stack(cctx, type) == FAIL) return FAIL; ! if (maptype != NULL && maptype[0].type_decl->tt_member != NULL ! && maptype[0].type_decl->tt_member != &t_any) // Check that map() didn't change the item types. ! generate_TYPECHECK(cctx, maptype[0].type_decl, -1, 1); return OK; } *** ../vim-8.2.4230/src/testdir/test_vim9_builtin.vim 2022-01-27 13:55:29.850840894 +0000 --- src/testdir/test_vim9_builtin.vim 2022-01-27 15:43:27.558970263 +0000 *************** *** 2230,2242 **** END CheckDefExecAndScriptFailure(lines, 'E1190: 2 arguments too few') lines =<< trim END def Map(i: number, v: number): string return 'bad' enddef ! echo map([1, 2, 3], Map) END CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(...): number but got func(number, number): string', 'E1012: Type mismatch; expected number but got string in map()']) enddef def Test_map_item_type() --- 2230,2247 ---- END CheckDefExecAndScriptFailure(lines, 'E1190: 2 arguments too few') + # declared list cannot change type lines =<< trim END def Map(i: number, v: number): string return 'bad' enddef ! var ll: list = [1, 2, 3] ! echo map(ll, Map) END CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(...): number but got func(number, number): string', 'E1012: Type mismatch; expected number but got string in map()']) + + # not declared list can change type + echo [1, 2, 3]->map((..._) => 'x') enddef def Test_map_item_type() *** ../vim-8.2.4230/src/testdir/test_vim9_assign.vim 2022-01-15 21:44:39.832970792 +0000 --- src/testdir/test_vim9_assign.vim 2022-01-27 16:26:09.472882359 +0000 *************** *** 1963,1969 **** var ll: list ll = [1, 2, 3]->map('"one"') END ! CheckDefExecFailure(lines, 'E1012: Type mismatch; expected number but got string') enddef def Test_cannot_use_let() --- 1963,1969 ---- var ll: list ll = [1, 2, 3]->map('"one"') END ! CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list but got list') enddef def Test_cannot_use_let() *** ../vim-8.2.4230/src/version.c 2022-01-27 15:04:19.004952329 +0000 --- src/version.c 2022-01-27 15:36:50.440630593 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4231, /**/ -- A year spent in artificial intelligence is enough to make one believe in God. /// 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 ///