To: vim_dev@googlegroups.com Subject: Patch 8.2.3869 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3869 Problem: Vim9: type checking for "any" is inconsistent. Solution: Always use a runtime type check for using "any" for a more specific type. Files: src/vim9type.c, src/vim9compile.c, src/vim9expr.c, src/testdir/test_vim9_func.vim *** ../vim-8.2.3868/src/vim9type.c 2021-12-21 13:30:38.732749872 +0000 --- src/vim9type.c 2021-12-22 13:08:44.653775876 +0000 *************** *** 477,483 **** ga_init2(&type_list, sizeof(type_T *), 10); actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE); if (actual_type != NULL) ! res = check_type(expected, actual_type, TRUE, where); clear_type_list(&type_list); return res; } --- 477,495 ---- ga_init2(&type_list, sizeof(type_T *), 10); actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE); if (actual_type != NULL) ! { ! res = check_type_maybe(expected, actual_type, TRUE, where); ! if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC ! && actual_type->tt_member == &t_unknown)) ! { ! // If a type check is needed that means assigning "any" or ! // "unknown" to a more specific type, which fails here. ! // Execpt when it looks like a lambda, since they have an ! // incomplete type. ! type_mismatch_where(expected, actual_type, where); ! res = FAIL; ! } ! } clear_type_list(&type_list); return res; } *************** *** 567,575 **** { // tt_type should match, except that a "partial" can be assigned to a // variable with type "func". ! // And "unknown" (using global variable) needs a runtime type check. if (!(expected->tt_type == actual->tt_type || actual->tt_type == VAR_UNKNOWN || (expected->tt_type == VAR_FUNC && actual->tt_type == VAR_PARTIAL))) { --- 579,589 ---- { // tt_type should match, except that a "partial" can be assigned to a // variable with type "func". ! // And "unknown" (using global variable) and "any" need a runtime type ! // check. if (!(expected->tt_type == actual->tt_type || actual->tt_type == VAR_UNKNOWN + || actual->tt_type == VAR_ANY || (expected->tt_type == VAR_FUNC && actual->tt_type == VAR_PARTIAL))) { *************** *** 585,594 **** { // "unknown" is used for an empty list or dict if (actual->tt_member != NULL && actual->tt_member != &t_unknown) ! ret = check_type(expected->tt_member, actual->tt_member, FALSE, where); } ! else if (expected->tt_type == VAR_FUNC) { // If the return type is unknown it can be anything, including // nothing, thus there is no point in checking. --- 599,608 ---- { // "unknown" is used for an empty list or dict if (actual->tt_member != NULL && actual->tt_member != &t_unknown) ! ret = check_type_maybe(expected->tt_member, actual->tt_member, FALSE, where); } ! else if (expected->tt_type == VAR_FUNC && actual != &t_any) { // If the return type is unknown it can be anything, including // nothing, thus there is no point in checking. *************** *** 596,603 **** { if (actual->tt_member != NULL && actual->tt_member != &t_unknown) ! ret = check_type(expected->tt_member, actual->tt_member, ! FALSE, where); else ret = MAYBE; } --- 610,617 ---- { if (actual->tt_member != NULL && actual->tt_member != &t_unknown) ! ret = check_type_maybe(expected->tt_member, ! actual->tt_member, FALSE, where); else ret = MAYBE; } *** ../vim-8.2.3868/src/vim9compile.c 2021-12-20 15:03:23.247346527 +0000 --- src/vim9compile.c 2021-12-22 10:23:22.215274437 +0000 *************** *** 366,373 **** || (actual->tt_type == VAR_FUNC && (expected->tt_type == VAR_FUNC || expected->tt_type == VAR_PARTIAL) ! && (actual->tt_member == &t_any || actual->tt_argcount < 0) ! && ((actual->tt_member == &t_void) == (expected->tt_member == &t_void)))) return TRUE; if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT) --- 366,376 ---- || (actual->tt_type == VAR_FUNC && (expected->tt_type == VAR_FUNC || expected->tt_type == VAR_PARTIAL) ! && (actual->tt_member == &t_any ! || actual->tt_member == &t_unknown ! || actual->tt_argcount < 0) ! && (actual->tt_member == &t_unknown || ! (actual->tt_member == &t_void) == (expected->tt_member == &t_void)))) return TRUE; if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT) *************** *** 412,419 **** // If the actual type can be the expected type add a runtime check. // If it's a constant a runtime check makes no sense. ! if (ret == MAYBE || ((!actual_is_const || actual == &t_any) ! && use_typecheck(actual, expected))) { generate_TYPECHECK(cctx, expected, offset, where.wt_index); return OK; --- 415,421 ---- // If the actual type can be the expected type add a runtime check. // If it's a constant a runtime check makes no sense. ! if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected)) { generate_TYPECHECK(cctx, expected, offset, where.wt_index); return OK; *************** *** 2547,2554 **** did_set_arg_type = TRUE; ufunc->uf_arg_types[arg_idx] = val_type; } ! else if (check_type(ufunc->uf_arg_types[arg_idx], val_type, ! TRUE, where) == FAIL) goto erret; if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL) --- 2549,2556 ---- did_set_arg_type = TRUE; ufunc->uf_arg_types[arg_idx] = val_type; } ! else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx], ! -1, where, &cctx, FALSE, FALSE) == FAIL) goto erret; if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL) *** ../vim-8.2.3868/src/vim9expr.c 2021-12-21 12:32:13.296529989 +0000 --- src/vim9expr.c 2021-12-22 12:54:15.358305817 +0000 *************** *** 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); } } } --- 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); } } } *************** *** 2846,2851 **** --- 2846,2852 ---- type_T **typep; generate_ppconst(cctx, ppconst); + ppconst->pp_is_const = FALSE; // If the types differ, the result has a more generic type. typep = ((type_T **)stack->ga_data) + stack->ga_len - 1; *** ../vim-8.2.3868/src/testdir/test_vim9_func.vim 2021-12-21 12:32:13.300529985 +0000 --- src/testdir/test_vim9_func.vim 2021-12-22 12:39:26.895411887 +0000 *************** *** 548,554 **** END CheckScriptFailure(lines, 'E1001: Variable not found: b') ! # using script variable requires matching type or type cast lines =<< trim END vim9script var a: any --- 548,554 ---- END CheckScriptFailure(lines, 'E1001: Variable not found: b') ! # using script variable requires matching type or type cast when executed lines =<< trim END vim9script var a: any *************** *** 557,574 **** 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 --- 557,564 ---- enddef defcompile END ! CheckScriptSuccess(lines + ['a = "text"', 'Func()']) ! CheckScriptFailure(lines + ['a = 123', 'Func()'], 'E1013: Argument 1: type mismatch, expected string but got number') # using global variable does not require type cast lines =<< trim END *** ../vim-8.2.3868/src/version.c 2021-12-21 13:30:38.736749839 +0000 --- src/version.c 2021-12-22 09:57:23.547319519 +0000 *************** *** 751,752 **** --- 751,754 ---- { /* Add new patch number below this line */ + /**/ + 3869, /**/ -- Warning label on a superhero Halloween costume: "Caution: Cape does not enable user to fly." /// 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 ///