To: vim_dev@googlegroups.com Subject: Patch 8.2.3866 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3866 Problem: Vim9: type checking global variables is inconsistent. Solution: Use the "unknown" type in more places. Files: src/globals.h, src/vim9expr.c, src/vim9instr.c, src/vim9cmds.c, src/evalfunc.c, src/testdir/test_vim9_func.vim *** ../vim-8.2.3865/src/globals.h 2021-12-17 20:15:30.448830724 +0000 --- src/globals.h 2021-12-21 10:24:45.896882818 +0000 *************** *** 404,412 **** --- 404,419 ---- // Commonly used types. + // "unknown" is used for when the type is really unknown, e.g. global + // variables. Also for when a function may or may not return something. EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, TTFLAG_STATIC, NULL, NULL); + + // "any" is used for when the type is mixed. Excludes "void". EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, TTFLAG_STATIC, NULL, NULL); + + // "void" is used for a function not returning anything. EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL); + EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL); EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL); EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL); *** ../vim-8.2.3865/src/vim9expr.c 2021-12-20 15:03:23.247346527 +0000 --- src/vim9expr.c 2021-12-21 12:23:36.524687742 +0000 *************** *** 90,96 **** vartype = (*typep)->tt_type; idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; // If the index is a string, the variable must be a Dict. ! if (*typep == &t_any && idxtype == &t_string) vartype = VAR_DICT; if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) { --- 90,96 ---- vartype = (*typep)->tt_type; idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; // If the index is a string, the variable must be a Dict. ! if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string) vartype = VAR_DICT; if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) { *************** *** 156,162 **** return FAIL; } } ! else if (vartype == VAR_LIST || *typep == &t_any) { if (is_slice) { --- 156,162 ---- return FAIL; } } ! else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown) { if (is_slice) { *************** *** 415,421 **** // Global, Buffer-local, Window-local and Tabpage-local // variables can be defined later, thus we don't check if it // exists, give an error at runtime. ! res = generate_LOAD(cctx, isn_type, 0, name, &t_any); } } } --- 415,421 ---- // Global, Buffer-local, Window-local and Tabpage-local // variables can be defined later, thus we don't check if it // exists, give an error at runtime. ! res = generate_LOAD(cctx, isn_type, 0, name, &t_unknown); } } } *************** *** 1428,1434 **** if (type == &t_bool) return OK; ! if (type == &t_any || type == &t_number || type == &t_number_bool) // Number 0 and 1 are OK to use as a bool. "any" could also be a bool. // This requires a runtime type check. return generate_COND2BOOL(cctx); --- 1428,1437 ---- if (type == &t_bool) return OK; ! if (type == &t_any ! || type == &t_unknown ! || type == &t_number ! || type == &t_number_bool) // Number 0 and 1 are OK to use as a bool. "any" could also be a bool. // This requires a runtime type check. return generate_COND2BOOL(cctx); *************** *** 2155,2163 **** 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) return FAIL; } } --- 2158,2167 ---- generate_ppconst(cctx, ppconst); actual = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (check_type_maybe(want_type, actual, FALSE, where) != OK) { ! if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) ! == FAIL) return FAIL; } } *** ../vim-8.2.3865/src/vim9instr.c 2021-12-21 09:42:05.626265159 +0000 --- src/vim9instr.c 2021-12-21 11:17:05.112606053 +0000 *************** *** 168,176 **** static int check_number_or_float(vartype_T type1, vartype_T type2, char_u *op) { ! if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT || type1 == VAR_ANY) && (type2 == VAR_NUMBER || type2 == VAR_FLOAT ! || type2 == VAR_ANY))) { if (*op == '+') emsg(_(e_wrong_argument_type_for_plus)); --- 168,177 ---- static int check_number_or_float(vartype_T type1, vartype_T type2, char_u *op) { ! if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT ! || type1 == VAR_ANY || type1 == VAR_UNKNOWN) && (type2 == VAR_NUMBER || type2 == VAR_FLOAT ! || type2 == VAR_ANY || type2 == VAR_UNKNOWN))) { if (*op == '+') emsg(_(e_wrong_argument_type_for_plus)); *************** *** 204,210 **** --- 205,213 ---- if (vartype != VAR_LIST && vartype != VAR_BLOB && type1->tt_type != VAR_ANY + && type1->tt_type != VAR_UNKNOWN && type2->tt_type != VAR_ANY + && type2->tt_type != VAR_UNKNOWN && check_number_or_float( type1->tt_type, type2->tt_type, (char_u *)"+") == FAIL) return FAIL; *************** *** 293,300 **** --- 296,305 ---- break; case '%': if ((type1->tt_type != VAR_ANY + && type1->tt_type != VAR_UNKNOWN && type1->tt_type != VAR_NUMBER) || (type2->tt_type != VAR_ANY + && type2->tt_type != VAR_UNKNOWN && type2->tt_type != VAR_NUMBER)) { emsg(_(e_percent_requires_number_arguments)); *************** *** 1528,1534 **** RETURN_OK_IF_SKIP(cctx); ! if (type->tt_type == VAR_ANY) ret_type = &t_any; else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) { --- 1533,1539 ---- RETURN_OK_IF_SKIP(cctx); ! if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN) ret_type = &t_any; else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) { *************** *** 1620,1626 **** // check for dict type type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (type->tt_type != VAR_DICT && type != &t_any) { char *tofree; --- 1625,1631 ---- // check for dict type type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown) { char *tofree; *** ../vim-8.2.3865/src/vim9cmds.c 2021-12-21 09:42:05.626265159 +0000 --- src/vim9cmds.c 2021-12-21 11:20:32.837049712 +0000 *************** *** 843,850 **** // If we know the type of "var" and it is a not a supported type we can // give an error now. vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING ! && vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY) { semsg(_(e_for_loop_on_str_not_supported), vartype_name(vartype->tt_type)); --- 843,853 ---- // If we know the type of "var" and it is a not a supported type we can // give an error now. vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! if (vartype->tt_type != VAR_LIST ! && vartype->tt_type != VAR_STRING ! && vartype->tt_type != VAR_BLOB ! && vartype->tt_type != VAR_ANY ! && vartype->tt_type != VAR_UNKNOWN) { semsg(_(e_for_loop_on_str_not_supported), vartype_name(vartype->tt_type)); *** ../vim-8.2.3865/src/evalfunc.c 2021-12-20 09:36:20.101548272 +0000 --- src/evalfunc.c 2021-12-21 10:46:29.346624953 +0000 *************** *** 228,234 **** arg_float_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_number, type, context->arg_idx + 1); return FAIL; --- 228,236 ---- arg_float_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_FLOAT ! || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_number, type, context->arg_idx + 1); return FAIL; *************** *** 313,319 **** arg_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; --- 315,323 ---- arg_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; *************** *** 326,332 **** arg_string_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 330,338 ---- arg_string_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 339,345 **** arg_buffer(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 345,353 ---- arg_buffer(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 352,357 **** --- 360,366 ---- arg_buffer_or_dict_any(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER || type->tt_type == VAR_DICT) *************** *** 367,373 **** arg_lnum(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 376,384 ---- arg_lnum(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_NUMBER) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 379,385 **** static int arg_string_or_list_string(type_T *type, argcontext_T *context) { ! if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING) return OK; if (type->tt_type != VAR_LIST) { --- 390,398 ---- static int arg_string_or_list_string(type_T *type, argcontext_T *context) { ! if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING) return OK; if (type->tt_type != VAR_LIST) { *************** *** 401,407 **** arg_string_or_list_any(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 414,422 ---- arg_string_or_list_any(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_LIST) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 414,420 **** arg_string_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 429,437 ---- arg_string_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 427,433 **** arg_list_or_dict(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; --- 444,452 ---- arg_list_or_dict(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_DICT) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; *************** *** 440,448 **** arg_list_or_dict_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; --- 459,468 ---- arg_list_or_dict_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_BLOB) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; *************** *** 455,464 **** arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_BLOB ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; --- 475,485 ---- arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_BLOB ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; *************** *** 471,479 **** arg_string_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_BLOB ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; --- 492,501 ---- arg_string_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_LIST ! || type->tt_type == VAR_BLOB ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_list_any, type, context->arg_idx + 1); return FAIL; *************** *** 495,500 **** --- 517,523 ---- arg_chan_or_job(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_CHANNEL || type->tt_type == VAR_JOB) return OK; *************** *** 557,565 **** arg_str_or_nr_or_list(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_NUMBER ! || type->tt_type == VAR_LIST) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 580,589 ---- arg_str_or_nr_or_list(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_STRING ! || type->tt_type == VAR_NUMBER ! || type->tt_type == VAR_LIST) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 572,579 **** arg_dict_any_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; --- 596,604 ---- arg_dict_any_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY ! || type->tt_type == VAR_UNKNOWN ! || type->tt_type == VAR_DICT ! || type->tt_type == VAR_STRING) return OK; arg_type_mismatch(&t_string, type, context->arg_idx + 1); return FAIL; *************** *** 603,608 **** --- 628,634 ---- arg_get1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_BLOB || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT *************** *** 622,627 **** --- 648,654 ---- arg_len1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER || type->tt_type == VAR_BLOB *************** *** 657,662 **** --- 684,690 ---- arg_repeat1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER || type->tt_type == VAR_LIST) *************** *** 674,679 **** --- 702,708 ---- arg_slice1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB || type->tt_type == VAR_STRING) *************** *** 691,696 **** --- 720,726 ---- arg_count1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT) *************** *** 708,713 **** --- 738,744 ---- arg_cursor1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY + || type->tt_type == VAR_UNKNOWN || type->tt_type == VAR_NUMBER || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST) *** ../vim-8.2.3865/src/testdir/test_vim9_func.vim 2021-12-19 18:33:17.325954806 +0000 --- src/testdir/test_vim9_func.vim 2021-12-21 11:29:00.517302071 +0000 *************** *** 547,552 **** --- 547,585 ---- defcompile END CheckScriptFailure(lines, 'E1001: Variable not found: b') + + # using script variable requires matching type or type cast + lines =<< trim END + vim9script + var a: any + def Func(arg: string = a) + echo arg + enddef + defcompile + END + CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got any') + + lines =<< trim END + vim9script + var a: any + def Func(arg: string = a) + echo arg + enddef + a = 'works' + Func() + END + CheckScriptSuccess(lines) + + # using global variable does not require type cast + lines =<< trim END + vim9script + def Func(arg: string = g:str) + echo arg + enddef + g:str = 'works' + Func() + END + CheckScriptSuccess(lines) enddef def FuncWithComment( # comment *** ../vim-8.2.3865/src/version.c 2021-12-21 09:42:05.626265159 +0000 --- src/version.c 2021-12-21 10:28:53.488316227 +0000 *************** *** 751,752 **** --- 751,754 ---- { /* Add new patch number below this line */ + /**/ + 3866, /**/ -- From "know your smileys": :-O>-o Smiley American tourist (note big mouth and camera) /// 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 ///