From de69a7353e9bec552e15dbe3706a9f4e88080fce Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sun, 11 Jul 2021 14:28:25 +0200 Subject: [PATCH 01/42] patch 8.2.3141: no error when using :complete for :command without -nargs Problem: No error when using :complete for :command without -nargs. Solution: Give an error. (Martin Tournoij, closes #8544, closes #8541) --- src/errors.h | 2 ++ src/testdir/test_usercommands.vim | 36 +++++++++++++++---------------- src/usercmd.c | 10 ++------- src/version.c | 2 ++ 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/errors.h b/src/errors.h index d4f3179abe..7e823bfbf2 100644 --- a/src/errors.h +++ b/src/errors.h @@ -496,3 +496,5 @@ EXTERN char e_dict_required_for_argument_nr[] INIT(= N_("E1206: Dictionary required for argument %d")); EXTERN char e_expression_without_effect_str[] INIT(= N_("E1207: Expression without an effect: %s")); +EXTERN char e_complete_used_without_nargs[] + INIT(= N_("E1208: -complete used without -nargs")); diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim index c38424f1ee..93312f1ecf 100644 --- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -270,6 +270,8 @@ func Test_CmdErrors() call assert_fails('com! -complete=custom DoCmd :', 'E467:') call assert_fails('com! -complete=customlist DoCmd :', 'E467:') call assert_fails('com! -complete=behave,CustomComplete DoCmd :', 'E468:') + call assert_fails('com! -complete=file DoCmd :', 'E1208:') + call assert_fails('com! -nargs=0 -complete=file DoCmd :', 'E1208:') call assert_fails('com! -nargs=x DoCmd :', 'E176:') call assert_fails('com! -count=1 -count=2 DoCmd :', 'E177:') call assert_fails('com! -count=x DoCmd :', 'E178:') @@ -338,34 +340,30 @@ func Test_CmdCompletion() call feedkeys(":com DoC\\\"\", 'tx') call assert_equal('"com DoC', @:) - com! -complete=behave DoCmd : + com! -nargs=1 -complete=behave DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd mswin xterm', @:) - " This does not work. Why? - "call feedkeys(":DoCmd x\\\"\", 'tx') - "call assert_equal('"DoCmd xterm', @:) - - com! -complete=custom,CustomComplete DoCmd : + com! -nargs=* -complete=custom,CustomComplete DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd January February Mars', @:) - com! -complete=customlist,CustomCompleteList DoCmd : + com! -nargs=? -complete=customlist,CustomCompleteList DoCmd : call feedkeys(":DoCmd \\\"\", 'tx') call assert_equal('"DoCmd Monday Tuesday Wednesday', @:) - com! -complete=custom,CustomCompleteList DoCmd : + com! -nargs=+ -complete=custom,CustomCompleteList DoCmd : call assert_fails("call feedkeys(':DoCmd \', 'tx')", 'E730:') - com! -complete=customlist,CustomComp DoCmd : + com! -nargs=+ -complete=customlist,CustomComp DoCmd : call assert_fails("call feedkeys(':DoCmd \', 'tx')", 'E117:') " custom completion without a function - com! -complete=custom, DoCmd + com! -nargs=? -complete=custom, DoCmd call assert_beeps("call feedkeys(':DoCmd \t', 'tx')") " custom completion failure with the wrong function - com! -complete=custom,min DoCmd + com! -nargs=? -complete=custom,min DoCmd call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:') delcom DoCmd @@ -500,21 +498,21 @@ func Test_command_list() \ execute('command DoCmd')) " Test with various -complete= argument values (non-exhaustive list) - command! -complete=arglist DoCmd : + command! -nargs=1 -complete=arglist DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 arglist :", + \ .. "\n DoCmd 1 arglist :", \ execute('command DoCmd')) - command! -complete=augroup DoCmd : + command! -nargs=* -complete=augroup DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 augroup :", + \ .. "\n DoCmd * augroup :", \ execute('command DoCmd')) - command! -complete=custom,CustomComplete DoCmd : + command! -nargs=? -complete=custom,CustomComplete DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 custom :", + \ .. "\n DoCmd ? custom :", \ execute('command DoCmd')) - command! -complete=customlist,CustomComplete DoCmd : + command! -nargs=+ -complete=customlist,CustomComplete DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 customlist :", + \ .. "\n DoCmd + customlist :", \ execute('command DoCmd')) " Test with various -narg= argument values. diff --git a/src/usercmd.c b/src/usercmd.c index a4bbfd77cf..94ebb43af0 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -1019,21 +1019,15 @@ ex_command(exarg_T *eap) // we are listing commands p = skipwhite(end); if (!has_attr && ends_excmd2(eap->arg, p)) - { uc_list(name, end - name); - } else if (!ASCII_ISUPPER(*name)) - { emsg(_("E183: User defined commands must start with an uppercase letter")); - return; - } else if ((name_len == 1 && *name == 'X') || (name_len <= 4 && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) - { emsg(_("E841: Reserved name, cannot be used for user defined command")); - return; - } + else if (compl > 0 && (argt & EX_EXTRA) == 0) + emsg(_(e_complete_used_without_nargs)); else uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, addr_type_arg, eap->forceit); diff --git a/src/version.c b/src/version.c index 0ad55115b2..d8c9fb8762 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3141, /**/ 3140, /**/ From 1aeddeb8bd29a69fa118734c7f27d7df1b37801f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 14:55:49 +0200 Subject: [PATCH 02/42] patch 8.2.3142: Vim9: type check for has_key() argument is too strict Problem: Vim9: type check for has_key() argument is too strict. Solution: Also allow for a number key argument. (closes #8542) --- src/evalfunc.c | 3 ++- src/testdir/test_vim9_builtin.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 45df08d0c3..73012d45d6 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -446,6 +446,7 @@ argcheck_T arg2_number[] = {arg_number, arg_number}; argcheck_T arg2_string[] = {arg_string, arg_string}; argcheck_T arg2_list_nr[] = {arg_list_number, arg_list_number}; argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; +argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; @@ -1109,7 +1110,7 @@ static funcentry_T global_functions[] = ret_any, f_globpath}, {"has", 1, 2, 0, NULL, ret_number_bool, f_has}, - {"has_key", 2, 2, FEARG_1, arg2_dict_string, + {"has_key", 2, 2, FEARG_1, arg2_dict_string_or_nr, ret_number_bool, f_has_key}, {"haslocaldir", 0, 2, FEARG_1, arg2_number, ret_number, f_haslocaldir}, diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 6b6278b8d0..5bc51b11ca 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1131,6 +1131,12 @@ def Test_has() enddef def Test_has_key() + var d = {123: 'xx'} + assert_true(has_key(d, '123')) + assert_true(has_key(d, 123)) + assert_false(has_key(d, 'x')) + assert_false(has_key(d, 99)) + CheckDefAndScriptFailure2(['has_key([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') CheckDefAndScriptFailure2(['has_key({"a": 10}, ["a"])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef diff --git a/src/version.c b/src/version.c index d8c9fb8762..729d0e4a51 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3142, /**/ 3141, /**/ From d9162550aa47ca3865a5cadf78ff2212a1d8eca7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 15:26:13 +0200 Subject: [PATCH 03/42] patch 8.2.3143: Vim9: wrong context if lambda called from profiled function Problem: Vim9: A lambda may be compiled with the wrong context if it is called from a profiled function. Solution: Compile the lambda with and without profiling. (closes #8543) --- src/testdir/test_vim9_script.vim | 13 +++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index b21b63cbe0..eb4c5d120c 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4167,6 +4167,19 @@ def Test_option_modifier() set hlsearch& enddef +def ProfiledFunc() + var n = 3 + echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) +enddef + +" Execute this near the end, profiling doesn't stop until Vim exists. +" This only tests that it works, not the profiling output. +def Test_xx_profile_with_lambda() + profile start Xprofile.log + profile func ProfiledFunc + ProfiledFunc() +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/version.c b/src/version.c index 729d0e4a51..76dbacda3a 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3143, /**/ 3142, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c27a1cc34a..9aa11f6210 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3624,6 +3624,11 @@ compile_lambda(char_u **arg, cctx_T *cctx) ufunc->uf_ret_type = &t_unknown; compile_def_function(ufunc, FALSE, cctx->ctx_compile_type, cctx); + // When the outer function is compiled for profiling, the lambda may be + // called without profiling. Compile it here in the right context. + if (cctx->ctx_compile_type == CT_PROFILE) + compile_def_function(ufunc, FALSE, CT_NONE, cctx); + // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" // points into it. Point to the original line to avoid a dangling pointer. if (evalarg.eval_tofree_cmdline != NULL) From 0f1227f7d5a3e368f61d396c1640088c079fef91 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 16:01:58 +0200 Subject: [PATCH 04/42] patch 8.2.3144: Vim9: no error when using an invalid value for a line number Problem: Vim9: no error when using an invalid value for a line number. Solution: Give an error if the string value is not recognized. (closes #8536) --- src/errors.h | 2 ++ src/eval.c | 2 ++ src/testdir/test_vim9_builtin.vim | 23 +++++++++++++++++++++-- src/version.c | 2 ++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/errors.h b/src/errors.h index 7e823bfbf2..bfbe0296ed 100644 --- a/src/errors.h +++ b/src/errors.h @@ -498,3 +498,5 @@ EXTERN char e_expression_without_effect_str[] INIT(= N_("E1207: Expression without an effect: %s")); EXTERN char e_complete_used_without_nargs[] INIT(= N_("E1208: -complete used without -nargs")); +EXTERN char e_invalid_value_for_line_number_str[] + INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); diff --git a/src/eval.c b/src/eval.c index 4d94d67ee6..6537ffea41 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5376,6 +5376,8 @@ var2fpos( } return &pos; } + if (in_vim9script()) + semsg(_(e_invalid_value_for_line_number_str), name); return NULL; } diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 5bc51b11ca..e26c2c0dd1 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -474,7 +474,7 @@ def Test_cursor() var lines =<< trim END cursor('2', 1) END - CheckDefExecAndScriptFailure(lines, 'E475:') + CheckDefExecAndScriptFailure(lines, 'E1209:') enddef def Test_debugbreak() @@ -1036,6 +1036,25 @@ def Test_getjumplist() CheckDefFailure(['getjumplist(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_getline() + var lines =<< trim END + new + setline(1, ['hello', 'there', 'again']) + assert_equal('hello', getline(1)) + assert_equal('hello', getline('.')) + + normal 2Gvjv + assert_equal('there', getline("'<")) + assert_equal('again', getline("'>")) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + echo getline('1') + END + CheckDefExecAndScriptFailure(lines, 'E1209:') +enddef + def Test_getmarklist() CheckDefFailure(['getmarklist([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal([], getmarklist(10000)) @@ -1049,7 +1068,7 @@ enddef def Test_getpos() CheckDefFailure(['getpos(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal([0, 1, 1, 0], getpos('.')) - assert_equal([0, 0, 0, 0], getpos('a')) + CheckDefExecFailure(['getpos("a")'], 'E1209:') enddef def Test_getqflist() diff --git a/src/version.c b/src/version.c index 76dbacda3a..91a3677d56 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3144, /**/ 3143, /**/ From 4ece152ad60c4fbd5b98b849a39b8ad9a987d319 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 16:31:51 +0200 Subject: [PATCH 05/42] patch 8.2.3145: Vim9: profile test fails without profile feature Problem: Vim9: profile test fails without profile feature. Solution: Check the profile feature is present. --- src/testdir/test_vim9_script.vim | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index eb4c5d120c..ab0c031c54 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4175,6 +4175,8 @@ enddef " Execute this near the end, profiling doesn't stop until Vim exists. " This only tests that it works, not the profiling output. def Test_xx_profile_with_lambda() + CheckFeature profile + profile start Xprofile.log profile func ProfiledFunc ProfiledFunc() diff --git a/src/version.c b/src/version.c index 91a3677d56..82d2d1fa0f 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3145, /**/ 3144, /**/ From c03fe66ade4c79a4eb5fc05d1d549c8f931a04b6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 16:52:45 +0200 Subject: [PATCH 06/42] patch 8.2.3146: Vim9: line number wrong for :execute argument Problem: Vim9: line number wrong for :execute argument. Solution: Use the line number of the :execute command itself. (closes #8537) --- src/eval.c | 4 ++++ src/testdir/test_vim9_script.vim | 10 ++++++++++ src/version.c | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/eval.c b/src/eval.c index 6537ffea41..5dc1642a16 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6191,6 +6191,7 @@ ex_execute(exarg_T *eap) char_u *p; garray_T ga; int len; + long start_lnum = SOURCING_LNUM; ga_init2(&ga, 1, 80); @@ -6244,6 +6245,9 @@ ex_execute(exarg_T *eap) if (ret != FAIL && ga.ga_data != NULL) { + // use the first line of continuation lines for messages + SOURCING_LNUM = start_lnum; + if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr) { // Mark the already saved text as finishing the line, so that what diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index ab0c031c54..0602b2ae5b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4167,6 +4167,16 @@ def Test_option_modifier() set hlsearch& enddef +" This must be called last, it may cause following :def functions to fail +def Test_xxx_echoerr_line_number() + var lines =<< trim END + echoerr 'some' + .. ' error' + .. ' continued' + END + CheckDefExecAndScriptFailure(lines, 'some error continued', 1) +enddef + def ProfiledFunc() var n = 3 echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) diff --git a/src/version.c b/src/version.c index 82d2d1fa0f..8e1d88e3e9 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3146, /**/ 3145, /**/ From 648594eaf703fe9a862cb12a35702a10aff6e5a9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 17:55:01 +0200 Subject: [PATCH 07/42] patch 8.2.3147: Vim9: profiling does not work with a nested function Problem: Vim9: profiling does not work with a nested function. Solution: Also compile a nested function without profiling. (closes #8543) Handle that compiling may cause the table of compiled functions to change. --- src/testdir/test_vim9_script.vim | 16 +++++++++++++--- src/version.c | 2 ++ src/vim9compile.c | 10 ++++++++++ src/vim9execute.c | 21 +++++++++------------ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 0602b2ae5b..10f41c7bf8 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4177,19 +4177,29 @@ def Test_xxx_echoerr_line_number() CheckDefExecAndScriptFailure(lines, 'some error continued', 1) enddef -def ProfiledFunc() +def ProfiledWithLambda() var n = 3 echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) enddef +def ProfiledNested() + var x = 0 + def Nested(): any + return x + enddef + Nested() +enddef + " Execute this near the end, profiling doesn't stop until Vim exists. " This only tests that it works, not the profiling output. def Test_xx_profile_with_lambda() CheckFeature profile profile start Xprofile.log - profile func ProfiledFunc - ProfiledFunc() + profile func ProfiledWithLambda + ProfiledWithLambda() + profile func ProfiledNested + ProfiledNested() enddef " Keep this last, it messes up highlighting. diff --git a/src/version.c b/src/version.c index 8e1d88e3e9..993d163185 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3147, /**/ 3146, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 9aa11f6210..b04e750ef5 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3624,10 +3624,12 @@ compile_lambda(char_u **arg, cctx_T *cctx) ufunc->uf_ret_type = &t_unknown; compile_def_function(ufunc, FALSE, cctx->ctx_compile_type, cctx); +#ifdef FEAT_PROFILE // When the outer function is compiled for profiling, the lambda may be // called without profiling. Compile it here in the right context. if (cctx->ctx_compile_type == CT_PROFILE) compile_def_function(ufunc, FALSE, CT_NONE, cctx); +#endif // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" // points into it. Point to the original line to avoid a dangling pointer. @@ -5631,6 +5633,14 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) goto theend; } +#ifdef FEAT_PROFILE + // When the outer function is compiled for profiling, the nested function + // may be called without profiling. Compile it here in the right context. + if (COMPILE_TYPE(ufunc) == CT_PROFILE + && func_needs_compiling(ufunc, CT_NONE)) + compile_def_function(ufunc, FALSE, CT_NONE, cctx); +#endif + if (is_global) { char_u *func_name = vim_strnsave(name_start + 2, diff --git a/src/vim9execute.c b/src/vim9execute.c index 87f3c424ea..41249284dc 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -197,6 +197,7 @@ call_dfunc( int idx; estack_T *entry; funclocal_T *floc = NULL; + int res = OK; if (dfunc->df_deleted) { @@ -219,14 +220,6 @@ call_dfunc( (((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx)->df_ufunc); } - - // Profiling might be enabled/disabled along the way. This should not - // fail, since the function was compiled before and toggling profiling - // doesn't change any errors. - if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) - == FAIL) - return FAIL; } #endif @@ -235,10 +228,14 @@ call_dfunc( // When debugging and using "cont" switches to the not-debugged // instructions, may need to still compile them. - if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) - == FAIL) - || INSTRUCTIONS(dfunc) == NULL) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))) + { + res = compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL); + + // compile_def_function() may cause def_functions.ga_data to change + dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx; + } + if (res == FAIL || INSTRUCTIONS(dfunc) == NULL) { if (did_emsg_cumul + did_emsg == did_emsg_before) semsg(_(e_function_is_not_compiled_str), From 5231224e11bf468f5366a7400414368908c40795 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 18:23:19 +0200 Subject: [PATCH 08/42] patch 8.2.3148: Vim9: function arg type check does not handle base offset Problem: Vim9: function arg type check does not handle base offset. Solution: Take the base offset into account when checking builtin function argument types. --- src/evalfunc.c | 3 ++- src/testdir/test_vim9_builtin.vim | 2 ++ src/version.c | 2 ++ src/vim9compile.c | 11 +++++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 73012d45d6..3041a6c380 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -450,6 +450,7 @@ argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; +argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list, arg_string}; argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; @@ -1832,7 +1833,7 @@ static funcentry_T global_functions[] = ret_string, f_visualmode}, {"wildmenumode", 0, 0, 0, NULL, ret_number, f_wildmenumode}, - {"win_execute", 2, 3, FEARG_2, NULL, + {"win_execute", 2, 3, FEARG_2, arg23_win_execute, ret_string, f_win_execute}, {"win_findbuf", 1, 1, FEARG_1, arg1_number, ret_list_number, f_win_findbuf}, diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index e26c2c0dd1..a17d92a19a 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -2305,6 +2305,8 @@ enddef def Test_win_execute() assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()')) + assert_equal("\n" .. winnr(), 'echo winnr()'->win_execute(win_getid())) + assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()', 'silent')) assert_equal('', win_execute(342343, 'echo winnr()')) enddef diff --git a/src/version.c b/src/version.c index 993d163185..10e01ac86b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3148, /**/ 3147, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index b04e750ef5..15c8ef6a8c 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1781,6 +1781,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) garray_T *stack = &cctx->ctx_type_stack; int argoff; type_T **argtypes = NULL; + type_T *shuffled_argtypes[MAX_FUNC_ARGS]; type_T *maptype = NULL; RETURN_OK_IF_SKIP(cctx); @@ -1800,6 +1801,16 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) { // Check the types of the arguments. argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount; + if (method_call && argoff > 1) + { + int i; + + for (i = 0; i < argcount; ++i) + shuffled_argtypes[i] = (i < argoff - 1) + ? argtypes[i + 1] + : (i == argoff - 1) ? argtypes[0] : argtypes[i]; + argtypes = shuffled_argtypes; + } if (internal_func_check_arg_types(argtypes, func_idx, argcount, cctx) == FAIL) return FAIL; From cc7eb2aa7a7f2e6ae41f1e7cf60965c083d8a9e9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 19:12:04 +0200 Subject: [PATCH 09/42] patch 8.2.3149: some plugins have a problem with the error check Problem: Some plugins have a problem with the error check for using :command with -complete but without -nargs. Solution: In legacy script only give a warning message. --- src/message.c | 21 ++++++++++++++++++++- src/proto/message.pro | 1 + src/testdir/test_usercommands.vim | 22 ++++++++++++++++++++-- src/usercmd.c | 10 +++++++++- src/version.c | 2 ++ 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/message.c b/src/message.c index cb713d7210..7fb7264bd8 100644 --- a/src/message.c +++ b/src/message.c @@ -3613,6 +3613,12 @@ verbose_open(void) */ void give_warning(char_u *message, int hl) +{ + give_warning_with_source(message, hl, FALSE); +} + + void +give_warning_with_source(char_u *message, int hl, int with_source) { // Don't do this for ":silent". if (msg_silent != 0) @@ -3629,8 +3635,21 @@ give_warning(char_u *message, int hl) keep_msg_attr = HL_ATTR(HLF_W); else keep_msg_attr = 0; - if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) + + if (with_source) + { + // Do what msg() does, but with a column offset if the warning should + // be after the mode message. + msg_start(); + msg_source(HL_ATTR(HLF_W)); + msg_puts(" "); + msg_puts_attr((char *)message, HL_ATTR(HLF_W) | MSG_HIST); + msg_clr_eos(); + (void)msg_end(); + } + else if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) set_keep_msg(message, keep_msg_attr); + msg_didout = FALSE; // overwrite this message msg_nowait = TRUE; // don't wait for this message msg_col = 0; diff --git a/src/proto/message.pro b/src/proto/message.pro index 16c3354840..d3ec949030 100644 --- a/src/proto/message.pro +++ b/src/proto/message.pro @@ -69,6 +69,7 @@ void verbose_leave_scroll(void); void verbose_stop(void); int verbose_open(void); void give_warning(char_u *message, int hl); +void give_warning_with_source(char_u *message, int hl, int with_source); void give_warning2(char_u *message, char_u *a1, int hl); void msg_advance(int col); int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd); diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim index 93312f1ecf..f0f056f88c 100644 --- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -1,5 +1,7 @@ " Tests for user defined commands +source vim9.vim + " Test for in user defined commands function Test_cmdmods() let g:mods = '' @@ -270,13 +272,29 @@ func Test_CmdErrors() call assert_fails('com! -complete=custom DoCmd :', 'E467:') call assert_fails('com! -complete=customlist DoCmd :', 'E467:') call assert_fails('com! -complete=behave,CustomComplete DoCmd :', 'E468:') - call assert_fails('com! -complete=file DoCmd :', 'E1208:') - call assert_fails('com! -nargs=0 -complete=file DoCmd :', 'E1208:') call assert_fails('com! -nargs=x DoCmd :', 'E176:') call assert_fails('com! -count=1 -count=2 DoCmd :', 'E177:') call assert_fails('com! -count=x DoCmd :', 'E178:') call assert_fails('com! -range=x DoCmd :', 'E178:') + com! -complete=file DoCmd : + call assert_match('E1208:', v:warningmsg) + let v:warningmsg = '' + com! -nargs=0 -complete=file DoCmd : + call assert_match('E1208:', v:warningmsg) + + let lines =<< trim END + vim9script + com! -complete=file DoCmd : + END + call CheckScriptFailure(lines, 'E1208', 2) + + let lines =<< trim END + vim9script + com! -nargs=0 -complete=file DoCmd : + END + call CheckScriptFailure(lines, 'E1208', 2) + com! -nargs=0 DoCmd : call assert_fails('DoCmd x', 'E488:') diff --git a/src/usercmd.c b/src/usercmd.c index 94ebb43af0..42b9014f38 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -1027,7 +1027,15 @@ ex_command(exarg_T *eap) && STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0)) emsg(_("E841: Reserved name, cannot be used for user defined command")); else if (compl > 0 && (argt & EX_EXTRA) == 0) - emsg(_(e_complete_used_without_nargs)); + { + // Some plugins rely on silently ignoring the mistake, only make this + // an error in Vim9 script. + if (in_vim9script()) + emsg(_(e_complete_used_without_nargs)); + else + give_warning_with_source( + (char_u *)_(e_complete_used_without_nargs), TRUE, TRUE); + } else uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, addr_type_arg, eap->forceit); diff --git a/src/version.c b/src/version.c index 10e01ac86b..1102e94fc4 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3149, /**/ 3148, /**/ From c72bdd28ac5fe079825155930af8e792580139bb Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sun, 11 Jul 2021 19:44:18 +0200 Subject: [PATCH 10/42] patch 8.2.3150: Vim9: argument types are not checked at compile time Problem: Vim9: argument types are not checked at compile time. Solution: Add more type checks. (Yegappan Lakshmanan, closes #8545) --- src/evalfunc.c | 70 ++++++++++++++++++++++--------- src/testdir/test_vim9_builtin.vim | 64 +++++++++++++++++++++++++++- src/testing.c | 3 ++ src/version.c | 2 + 4 files changed, 118 insertions(+), 21 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 3041a6c380..4aa3b6d2af 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -322,7 +322,7 @@ arg_string_or_nr(type_T *type, argcontext_T *context) * Check "type" is a string or a list of strings. */ static int -arg_string_or_list(type_T *type, argcontext_T *context) +arg_string_or_list_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING) return OK; @@ -339,6 +339,19 @@ arg_string_or_list(type_T *type, argcontext_T *context) return FAIL; } +/* + * Check "type" is a string or a list of 'any' + */ + static int +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; +} + /* * Check "type" is a list or a dict. */ @@ -412,6 +425,20 @@ arg_item_of_prev(type_T *type, argcontext_T *context) return check_arg_type(expected, type, context); } +/* + * Check "type" is a string or a number or a list + */ + static int +arg_str_or_nr_or_list(type_T *type, argcontext_T *context) +{ + if (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; +} + /* * Check "type" which is the third argument of extend(). */ @@ -438,7 +465,8 @@ argcheck_T arg1_list_nr[] = {arg_list_number}; argcheck_T arg1_list_string[] = {arg_list_string}; argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; -argcheck_T arg1_string_or_list[] = {arg_string_or_list}; +argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any}; +argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string}; argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; @@ -449,14 +477,18 @@ argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; -argcheck_T arg2_execute[] = {arg_string_or_list, arg_string}; -argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list, arg_string}; -argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; -argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; +argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; +argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; +argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string}; +argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; +argcheck_T arg2_setline[] = {arg_string_or_nr, arg_string_or_list_any}; +argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_string_or_list_any}; +argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; +argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; /* @@ -765,7 +797,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_assert_notequal}, {"assert_notmatch", 2, 3, FEARG_2, arg3_string, ret_number_bool, f_assert_notmatch}, - {"assert_report", 1, 1, FEARG_1, NULL, + {"assert_report", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_report}, {"assert_true", 1, 2, FEARG_1, NULL, ret_number_bool, f_assert_true}, @@ -781,7 +813,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list, + {"balloon_show", 1, 1, FEARG_1, arg1_string_or_list_any, ret_void, #ifdef FEAT_BEVAL f_balloon_show @@ -877,7 +909,7 @@ static funcentry_T global_functions[] = ret_number, f_char2nr}, {"charclass", 1, 1, FEARG_1, arg1_string, ret_number, f_charclass}, - {"charcol", 1, 1, FEARG_1, arg1_string_or_list, + {"charcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_charcol}, {"charidx", 2, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_charidx}, @@ -887,7 +919,7 @@ static funcentry_T global_functions[] = ret_number, f_cindent}, {"clearmatches", 0, 1, FEARG_1, arg1_number, ret_void, f_clearmatches}, - {"col", 1, 1, FEARG_1, arg1_string_or_list, + {"col", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_col}, {"complete", 2, 2, FEARG_2, NULL, ret_void, f_complete}, @@ -1301,17 +1333,17 @@ static funcentry_T global_functions[] = NULL #endif }, - {"popup_atcursor", 2, 2, FEARG_1, NULL, + {"popup_atcursor", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_atcursor)}, - {"popup_beval", 2, 2, FEARG_1, NULL, + {"popup_beval", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_beval)}, {"popup_clear", 0, 1, 0, NULL, ret_void, PROP_FUNC(f_popup_clear)}, {"popup_close", 1, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_close)}, - {"popup_create", 2, 2, FEARG_1, NULL, + {"popup_create", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_create)}, - {"popup_dialog", 2, 2, FEARG_1, NULL, + {"popup_dialog", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_dialog)}, {"popup_filter_menu", 2, 2, 0, NULL, ret_bool, PROP_FUNC(f_popup_filter_menu)}, @@ -1331,11 +1363,11 @@ static funcentry_T global_functions[] = ret_list_number, PROP_FUNC(f_popup_list)}, {"popup_locate", 2, 2, 0, arg2_number, ret_number, PROP_FUNC(f_popup_locate)}, - {"popup_menu", 2, 2, FEARG_1, NULL, + {"popup_menu", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_menu)}, {"popup_move", 2, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_move)}, - {"popup_notification", 2, 2, FEARG_1, NULL, + {"popup_notification", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_notification)}, {"popup_setoptions", 2, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_setoptions)}, @@ -1541,7 +1573,7 @@ static funcentry_T global_functions[] = ret_string, f_shellescape}, {"shiftwidth", 0, 1, FEARG_1, arg1_number, ret_number, f_shiftwidth}, - {"sign_define", 1, 2, FEARG_1, arg2_string_dict, + {"sign_define", 1, 2, FEARG_1, arg2_string_or_list_dict, ret_any, SIGN_FUNC(f_sign_define)}, {"sign_getdefined", 0, 1, FEARG_1, NULL, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)}, @@ -1553,7 +1585,7 @@ static funcentry_T global_functions[] = ret_number, SIGN_FUNC(f_sign_place)}, {"sign_placelist", 1, 1, FEARG_1, NULL, ret_list_number, SIGN_FUNC(f_sign_placelist)}, - {"sign_undefine", 0, 1, FEARG_1, arg1_string_or_list, + {"sign_undefine", 0, 1, FEARG_1, arg1_string_or_list_string, ret_number_bool, SIGN_FUNC(f_sign_undefine)}, {"sign_unplace", 1, 2, FEARG_1, arg2_string_dict, ret_number_bool, SIGN_FUNC(f_sign_unplace)}, @@ -1827,7 +1859,7 @@ static funcentry_T global_functions[] = ret_list_any, f_uniq}, {"values", 1, 1, FEARG_1, arg1_dict, ret_list_any, f_values}, - {"virtcol", 1, 1, FEARG_1, arg1_string_or_list, + {"virtcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_virtcol}, {"visualmode", 0, 1, 0, NULL, ret_string, f_visualmode}, diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index a17d92a19a..2a58747bf6 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -213,12 +213,19 @@ def Test_assert_notmatch() CheckDefFailure(['assert_notmatch("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special') enddef +def Test_assert_report() + CheckDefAndScriptFailure2(['assert_report([1, 2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') +enddef + def Test_balloon_show() CheckGui CheckFeature balloon_eval assert_fails('balloon_show(10)', 'E1174:') assert_fails('balloon_show(true)', 'E1174:') + + CheckDefAndScriptFailure2(['balloon_show(1.2)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['balloon_show({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E1174: String required for argument 1') enddef def Test_balloon_split() @@ -387,6 +394,13 @@ enddef def Test_charcol() CheckDefFailure(['charcol(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['charcol({a: 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict') + new + setline(1, ['abcdefgh']) + cursor(1, 4) + assert_equal(4, charcol('.')) + assert_equal(9, charcol([1, '$'])) + assert_equal(0, charcol([10, '$'])) + bw! enddef def Test_charidx() @@ -412,8 +426,11 @@ enddef def Test_col() new - setline(1, 'asdf') - col([1, '$'])->assert_equal(5) + setline(1, 'abcdefgh') + cursor(1, 4) + assert_equal(4, col('.')) + col([1, '$'])->assert_equal(9) + assert_equal(0, col([10, '$'])) assert_fails('col(true)', 'E1174:') @@ -1503,11 +1520,36 @@ def Test_or() CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_popup_atcursor() + CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_beval() + CheckDefAndScriptFailure2(['popup_beval({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_dialog() + CheckDefAndScriptFailure2(['popup_dialog({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + def Test_popup_locate() CheckDefAndScriptFailure2(['popup_locate("a", 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number') enddef +def Test_popup_menu() + CheckDefAndScriptFailure2(['popup_menu({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_menu("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_popup_notification() + CheckDefAndScriptFailure2(['popup_notification({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') + CheckDefAndScriptFailure2(['popup_notification("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + def Test_prevnonblank() CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') assert_equal(0, prevnonblank(1)) @@ -1887,6 +1929,17 @@ def Test_setfperm() CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob') enddef +def Test_setline() + new + setline(1, range(1, 4)) + assert_equal(['1', '2', '3', '4'], getline(1, '$')) + setline(1, ['a', 'b', 'c', 'd']) + assert_equal(['a', 'b', 'c', 'd'], getline(1, '$')) + setline(1, 'one') + assert_equal(['one', 'b', 'c', 'd'], getline(1, '$')) + bw! +enddef + def Test_setloclist() var items = [{filename: '/tmp/file', lnum: 1, valid: true}] var what = {items: items} @@ -2301,6 +2354,13 @@ enddef def Test_virtcol() CheckDefAndScriptFailure2(['virtcol(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1') + new + setline(1, ['abcdefgh']) + cursor(1, 4) + assert_equal(4, virtcol('.')) + assert_equal(9, virtcol([1, '$'])) + assert_equal(0, virtcol([10, '$'])) + bw! enddef def Test_win_execute() diff --git a/src/testing.c b/src/testing.c index c2389bdeeb..80596d44bc 100644 --- a/src/testing.c +++ b/src/testing.c @@ -824,6 +824,9 @@ f_assert_report(typval_T *argvars, typval_T *rettv) { garray_T ga; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + prepare_assert_error(&ga); ga_concat(&ga, tv_get_string(&argvars[0])); assert_error(&ga); diff --git a/src/version.c b/src/version.c index 1102e94fc4..0047c7dbc8 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3150, /**/ 3149, /**/ From ffcfddc759e583471a1ed55e0938d042bf68c507 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 20:22:30 +0200 Subject: [PATCH 11/42] patch 8.2.3151: Vim9: profiling fails if nested function is also profiled Problem: Vim9: profiling fails if nested function is also profiled. Solution: Use the compile type from the outer function. (closes #8543) --- src/testdir/test_vim9_script.vim | 17 +++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 16 +++++++++++----- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 10f41c7bf8..b4107e97d1 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4190,6 +4190,14 @@ def ProfiledNested() Nested() enddef +def ProfiledNestedProfiled() + var x = 0 + def Nested(): any + return x + enddef + Nested() +enddef + " Execute this near the end, profiling doesn't stop until Vim exists. " This only tests that it works, not the profiling output. def Test_xx_profile_with_lambda() @@ -4198,8 +4206,17 @@ def Test_xx_profile_with_lambda() profile start Xprofile.log profile func ProfiledWithLambda ProfiledWithLambda() + profile func ProfiledNested ProfiledNested() + + # Also profile the nested function. Use a different function, although the + # contents is the same, to make sure it was not already compiled. + profile func * + ProfiledNestedProfiled() + + profdel func * + profile pause enddef " Keep this last, it messes up highlighting. diff --git a/src/version.c b/src/version.c index 0047c7dbc8..7f9f49efd1 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3151, /**/ 3150, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 15c8ef6a8c..d25183f19e 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5570,6 +5570,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) char_u *lambda_name; ufunc_T *ufunc; int r = FAIL; + compiletype_T compile_type; if (eap->forceit) { @@ -5636,9 +5637,15 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) } } - if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) - && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx) - == FAIL) + compile_type = COMPILE_TYPE(ufunc); +#ifdef FEAT_PROFILE + // If the outer function is profiled, also compile the nested function for + // profiling. + if (cctx->ctx_compile_type == CT_PROFILE) + compile_type = CT_PROFILE; +#endif + if (func_needs_compiling(ufunc, compile_type) + && compile_def_function(ufunc, TRUE, compile_type, cctx) == FAIL) { func_ptr_unref(ufunc); goto theend; @@ -5647,8 +5654,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) #ifdef FEAT_PROFILE // When the outer function is compiled for profiling, the nested function // may be called without profiling. Compile it here in the right context. - if (COMPILE_TYPE(ufunc) == CT_PROFILE - && func_needs_compiling(ufunc, CT_NONE)) + if (compile_type == CT_PROFILE && func_needs_compiling(ufunc, CT_NONE)) compile_def_function(ufunc, FALSE, CT_NONE, cctx); #endif From 11005b078d2485a306c74f77c9dd158fdd7f3cbe Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 11 Jul 2021 20:59:00 +0200 Subject: [PATCH 12/42] patch 8.2.3152: Vim9: accessing "s:" results in an error Problem: Vim9: accessing "s:" results in an error. Solution: Do not try to lookup a script variable for "s:". (closes #8549) --- src/evalvars.c | 3 ++- src/testdir/test_vim9_expr.vim | 7 +++++++ src/version.c | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/evalvars.c b/src/evalvars.c index 66018cff05..27d7328715 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2660,7 +2660,8 @@ eval_variable( } else if (rettv != NULL) { - if (ht != NULL && ht == get_script_local_ht()) + if (ht != NULL && ht == get_script_local_ht() + && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv) { svar_T *sv = find_typval_in_script(tv); diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 79a4ea36e5..f0e15c37ec 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2478,6 +2478,13 @@ def Test_expr7_dict_vim9script() else CheckDefAndScriptFailure(lines, 'E117:', 0) endif + + lines =<< trim END + vim9script + var x = 99 + assert_equal({x: 99}, s:) + END + CheckScriptSuccess(lines) enddef def Test_expr7_call_2bool() diff --git a/src/version.c b/src/version.c index 7f9f49efd1..21394aa1a7 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3152, /**/ 3151, /**/ From 7b7a118e74d25ff35cd277c2bb5191ae44bb20b2 Mon Sep 17 00:00:00 2001 From: Tsuyoshi CHO Date: Sun, 11 Jul 2021 21:51:17 +0200 Subject: [PATCH 13/42] patch 8.2.3153: URLs with a dash in the scheme are not recognized Problem: URLs with a dash in the scheme are not recognized. Solution: Allow for a scheme with a dash, but not at the start or end. (Tsuyoshi CHO, closes #8299) --- src/misc1.c | 21 ++++++++++++++++++--- src/testdir/test_buffer.vim | 29 +++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/misc1.c b/src/misc1.c index d112d9b95d..554f10b186 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -2600,8 +2600,8 @@ path_is_url(char_u *p) } /* - * Check if "fname" starts with "name://". Return URL_SLASH if it does. - * Return URL_BACKSLASH for "name:\\". + * Check if "fname" starts with "name://" or "name:\\". + * Return URL_SLASH for "name://", URL_BACKSLASH for "name:\\". * Return zero otherwise. */ int @@ -2609,7 +2609,22 @@ path_with_url(char_u *fname) { char_u *p; - for (p = fname; isalpha(*p); ++p) + // We accept alphabetic characters and a dash in scheme part. + // RFC 3986 allows for more, but it increases the risk of matching + // non-URL text. + + // first character must be alpha + if (!isalpha(*fname)) + return 0; + + // check body: alpha or dash + for (p = fname; (isalpha(*p) || (*p == '-')); ++p) ; + + // check last char is not a dash + if (p[-1] == '-') + return 0; + + // "://" or ":\\" must follow return path_is_url(p); } diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim index 960a760ebd..aa2fe7ac64 100644 --- a/src/testdir/test_buffer.vim +++ b/src/testdir/test_buffer.vim @@ -381,6 +381,35 @@ func Test_balt() call assert_equal('OtherBuffer', bufname()) endfunc +" Test for buffer match URL(scheme) check +" scheme is alpha and inner hyphen only. +func Test_buffer_scheme() + CheckMSWindows + + set noshellslash + %bwipe! + let bufnames = [ + \ #{id: 'b0', name: 'test://xyz/foo/b0' , match: 1}, + \ #{id: 'b1', name: 'test+abc://xyz/foo/b1', match: 0}, + \ #{id: 'b2', name: 'test_abc://xyz/foo/b2', match: 0}, + \ #{id: 'b3', name: 'test-abc://xyz/foo/b3', match: 1}, + \ #{id: 'b4', name: '-test://xyz/foo/b4' , match: 0}, + \ #{id: 'b5', name: 'test-://xyz/foo/b5' , match: 0}, + \] + for buf in bufnames + new `=buf.name` + if buf.match + call assert_equal(buf.name, getbufinfo(buf.id)[0].name) + else + " slashes will have become backslashes + call assert_notequal(buf.name, getbufinfo(buf.id)[0].name) + endif + bwipe + endfor + + set shellslash& +endfunc + " Test for the 'maxmem' and 'maxmemtot' options func Test_buffer_maxmem() " use 1KB per buffer and 2KB for all the buffers diff --git a/src/version.c b/src/version.c index 21394aa1a7..940c7192fa 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3153, /**/ 3152, /**/ From 841e498c5d1765eab17bce5242543b47dfc25b41 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sun, 11 Jul 2021 22:04:25 +0200 Subject: [PATCH 14/42] patch 8.2.3154: Vim9: some type checks for builtin functions fail Problem: Vim9: some type checks for builtin functions fail. Solution: Correct the type checks. (Yegappan Lakshmanan, closes #8551, closes #8550) --- src/evalfunc.c | 7 ++++--- src/testdir/test_vim9_builtin.vim | 15 +++++++++++++++ src/version.c | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 4aa3b6d2af..060b5bbb28 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -431,9 +431,10 @@ arg_item_of_prev(type_T *type, argcontext_T *context) static int arg_str_or_nr_or_list(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_STRING - || type->tt_type == VAR_NUMBER - || type->tt_type == VAR_LIST) + 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; diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 2a58747bf6..f3e44e3b9e 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1523,6 +1523,12 @@ enddef def Test_popup_atcursor() CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') + + # Pass variable of type 'any' to popup_atcursor() + var what: any = 'Hello' + var popupID = what->popup_atcursor({moved: 'any'}) + assert_equal(0, popupID->popup_getoptions().tabpage) + popupID->popup_close() enddef def Test_popup_beval() @@ -1530,6 +1536,14 @@ def Test_popup_beval() CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_popup_create() + # Pass variable of type 'any' to popup_create() + var what: any = 'Hello' + var popupID = what->popup_create({}) + assert_equal(0, popupID->popup_getoptions().tabpage) + popupID->popup_close() +enddef + def Test_popup_dialog() CheckDefAndScriptFailure2(['popup_dialog({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') @@ -2358,6 +2372,7 @@ def Test_virtcol() setline(1, ['abcdefgh']) cursor(1, 4) assert_equal(4, virtcol('.')) + assert_equal(4, virtcol([1, 4])) assert_equal(9, virtcol([1, '$'])) assert_equal(0, virtcol([10, '$'])) bw! diff --git a/src/version.c b/src/version.c index 940c7192fa..9159011a71 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3154, /**/ 3153, /**/ From 042414fa0053388f9a35cad61886405507554068 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Mon, 12 Jul 2021 21:43:19 +0200 Subject: [PATCH 15/42] patch 8.2.3155: some option related code not covered by tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Some option related code not covered by tests. Solution: Add a few test cases. (Dominique Pellé, closes #8552) --- src/testdir/test_options.vim | 44 ++++++++++++++++++++++++++++++++++++ src/testdir/test_set.vim | 19 ++++++++++++++++ src/version.c | 2 ++ 3 files changed, 65 insertions(+) diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index dedac5a65d..e10ad5445a 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -933,6 +933,28 @@ func Test_opt_local_to_global() set autoread& endfunc +func Test_set_in_sandbox() + " Some boolean options cannot be set in sandbox, some can. + call assert_fails('sandbox set modelineexpr', 'E48:') + sandbox set number + call assert_true(&number) + set number& + + " Some boolean options cannot be set in sandbox, some can. + if has('python') || has('python3') + call assert_fails('sandbox set pyxversion=3', 'E48:') + endif + sandbox set tabstop=4 + call assert_equal(4, &tabstop) + set tabstop& + + " Some string options cannot be set in sandbox, some can. + call assert_fails('sandbox set backupdir=/tmp', 'E48:') + sandbox set filetype=perl + call assert_equal('perl', &filetype) + set filetype& +endfunc + " Test for incrementing, decrementing and multiplying a number option value func Test_opt_num_op() set shiftwidth=4 @@ -1149,4 +1171,26 @@ func Test_opt_errorbells() set noerrorbells endfunc +func Test_opt_scrolljump() + help + resize 10 + + " Test with positive 'scrolljump'. + set scrolljump=2 + norm! Lj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':3, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + " Test with negative 'scrolljump' (percentage of window height). + set scrolljump=-40 + norm! ggLj + call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0, + \ 'topline':5, 'coladd':0, 'skipcol':0, 'curswant':0}, + \ winsaveview()) + + set scrolljump& + bw +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_set.vim b/src/testdir/test_set.vim index 2b1e9eeee0..7215772a00 100644 --- a/src/testdir/test_set.vim +++ b/src/testdir/test_set.vim @@ -26,4 +26,23 @@ function Test_set_add() let &wig = wig_save endfunction + +" :set, :setlocal, :setglobal without arguments show values of options. +func Test_set_no_arg() + set textwidth=79 + let a = execute('set') + call assert_match("^\n--- Options ---\n.*textwidth=79\\>", a) + set textwidth& + + setlocal textwidth=78 + let a = execute('setlocal') + call assert_match("^\n--- Local option values ---\n.*textwidth=78\\>", a) + setlocal textwidth& + + setglobal textwidth=77 + let a = execute('setglobal') + call assert_match("^\n--- Global option values ---\n.*textwidth=77\\>", a) + setglobal textwidth& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 9159011a71..f2f229f916 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3155, /**/ 3154, /**/ From ee41052ccb65f8109f285fc43eed3e232de68375 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Mon, 12 Jul 2021 22:15:24 +0200 Subject: [PATCH 16/42] patch 8.2.3156: Vim9: term_getansicolors() test fails without +termguicolors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Vim9: term_getansicolors() test fails without +termguicolors. Solution: Add a check for the feature. (Dominique Pellé, closes #8555) --- src/testdir/test_vim9_builtin.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index f3e44e3b9e..03bc3fbe30 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -2217,6 +2217,7 @@ enddef def Test_term_getansicolors() CheckRunVimInTerminal + CheckFeature termguicolors CheckDefAndScriptFailure2(['term_getansicolors(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') enddef diff --git a/src/version.c b/src/version.c index f2f229f916..c2314cdf2c 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3156, /**/ 3155, /**/ From 16e26a31161d65baca7885c46c43ab4a48399c92 Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Tue, 13 Jul 2021 19:09:12 +0200 Subject: [PATCH 17/42] patch 8.2.3157: crypt test may fail on MS-Windows Problem: Crypt test may fail on MS-Windows. Solution: Ignore "[unix]" in the file message. (Christian Brabandt, closes #8561) --- src/testdir/test_crypt.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index a18dfa3d17..883c899cfe 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -162,8 +162,8 @@ func Test_uncrypt_xchacha20_2() call assert_equal(range(1, 4000)->map( {_, v -> string(v)}), getline(1,'$')) set key= w! ++ff=unix - " enryption removed - call assert_match('"Xcrypt_sodium.txt" 4000L, 18893B written', execute(':message')) + " enryption removed (on MS-Windows the .* matches [unix]) + call assert_match('"Xcrypt_sodium.txt".*4000L, 18893B written', execute(':message')) bw! call delete('Xcrypt_sodium.txt') set cryptmethod&vim diff --git a/src/version.c b/src/version.c index c2314cdf2c..ace5a9d83a 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3157, /**/ 3156, /**/ From 1840a7b4e3577e617f724c9d07ccc78195cc010a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Jul 2021 20:32:29 +0200 Subject: [PATCH 18/42] patch 8.2.3158: strange error message when using islocked() with a number Problem: Strange error message when using islocked() with a number. (Yegappan Lakshmanan) Solution: Check that the name is empty. --- src/evalfunc.c | 5 ++++- src/testdir/test_functions.vim | 5 +++++ src/version.c | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 060b5bbb28..029c8a6411 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5961,7 +5961,10 @@ f_islocked(typval_T *argvars, typval_T *rettv) if (end != NULL && lv.ll_name != NULL) { if (*end != NUL) - semsg(_(e_trailing_arg), end); + { + semsg(_(lv.ll_name == lv.ll_name_end + ? e_invarg2 : e_trailing_arg), end); + } else { if (lv.ll_tv == NULL) diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index a4ca5d45ff..e0b0314d39 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -95,6 +95,11 @@ func Test_test_void() call assert_fails('let x = copy([test_void()])', 'E1031:') endfunc +func Test_islocked() + call assert_fails('call islocked(99)', 'E475:') + call assert_fails('call islocked("s: x")', 'E488:') +endfunc + func Test_len() call assert_equal(1, len(0)) call assert_equal(2, len(12)) diff --git a/src/version.c b/src/version.c index ace5a9d83a..3de3048447 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3158, /**/ 3157, /**/ From 5bea41dea34bcc73c4efb1b554ad0a2018966ecc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 13 Jul 2021 22:21:44 +0200 Subject: [PATCH 19/42] patch 8.2.3159: cursor displayed in wrong position after deleting line Problem: Cursor displayed in wrong position after deleting line. Solution: When deleting lines do not approximate botline. (fixes #8559) --- src/change.c | 9 ++++++--- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/change.c b/src/change.c index 248e6d8487..73ea64ff19 100644 --- a/src/change.c +++ b/src/change.c @@ -563,9 +563,12 @@ changed_common( changed_cline_bef_curs_win(wp); if (wp->w_botline >= lnum) { - // Assume that botline doesn't change (inserted lines make - // other lines scroll down below botline). - approximate_botline_win(wp); + if (xtra < 0) + invalidate_botline_win(wp); + else + // Assume that botline doesn't change (inserted lines make + // other lines scroll down below botline). + approximate_botline_win(wp); } // Check if any w_lines[] entries have become invalid. diff --git a/src/version.c b/src/version.c index 3de3048447..86a6380727 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3159, /**/ 3158, /**/ From 4a0b85ad0193ac162e2d8458e4b1c5ad2e2b0193 Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Wed, 14 Jul 2021 20:00:27 +0200 Subject: [PATCH 20/42] patch 8.2.3160: 'breakindent' does not work well for bulleted lists Problem: 'breakindent' does not work well for bulleted and numbered lists. Solution: Add the "list" entry to 'breakindentopt'. (Christian Brabandt, closes #8564, closes #1661) --- runtime/doc/options.txt | 5 ++- src/indent.c | 23 +++++++++++ src/structs.h | 1 + src/testdir/test_breakindent.vim | 70 ++++++++++++++++++++++++++++++++ src/version.c | 2 + 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index af2e23eca7..aaac094884 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1326,7 +1326,10 @@ A jump table for the options with a short description can be found at |Q_op|. continuation (positive). sbr Display the 'showbreak' value before applying the additional indent. - The default value for min is 20 and shift is 0. + list:{n} Adds an additional indent for lines that match a + numbered or bulleted list (using the + 'formatlistpat' setting). + The default value for min is 20, shift and list is 0. *'browsedir'* *'bsdir'* 'browsedir' 'bsdir' string (default: "last") diff --git a/src/indent.c b/src/indent.c index a26344b7d6..cf07f4af6e 100644 --- a/src/indent.c +++ b/src/indent.c @@ -854,6 +854,7 @@ briopt_check(win_T *wp) int bri_shift = 0; long bri_min = 20; int bri_sbr = FALSE; + int bri_list = 0; p = wp->w_p_briopt; while (*p != NUL) @@ -874,6 +875,11 @@ briopt_check(win_T *wp) p += 3; bri_sbr = TRUE; } + else if (STRNCMP(p, "list:", 5) == 0) + { + p += 5; + bri_list = getdigits(&p); + } if (*p != ',' && *p != NUL) return FAIL; if (*p == ',') @@ -883,6 +889,7 @@ briopt_check(win_T *wp) wp->w_briopt_shift = bri_shift; wp->w_briopt_min = bri_min; wp->w_briopt_sbr = bri_sbr; + wp->w_briopt_list = bri_list; return OK; } @@ -941,9 +948,25 @@ get_breakindent_win( // Add offset for number column, if 'n' is in 'cpoptions' bri += win_col_off2(wp); + // add additional indent for numbered lists + if (wp->w_briopt_list > 0) + { + regmatch_T regmatch; + + regmatch.regprog = vim_regcomp(curbuf->b_p_flp, + RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT); + if (regmatch.regprog != NULL) + { + if (vim_regexec(®match, line, 0)) + bri += wp->w_briopt_list; + vim_regfree(regmatch.regprog); + } + } + // never indent past left window margin if (bri < 0) bri = 0; + // always leave at least bri_min characters on the left, // if text width is sufficient else if (bri > eff_wwidth - wp->w_briopt_min) diff --git a/src/structs.h b/src/structs.h index f1f8f32583..5331183e1f 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3671,6 +3671,7 @@ struct window_S int w_briopt_min; // minimum width for breakindent int w_briopt_shift; // additional shift for breakindent int w_briopt_sbr; // sbr in 'briopt' + int w_briopt_list; // additional indent for lists #endif // transform a pointer to a "onebuf" option into a "allbuf" option diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim index bb0f6dd4a9..bfca06aec0 100644 --- a/src/testdir/test_breakindent.vim +++ b/src/testdir/test_breakindent.vim @@ -15,6 +15,10 @@ func s:screen_lines(lnum, width) abort return ScreenLines([a:lnum, a:lnum + 2], a:width) endfunc +func s:screen_lines2(lnums, lnume, width) abort + return ScreenLines([a:lnums, a:lnume], a:width) +endfunc + func s:compare_lines(expect, actual) call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) endfunc @@ -708,4 +712,70 @@ func Test_breakindent20_cpo_n_nextpage() call s:close_windows('set breakindent& briopt& cpo& number&') endfunc +func Test_breakindent20_list() + call s:test_windows('setl breakindent breakindentopt= linebreak') + " default: + call setline(1, [' 1. Congress shall make no law', + \ ' 2.) Congress shall make no law', + \ ' 3.] Congress shall make no law']) + norm! 1gg + redraw! + let lines = s:screen_lines2(1, 6, 20) + let expect = [ + \ " 1. Congress ", + \ "shall make no law ", + \ " 2.) Congress ", + \ "shall make no law ", + \ " 3.] Congress ", + \ "shall make no law ", + \ ] + call s:compare_lines(expect, lines) + " set mininum indent + setl briopt=min:5 + redraw! + let lines = s:screen_lines2(1, 6, 20) + let expect = [ + \ " 1. Congress ", + \ " shall make no law ", + \ " 2.) Congress ", + \ " shall make no law ", + \ " 3.] Congress ", + \ " shall make no law ", + \ ] + call s:compare_lines(expect, lines) + " set additional handing indent + setl briopt+=list:4 + redraw! + let expect = [ + \ " 1. Congress ", + \ " shall make no ", + \ " law ", + \ " 2.) Congress ", + \ " shall make no ", + \ " law ", + \ " 3.] Congress ", + \ " shall make no ", + \ " law ", + \ ] + let lines = s:screen_lines2(1, 9, 20) + call s:compare_lines(expect, lines) + " reset linebreak option + " Note: it indents by one additional + " space, because of the leading space. + setl linebreak&vim list listchars=eol:$,space:_ + redraw! + let expect = [ + \ "__1.__Congress_shall", + \ " _make_no_law$ ", + \ "__2.)_Congress_shall", + \ " _make_no_law$ ", + \ "__3.]_Congress_shall", + \ " _make_no_law$ ", + \ ] + let lines = s:screen_lines2(1, 6, 20) + call s:compare_lines(expect, lines) + + call s:close_windows('set breakindent& briopt& linebreak& list& listchars&') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 86a6380727..e20a32c612 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3160, /**/ 3159, /**/ From c816a2c22667108fcd61f445de2c926f78ff9fa7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 14 Jul 2021 21:00:41 +0200 Subject: [PATCH 21/42] patch 8.2.3161: Vim9: no error when reltime() has invalid arguments Problem: Vim9: no error when reltime() has invalid arguments. Solution: Add an error. (closes #8562) --- src/testdir/test_vim9_builtin.vim | 13 +++++++++++++ src/time.c | 12 ++++++++++++ src/version.c | 2 ++ 3 files changed, 27 insertions(+) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 03bc3fbe30..f5315f91f1 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1652,6 +1652,11 @@ def Test_readfile() enddef def Test_reltime() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltime()'], 'E474:') + CheckDefExecAndScriptFailure(['[]->reltime([])'], 'E474:') + CheckDefFailure(['reltime("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') CheckDefFailure(['reltime(["x", "y"])'], 'E1013: Argument 1: type mismatch, expected list but got list') CheckDefFailure(['reltime([1, 2], 10)'], 'E1013: Argument 2: type mismatch, expected list but got number') @@ -1663,12 +1668,20 @@ def Test_reltime() enddef def Test_reltimefloat() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltimefloat()'], 'E474:') + CheckDefFailure(['reltimefloat("x")'], 'E1013: Argument 1: type mismatch, expected list but got string') CheckDefFailure(['reltimefloat([1.1])'], 'E1013: Argument 1: type mismatch, expected list but got list') assert_true(type(reltimefloat(reltime())) == v:t_float) enddef def Test_reltimestr() + CheckFeature reltime + + CheckDefExecAndScriptFailure(['[]->reltimestr()'], 'E474:') + CheckDefFailure(['reltimestr(true)'], 'E1013: Argument 1: type mismatch, expected list but got bool') CheckDefFailure(['reltimestr([true])'], 'E1013: Argument 1: type mismatch, expected list but got list') assert_true(type(reltimestr(reltime())) == v:t_string) diff --git a/src/time.c b/src/time.c index 6d4ad5d51e..02c5da9dd1 100644 --- a/src/time.c +++ b/src/time.c @@ -178,7 +178,11 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) else if (argvars[1].v_type == VAR_UNKNOWN) { if (list2proftime(&argvars[0], &res) == FAIL) + { + if (in_vim9script()) + emsg(_(e_invarg)); return; + } profile_end(&res); } else @@ -186,7 +190,11 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) // Two arguments: compute the difference. if (list2proftime(&argvars[0], &start) == FAIL || list2proftime(&argvars[1], &res) == FAIL) + { + if (in_vim9script()) + emsg(_(e_invarg)); return; + } profile_sub(&res, &start); } @@ -223,6 +231,8 @@ f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) # ifdef FEAT_RELTIME if (list2proftime(&argvars[0], &tm) == OK) rettv->vval.v_float = profile_float(&tm); + else if (in_vim9script()) + emsg(_(e_invarg)); # endif } # endif @@ -242,6 +252,8 @@ f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) # ifdef FEAT_RELTIME if (list2proftime(&argvars[0], &tm) == OK) rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); + else if (in_vim9script()) + emsg(_(e_invarg)); # endif } diff --git a/src/version.c b/src/version.c index e20a32c612..7e3455d907 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3161, /**/ 3160, /**/ From 1a71d31bf34b0b2b08517903826004ec6fd440e5 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Thu, 15 Jul 2021 12:49:58 +0200 Subject: [PATCH 22/42] patch 8.2.3162: Vim9: argument types are not checked at compile time Problem: Vim9: argument types are not checked at compile time. Solution: Add more type checks. (Yegappan Lakshmanan, closes #8560) --- runtime/doc/channel.txt | 2 +- src/clientserver.c | 9 +- src/cmdhist.c | 6 + src/errors.h | 2 + src/evalfunc.c | 249 ++++++------ src/evalwindow.c | 6 + src/filepath.c | 6 + src/globals.h | 1 + src/popupwin.c | 50 ++- src/proto/typval.pro | 1 + src/sign.c | 4 + src/strings.c | 25 +- src/terminal.c | 5 + src/testdir/test_normal.vim | 2 +- src/testdir/test_reltime.vim | 4 +- src/testdir/test_vim9_builtin.vim | 605 +++++++++++++++++++++++------- src/testdir/test_vim9_expr.vim | 2 +- src/testing.c | 15 +- src/textprop.c | 9 +- src/time.c | 27 +- src/typval.c | 17 + src/version.c | 2 + 22 files changed, 780 insertions(+), 269 deletions(-) diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt index 6e5cfc8356..4049f22b44 100644 --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -852,7 +852,7 @@ available. job_getchannel({job}) *job_getchannel()* Get the channel handle that {job} is using. To check if the job has no channel: > - if string(job_getchannel()) == 'channel fail' + if string(job_getchannel(job)) == 'channel fail' < Can also be used as a |method|: > GetJob()->job_getchannel() diff --git a/src/clientserver.c b/src/clientserver.c index 7215aa7ffb..00bea6f56a 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -887,8 +887,15 @@ f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) char_u *r = NULL; #ifdef FEAT_CLIENTSERVER - char_u *serverid = tv_get_string_chk(&argvars[0]); + char_u *serverid; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + serverid = tv_get_string_chk(&argvars[0]); if (serverid != NULL && !check_restricted() && !check_secure()) { int timeout = 0; diff --git a/src/cmdhist.c b/src/cmdhist.c index 8bb3cb61c7..1b04e62237 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -597,6 +597,12 @@ f_histget(typval_T *argvars UNUSED, typval_T *rettv) int idx; char_u *str; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + str = tv_get_string_chk(&argvars[0]); // NULL on type error if (str == NULL) rettv->vval.v_string = NULL; diff --git a/src/errors.h b/src/errors.h index bfbe0296ed..09679b23ac 100644 --- a/src/errors.h +++ b/src/errors.h @@ -500,3 +500,5 @@ EXTERN char e_complete_used_without_nargs[] INIT(= N_("E1208: -complete used without -nargs")); EXTERN char e_invalid_value_for_line_number_str[] INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); +EXTERN char e_number_required_for_argument_nr[] + INIT(= N_("E1210: Number required for argument %d")); diff --git a/src/evalfunc.c b/src/evalfunc.c index 029c8a6411..dee1ecb0fc 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -254,6 +254,15 @@ arg_dict_any(type_T *type, argcontext_T *context) return check_arg_type(&t_dict_any, type, context); } +/* + * Check "type" is a list of 'any'. + */ + static int +arg_list_any(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_list_any, type, context); +} + /* * Check "type" is a list of numbers. */ @@ -287,9 +296,6 @@ arg_string(type_T *type, argcontext_T *context) static int arg_bool(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_ANY - || type->tt_type == VAR_NUMBER || type->tt_type == VAR_BOOL) - return OK; return check_arg_type(&t_bool, type, context); } @@ -353,7 +359,7 @@ arg_string_or_list_any(type_T *type, argcontext_T *context) } /* - * Check "type" is a list or a dict. + * Check "type" is a list of 'any' or a dict of 'any'. */ static int arg_list_or_dict(type_T *type, argcontext_T *context) @@ -365,13 +371,23 @@ arg_list_or_dict(type_T *type, argcontext_T *context) return FAIL; } +/* + * Check "type" is a job. + */ + static int +arg_job(type_T *type, argcontext_T *context) +{ + return check_arg_type(&t_job, type, context); +} + /* * Check "type" is a channel or a job. */ static int arg_chan_or_job(type_T *type, argcontext_T *context) { - if (type->tt_type == VAR_CHANNEL || type->tt_type == VAR_JOB) + if (type->tt_type == VAR_ANY || + type->tt_type == VAR_CHANNEL || type->tt_type == VAR_JOB) return OK; arg_type_mismatch(&t_channel, type, context->arg_idx + 1); return FAIL; @@ -459,38 +475,47 @@ arg_extend3(type_T *type, argcontext_T *context) /* * Lists of functions that check the argument types of a builtin function. */ -argcheck_T arg1_string[] = {arg_string}; -argcheck_T arg1_number[] = {arg_number}; -argcheck_T arg1_dict[] = {arg_dict_any}; -argcheck_T arg1_list_nr[] = {arg_list_number}; -argcheck_T arg1_list_string[] = {arg_list_string}; -argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; -argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; -argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any}; -argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string}; -argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; -argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; -argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; -argcheck_T arg2_number[] = {arg_number, arg_number}; -argcheck_T arg2_string[] = {arg_string, arg_string}; -argcheck_T arg2_list_nr[] = {arg_list_number, arg_list_number}; -argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; -argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; -argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; -argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; -argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; -argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; -argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; -argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; -argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; -argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; -argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string}; -argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; -argcheck_T arg2_setline[] = {arg_string_or_nr, arg_string_or_list_any}; -argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_string_or_list_any}; -argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; -argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; -argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; +static argcheck_T arg1_string[] = {arg_string}; +static argcheck_T arg1_number[] = {arg_number}; +static argcheck_T arg1_bool[] = {arg_bool}; +static argcheck_T arg1_dict_any[] = {arg_dict_any}; +static argcheck_T arg1_job[] = {arg_job}; +static argcheck_T arg1_list_any[] = {arg_list_any}; +static argcheck_T arg1_list_nr[] = {arg_list_number}; +static argcheck_T arg1_list_string[] = {arg_list_string}; +static argcheck_T arg1_float_or_nr[] = {arg_float_or_nr}; +static argcheck_T arg1_string_or_nr[] = {arg_string_or_nr}; +static argcheck_T arg1_string_or_list_any[] = {arg_string_or_list_any}; +static argcheck_T arg1_string_or_list_string[] = {arg_string_or_list_string}; +static argcheck_T arg1_list_or_blob[] = {arg_list_or_blob}; +static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict}; +static argcheck_T arg1_chan_or_job[] = {arg_chan_or_job}; +static argcheck_T arg2_float_or_nr[] = {arg_float_or_nr, arg_float_or_nr}; +static argcheck_T arg2_number[] = {arg_number, arg_number}; +static argcheck_T arg2_string[] = {arg_string, arg_string}; +static argcheck_T arg2_list_nr[] = {arg_list_number, arg_list_number}; +static argcheck_T arg2_nr_string[] = {arg_number, arg_string}; +static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; +static argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; +static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; +static argcheck_T arg2_string_nr[] = {arg_string, arg_number}; +//static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; +static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; +static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; +static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any}; +static argcheck_T arg2_nr_dict_any[] = {arg_number, arg_dict_any}; +//static argcheck_T arg2_string_number[] = {arg_string, arg_number}; +static argcheck_T arg3_string[] = {arg_string, arg_string, arg_string}; +static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; +static argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; +static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; +static argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string}; +static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; +static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL}; +static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list}; +static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; +static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; +static argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; /* * Functions that return the return type of a builtin function. @@ -762,9 +787,9 @@ static funcentry_T global_functions[] = ret_first_arg, f_add}, {"and", 2, 2, FEARG_1, arg2_number, ret_number, f_and}, - {"append", 2, 2, FEARG_2, NULL, + {"append", 2, 2, FEARG_2, arg2_setline, ret_number_bool, f_append}, - {"appendbufline", 3, 3, FEARG_3, NULL, + {"appendbufline", 3, 3, FEARG_3, arg3_setbufline, ret_number_bool, f_appendbufline}, {"argc", 0, 1, 0, arg1_number, ret_number, f_argc}, @@ -776,7 +801,7 @@ static funcentry_T global_functions[] = ret_argv, f_argv}, {"asin", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_asin)}, - {"assert_beeps", 1, 2, FEARG_1, NULL, + {"assert_beeps", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_beeps}, {"assert_equal", 2, 3, FEARG_2, NULL, ret_number_bool, f_assert_equal}, @@ -792,7 +817,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_assert_inrange}, {"assert_match", 2, 3, FEARG_2, arg3_string, ret_number_bool, f_assert_match}, - {"assert_nobeep", 1, 2, FEARG_1, NULL, + {"assert_nobeep", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_assert_nobeep}, {"assert_notequal", 2, 3, FEARG_2, NULL, ret_number_bool, f_assert_notequal}, @@ -860,9 +885,9 @@ static funcentry_T global_functions[] = ret_number, f_bufwinnr}, {"byte2line", 1, 1, FEARG_1, arg1_number, ret_number, f_byte2line}, - {"byteidx", 2, 2, FEARG_1, NULL, + {"byteidx", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_byteidx}, - {"byteidxcomp", 2, 2, FEARG_1, NULL, + {"byteidxcomp", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_byteidxcomp}, {"call", 2, 3, FEARG_1, NULL, ret_any, f_call}, @@ -880,7 +905,7 @@ static funcentry_T global_functions[] = ret_any, JOB_FUNC(f_ch_evalraw)}, {"ch_getbufnr", 2, 2, FEARG_1, NULL, ret_number, JOB_FUNC(f_ch_getbufnr)}, - {"ch_getjob", 1, 1, FEARG_1, NULL, + {"ch_getjob", 1, 1, FEARG_1, arg1_chan_or_job, ret_job, JOB_FUNC(f_ch_getjob)}, {"ch_info", 1, 1, FEARG_1, arg1_chan_or_job, ret_dict_any, JOB_FUNC(f_ch_info)}, @@ -890,19 +915,19 @@ static funcentry_T global_functions[] = ret_void, JOB_FUNC(f_ch_logfile)}, {"ch_open", 1, 2, FEARG_1, arg2_string_dict, ret_channel, JOB_FUNC(f_ch_open)}, - {"ch_read", 1, 2, FEARG_1, NULL, + {"ch_read", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_read)}, - {"ch_readblob", 1, 2, FEARG_1, NULL, + {"ch_readblob", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_blob, JOB_FUNC(f_ch_readblob)}, - {"ch_readraw", 1, 2, FEARG_1, NULL, + {"ch_readraw", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_readraw)}, {"ch_sendexpr", 2, 3, FEARG_1, NULL, ret_void, JOB_FUNC(f_ch_sendexpr)}, {"ch_sendraw", 2, 3, FEARG_1, NULL, ret_void, JOB_FUNC(f_ch_sendraw)}, - {"ch_setoptions", 2, 2, FEARG_1, NULL, + {"ch_setoptions", 2, 2, FEARG_1, arg2_chan_or_job_dict, ret_void, JOB_FUNC(f_ch_setoptions)}, - {"ch_status", 1, 2, FEARG_1, NULL, + {"ch_status", 1, 2, FEARG_1, arg2_chan_or_job_dict, ret_string, JOB_FUNC(f_ch_status)}, {"changenr", 0, 0, 0, NULL, ret_number, f_changenr}, @@ -964,7 +989,7 @@ static funcentry_T global_functions[] = ret_number, f_diff_filler}, {"diff_hlID", 2, 2, FEARG_1, NULL, ret_number, f_diff_hlID}, - {"echoraw", 1, 1, FEARG_1, NULL, + {"echoraw", 1, 1, FEARG_1, arg1_string, ret_void, f_echoraw}, {"empty", 1, 1, FEARG_1, NULL, ret_number_bool, f_empty}, @@ -1040,7 +1065,7 @@ static funcentry_T global_functions[] = ret_func_any, f_funcref}, {"function", 1, 3, FEARG_1, NULL, ret_f_function, f_function}, - {"garbagecollect", 0, 1, 0, NULL, + {"garbagecollect", 0, 1, 0, arg1_bool, ret_void, f_garbagecollect}, {"get", 2, 3, FEARG_1, NULL, ret_any, f_get}, @@ -1052,15 +1077,15 @@ static funcentry_T global_functions[] = ret_any, f_getbufvar}, {"getchangelist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_any, f_getchangelist}, - {"getchar", 0, 1, 0, NULL, + {"getchar", 0, 1, 0, arg1_bool, ret_any, f_getchar}, {"getcharmod", 0, 0, 0, NULL, ret_number, f_getcharmod}, - {"getcharpos", 1, 1, FEARG_1, NULL, + {"getcharpos", 1, 1, FEARG_1, arg1_string, ret_list_number, f_getcharpos}, {"getcharsearch", 0, 0, 0, NULL, ret_dict_any, f_getcharsearch}, - {"getcharstr", 0, 1, 0, NULL, + {"getcharstr", 0, 1, 0, arg1_bool, ret_string, f_getcharstr}, {"getcmdline", 0, 0, 0, NULL, ret_string, f_getcmdline}, @@ -1096,7 +1121,7 @@ static funcentry_T global_functions[] = ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, NULL, ret_f_getline, f_getline}, - {"getloclist", 1, 2, 0, NULL, + {"getloclist", 1, 2, 0, arg2_nr_dict_any, ret_list_or_dict_1, f_getloclist}, {"getmarklist", 0, 1, FEARG_1, arg1_string_or_nr, ret_list_dict_any, f_getmarklist}, @@ -1108,7 +1133,7 @@ static funcentry_T global_functions[] = ret_number, f_getpid}, {"getpos", 1, 1, FEARG_1, arg1_string, ret_list_number, f_getpos}, - {"getqflist", 0, 1, 0, arg1_dict, + {"getqflist", 0, 1, 0, arg1_dict_any, ret_list_or_dict_0, f_getqflist}, {"getreg", 0, 3, FEARG_1, NULL, ret_getreg, f_getreg}, @@ -1158,7 +1183,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_histadd}, {"histdel", 1, 2, FEARG_1, NULL, ret_number_bool, f_histdel}, - {"histget", 1, 2, FEARG_1, NULL, + {"histget", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_histget}, {"histnr", 1, 1, FEARG_1, arg1_string, ret_number, f_histnr}, @@ -1196,21 +1221,21 @@ static funcentry_T global_functions[] = ret_number_bool, f_isdirectory}, {"isinf", 1, 1, FEARG_1, arg1_float_or_nr, ret_number, MATH_FUNC(f_isinf)}, - {"islocked", 1, 1, FEARG_1, NULL, + {"islocked", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_islocked}, {"isnan", 1, 1, FEARG_1, arg1_float_or_nr, ret_number_bool, MATH_FUNC(f_isnan)}, - {"items", 1, 1, FEARG_1, arg1_dict, + {"items", 1, 1, FEARG_1, arg1_dict_any, ret_list_items, f_items}, - {"job_getchannel", 1, 1, FEARG_1, NULL, + {"job_getchannel", 1, 1, FEARG_1, arg1_job, ret_channel, JOB_FUNC(f_job_getchannel)}, - {"job_info", 0, 1, FEARG_1, NULL, + {"job_info", 0, 1, FEARG_1, arg1_job, ret_job_info, JOB_FUNC(f_job_info)}, {"job_setoptions", 2, 2, FEARG_1, NULL, ret_void, JOB_FUNC(f_job_setoptions)}, {"job_start", 1, 2, FEARG_1, NULL, ret_job, JOB_FUNC(f_job_start)}, - {"job_status", 1, 1, FEARG_1, NULL, + {"job_status", 1, 1, FEARG_1, arg1_job, ret_string, JOB_FUNC(f_job_status)}, {"job_stop", 1, 2, FEARG_1, NULL, ret_number_bool, JOB_FUNC(f_job_stop)}, @@ -1224,7 +1249,7 @@ static funcentry_T global_functions[] = ret_any, f_json_decode}, {"json_encode", 1, 1, FEARG_1, NULL, ret_string, f_json_encode}, - {"keys", 1, 1, FEARG_1, arg1_dict, + {"keys", 1, 1, FEARG_1, arg1_dict_any, ret_list_string, f_keys}, {"last_buffer_nr", 0, 0, 0, arg1_string_or_nr, // obsolete ret_number, f_last_buffer_nr}, @@ -1234,7 +1259,7 @@ static funcentry_T global_functions[] = ret_string, f_libcall}, {"libcallnr", 3, 3, FEARG_3, NULL, ret_number, f_libcallnr}, - {"line", 1, 2, FEARG_1, NULL, + {"line", 1, 2, FEARG_1, arg2_string_nr, ret_number, f_line}, {"line2byte", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_line2byte}, @@ -1294,7 +1319,7 @@ static funcentry_T global_functions[] = ret_string, f_matchstr}, {"matchstrpos", 2, 4, FEARG_1, NULL, ret_list_any, f_matchstrpos}, - {"max", 1, 1, FEARG_1, NULL, + {"max", 1, 1, FEARG_1, arg1_list_or_dict, ret_number, f_max}, {"menu_info", 1, 2, FEARG_1, arg2_string, ret_dict_any, @@ -1304,13 +1329,13 @@ static funcentry_T global_functions[] = NULL #endif }, - {"min", 1, 1, FEARG_1, NULL, + {"min", 1, 1, FEARG_1, arg1_list_or_dict, ret_number, f_min}, {"mkdir", 1, 3, FEARG_1, arg3_string_string_nr, ret_number_bool, f_mkdir}, - {"mode", 0, 1, FEARG_1, NULL, + {"mode", 0, 1, FEARG_1, arg1_bool, ret_string, f_mode}, - {"mzeval", 1, 1, FEARG_1, NULL, + {"mzeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_MZSCHEME f_mzeval @@ -1324,9 +1349,9 @@ static funcentry_T global_functions[] = ret_string, f_nr2char}, {"or", 2, 2, FEARG_1, arg2_number, ret_number, f_or}, - {"pathshorten", 1, 2, FEARG_1, NULL, + {"pathshorten", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_pathshorten}, - {"perleval", 1, 1, FEARG_1, NULL, + {"perleval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PERL f_perleval @@ -1338,7 +1363,7 @@ static funcentry_T global_functions[] = ret_number, PROP_FUNC(f_popup_atcursor)}, {"popup_beval", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_beval)}, - {"popup_clear", 0, 1, 0, NULL, + {"popup_clear", 0, 1, 0, arg1_bool, ret_void, PROP_FUNC(f_popup_clear)}, {"popup_close", 1, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_close)}, @@ -1346,19 +1371,19 @@ static funcentry_T global_functions[] = ret_number, PROP_FUNC(f_popup_create)}, {"popup_dialog", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_dialog)}, - {"popup_filter_menu", 2, 2, 0, NULL, + {"popup_filter_menu", 2, 2, 0, arg2_nr_string, ret_bool, PROP_FUNC(f_popup_filter_menu)}, - {"popup_filter_yesno", 2, 2, 0, NULL, + {"popup_filter_yesno", 2, 2, 0, arg2_nr_string, ret_bool, PROP_FUNC(f_popup_filter_yesno)}, {"popup_findinfo", 0, 0, 0, NULL, ret_number, PROP_FUNC(f_popup_findinfo)}, {"popup_findpreview", 0, 0, 0, NULL, ret_number, PROP_FUNC(f_popup_findpreview)}, - {"popup_getoptions", 1, 1, FEARG_1, NULL, + {"popup_getoptions", 1, 1, FEARG_1, arg1_number, ret_dict_any, PROP_FUNC(f_popup_getoptions)}, - {"popup_getpos", 1, 1, FEARG_1, NULL, + {"popup_getpos", 1, 1, FEARG_1, arg1_number, ret_dict_any, PROP_FUNC(f_popup_getpos)}, - {"popup_hide", 1, 1, FEARG_1, NULL, + {"popup_hide", 1, 1, FEARG_1, arg1_number, ret_void, PROP_FUNC(f_popup_hide)}, {"popup_list", 0, 0, 0, NULL, ret_list_number, PROP_FUNC(f_popup_list)}, @@ -1366,15 +1391,15 @@ static funcentry_T global_functions[] = ret_number, PROP_FUNC(f_popup_locate)}, {"popup_menu", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_menu)}, - {"popup_move", 2, 2, FEARG_1, NULL, + {"popup_move", 2, 2, FEARG_1, arg2_nr_dict_any, ret_void, PROP_FUNC(f_popup_move)}, {"popup_notification", 2, 2, FEARG_1, arg2_str_or_nr_or_list_dict, ret_number, PROP_FUNC(f_popup_notification)}, - {"popup_setoptions", 2, 2, FEARG_1, NULL, + {"popup_setoptions", 2, 2, FEARG_1, arg2_nr_dict_any, ret_void, PROP_FUNC(f_popup_setoptions)}, {"popup_settext", 2, 2, FEARG_1, NULL, ret_void, PROP_FUNC(f_popup_settext)}, - {"popup_show", 1, 1, FEARG_1, NULL, + {"popup_show", 1, 1, FEARG_1, arg1_number, ret_void, PROP_FUNC(f_popup_show)}, {"pow", 2, 2, FEARG_1, arg2_float_or_nr, ret_float, FLOAT_FUNC(f_pow)}, @@ -1396,7 +1421,7 @@ static funcentry_T global_functions[] = ret_void, PROP_FUNC(f_prop_clear)}, {"prop_find", 1, 2, FEARG_1, arg2_dict_string, ret_dict_any, PROP_FUNC(f_prop_find)}, - {"prop_list", 1, 2, FEARG_1, NULL, + {"prop_list", 1, 2, FEARG_1, arg2_nr_dict_any, ret_list_dict_any, PROP_FUNC(f_prop_list)}, {"prop_remove", 1, 3, FEARG_1, NULL, ret_number, PROP_FUNC(f_prop_remove)}, @@ -1408,13 +1433,13 @@ static funcentry_T global_functions[] = ret_void, PROP_FUNC(f_prop_type_delete)}, {"prop_type_get", 1, 2, FEARG_1, arg2_string_dict, ret_dict_any, PROP_FUNC(f_prop_type_get)}, - {"prop_type_list", 0, 1, FEARG_1, NULL, + {"prop_type_list", 0, 1, FEARG_1, arg1_dict_any, ret_list_string, PROP_FUNC(f_prop_type_list)}, {"pum_getpos", 0, 0, 0, NULL, ret_dict_number, f_pum_getpos}, {"pumvisible", 0, 0, 0, NULL, ret_number_bool, f_pumvisible}, - {"py3eval", 1, 1, FEARG_1, NULL, + {"py3eval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PYTHON3 f_py3eval @@ -1422,7 +1447,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"pyeval", 1, 1, FEARG_1, NULL, + {"pyeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_PYTHON f_pyeval @@ -1430,7 +1455,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"pyxeval", 1, 1, FEARG_1, NULL, + {"pyxeval", 1, 1, FEARG_1, arg1_string, ret_any, #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) f_pyxeval @@ -1468,7 +1493,7 @@ static funcentry_T global_functions[] = ret_string, f_remote_foreground}, {"remote_peek", 1, 2, FEARG_1, arg2_string, ret_number, f_remote_peek}, - {"remote_read", 1, 2, FEARG_1, NULL, + {"remote_read", 1, 2, FEARG_1, arg2_string_nr, ret_string, f_remote_read}, {"remote_send", 2, 3, FEARG_1, NULL, ret_string, f_remote_send}, @@ -1486,7 +1511,7 @@ static funcentry_T global_functions[] = ret_first_arg, f_reverse}, {"round", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_round)}, - {"rubyeval", 1, 1, FEARG_1, NULL, + {"rubyeval", 1, 1, FEARG_1, arg1_string, ret_any, #ifdef FEAT_RUBY f_rubyeval @@ -1510,7 +1535,7 @@ static funcentry_T global_functions[] = ret_string, f_screenstring}, {"search", 1, 5, FEARG_1, NULL, ret_number, f_search}, - {"searchcount", 0, 1, FEARG_1, arg1_dict, + {"searchcount", 0, 1, FEARG_1, arg1_dict_any, ret_dict_any, f_searchcount}, {"searchdecl", 1, 3, FEARG_1, NULL, ret_number_bool, f_searchdecl}, @@ -1524,15 +1549,15 @@ static funcentry_T global_functions[] = ret_number_bool, f_server2client}, {"serverlist", 0, 0, 0, NULL, ret_string, f_serverlist}, - {"setbufline", 3, 3, FEARG_3, NULL, + {"setbufline", 3, 3, FEARG_3, arg3_setbufline, ret_number_bool, f_setbufline}, {"setbufvar", 3, 3, FEARG_3, NULL, ret_void, f_setbufvar}, - {"setcellwidths", 1, 1, FEARG_1, NULL, + {"setcellwidths", 1, 1, FEARG_1, arg1_list_any, ret_void, f_setcellwidths}, {"setcharpos", 2, 2, FEARG_2, NULL, ret_number_bool, f_setcharpos}, - {"setcharsearch", 1, 1, FEARG_1, arg1_dict, + {"setcharsearch", 1, 1, FEARG_1, arg1_dict_any, ret_void, f_setcharsearch}, {"setcmdpos", 1, 1, FEARG_1, arg1_number, ret_number_bool, f_setcmdpos}, @@ -1542,7 +1567,7 @@ static funcentry_T global_functions[] = ret_void, f_setenv}, {"setfperm", 2, 2, FEARG_1, arg2_string, ret_number_bool, f_setfperm}, - {"setline", 2, 2, FEARG_2, NULL, + {"setline", 2, 2, FEARG_2, arg2_setline, ret_number_bool, f_setline}, {"setloclist", 2, 4, FEARG_2, NULL, ret_number_bool, f_setloclist}, @@ -1576,7 +1601,7 @@ static funcentry_T global_functions[] = ret_number, f_shiftwidth}, {"sign_define", 1, 2, FEARG_1, arg2_string_or_list_dict, ret_any, SIGN_FUNC(f_sign_define)}, - {"sign_getdefined", 0, 1, FEARG_1, NULL, + {"sign_getdefined", 0, 1, FEARG_1, arg1_string, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)}, {"sign_getplaced", 0, 2, FEARG_1, NULL, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)}, @@ -1584,13 +1609,13 @@ static funcentry_T global_functions[] = ret_number, SIGN_FUNC(f_sign_jump)}, {"sign_place", 4, 5, FEARG_1, NULL, ret_number, SIGN_FUNC(f_sign_place)}, - {"sign_placelist", 1, 1, FEARG_1, NULL, + {"sign_placelist", 1, 1, FEARG_1, arg1_list_any, ret_list_number, SIGN_FUNC(f_sign_placelist)}, {"sign_undefine", 0, 1, FEARG_1, arg1_string_or_list_string, ret_number_bool, SIGN_FUNC(f_sign_undefine)}, {"sign_unplace", 1, 2, FEARG_1, arg2_string_dict, ret_number_bool, SIGN_FUNC(f_sign_unplace)}, - {"sign_unplacelist", 1, 2, FEARG_1, NULL, + {"sign_unplacelist", 1, 2, FEARG_1, arg1_list_any, ret_list_number, SIGN_FUNC(f_sign_unplacelist)}, {"simplify", 1, 1, FEARG_1, arg1_string, ret_string, f_simplify}, @@ -1630,15 +1655,15 @@ static funcentry_T global_functions[] = ret_list_number, f_str2list}, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_str2nr}, - {"strcharlen", 1, 1, FEARG_1, NULL, + {"strcharlen", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_strcharlen}, {"strcharpart", 2, 4, FEARG_1, NULL, ret_string, f_strcharpart}, {"strchars", 1, 2, FEARG_1, NULL, ret_number, f_strchars}, - {"strdisplaywidth", 1, 2, FEARG_1, NULL, + {"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr, ret_number, f_strdisplaywidth}, - {"strftime", 1, 2, FEARG_1, NULL, + {"strftime", 1, 2, FEARG_1, arg2_string_nr, ret_string, #ifdef HAVE_STRFTIME f_strftime @@ -1646,7 +1671,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"strgetchar", 2, 2, FEARG_1, NULL, + {"strgetchar", 2, 2, FEARG_1, arg2_string_nr, ret_number, f_strgetchar}, {"stridx", 2, 3, FEARG_1, arg3_string_string_nr, ret_number, f_stridx}, @@ -1696,7 +1721,7 @@ static funcentry_T global_functions[] = ret_list_number, f_tabpagebuflist}, {"tabpagenr", 0, 1, 0, arg1_string, ret_number, f_tabpagenr}, - {"tabpagewinnr", 1, 2, FEARG_1, NULL, + {"tabpagewinnr", 1, 2, FEARG_1, arg2_nr_string, ret_number, f_tabpagewinnr}, {"tagfiles", 0, 0, 0, NULL, ret_list_string, f_tagfiles}, @@ -1724,7 +1749,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"term_getattr", 2, 2, FEARG_1, NULL, + {"term_getattr", 2, 2, FEARG_1, arg2_nr_string, ret_number, TERM_FUNC(f_term_getattr)}, {"term_getcursor", 1, 1, FEARG_1, arg1_string_or_nr, ret_list_any, TERM_FUNC(f_term_getcursor)}, @@ -1806,7 +1831,7 @@ static funcentry_T global_functions[] = ret_string, f_test_null_string}, {"test_option_not_set", 1, 1, FEARG_1, arg1_string, ret_void, f_test_option_not_set}, - {"test_override", 2, 2, FEARG_2, NULL, + {"test_override", 2, 2, FEARG_2, arg2_string_nr, ret_void, f_test_override}, {"test_refcount", 1, 1, FEARG_1, NULL, ret_number, f_test_refcount}, @@ -1858,11 +1883,11 @@ static funcentry_T global_functions[] = ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, NULL, ret_list_any, f_uniq}, - {"values", 1, 1, FEARG_1, arg1_dict, + {"values", 1, 1, FEARG_1, arg1_dict_any, ret_list_any, f_values}, {"virtcol", 1, 1, FEARG_1, arg1_string_or_list_any, ret_number, f_virtcol}, - {"visualmode", 0, 1, 0, NULL, + {"visualmode", 0, 1, 0, arg1_bool, ret_string, f_visualmode}, {"wildmenumode", 0, 0, 0, NULL, ret_number, f_wildmenumode}, @@ -1900,7 +1925,7 @@ static funcentry_T global_functions[] = ret_number, f_winnr}, {"winrestcmd", 0, 0, 0, NULL, ret_string, f_winrestcmd}, - {"winrestview", 1, 1, FEARG_1, arg1_dict, + {"winrestview", 1, 1, FEARG_1, arg1_dict_any, ret_void, f_winrestview}, {"winsaveview", 0, 0, 0, NULL, ret_dict_number, f_winsaveview}, @@ -2763,8 +2788,12 @@ f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) static void f_echoraw(typval_T *argvars, typval_T *rettv UNUSED) { - char_u *str = tv_get_string_chk(&argvars[0]); + char_u *str; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + + str = tv_get_string_chk(&argvars[0]); if (str != NULL && *str != NUL) { out_str(str); @@ -5956,6 +5985,10 @@ f_islocked(typval_T *argvars, typval_T *rettv) dictitem_T *di; rettv->vval.v_number = -1; + + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; + end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE, GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START); if (end != NULL && lv.ll_name != NULL) @@ -6122,6 +6155,12 @@ f_line(typval_T *argvars, typval_T *rettv) win_T *save_curwin; tabpage_T *save_curtab; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) { // use window specified in the second argument diff --git a/src/evalwindow.c b/src/evalwindow.c index 0e1a202da3..329413d0bd 100644 --- a/src/evalwindow.c +++ b/src/evalwindow.c @@ -653,6 +653,12 @@ f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) int nr = 1; tabpage_T *tp; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_string_arg(argvars, 1) == FAIL))) + return; + tp = find_tabpage((int)tv_get_number(&argvars[0])); if (tp == NULL) nr = 0; diff --git a/src/filepath.c b/src/filepath.c index 0e29977227..40b5761aee 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -1447,6 +1447,12 @@ f_pathshorten(typval_T *argvars, typval_T *rettv) char_u *p; int trim_len = 1; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) { trim_len = (int)tv_get_number(&argvars[1]); diff --git a/src/globals.h b/src/globals.h index 54ecb8e1f0..e486b6ea13 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1698,6 +1698,7 @@ EXTERN char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%s\"")); EXTERN char e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\"")); EXTERN char e_stringreq[] INIT(= N_("E928: String required")); +EXTERN char e_numberreq[] INIT(= N_("E889: Number required")); EXTERN char e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary")); EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required")); EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld")); diff --git a/src/popupwin.c b/src/popupwin.c index 8751bb4059..0f6166aca1 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2359,13 +2359,21 @@ filter_handle_drag(win_T *wp, int c, typval_T *rettv) void f_popup_filter_menu(typval_T *argvars, typval_T *rettv) { - int id = tv_get_number(&argvars[0]); - win_T *wp = win_id2wp(id); - char_u *key = tv_get_string(&argvars[1]); + int id; + win_T *wp; + char_u *key; typval_T res; int c; linenr_T old_lnum; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + id = tv_get_number(&argvars[0]); + wp = win_id2wp(id); + key = tv_get_string(&argvars[1]); // If the popup has been closed do not consume the key. if (wp == NULL) return; @@ -2416,12 +2424,20 @@ f_popup_filter_menu(typval_T *argvars, typval_T *rettv) void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv) { - int id = tv_get_number(&argvars[0]); - win_T *wp = win_id2wp(id); - char_u *key = tv_get_string(&argvars[1]); + int id; + win_T *wp; + char_u *key; typval_T res; int c; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + id = tv_get_number(&argvars[0]); + wp = win_id2wp(id); + key = tv_get_string(&argvars[1]); // If the popup has been closed don't consume the key. if (wp == NULL) return; @@ -2727,9 +2743,16 @@ close_all_popups(int force) f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) { dict_T *dict; - int id = (int)tv_get_number(argvars); - win_T *wp = find_popup_win(id); + int id; + win_T *wp; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL)) + return; + + id = (int)tv_get_number(argvars); + wp = find_popup_win(id); if (wp == NULL) return; // invalid {id} @@ -2754,10 +2777,17 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED) f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED) { dict_T *dict; - int id = (int)tv_get_number(argvars); - win_T *wp = find_popup_win(id); + int id; + win_T *wp; linenr_T old_firstline; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL)) + return; + + id = (int)tv_get_number(argvars); + wp = find_popup_win(id); if (wp == NULL) return; // invalid {id} diff --git a/src/proto/typval.pro b/src/proto/typval.pro index f6dd01ebb3..b1864bca0d 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -11,6 +11,7 @@ varnumber_T tv_get_bool_chk(typval_T *varp, int *denote); float_T tv_get_float(typval_T *varp); int check_for_string_arg(typval_T *args, int idx); int check_for_nonempty_string_arg(typval_T *args, int idx); +int check_for_number_arg(typval_T *args, int idx); int check_for_dict_arg(typval_T *args, int idx); char_u *tv_get_string(typval_T *varp); char_u *tv_get_string_strict(typval_T *varp); diff --git a/src/sign.c b/src/sign.c index fd373b5c3e..bd8cb6c6b2 100644 --- a/src/sign.c +++ b/src/sign.c @@ -2274,7 +2274,11 @@ f_sign_getdefined(typval_T *argvars, typval_T *rettv) return; if (argvars[0].v_type != VAR_UNKNOWN) + { + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return; name = tv_get_string(&argvars[0]); + } sign_getlist(name, rettv->vval.v_list); } diff --git a/src/strings.c b/src/strings.c index 61ffd84fe9..a87922d469 100644 --- a/src/strings.c +++ b/src/strings.c @@ -795,9 +795,15 @@ byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) char_u *str; varnumber_T idx; + rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + str = tv_get_string_chk(&argvars[0]); idx = tv_get_number_chk(&argvars[1], NULL); - rettv->vval.v_number = -1; if (str == NULL || idx < 0) return; @@ -981,6 +987,12 @@ f_strgetchar(typval_T *argvars, typval_T *rettv) int byteidx = 0; rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + str = tv_get_string_chk(&argvars[0]); if (str == NULL) return; @@ -1110,9 +1122,18 @@ f_strchars(typval_T *argvars, typval_T *rettv) void f_strdisplaywidth(typval_T *argvars, typval_T *rettv) { - char_u *s = tv_get_string(&argvars[0]); + char_u *s; int col = 0; + rettv->vval.v_number = -1; + + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + s = tv_get_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) col = (int)tv_get_number(&argvars[1]); diff --git a/src/terminal.c b/src/terminal.c index 9de516cc8b..9db04756d6 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -5689,6 +5689,11 @@ f_term_getattr(typval_T *argvars, typval_T *rettv) {"reverse", HL_INVERSE}, }; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || check_for_string_arg(argvars, 1) == FAIL)) + return; + attr = tv_get_number(&argvars[0]); name = tv_get_string_chk(&argvars[1]); if (name == NULL) diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 63acebc6e1..f8dbf8aeda 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -2614,7 +2614,7 @@ func Test_normal40_ctrl_bsl() set noim call assert_equal('are some words', getline(1)) call assert_false(&insertmode) - call assert_beeps("normal! \\", 'xt') + call assert_beeps("normal! \\") if has('cmdwin') " Using CTRL-\ CTRL-N in cmd window should close the window diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim index f4ce5de118..c76d7a1684 100644 --- a/src/testdir/test_reltime.vim +++ b/src/testdir/test_reltime.vim @@ -24,8 +24,8 @@ func Test_reltime() call assert_true(reltimefloat(differs) < 0.1) call assert_true(reltimefloat(differs) > 0.0) - call assert_equal(0, reltime({})) - call assert_equal(0, reltime({}, {})) + call assert_equal([], reltime({})) + call assert_equal([], reltime({}, {})) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index f5315f91f1..f7c2f98ea1 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -75,6 +75,41 @@ def Test_abs() endif enddef +def Test_add_blob() + var b1: blob = 0z12 + add(b1, 0x34) + assert_equal(0z1234, b1) + + var b2: blob # defaults to empty blob + add(b2, 0x67) + assert_equal(0z67, b2) + + var lines =<< trim END + var b: blob + add(b, "x") + END + CheckDefFailure(lines, 'E1012:', 2) + + lines =<< trim END + add(test_null_blob(), 123) + END + CheckDefExecAndScriptFailure(lines, 'E1131:', 1) + + lines =<< trim END + var b: blob = test_null_blob() + add(b, 123) + END + CheckDefExecFailure(lines, 'E1131:', 2) + + # Getting variable with NULL blob allocates a new blob at script level + lines =<< trim END + vim9script + var b: blob = test_null_blob() + add(b, 123) + END + CheckScriptSuccess(lines) +enddef + def Test_add_list() var l: list # defaults to empty list add(l, 9) @@ -120,41 +155,6 @@ def Test_add_list() CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 3) enddef -def Test_add_blob() - var b1: blob = 0z12 - add(b1, 0x34) - assert_equal(0z1234, b1) - - var b2: blob # defaults to empty blob - add(b2, 0x67) - assert_equal(0z67, b2) - - var lines =<< trim END - var b: blob - add(b, "x") - END - CheckDefFailure(lines, 'E1012:', 2) - - lines =<< trim END - add(test_null_blob(), 123) - END - CheckDefExecAndScriptFailure(lines, 'E1131:', 1) - - lines =<< trim END - var b: blob = test_null_blob() - add(b, 123) - END - CheckDefExecFailure(lines, 'E1131:', 2) - - # Getting variable with NULL blob allocates a new blob at script level - lines =<< trim END - vim9script - var b: blob = test_null_blob() - add(b, 123) - END - CheckScriptSuccess(lines) -enddef - def Test_and() CheckDefAndScriptFailure2(['and("x", 0x2)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') CheckDefAndScriptFailure2(['and(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number') @@ -171,6 +171,30 @@ def Test_append() append(0, 'zero') assert_equal('zero', getline(1)) + append(0, {a: 10}) + assert_equal("{'a': 10}", getline(1)) + append(0, function('min')) + assert_equal("function('min')", getline(1)) + CheckDefAndScriptFailure2(['append([1], "x")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') + bwipe! +enddef + +def Test_appendbufline() + new + var bnum: number = bufnr() + :wincmd w + appendbufline(bnum, 0, range(3)) + var res1: number = appendbufline(bnum, 1, 'one') + assert_equal(0, res1) + var res2: bool = appendbufline(bnum, 3, 'two') + assert_equal(false, res2) + assert_equal(['0', 'one', '1', 'two', '2', ''], getbufline(bnum, 1, '$')) + appendbufline(bnum, 0, 'zero') + assert_equal(['zero'], getbufline(bnum, 1)) + CheckDefFailure(['appendbufline([1], 1, "x")'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['appendbufline(1, [1], "x")'], 'E1013: Argument 2: type mismatch, expected string but got list') + CheckDefFailure(['appendbufline(1, 1, {"a": 10})'], 'E1013: Argument 3: type mismatch, expected string but got dict') + bnum->bufwinid()->win_gotoid() bwipe! enddef @@ -190,6 +214,10 @@ def Test_argv() CheckDefFailure(['argv("x", "y")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_assert_beeps() + CheckDefAndScriptFailure2(['assert_beeps(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + def Test_assert_equalfile() CheckDefFailure(['assert_equalfile(1, "f2")'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['assert_equalfile("f1", true)'], 'E1013: Argument 2: type mismatch, expected string but got bool') @@ -207,6 +235,10 @@ def Test_assert_match() CheckDefFailure(['assert_match("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special') enddef +def Test_assert_nobeep() + CheckDefAndScriptFailure2(['assert_nobeep(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + def Test_assert_notmatch() CheckDefFailure(['assert_notmatch({}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict') CheckDefFailure(['assert_notmatch("a", 1)'], 'E1013: Argument 2: type mismatch, expected string but got number') @@ -328,6 +360,16 @@ def Test_byte2line() assert_equal(-1, byte2line(0)) enddef +def Test_byteidx() + CheckDefAndScriptFailure2(['byteidx(1, 2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['byteidx("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_byteidxcomp() + CheckDefAndScriptFailure2(['byteidxcomp(1, 2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['byteidxcomp("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_call_call() var l = [3, 2, 1] call('reverse', [l]) @@ -355,6 +397,12 @@ def Test_ch_close_in() CheckDefFailure(['ch_close_in(true)'], 'E1013: Argument 1: type mismatch, expected channel but got bool') enddef +def Test_ch_getjob() + CheckDefAndScriptFailure2(['ch_getjob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument:') + CheckDefAndScriptFailure2(['ch_getjob({"a": 10})'], 'E1013: Argument 1: type mismatch, expected channel but got dict', 'E731: Using a Dictionary as a String') + assert_equal(0, ch_getjob(test_null_channel())) +enddef + def Test_ch_info() if !has('channel') CheckFeature channel @@ -381,6 +429,46 @@ def Test_ch_open() CheckDefAndScriptFailure2(['ch_open("a", [1])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') enddef +def Test_ch_read() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_read(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_read(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_readblob() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_readblob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_readblob(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_readraw() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_readraw(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_readraw(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_ch_setoptions() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_setoptions(1, {})'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefFailure(['ch_setoptions(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list') +enddef + +def Test_ch_status() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['ch_status(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument') + CheckDefAndScriptFailure2(['ch_status(test_null_channel(), [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + def Test_char2nr() char2nr('あ', true)->assert_equal(12354) @@ -440,6 +528,13 @@ def Test_col() bw! enddef +def Test_complete_info() + CheckDefFailure(['complete_info("")'], 'E1013: Argument 1: type mismatch, expected list but got string') + CheckDefFailure(['complete_info({})'], 'E1013: Argument 1: type mismatch, expected list but got dict') + assert_equal({'pum_visible': 0, 'mode': '', 'selected': -1, 'items': []}, complete_info()) + assert_equal({'mode': '', 'items': []}, complete_info(['mode', 'items'])) +enddef + def Test_confirm() if !has('dialog_con') && !has('dialog_gui') CheckFeature dialog_con @@ -450,13 +545,6 @@ def Test_confirm() assert_fails('confirm("yes", "maybe", 2, true)', 'E1174:') enddef -def Test_complete_info() - CheckDefFailure(['complete_info("")'], 'E1013: Argument 1: type mismatch, expected list but got string') - CheckDefFailure(['complete_info({})'], 'E1013: Argument 1: type mismatch, expected list but got dict') - assert_equal({'pum_visible': 0, 'mode': '', 'selected': -1, 'items': []}, complete_info()) - assert_equal({'mode': '', 'items': []}, complete_info(['mode', 'items'])) -enddef - def Test_copy_return_type() var l = copy([1, 2, 3]) var res = 0 @@ -514,6 +602,11 @@ def Test_diff_filler() assert_equal(0, diff_filler('.')) enddef +def Test_echoraw() + CheckDefAndScriptFailure2(['echoraw(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['echoraw(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') +enddef + def Test_escape() CheckDefFailure(['escape("a", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') CheckDefFailure(['escape(10, " ")'], 'E1013: Argument 1: type mismatch, expected string but got number') @@ -604,25 +697,6 @@ def Test_extend_arg_types() CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') enddef -def Test_extendnew() - assert_equal([1, 2, 'a'], extendnew([1, 2], ['a'])) - assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'})) - - CheckDefFailure(['extendnew({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') - CheckDefFailure(['extendnew({a: 1}, [42])'], 'E1013: Argument 2: type mismatch, expected dict but got list') - CheckDefFailure(['extendnew([1, 2], "x")'], 'E1013: Argument 2: type mismatch, expected list but got string') - CheckDefFailure(['extendnew([1, 2], {x: 1})'], 'E1013: Argument 2: type mismatch, expected list but got dict') -enddef - -def Test_extend_return_type() - var l = extend([1, 2], [3]) - var res = 0 - for n in l - res += n - endfor - res->assert_equal(6) -enddef - func g:ExtendDict(d) call extend(a:d, #{xx: 'x'}) endfunc @@ -673,6 +747,15 @@ def Test_extend_list_item_type() CheckScriptFailure(['vim9script'] + lines, 'E1012:', 1) enddef +def Test_extend_return_type() + var l = extend([1, 2], [3]) + var res = 0 + for n in l + res += n + endfor + res->assert_equal(6) +enddef + def Test_extend_with_error_function() var lines =<< trim END vim9script @@ -693,6 +776,16 @@ def Test_extend_with_error_function() CheckScriptFailure(lines, 'E1001: Variable not found: m') enddef +def Test_extendnew() + assert_equal([1, 2, 'a'], extendnew([1, 2], ['a'])) + assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'})) + + CheckDefFailure(['extendnew({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') + CheckDefFailure(['extendnew({a: 1}, [42])'], 'E1013: Argument 2: type mismatch, expected dict but got list') + CheckDefFailure(['extendnew([1, 2], "x")'], 'E1013: Argument 2: type mismatch, expected list but got string') + CheckDefFailure(['extendnew([1, 2], {x: 1})'], 'E1013: Argument 2: type mismatch, expected list but got dict') +enddef + def Test_feedkeys() CheckDefFailure(['feedkeys(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') CheckDefFailure(['feedkeys("x", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') @@ -703,36 +796,6 @@ def Test_feedkeys() unlet g:TestVar enddef -def Test_indent() - CheckDefAndScriptFailure2(['indent([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') - CheckDefAndScriptFailure2(['indent(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1138: Using a Bool as a Number') - assert_equal(0, indent(1)) -enddef - -def Test_input() - CheckDefFailure(['input(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['input(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') - CheckDefFailure(['input("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['input("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E180: Invalid complete value') -enddef - -def Test_inputdialog() - CheckDefFailure(['inputdialog(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') - CheckDefAndScriptFailure2(['inputdialog(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') - CheckDefFailure(['inputdialog("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') - CheckDefFailure(['inputdialog("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number') -enddef - -def Test_job_info_return_type() - if has('job') - job_start(&shell) - var jobs = job_info() - assert_equal('list', typename(jobs)) - assert_equal('dict', typename(job_info(jobs[0]))) - job_stop(jobs[0]) - endif -enddef - def Test_filereadable() assert_false(filereadable("")) assert_false(filereadable(test_null_string())) @@ -928,6 +991,8 @@ enddef def Test_garbagecollect() garbagecollect(true) + CheckDefAndScriptFailure2(['garbagecollect("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') + CheckDefAndScriptFailure2(['garbagecollect(20)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') enddef def Test_getbufinfo() @@ -967,6 +1032,19 @@ def Test_getchar() while getchar(0) endwhile getchar(true)->assert_equal(0) + getchar(1)->assert_equal(0) + CheckDefAndScriptFailure2(['getchar(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') + CheckDefAndScriptFailure2(['getchar("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') +enddef + +def Test_getcharpos() + CheckDefAndScriptFailure2(['getcharpos(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['getcharpos(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + +def Test_getcharstr() + CheckDefAndScriptFailure2(['getcharstr(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') + CheckDefAndScriptFailure2(['getcharstr("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string', 'E1135: Using a String as a Bool') enddef def Test_getenv() @@ -1003,14 +1081,6 @@ def Test_getcwd() CheckDefFailure(['getcwd(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef -def Test_getloclist_return_type() - var l = getloclist(1) - l->assert_equal([]) - - var d = getloclist(1, {items: 0}) - d->assert_equal({items: []}) -enddef - def Test_getfontname() CheckDefFailure(['getfontname(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') enddef @@ -1072,6 +1142,19 @@ def Test_getline() CheckDefExecAndScriptFailure(lines, 'E1209:') enddef +def Test_getloclist() + CheckDefAndScriptFailure2(['getloclist("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['getloclist(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') +enddef + +def Test_getloclist_return_type() + var l = getloclist(1) + l->assert_equal([]) + + var d = getloclist(1, {items: 0}) + d->assert_equal({items: []}) +enddef + def Test_getmarklist() CheckDefFailure(['getmarklist([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal([], getmarklist(10000)) @@ -1197,6 +1280,11 @@ def Test_histadd() assert_equal('skyblue', histget('/', -1)) enddef +def Test_histget() + CheckDefAndScriptFailure2(['histget(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['histget("a", "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_histnr() CheckDefFailure(['histnr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal(-1, histnr('abc')) @@ -1219,10 +1307,30 @@ def Test_iconv() assert_equal('abc', iconv('abc', 'fromenc', 'toenc')) enddef +def Test_indent() + CheckDefAndScriptFailure2(['indent([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') + CheckDefAndScriptFailure2(['indent(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1138: Using a Bool as a Number') + assert_equal(0, indent(1)) +enddef + def Test_index() index(['a', 'b', 'a', 'B'], 'b', 2, true)->assert_equal(3) enddef +def Test_input() + CheckDefFailure(['input(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['input(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + CheckDefFailure(['input("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['input("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number', 'E180: Invalid complete value') +enddef + +def Test_inputdialog() + CheckDefFailure(['inputdialog(5)'], 'E1013: Argument 1: type mismatch, expected string but got number') + CheckDefAndScriptFailure2(['inputdialog(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + CheckDefFailure(['inputdialog("p", 10)'], 'E1013: Argument 2: type mismatch, expected string but got number') + CheckDefFailure(['inputdialog("p", "q", 20)'], 'E1013: Argument 3: type mismatch, expected string but got number') +enddef + def Test_inputlist() CheckDefFailure(['inputlist(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') CheckDefFailure(['inputlist("abc")'], 'E1013: Argument 1: type mismatch, expected list but got string') @@ -1289,12 +1397,47 @@ def Test_isdirectory() assert_false(isdirectory('NonExistingDir')) enddef +def Test_islocked() + CheckDefAndScriptFailure2(['islocked(true)'], 'E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['var n1: number = 10', 'islocked(n1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + g:v1 = 10 + assert_false(islocked('g:v1')) + lockvar g:v1 + assert_true(islocked('g:v1')) + unlet g:v1 +enddef + def Test_items() CheckDefFailure(['[]->items()'], 'E1013: Argument 1: type mismatch, expected dict but got list') assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items()) assert_equal([], {}->items()) enddef +def Test_job_getchannel() + CheckDefAndScriptFailure2(['job_getchannel("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_getchannel(test_null_job())', 'E916: not a valid job') +enddef + +def Test_job_info() + CheckDefAndScriptFailure2(['job_info("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_info(test_null_job())', 'E916: not a valid job') +enddef + +def Test_job_info_return_type() + if has('job') + job_start(&shell) + var jobs = job_info() + assert_equal('list', typename(jobs)) + assert_equal('dict', typename(job_info(jobs[0]))) + job_stop(jobs[0]) + endif +enddef + +def Test_job_status() + CheckDefAndScriptFailure2(['job_status("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_equal('fail', job_status(test_null_job())) +enddef + def Test_js_decode() CheckDefFailure(['js_decode(10)'], 'E1013: Argument 1: type mismatch, expected string but got number') assert_equal([1, 2], js_decode('[1,2]')) @@ -1318,6 +1461,8 @@ enddef def Test_line() assert_fails('line(true)', 'E1174:') + CheckDefAndScriptFailure2(['line(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['line(".", "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') enddef def Test_line2byte() @@ -1476,6 +1621,7 @@ def Test_max() ? [1, max([2, 3])] : [4, 5] assert_equal([4, 5], l2) + CheckDefAndScriptFailure2(['max(5)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E712: Argument of max() must be a List or Dictionary') enddef def Test_menu_info() @@ -1497,6 +1643,7 @@ def Test_min() ? [1, min([2, 3])] : [4, 5] assert_equal([4, 5], l2) + CheckDefAndScriptFailure2(['min(5)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E712: Argument of min() must be a List or Dictionary') enddef def Test_mkdir() @@ -1506,6 +1653,18 @@ def Test_mkdir() delete('a', 'rf') enddef +def Test_mode() + CheckDefFailure(['mode("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string') + CheckDefFailure(['mode(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number') +enddef + +def Test_mzeval() + if !has('mzscheme') + CheckFeature mzscheme + endif + CheckDefAndScriptFailure2(['mzscheme(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_nextnonblank() CheckDefFailure(['nextnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') assert_equal(0, nextnonblank(1)) @@ -1520,6 +1679,18 @@ def Test_or() CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_pathshorten() + CheckDefAndScriptFailure2(['pathshorten(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['pathshorten("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_perleval() + if !has('perl') + CheckFeature perl + endif + CheckDefAndScriptFailure2(['perleval(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_popup_atcursor() CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') @@ -1536,6 +1707,11 @@ def Test_popup_beval() CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_popup_clear() + CheckDefAndScriptFailure2(['popup_clear(["a"])'], 'E1013: Argument 1: type mismatch, expected bool but got list', 'E745: Using a List as a Number') + CheckDefAndScriptFailure2(['popup_clear(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number', 'E1023: Using a Number as a Bool') +enddef + def Test_popup_create() # Pass variable of type 'any' to popup_create() var what: any = 'Hello' @@ -1549,6 +1725,31 @@ def Test_popup_dialog() CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_popup_filter_menu() + CheckDefAndScriptFailure2(['popup_filter_menu("x", "")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_filter_menu(1, 1)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + +def Test_popup_filter_yesno() + CheckDefAndScriptFailure2(['popup_filter_yesno("x", "")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_filter_yesno(1, 1)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + +def Test_popup_getoptions() + CheckDefAndScriptFailure2(['popup_getoptions("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_getoptions(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + +def Test_popup_getpos() + CheckDefAndScriptFailure2(['popup_getpos("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_getpos(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + +def Test_popup_hide() + CheckDefAndScriptFailure2(['popup_hide("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_hide(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + def Test_popup_locate() CheckDefAndScriptFailure2(['popup_locate("a", 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number') @@ -1559,11 +1760,26 @@ def Test_popup_menu() CheckDefAndScriptFailure2(['popup_menu("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_popup_move() + CheckDefAndScriptFailure2(['popup_move("x", {})'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_move(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + def Test_popup_notification() CheckDefAndScriptFailure2(['popup_notification({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E450: buffer number, text or a list required') CheckDefAndScriptFailure2(['popup_notification("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_popup_setoptions() + CheckDefAndScriptFailure2(['popup_setoptions("x", {})'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['popup_setoptions(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + +def Test_popup_show() + CheckDefAndScriptFailure2(['popup_show("a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') + CheckDefAndScriptFailure2(['popup_show(true)'], 'E1013: Argument 1: type mismatch, expected number but got bool', 'E1138: Using a Bool as a Number') +enddef + def Test_prevnonblank() CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special') assert_equal(0, prevnonblank(1)) @@ -1582,6 +1798,11 @@ def Test_prop_find() CheckDefAndScriptFailure2(['prop_find({"a": 10}, ["a"])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef +def Test_prop_list() + CheckDefAndScriptFailure2(['prop_list("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['prop_list(1, [])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E1206: Dictionary required for argument 2') +enddef + def Test_prop_type_add() CheckDefAndScriptFailure2(['prop_type_add({"a": 10}, "b")'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E731: Using a Dictionary as a String') CheckDefAndScriptFailure2(['prop_type_add("a", "b")'], 'E1013: Argument 2: type mismatch, expected dict but got string', 'E715: Dictionary required') @@ -1604,6 +1825,32 @@ def Test_prop_type_get() CheckDefAndScriptFailure2(['prop_type_get("a", "b")'], 'E1013: Argument 2: type mismatch, expected dict but got string', 'E715: Dictionary required') enddef +def Test_prop_type_list() + CheckDefAndScriptFailure2(['prop_type_list(["a"])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') + CheckDefAndScriptFailure2(['prop_type_list(2)'], 'E1013: Argument 1: type mismatch, expected dict but got number', 'E715: Dictionary required') +enddef + +def Test_py3eval() + if !has('python3') + CheckFeature python3 + endif + CheckDefAndScriptFailure2(['py3eval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + +def Test_pyeval() + if !has('python') + CheckFeature python + endif + CheckDefAndScriptFailure2(['pyeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + +def Test_pyxeval() + if !has('python') && !has('python3') + CheckFeature python + endif + CheckDefAndScriptFailure2(['pyxeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_rand() CheckDefFailure(['rand(10)'], 'E1013: Argument 1: type mismatch, expected list but got number') CheckDefFailure(['rand(["a"])'], 'E1013: Argument 1: type mismatch, expected list but got list') @@ -1704,6 +1951,13 @@ def Test_remote_peek() CheckDefAndScriptFailure2(['remote_peek("a5b6c7", [1])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E573: Invalid server id used') enddef +def Test_remote_read() + CheckFeature clientserver + CheckEnv DISPLAY + CheckDefAndScriptFailure2(['remote_read(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['remote_read("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_remote_startserver() CheckFeature clientserver CheckEnv DISPLAY @@ -1743,6 +1997,13 @@ def Test_reverse_return_type() res->assert_equal(6) enddef +def Test_rubyeval() + if !has('ruby') + CheckFeature ruby + endif + CheckDefAndScriptFailure2(['rubyeval([2])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') +enddef + def Test_screenattr() CheckDefFailure(['screenattr("x", 1)'], 'E1013: Argument 1: type mismatch, expected number but got string') CheckDefFailure(['screenattr(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') @@ -1813,6 +2074,7 @@ def Test_searchcount() maxcount: 99, incomplete: 0}) bwipe! + CheckDefAndScriptFailure2(['searchcount([1])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef def Test_searchpair() @@ -1956,6 +2218,27 @@ def Test_setfperm() CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob') enddef +def Test_setbufline() + new + var bnum = bufnr('%') + :wincmd w + setbufline(bnum, 1, range(1, 3)) + setbufline(bnum, 4, 'one') + setbufline(bnum, 5, 10) + setbufline(bnum, 6, ['two', 11]) + assert_equal(['1', '2', '3', 'one', '10', 'two', '11'], getbufline(bnum, 1, '$')) + CheckDefFailure(['setbufline([1], 1, "x")'], 'E1013: Argument 1: type mismatch, expected string but got list') + CheckDefFailure(['setbufline(1, [1], "x")'], 'E1013: Argument 2: type mismatch, expected string but got list') + CheckDefFailure(['setbufline(1, 1, {"a": 10})'], 'E1013: Argument 3: type mismatch, expected string but got dict') + bnum->bufwinid()->win_gotoid() + bw! +enddef + +def Test_setcellwidths() + CheckDefAndScriptFailure2(['setcellwidths(1)'], 'E1013: Argument 1: type mismatch, expected list but got number', 'E714: List required') + CheckDefAndScriptFailure2(['setcellwidths({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + def Test_setline() new setline(1, range(1, 4)) @@ -1964,6 +2247,9 @@ def Test_setline() assert_equal(['a', 'b', 'c', 'd'], getline(1, '$')) setline(1, 'one') assert_equal(['one', 'b', 'c', 'd'], getline(1, '$')) + setline(1, 10) + assert_equal(['10', 'b', 'c', 'd'], getline(1, '$')) + CheckDefAndScriptFailure2(['setline([1], "x")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') bw! enddef @@ -1998,6 +2284,16 @@ def Test_sign_define() CheckDefAndScriptFailure2(['sign_define("a", ["b"])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_sign_getdefined() + CheckDefAndScriptFailure2(['sign_getdefined(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['sign_getdefined(2)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') +enddef + +def Test_sign_placelist() + CheckDefAndScriptFailure2(['sign_placelist("x")'], 'E1013: Argument 1: type mismatch, expected list but got string', 'E714: List required') + CheckDefAndScriptFailure2(['sign_placelist({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + def Test_sign_undefine() CheckDefAndScriptFailure2(['sign_undefine({})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E731: Using a Dictionary as a String') CheckDefAndScriptFailure2(['sign_undefine([1])'], 'E1013: Argument 1: type mismatch, expected list but got list', 'E155: Unknown sign:') @@ -2009,6 +2305,11 @@ def Test_sign_unplace() CheckDefAndScriptFailure2(['sign_unplace("a", ["b"])'], 'E1013: Argument 2: type mismatch, expected dict but got list', 'E715: Dictionary required') enddef +def Test_sign_unplacelist() + CheckDefAndScriptFailure2(['sign_unplacelist("x")'], 'E1013: Argument 1: type mismatch, expected list but got string', 'E714: List required') + CheckDefAndScriptFailure2(['sign_unplacelist({"a": 10})'], 'E1013: Argument 1: type mismatch, expected list but got dict', 'E714: List required') +enddef + def Test_simplify() CheckDefFailure(['simplify(100)'], 'E1013: Argument 1: type mismatch, expected string but got number') call assert_equal('NonExistingFile', simplify('NonExistingFile')) @@ -2117,10 +2418,31 @@ def Test_str2nr() CheckScriptFailure(['vim9script', 'echo str2nr("123", 10, "x")'], 'E1135:') enddef +def Test_strcharlen() + CheckDefAndScriptFailure2(['strcharlen([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + "abc"->strcharlen()->assert_equal(3) + strcharlen(99)->assert_equal(2) +enddef + def Test_strchars() strchars("A\u20dd", true)->assert_equal(1) enddef +def Test_strdisplaywidth() + CheckDefAndScriptFailure2(['strdisplaywidth(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strdisplaywidth("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_strftime() + CheckDefAndScriptFailure2(['strftime(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strftime("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_strgetchar() + CheckDefAndScriptFailure2(['strgetchar(1, 1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strgetchar("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_stridx() CheckDefAndScriptFailure2(['stridx([1], "b")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') CheckDefAndScriptFailure2(['stridx("a", {})'], 'E1013: Argument 2: type mismatch, expected string but got dict', 'E731: Using a Dictionary as a String') @@ -2211,6 +2533,11 @@ def Test_tabpagenr() assert_equal(1, tabpagenr()) enddef +def Test_tabpagewinnr() + CheckDefAndScriptFailure2(['tabpagewinnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['tabpagewinnr(1, 2)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + def Test_taglist() CheckDefAndScriptFailure2(['taglist([1])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') CheckDefAndScriptFailure2(['taglist("a", [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E730: Using a List as a String') @@ -2234,6 +2561,12 @@ def Test_term_getansicolors() CheckDefAndScriptFailure2(['term_getansicolors(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E745: Using a List as a Number') enddef +def Test_term_getattr() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_getattr("x", "a")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1') + CheckDefAndScriptFailure2(['term_getattr(1, 2)'], 'E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2') +enddef + def Test_term_getcursor() CheckRunVimInTerminal CheckDefAndScriptFailure2(['term_getcursor({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict', 'E728: Using a Dictionary as a Number') @@ -2310,6 +2643,11 @@ def Test_test_option_not_set() CheckDefAndScriptFailure2(['test_option_not_set([])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E474: Invalid argument') enddef +def Test_test_override() + CheckDefAndScriptFailure2(['test_override(1, 1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['test_override("a", "x")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_test_setmouse() CheckDefAndScriptFailure2(['test_setmouse("a", 10)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument') CheckDefAndScriptFailure2(['test_setmouse(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument') @@ -2392,6 +2730,11 @@ def Test_virtcol() bw! enddef +def Test_visualmode() + CheckDefFailure(['visualmode("1")'], 'E1013: Argument 1: type mismatch, expected bool but got string') + CheckDefFailure(['visualmode(2)'], 'E1013: Argument 1: type mismatch, expected bool but got number') +enddef + def Test_win_execute() assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()')) assert_equal("\n" .. winnr(), 'echo winnr()'->win_execute(win_getid())) @@ -2411,12 +2754,44 @@ def Test_win_getid() assert_equal(win_getid(), win_getid(1, 1)) enddef +def Test_win_gettype() + CheckDefAndScriptFailure2(['win_gettype("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_gotoid() + CheckDefAndScriptFailure2(['win_gotoid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_id2tabwin() + CheckDefAndScriptFailure2(['win_id2tabwin("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_id2win() + CheckDefAndScriptFailure2(['win_id2win("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_win_screenpos() + CheckDefAndScriptFailure2(['win_screenpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + def Test_win_splitmove() split win_splitmove(1, 2, {vertical: true, rightbelow: true}) close enddef +def Test_winbufnr() + CheckDefAndScriptFailure2(['winbufnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_winheight() + CheckDefAndScriptFailure2(['winheight("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + +def Test_winlayout() + CheckDefAndScriptFailure2(['winlayout("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') +enddef + def Test_winnr() CheckDefFailure(['winnr([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal(1, winnr()) @@ -2449,38 +2824,6 @@ def Test_winsaveview() CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected list but got dict', 1) enddef -def Test_win_gettype() - CheckDefAndScriptFailure2(['win_gettype("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_gotoid() - CheckDefAndScriptFailure2(['win_gotoid("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_id2tabwin() - CheckDefAndScriptFailure2(['win_id2tabwin("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_id2win() - CheckDefAndScriptFailure2(['win_id2win("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_win_screenpos() - CheckDefAndScriptFailure2(['win_screenpos("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winbufnr() - CheckDefAndScriptFailure2(['winbufnr("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winheight() - CheckDefAndScriptFailure2(['winheight("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - -def Test_winlayout() - CheckDefAndScriptFailure2(['winlayout("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') -enddef - def Test_winwidth() CheckDefAndScriptFailure2(['winwidth("x")'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number') enddef diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index f0e15c37ec..59ac957131 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2982,7 +2982,7 @@ def Test_expr7_method_call() enddef RetVoid()->byteidx(3) END - CheckDefExecAndScriptFailure(lines, 'E1031:') + CheckDefExecFailure(lines, 'E1013:') enddef diff --git a/src/testing.c b/src/testing.c index 80596d44bc..42030d726d 100644 --- a/src/testing.c +++ b/src/testing.c @@ -340,10 +340,14 @@ assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, char_u *cmd) static int assert_beeps(typval_T *argvars, int no_beep) { - char_u *cmd = tv_get_string_chk(&argvars[0]); + char_u *cmd; garray_T ga; int ret = 0; + if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + return 0; + + cmd = tv_get_string_chk(&argvars[0]); called_vim_beep = FALSE; suppress_errthrow = TRUE; emsg_silent = FALSE; @@ -367,7 +371,7 @@ assert_beeps(typval_T *argvars, int no_beep) } /* - * "assert_beeps(cmd [, error])" function + * "assert_beeps(cmd)" function */ void f_assert_beeps(typval_T *argvars, typval_T *rettv) @@ -376,7 +380,7 @@ f_assert_beeps(typval_T *argvars, typval_T *rettv) } /* - * "assert_nobeep(cmd [, error])" function + * "assert_nobeep(cmd)" function */ void f_assert_nobeep(typval_T *argvars, typval_T *rettv) @@ -947,6 +951,11 @@ f_test_override(typval_T *argvars, typval_T *rettv UNUSED) int val; static int save_starting = -1; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || check_for_number_arg(argvars, 1) == FAIL)) + return; + if (argvars[0].v_type != VAR_STRING || (argvars[1].v_type) != VAR_NUMBER) emsg(_(e_invarg)); diff --git a/src/textprop.c b/src/textprop.c index 78696fc650..c2000a3c3e 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -769,9 +769,16 @@ f_prop_find(typval_T *argvars, typval_T *rettv) void f_prop_list(typval_T *argvars, typval_T *rettv) { - linenr_T lnum = tv_get_number(&argvars[0]); + linenr_T lnum; buf_T *buf = curbuf; + if (in_vim9script() + && (check_for_number_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN && + check_for_dict_arg(argvars, 1) == FAIL))) + return; + + lnum = tv_get_number(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) diff --git a/src/time.c b/src/time.c index 02c5da9dd1..796fc58c96 100644 --- a/src/time.c +++ b/src/time.c @@ -169,6 +169,10 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) # ifdef FEAT_RELTIME proftime_T res; proftime_T start; + long n1, n2; + + if (rettv_list_alloc(rettv) != OK) + return; if (argvars[0].v_type == VAR_UNKNOWN) { @@ -198,20 +202,15 @@ f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) profile_sub(&res, &start); } - if (rettv_list_alloc(rettv) == OK) - { - long n1, n2; - # ifdef MSWIN - n1 = res.HighPart; - n2 = res.LowPart; + n1 = res.HighPart; + n2 = res.LowPart; # else - n1 = res.tv_sec; - n2 = res.tv_usec; + n1 = res.tv_sec; + n2 = res.tv_usec; # endif - list_append_number(rettv->vval.v_list, (varnumber_T)n1); - list_append_number(rettv->vval.v_list, (varnumber_T)n2); - } + list_append_number(rettv->vval.v_list, (varnumber_T)n1); + list_append_number(rettv->vval.v_list, (varnumber_T)n2); # endif } @@ -269,6 +268,12 @@ f_strftime(typval_T *argvars, typval_T *rettv) time_t seconds; char_u *p; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + rettv->v_type = VAR_STRING; p = tv_get_string(&argvars[0]); diff --git a/src/typval.c b/src/typval.c index b223318311..6e0b528e79 100644 --- a/src/typval.c +++ b/src/typval.c @@ -384,6 +384,23 @@ check_for_nonempty_string_arg(typval_T *args, int idx) return OK; } +/* + * Give an error and return FAIL unless "tv" is a number. + */ + int +check_for_number_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_NUMBER) + { + if (idx >= 0) + semsg(_(e_number_required_for_argument_nr), idx + 1); + else + emsg(_(e_numberreq)); + return FAIL; + } + return OK; +} + /* * Give an error and return FAIL unless "tv" is a dict. */ diff --git a/src/version.c b/src/version.c index 7e3455d907..341faea42d 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3162, /**/ 3161, /**/ From 1557b16dad2b1a3466a93d015575cd7fdb4661c9 Mon Sep 17 00:00:00 2001 From: Wei-Chung Wen Date: Thu, 15 Jul 2021 13:13:39 +0200 Subject: [PATCH 23/42] patch 8.2.3163: location list window may open a wrong file Problem: Location list window may open a wrong file. Solution: Also update the qf_ptr field. (Wei-Chung Wen, closes #8565, closes #8566) --- src/quickfix.c | 1 + src/testdir/test_quickfix.vim | 33 +++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 36 insertions(+) diff --git a/src/quickfix.c b/src/quickfix.c index 4ac4a01a10..39424ca680 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -3461,6 +3461,7 @@ qf_jump_newwin(qf_info_T *qi, } qfl->qf_index = qf_index; + qfl->qf_ptr = qf_ptr; if (qf_win_pos_update(qi, old_qf_index)) // No need to print the error message if it's visible in the error // window diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index a6a20a8451..e5a6d6cdbc 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -5554,4 +5554,37 @@ func Test_vimgrep_fuzzy_match() call delete('Xfile2') endfunc +func Test_locationlist_open_in_newtab() + call s:create_test_file('Xqftestfile1') + call s:create_test_file('Xqftestfile2') + call s:create_test_file('Xqftestfile3') + + %bwipe! + + lgetexpr ['Xqftestfile1:5:Line5', + \ 'Xqftestfile2:10:Line10', + \ 'Xqftestfile3:16:Line16'] + + silent! llast + call assert_equal(1, tabpagenr('$')) + call assert_equal('Xqftestfile3', bufname()) + + set switchbuf=newtab + + silent! lfirst + call assert_equal(2, tabpagenr('$')) + call assert_equal('Xqftestfile1', bufname()) + + silent! lnext + call assert_equal(3, tabpagenr('$')) + call assert_equal('Xqftestfile2', bufname()) + + call delete('Xqftestfile1') + call delete('Xqftestfile2') + call delete('Xqftestfile3') + set switchbuf&vim + + %bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 341faea42d..edf5306f74 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3163, /**/ 3162, /**/ From 0894e0d8087aad4d467fd7b3d87b1930fe661916 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 14:14:30 +0200 Subject: [PATCH 24/42] patch 8.2.3164: MS-Windows: reported version lacks patchlevel Problem: MS-Windows: reported version lacks patchlevel, causing some update tools to update too often. (Klaus Frank) Solution: Add the patchlevel to the version. (Christian Brabandt) --- src/dosinst.c | 5 ++++- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dosinst.c b/src/dosinst.c index 2d2b95c10a..608f381f12 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -1580,6 +1580,7 @@ install_registry(void) char display_name[BUFSIZE]; char uninstall_string[BUFSIZE]; char icon_string[BUFSIZE]; + char version_string[BUFSIZE]; int i; int loop_count = is_64bit_os() ? 2 : 1; DWORD flag; @@ -1652,13 +1653,15 @@ install_registry(void) sprintf(icon_string, "%s\\gvim.exe,0", installdir); + sprintf(version_string, VIM_VERSION_SHORT "." VIM_VERSION_PATCHLEVEL_STR); + lRet = register_uninstall( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT, display_name, uninstall_string, icon_string, - VIM_VERSION_SHORT, + version_string, "Bram Moolenaar et al."); if (ERROR_SUCCESS != lRet) return FAIL; diff --git a/src/version.c b/src/version.c index edf5306f74..9d355c8ede 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3164, /**/ 3163, /**/ From 9e60e899ee546a8a35c4cbe0319971719c1839e9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 15:40:58 +0200 Subject: [PATCH 25/42] patch 8.2.3165: Vim9: in a || expression the error line number may be wrong Problem: Vim9: in a || expression the error line number may be wrong. Solution: Save and restore the line number when checking the type. (closes #8569) --- src/testdir/test_vim9_expr.vim | 7 +++++++ src/version.c | 2 ++ src/vim9compile.c | 3 +++ 3 files changed, 12 insertions(+) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 59ac957131..ae48a89604 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -401,6 +401,13 @@ def Test_expr2_fails() # comment END CheckScriptFailure(lines, 'E1004: White space required before and after ''||'' at "||true"', 3) + + lines =<< trim END + var x = false + || false + || a.b + END + CheckDefFailure(lines, 'E1001:', 3) enddef " test && diff --git a/src/version.c b/src/version.c index 9d355c8ede..ba8362bccf 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3165, /**/ 3164, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index d25183f19e..4763e9550b 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5095,6 +5095,7 @@ compile_and_or( while (p[0] == opchar && p[1] == opchar) { long start_lnum = SOURCING_LNUM; + long save_sourcing_lnum; int start_ctx_lnum = cctx->ctx_lnum; int save_lnum; @@ -5116,6 +5117,7 @@ compile_and_or( generate_ppconst(cctx, ppconst); // Every part must evaluate to a bool. + save_sourcing_lnum = SOURCING_LNUM; SOURCING_LNUM = start_lnum; save_lnum = cctx->ctx_lnum; cctx->ctx_lnum = start_ctx_lnum; @@ -5138,6 +5140,7 @@ compile_and_or( ? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0); // eval the next expression + SOURCING_LNUM = save_sourcing_lnum; if (may_get_next_line_error(p + 2, arg, cctx) == FAIL) { ga_clear(&end_ga); From b5841b99e678da187b68c21f46d56a608a0dc10c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 18:09:53 +0200 Subject: [PATCH 26/42] patch 8.2.3166: Vim9: nested autoload call error overruled by "Unknown error" Problem: Vim9: nested autoload call error overruled by "Unknown error". Solution: Check need_rethrow before giving an "Unknown error". (closes #8568) --- src/testdir/test_vim9_script.vim | 40 ++++++++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 3 ++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index b4107e97d1..bd06f7a2e9 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -3699,6 +3699,46 @@ def Test_script_var_in_autocmd() CheckScriptSuccess(lines) enddef +def Test_error_in_autoload_script() + var save_rtp = &rtp + var dir = getcwd() .. '/Xruntime' + &rtp = dir + mkdir(dir .. '/autoload', 'p') + + var lines =<< trim END + vim9script noclear + def script#autoloaded() + enddef + def Broken() + var x: any = '' + eval x != 0 + enddef + Broken() + END + writefile(lines, dir .. '/autoload/script.vim') + + lines =<< trim END + vim9script + def CallAutoloaded() + script#autoloaded() + enddef + + function Legacy() + try + call s:CallAutoloaded() + catch + call assert_match('E1030: Using a String as a Number', v:exception) + endtry + endfunction + + Legacy() + END + CheckScriptSuccess(lines) + + &rtp = save_rtp + delete(dir, 'rf') +enddef + def Test_cmdline_win() # if the Vim syntax highlighting uses Vim9 constructs they can be used from # the command line window. diff --git a/src/version.c b/src/version.c index ba8362bccf..896ca07b8b 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3166, /**/ 3165, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 41249284dc..b882c4d111 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -4737,7 +4737,8 @@ failed_early: // Not sure if this is necessary. suppress_errthrow = save_suppress_errthrow; - if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before) + if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before + && !need_rethrow) semsg(_(e_unknown_error_while_executing_str), printable_func_name(ufunc)); funcdepth_restore(orig_funcdepth); From 547f94f33098b060da9d62c29d9fcbe9bf1e2b11 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 18:14:56 +0200 Subject: [PATCH 27/42] patch 8.2.3167: get E12 in a job callback when searching for tags Problem: Get E12 in a job callback when searching for tags. (Andy Stewart) Solution: Use the sandbox only for executing a command, not for searching. (closes #8511) --- src/tag.c | 32 ++++++++++++++++---------------- src/version.c | 2 ++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/tag.c b/src/tag.c index 256f885c82..4e96e0d430 100644 --- a/src/tag.c +++ b/src/tag.c @@ -3312,7 +3312,6 @@ jumpto_tag( int forceit, // :ta with ! int keep_help) // keep help flag (FALSE for cscope) { - int save_secure; optmagic_T save_magic_overruled; int save_p_ws, save_p_scs, save_p_ic; linenr_T save_lnum; @@ -3500,11 +3499,6 @@ jumpto_tag( curwin->w_set_curswant = TRUE; postponed_split = 0; - save_secure = secure; - secure = 1; -#ifdef HAVE_SANDBOX - ++sandbox; -#endif save_magic_overruled = magic_overruled; magic_overruled = OPTION_MAGIC_OFF; // always execute with 'nomagic' #ifdef FEAT_SEARCH_EXTRA @@ -3621,22 +3615,28 @@ jumpto_tag( } else { + int save_secure = secure; + + // Setup the sandbox for executing the command from the tags file. + secure = 1; +#ifdef HAVE_SANDBOX + ++sandbox; +#endif curwin->w_cursor.lnum = 1; // start command in line 1 do_cmdline_cmd(pbuf); retval = OK; + + // When the command has done something that is not allowed make + // sure the error message can be seen. + if (secure == 2) + wait_return(TRUE); + secure = save_secure; +#ifdef HAVE_SANDBOX + --sandbox; +#endif } - /* - * When the command has done something that is not allowed make sure - * the error message can be seen. - */ - if (secure == 2) - wait_return(TRUE); - secure = save_secure; magic_overruled = save_magic_overruled; -#ifdef HAVE_SANDBOX - --sandbox; -#endif #ifdef FEAT_SEARCH_EXTRA // restore no_hlsearch when keeping the old search pattern if (search_options) diff --git a/src/version.c b/src/version.c index 896ca07b8b..6a4943d50f 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3167, /**/ 3166, /**/ From 378697ac58b8f9705286e36d1805a052e96fb86e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 19:23:18 +0200 Subject: [PATCH 28/42] patch 8.2.3168: Vim9: type error for constant of type any Problem: Vim9: type error for constant of type any. Solution: Do add a runtime type check if a constant has type any. (closes #8570) --- src/testdir/test_vim9_assign.vim | 10 ++++++++++ src/version.c | 2 ++ src/vim9compile.c | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 6bbbc3681e..3599d6c5d1 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1667,6 +1667,16 @@ def Test_var_type_check() s:d = {} END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d = {a: 1, b: [2]} + def Func(b: bool) + var l: list = b ? d.b : [3] + enddef + defcompile + END + CheckScriptSuccess(lines) enddef let g:dict_number = #{one: 1, two: 2} diff --git a/src/version.c b/src/version.c index 6a4943d50f..b8c782eef2 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3168, /**/ 3167, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 4763e9550b..956ce44eb0 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1051,7 +1051,8 @@ need_type( // 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 && use_typecheck(actual, expected)) + if ((!actual_is_const || actual == &t_any) + && use_typecheck(actual, expected)) { generate_TYPECHECK(cctx, expected, offset, arg_idx); return OK; From 5245beb37cb52991a745644c20d7ca1b0138ef2c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 22:03:50 +0200 Subject: [PATCH 29/42] patch 8.2.3169: Vim9: cannot handle nested inline function Problem: Vim9: cannot handle nested inline function. Solution: Check for nested inline function. (closes #8575) --- src/testdir/test_vim9_expr.vim | 3 ++- src/testdir/test_vim9_func.vim | 10 +++++++++ src/userfunc.c | 38 +++++++++++++++++++++++++++++----- src/version.c | 2 ++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index ae48a89604..cd6ffa4463 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2082,7 +2082,8 @@ def Test_expr7_lambda_block() var Func = (nr: number): int => { return nr END - CheckDefAndScriptFailure(lines, 'E1171', 1) # line nr is function start + CheckDefFailure(lines, 'E1171', 0) # line nr is function start + CheckScriptFailure(['vim9script'] + lines, 'E1171', 2) lines =<< trim END var Func = (nr: number): int => { diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 08e68d147c..c89c13e2dc 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2255,6 +2255,16 @@ def Test_nested_inline_lambda() assert_equal('--there', F('unused')('there')('--')) END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + echo range(4)->mapnew((_, v) => { + return range(v) ->mapnew((_, s) => { + return string(s) + }) + }) + END + CheckScriptSuccess(lines) enddef def Shadowed(): list diff --git a/src/userfunc.c b/src/userfunc.c index 4234681cd7..e21f15c142 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -634,6 +634,7 @@ get_function_body( || eap->cmdidx == CMD_block; #define MAX_FUNC_NESTING 50 char nesting_def[MAX_FUNC_NESTING]; + char nesting_inline[MAX_FUNC_NESTING]; int nesting = 0; getline_opt_T getline_options; int indent = 2; @@ -658,7 +659,8 @@ get_function_body( ((char_u **)(newlines->ga_data))[newlines->ga_len++] = NULL; } - nesting_def[nesting] = vim9_function; + nesting_def[0] = vim9_function; + nesting_inline[0] = eap->cmdidx == CMD_block; getline_options = vim9_function ? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT; for (;;) @@ -705,10 +707,10 @@ get_function_body( SOURCING_LNUM = sourcing_lnum_top; if (skip_until != NULL) semsg(_(e_missing_heredoc_end_marker_str), skip_until); + else if (nesting_inline[nesting]) + emsg(_(e_missing_end_block)); else if (eap->cmdidx == CMD_def) emsg(_(e_missing_enddef)); - else if (eap->cmdidx == CMD_block) - emsg(_(e_missing_end_block)); else emsg(_("E126: Missing :endfunction")); goto theend; @@ -765,7 +767,8 @@ get_function_body( } else { - int c; + int c; + char_u *end; // skip ':' and blanks for (p = theline; VIM_ISWHITE(*p) || *p == ':'; ++p) @@ -773,7 +776,7 @@ get_function_body( // Check for "endfunction", "enddef" or "}". // When a ":" follows it must be a dict key; "enddef: value," - if ((nesting == 0 && eap->cmdidx == CMD_block) + if (nesting_inline[nesting] ? *p == '}' : (checkforcmd(&p, nesting_def[nesting] ? "enddef" : "endfunction", 4) @@ -857,6 +860,31 @@ get_function_body( { ++nesting; nesting_def[nesting] = (c == 'd'); + nesting_inline[nesting] = FALSE; + indent += 2; + } + } + } + + // Check for nested inline function. + end = p + STRLEN(p) - 1; + while (end > p && VIM_ISWHITE(*end)) + --end; + if (*end == '{') + { + --end; + while (end > p && VIM_ISWHITE(*end)) + --end; + if (end > p - 2 && end[-1] == '=' && end[0] == '>') + { + // found trailing "=> {", start of an inline function + if (nesting == MAX_FUNC_NESTING - 1) + emsg(_(e_function_nesting_too_deep)); + else + { + ++nesting; + nesting_def[nesting] = TRUE; + nesting_inline[nesting] = TRUE; indent += 2; } } diff --git a/src/version.c b/src/version.c index b8c782eef2..f436e54904 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3169, /**/ 3168, /**/ From d8cee76b498507c48706f651aeb78b93b5376d00 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 23:15:59 +0200 Subject: [PATCH 30/42] patch 8.2.3170: Illegal memory access in test Problem: Illegal memory access in test. Solution: Check pointer is not before the start of the line. --- src/userfunc.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/userfunc.c b/src/userfunc.c index e21f15c142..d8c943b23d 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -870,7 +870,7 @@ get_function_body( end = p + STRLEN(p) - 1; while (end > p && VIM_ISWHITE(*end)) --end; - if (*end == '{') + if (end > p && *end == '{') { --end; while (end > p && VIM_ISWHITE(*end)) diff --git a/src/version.c b/src/version.c index f436e54904..5b3a97b439 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3170, /**/ 3169, /**/ From f5f1b59d3b98f1a00180cbaf0a12115fb58b573a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Jul 2021 23:44:54 +0200 Subject: [PATCH 31/42] patch 8.2.3171: another illegal memory access in test Problem: Another illegal memory access in test. Solution: Check pointer is after the start of the line. --- src/userfunc.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/userfunc.c b/src/userfunc.c index d8c943b23d..3dfa680972 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -875,7 +875,7 @@ get_function_body( --end; while (end > p && VIM_ISWHITE(*end)) --end; - if (end > p - 2 && end[-1] == '=' && end[0] == '>') + if (end > p + 2 && end[-1] == '=' && end[0] == '>') { // found trailing "=> {", start of an inline function if (nesting == MAX_FUNC_NESTING - 1) diff --git a/src/version.c b/src/version.c index 5b3a97b439..3caf18dcad 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3171, /**/ 3170, /**/ From 20c370d9f2ee89cb854054edf71f5004f6efff77 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 16 Jul 2021 10:39:28 +0200 Subject: [PATCH 32/42] patch 8.2.3172: MzScheme test fails Problem: MzScheme test fails. (Christian Brabandt) Solution: Correct function name. --- src/testdir/test_vim9_builtin.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index f7c2f98ea1..98ed85fb32 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1662,7 +1662,7 @@ def Test_mzeval() if !has('mzscheme') CheckFeature mzscheme endif - CheckDefAndScriptFailure2(['mzscheme(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') + CheckDefAndScriptFailure2(['mzeval(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E730: Using a List as a String') enddef def Test_nextnonblank() diff --git a/src/version.c b/src/version.c index 3caf18dcad..78d6088e41 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3172, /**/ 3171, /**/ From a9a7c0c602b231dc37c4b0f62ade0421c84fca03 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sat, 17 Jul 2021 19:11:07 +0200 Subject: [PATCH 33/42] patch 8.2.3173: Vim9: argument types are not checked at compile time Problem: Vim9: argument types are not checked at compile time. Solution: Add more type checks. (Yegappan Lakshmanan, closes #8581) --- src/diff.c | 10 +- src/errors.h | 4 + src/evalfunc.c | 77 ++++++++++----- src/globals.h | 1 + src/job.c | 7 ++ src/proto/typval.pro | 2 + src/strings.c | 12 +++ src/terminal.c | 51 +++++++++- src/testdir/test_vim9_builtin.vim | 151 ++++++++++++++++++++++++++++++ src/typval.c | 43 ++++++++- src/version.c | 2 + 11 files changed, 329 insertions(+), 31 deletions(-) diff --git a/src/diff.c b/src/diff.c index 6f25c373c4..4c8afb12bd 100644 --- a/src/diff.c +++ b/src/diff.c @@ -3283,7 +3283,7 @@ f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_DIFF - linenr_T lnum = tv_get_lnum(argvars); + linenr_T lnum; static linenr_T prev_lnum = 0; static varnumber_T changedtick = 0; static int fnum = 0; @@ -3293,6 +3293,14 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) int filler_lines; int col; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + + lnum = tv_get_lnum(argvars); if (lnum < 0) // ignore type error in {lnum} arg lnum = 0; if (lnum != prev_lnum diff --git a/src/errors.h b/src/errors.h index 09679b23ac..46de733bc6 100644 --- a/src/errors.h +++ b/src/errors.h @@ -502,3 +502,7 @@ EXTERN char e_invalid_value_for_line_number_str[] INIT(= N_("E1209: Invalid value for a line number: \"%s\"")); EXTERN char e_number_required_for_argument_nr[] INIT(= N_("E1210: Number required for argument %d")); +EXTERN char e_list_required_for_argument_nr[] + INIT(= N_("E1211: List required for argument %d")); +EXTERN char e_bool_required_for_argument_nr[] + INIT(= N_("E1211: Bool required for argument %d")); diff --git a/src/evalfunc.c b/src/evalfunc.c index dee1ecb0fc..2964d23912 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -499,9 +499,12 @@ static argcheck_T arg2_dict_string[] = {arg_dict_any, arg_string}; static argcheck_T arg2_dict_string_or_nr[] = {arg_dict_any, arg_string_or_nr}; static argcheck_T arg2_string_dict[] = {arg_string, arg_dict_any}; static argcheck_T arg2_string_nr[] = {arg_string, arg_number}; +static argcheck_T arg2_string_bool[] = {arg_string, arg_bool}; //static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev}; static argcheck_T arg2_str_or_nr_or_list_dict[] = {arg_str_or_nr_or_list, arg_dict_any}; static argcheck_T arg2_string_or_list_dict[] = {arg_string_or_list_any, arg_dict_any}; +static argcheck_T arg2_string_or_nr_string[] = {arg_string_or_nr, arg_string}; +static argcheck_T arg2_string_or_nr_nr[] = {arg_string_or_nr, arg_number}; static argcheck_T arg2_chan_or_job_dict[] = {arg_chan_or_job, arg_dict_any}; static argcheck_T arg2_nr_dict_any[] = {arg_number, arg_dict_any}; //static argcheck_T arg2_string_number[] = {arg_string, arg_number}; @@ -510,12 +513,13 @@ static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; static argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool}; static argcheck_T arg3_string_string_nr[] = {arg_string, arg_string, arg_number}; static argcheck_T arg2_execute[] = {arg_string_or_list_string, arg_string}; -static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; -static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL}; -static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list}; static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3}; static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3}; static argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number}; +static argcheck_T arg3_setbufline[] = {arg_string_or_nr, arg_string_or_nr, arg_str_or_nr_or_list}; +static argcheck_T arg2_setline[] = {arg_string_or_nr, NULL}; +static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string, arg_string}; +static argcheck_T arg4_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number}; /* * Functions that return the return type of a builtin function. @@ -931,7 +935,7 @@ static funcentry_T global_functions[] = ret_string, JOB_FUNC(f_ch_status)}, {"changenr", 0, 0, 0, NULL, ret_number, f_changenr}, - {"char2nr", 1, 2, FEARG_1, NULL, + {"char2nr", 1, 2, FEARG_1, arg2_string_bool, ret_number, f_char2nr}, {"charclass", 1, 1, FEARG_1, arg1_string, ret_number, f_charclass}, @@ -987,7 +991,7 @@ static funcentry_T global_functions[] = ret_number_bool, f_did_filetype}, {"diff_filler", 1, 1, FEARG_1, arg1_string_or_nr, ret_number, f_diff_filler}, - {"diff_hlID", 2, 2, FEARG_1, NULL, + {"diff_hlID", 2, 2, FEARG_1, arg2_string_or_nr_nr, ret_number, f_diff_hlID}, {"echoraw", 1, 1, FEARG_1, arg1_string, ret_void, f_echoraw}, @@ -1251,7 +1255,7 @@ static funcentry_T global_functions[] = ret_string, f_json_encode}, {"keys", 1, 1, FEARG_1, arg1_dict_any, ret_list_string, f_keys}, - {"last_buffer_nr", 0, 0, 0, arg1_string_or_nr, // obsolete + {"last_buffer_nr", 0, 0, 0, NULL, // obsolete ret_number, f_last_buffer_nr}, {"len", 1, 1, FEARG_1, NULL, ret_number, f_len}, @@ -1297,7 +1301,7 @@ static funcentry_T global_functions[] = ret_first_cont, f_mapnew}, {"mapset", 3, 3, FEARG_1, NULL, ret_void, f_mapset}, - {"match", 2, 4, FEARG_1, NULL, + {"match", 2, 4, FEARG_1, arg4_match_func, ret_any, f_match}, {"matchadd", 2, 5, FEARG_1, NULL, ret_number, f_matchadd}, @@ -1307,17 +1311,17 @@ static funcentry_T global_functions[] = ret_list_string, f_matcharg}, {"matchdelete", 1, 2, FEARG_1, arg2_number, ret_number_bool, f_matchdelete}, - {"matchend", 2, 4, FEARG_1, NULL, + {"matchend", 2, 4, FEARG_1, arg4_match_func, ret_number, f_matchend}, {"matchfuzzy", 2, 3, FEARG_1, NULL, ret_list_string, f_matchfuzzy}, {"matchfuzzypos", 2, 3, FEARG_1, NULL, ret_list_any, f_matchfuzzypos}, - {"matchlist", 2, 4, FEARG_1, NULL, + {"matchlist", 2, 4, FEARG_1, arg4_match_func, ret_list_string, f_matchlist}, - {"matchstr", 2, 4, FEARG_1, NULL, + {"matchstr", 2, 4, FEARG_1, arg4_match_func, ret_string, f_matchstr}, - {"matchstrpos", 2, 4, FEARG_1, NULL, + {"matchstrpos", 2, 4, FEARG_1, arg4_match_func, ret_list_any, f_matchstrpos}, {"max", 1, 1, FEARG_1, arg1_list_or_dict, ret_number, f_max}, @@ -1413,7 +1417,7 @@ static funcentry_T global_functions[] = ret_void, JOB_FUNC(f_prompt_setcallback)}, {"prompt_setinterrupt", 2, 2, FEARG_1, NULL, ret_void, JOB_FUNC(f_prompt_setinterrupt)}, - {"prompt_setprompt", 2, 2, FEARG_1, NULL, + {"prompt_setprompt", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, JOB_FUNC(f_prompt_setprompt)}, {"prop_add", 3, 3, FEARG_1, NULL, ret_void, PROP_FUNC(f_prop_add)}, @@ -1651,7 +1655,7 @@ static funcentry_T global_functions[] = ret_string, f_state}, {"str2float", 1, 1, FEARG_1, arg1_string, ret_float, FLOAT_FUNC(f_str2float)}, - {"str2list", 1, 2, FEARG_1, NULL, + {"str2list", 1, 2, FEARG_1, arg2_string_bool, ret_list_number, f_str2list}, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_str2nr}, @@ -1659,7 +1663,7 @@ static funcentry_T global_functions[] = ret_number, f_strcharlen}, {"strcharpart", 2, 4, FEARG_1, NULL, ret_string, f_strcharpart}, - {"strchars", 1, 2, FEARG_1, NULL, + {"strchars", 1, 2, FEARG_1, arg2_string_bool, ret_number, f_strchars}, {"strdisplaywidth", 1, 2, FEARG_1, arg2_string_nr, ret_number, f_strdisplaywidth}, @@ -1709,9 +1713,9 @@ static funcentry_T global_functions[] = ret_string, f_synIDattr}, {"synIDtrans", 1, 1, FEARG_1, arg1_number, ret_number, f_synIDtrans}, - {"synconcealed", 2, 2, 0, NULL, + {"synconcealed", 2, 2, 0, arg2_string_or_nr_nr, ret_list_any, f_synconcealed}, - {"synstack", 2, 2, 0, NULL, + {"synstack", 2, 2, 0, arg2_string_or_nr_nr, ret_list_number, f_synstack}, {"system", 1, 2, FEARG_1, NULL, ret_string, f_system}, @@ -1771,7 +1775,7 @@ static funcentry_T global_functions[] = ret_list_number, TERM_FUNC(f_term_list)}, {"term_scrape", 2, 2, FEARG_1, NULL, ret_list_dict_any, TERM_FUNC(f_term_scrape)}, - {"term_sendkeys", 2, 2, FEARG_1, NULL, + {"term_sendkeys", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_sendkeys)}, {"term_setansicolors", 2, 2, FEARG_1, NULL, ret_void, @@ -1781,17 +1785,17 @@ static funcentry_T global_functions[] = NULL #endif }, - {"term_setapi", 2, 2, FEARG_1, NULL, + {"term_setapi", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setapi)}, - {"term_setkill", 2, 2, FEARG_1, NULL, + {"term_setkill", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setkill)}, - {"term_setrestore", 2, 2, FEARG_1, NULL, + {"term_setrestore", 2, 2, FEARG_1, arg2_string_or_nr_string, ret_void, TERM_FUNC(f_term_setrestore)}, {"term_setsize", 3, 3, FEARG_1, NULL, ret_void, TERM_FUNC(f_term_setsize)}, {"term_start", 1, 2, FEARG_1, NULL, ret_number, TERM_FUNC(f_term_start)}, - {"term_wait", 1, 2, FEARG_1, NULL, + {"term_wait", 1, 2, FEARG_1, arg2_string_or_nr_nr, ret_void, TERM_FUNC(f_term_wait)}, {"terminalprops", 0, 0, 0, NULL, ret_dict_string, f_terminalprops}, @@ -2473,8 +2477,12 @@ f_changenr(typval_T *argvars UNUSED, typval_T *rettv) static void f_char2nr(typval_T *argvars, typval_T *rettv) { - if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) return; + if (has_mbyte) { int utf8 = 0; @@ -6304,6 +6312,17 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) rettv->vval.v_string = NULL; } + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_LIST + && check_for_string_arg(argvars, 0) == FAIL) + || (check_for_string_arg(argvars, 1) == FAIL) + || (argvars[2].v_type != VAR_UNKNOWN + && (check_for_number_arg(argvars, 2) == FAIL + || (argvars[3].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 3) == FAIL))))) + goto theend; + if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL) @@ -8961,6 +8980,13 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) rettv_list_set(rettv, NULL); + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) lnum = tv_get_lnum(argvars); // -1 on type error col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error @@ -9017,6 +9043,13 @@ f_synstack(typval_T *argvars UNUSED, typval_T *rettv) rettv_list_set(rettv, NULL); + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_number_arg(argvars, 1) == FAIL)) + return; + #ifdef FEAT_SYN_HL lnum = tv_get_lnum(argvars); // -1 on type error col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error diff --git a/src/globals.h b/src/globals.h index e486b6ea13..7829f2a4e2 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1699,6 +1699,7 @@ EXTERN char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"% EXTERN char e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\"")); EXTERN char e_stringreq[] INIT(= N_("E928: String required")); EXTERN char e_numberreq[] INIT(= N_("E889: Number required")); +EXTERN char e_boolreq[] INIT(= N_("E839: Number required")); EXTERN char e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary")); EXTERN char e_dictreq[] INIT(= N_("E715: Dictionary required")); EXTERN char e_listidx[] INIT(= N_("E684: list index out of range: %ld")); diff --git a/src/job.c b/src/job.c index 189c06eb6e..1271c779da 100644 --- a/src/job.c +++ b/src/job.c @@ -1725,6 +1725,13 @@ f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED) buf_T *buf; char_u *text; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + if (check_secure()) return; buf = tv_get_buf(&argvars[0], FALSE); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index b1864bca0d..ccde9a6b68 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -12,6 +12,8 @@ float_T tv_get_float(typval_T *varp); int check_for_string_arg(typval_T *args, int idx); int check_for_nonempty_string_arg(typval_T *args, int idx); int check_for_number_arg(typval_T *args, int idx); +int check_for_bool_arg(typval_T *args, int idx); +int check_for_list_arg(typval_T *args, int idx); int check_for_dict_arg(typval_T *args, int idx); char_u *tv_get_string(typval_T *varp); char_u *tv_get_string_strict(typval_T *varp); diff --git a/src/strings.c b/src/strings.c index a87922d469..98d420c6aa 100644 --- a/src/strings.c +++ b/src/strings.c @@ -902,6 +902,12 @@ f_str2list(typval_T *argvars, typval_T *rettv) if (rettv_list_alloc(rettv) == FAIL) return; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) utf8 = (int)tv_get_bool_chk(&argvars[1], NULL); @@ -1108,6 +1114,12 @@ f_strchars(typval_T *argvars, typval_T *rettv) { varnumber_T skipcc = FALSE; + if (in_vim9script() + && (check_for_string_arg(argvars, 0) == FAIL + || (argvars[1].v_type != VAR_UNKNOWN + && check_for_bool_arg(argvars, 1) == FAIL))) + return; + if (argvars[1].v_type != VAR_UNKNOWN) skipcc = tv_get_bool(&argvars[1]); if (skipcc < 0 || skipcc > 1) diff --git a/src/terminal.c b/src/terminal.c index 9db04756d6..52645643b5 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -6093,10 +6093,18 @@ f_term_scrape(typval_T *argvars, typval_T *rettv) void f_term_sendkeys(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_sendkeys()"); + buf_T *buf; char_u *msg; term_T *term; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_sendkeys()"); if (buf == NULL) return; @@ -6193,10 +6201,18 @@ f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED) void f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_setapi()"); + buf_T *buf; term_T *term; char_u *api; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setapi()"); if (buf == NULL) return; term = buf->b_term; @@ -6215,10 +6231,18 @@ f_term_setapi(typval_T *argvars, typval_T *rettv UNUSED) f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #if defined(FEAT_SESSION) - buf_T *buf = term_get_buf(argvars, "term_setrestore()"); + buf_T *buf; term_T *term; char_u *cmd; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setrestore()"); if (buf == NULL) return; term = buf->b_term; @@ -6237,10 +6261,18 @@ f_term_setrestore(typval_T *argvars UNUSED, typval_T *rettv UNUSED) void f_term_setkill(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_setkill()"); + buf_T *buf; term_T *term; char_u *how; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) + || check_for_string_arg(argvars, 1) == FAIL)) + return; + + buf = term_get_buf(argvars, "term_setkill()"); if (buf == NULL) return; term = buf->b_term; @@ -6286,8 +6318,17 @@ f_term_start(typval_T *argvars, typval_T *rettv) void f_term_wait(typval_T *argvars, typval_T *rettv UNUSED) { - buf_T *buf = term_get_buf(argvars, "term_wait()"); + buf_T *buf; + if (in_vim9script() + && ((argvars[0].v_type != VAR_STRING + && argvars[0].v_type != VAR_NUMBER + && check_for_string_arg(argvars, 0) == FAIL) || + (argvars[1].v_type != VAR_UNKNOWN + && check_for_number_arg(argvars, 1) == FAIL))) + return; + + buf = term_get_buf(argvars, "term_wait()"); if (buf == NULL) return; if (buf->b_term->tl_job == NULL) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 98ed85fb32..0668797386 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -473,6 +473,12 @@ def Test_char2nr() char2nr('あ', true)->assert_equal(12354) assert_fails('char2nr(true)', 'E1174:') + CheckDefAndScriptFailure2(['char2nr(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['char2nr("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal(97, char2nr('a', 1)) + assert_equal(97, char2nr('a', 0)) + assert_equal(97, char2nr('a', true)) + assert_equal(97, char2nr('a', false)) enddef def Test_charclass() @@ -602,6 +608,11 @@ def Test_diff_filler() assert_equal(0, diff_filler('.')) enddef +def Test_diff_hlID() + CheckDefAndScriptFailure2(['diff_hlID(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['diff_hlID(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_echoraw() CheckDefAndScriptFailure2(['echoraw(1)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') CheckDefAndScriptFailure2(['echoraw(["x"])'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') @@ -1599,6 +1610,21 @@ def Test_map_failure() delete('Xtmpfile') enddef +def Test_match() + CheckDefAndScriptFailure2(['match(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['match(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['match("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['match("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(2, match('ab12cd', '12')) + assert_equal(-1, match('ab12cd', '34')) + assert_equal(6, match('ab12cd12ef', '12', 4)) + assert_equal(2, match('abcd', '..', 0, 3)) + assert_equal(1, match(['a', 'b', 'c'], 'b')) + assert_equal(-1, match(['a', 'b', 'c'], 'd')) + assert_equal(3, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(5, match(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + def Test_matcharg() CheckDefFailure(['matcharg("x")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef @@ -1609,6 +1635,71 @@ def Test_matchdelete() CheckDefFailure(['matchdelete(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string') enddef +def Test_matchend() + CheckDefAndScriptFailure2(['matchend(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchend(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchend("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchend("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(4, matchend('ab12cd', '12')) + assert_equal(-1, matchend('ab12cd', '34')) + assert_equal(8, matchend('ab12cd12ef', '12', 4)) + assert_equal(4, matchend('abcd', '..', 0, 3)) + assert_equal(1, matchend(['a', 'b', 'c'], 'b')) + assert_equal(-1, matchend(['a', 'b', 'c'], 'd')) + assert_equal(3, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(5, matchend(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchlist() + CheckDefAndScriptFailure2(['matchlist(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchlist(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchlist("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchlist("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + var l: list = ['12', '', '', '', '', '', '', '', '', ''] + assert_equal(l, matchlist('ab12cd', '12')) + assert_equal([], matchlist('ab12cd', '34')) + assert_equal(l, matchlist('ab12cd12ef', '12', 4)) + l[0] = 'cd' + assert_equal(l, matchlist('abcd', '..', 0, 3)) + l[0] = 'b' + assert_equal(l, matchlist(['a', 'b', 'c'], 'b')) + assert_equal([], matchlist(['a', 'b', 'c'], 'd')) + assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(l, matchlist(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchstr() + CheckDefAndScriptFailure2(['matchstr(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchstr(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchstr("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchstr("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal('12', matchstr('ab12cd', '12')) + assert_equal('', matchstr('ab12cd', '34')) + assert_equal('12', matchstr('ab12cd12ef', '12', 4)) + assert_equal('cd', matchstr('abcd', '..', 0, 3)) + assert_equal('b', matchstr(['a', 'b', 'c'], 'b')) + assert_equal('', matchstr(['a', 'b', 'c'], 'd')) + assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal('b', matchstr(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + +def Test_matchstrpos() + CheckDefAndScriptFailure2(['matchstrpos(0z12, "p")'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['matchstrpos(["s"], [2])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') + CheckDefAndScriptFailure2(['matchstrpos("s", "p", "q")'], 'E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3') + CheckDefAndScriptFailure2(['matchstrpos("s", "p", 1, "r")'], 'E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4') + assert_equal(['12', 2, 4], matchstrpos('ab12cd', '12')) + assert_equal(['', -1, -1], matchstrpos('ab12cd', '34')) + assert_equal(['12', 6, 8], matchstrpos('ab12cd12ef', '12', 4)) + assert_equal(['cd', 2, 4], matchstrpos('abcd', '..', 0, 3)) + assert_equal(['b', 1, 0, 1], matchstrpos(['a', 'b', 'c'], 'b')) + assert_equal(['', -1, -1, -1], matchstrpos(['a', 'b', 'c'], 'd')) + assert_equal(['b', 3, 0, 1], + matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2)) + assert_equal(['b', 5, 0, 1], + matchstrpos(['a', 'b', 'c', 'b', 'd', 'b'], 'b', 2, 2)) +enddef + def Test_max() g:flag = true var l1: list = g:flag @@ -1792,6 +1883,14 @@ def Test_prompt_getprompt() endif enddef +def Test_prompt_setprompt() + if !has('channel') + CheckFeature channel + endif + CheckDefAndScriptFailure2(['prompt_setprompt([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['prompt_setprompt(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + def Test_prop_find() CheckDefAndScriptFailure2(['prop_find([1, 2])'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') CheckDefAndScriptFailure2(['prop_find([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict but got list', 'E715: Dictionary required') @@ -2407,6 +2506,14 @@ def Run_str2float() endif enddef +def Test_str2list() + CheckDefAndScriptFailure2(['str2list(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['str2list("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal([97], str2list('a')) + assert_equal([97], str2list('a', 1)) + assert_equal([97], str2list('a', true)) +enddef + def Test_str2nr() str2nr("1'000'000", 10, true)->assert_equal(1000000) @@ -2426,6 +2533,11 @@ enddef def Test_strchars() strchars("A\u20dd", true)->assert_equal(1) + CheckDefAndScriptFailure2(['strchars(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['strchars("a", 2)'], 'E1013: Argument 2: type mismatch, expected bool but got number', 'E1211: Bool required for argument 2') + assert_equal(3, strchars('abc')) + assert_equal(3, strchars('abc', 1)) + assert_equal(3, strchars('abc', true)) enddef def Test_strdisplaywidth() @@ -2521,6 +2633,16 @@ def Test_synIDtrans() CheckDefFailure(['synIDtrans("a")'], 'E1013: Argument 1: type mismatch, expected number but got string') enddef +def Test_synconcealed() + CheckDefAndScriptFailure2(['synconcealed(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['synconcealed(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + +def Test_synstack() + CheckDefAndScriptFailure2(['synstack(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['synstack(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_tabpagebuflist() CheckDefFailure(['tabpagebuflist("t")'], 'E1013: Argument 1: type mismatch, expected number but got string') assert_equal([bufnr('')], tabpagebuflist()) @@ -2607,6 +2729,29 @@ def Test_term_gettty() endif enddef +def Test_term_sendkeys() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_sendkeys([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_sendkeys(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setapi() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setapi([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setapi(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setkill() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setkill([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setkill(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef + +def Test_term_setrestore() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_setrestore([], "p")'], 'E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_setrestore(1, [])'], 'E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2') +enddef def Test_term_start() if !has('terminal') MissingFeature 'terminal' @@ -2619,6 +2764,12 @@ def Test_term_start() endif enddef +def Test_term_wait() + CheckRunVimInTerminal + CheckDefAndScriptFailure2(['term_wait(0z10, 1)'], 'E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1') + CheckDefAndScriptFailure2(['term_wait(1, "a")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2') +enddef + def Test_test_alloc_fail() CheckDefAndScriptFailure2(['test_alloc_fail("a", 10, 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E474: Invalid argument') CheckDefAndScriptFailure2(['test_alloc_fail(10, "b", 20)'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E474: Invalid argument') diff --git a/src/typval.c b/src/typval.c index 6e0b528e79..03891c806d 100644 --- a/src/typval.c +++ b/src/typval.c @@ -352,7 +352,7 @@ tv_get_float(typval_T *varp) #endif /* - * Give an error and return FAIL unless "tv" is a string. + * Give an error and return FAIL unless "args[idx]" is a string. */ int check_for_string_arg(typval_T *args, int idx) @@ -385,7 +385,7 @@ check_for_nonempty_string_arg(typval_T *args, int idx) } /* - * Give an error and return FAIL unless "tv" is a number. + * Give an error and return FAIL unless "args[idx]" is a number. */ int check_for_number_arg(typval_T *args, int idx) @@ -402,7 +402,44 @@ check_for_number_arg(typval_T *args, int idx) } /* - * Give an error and return FAIL unless "tv" is a dict. + * Give an error and return FAIL unless "args[idx]" is a bool. + */ + int +check_for_bool_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_BOOL + && !(args[idx].v_type == VAR_NUMBER + && (args[idx].vval.v_number == 0 + || args[idx].vval.v_number == 1))) + { + if (idx >= 0) + semsg(_(e_bool_required_for_argument_nr), idx + 1); + else + emsg(_(e_boolreq)); + return FAIL; + } + return OK; +} + +/* + * Give an error and return FAIL unless "args[idx]" is a list. + */ + int +check_for_list_arg(typval_T *args, int idx) +{ + if (args[idx].v_type != VAR_LIST) + { + if (idx >= 0) + semsg(_(e_list_required_for_argument_nr), idx + 1); + else + emsg(_(e_listreq)); + return FAIL; + } + return OK; +} + +/* + * Give an error and return FAIL unless "args[idx]" is a dict. */ int check_for_dict_arg(typval_T *args, int idx) diff --git a/src/version.c b/src/version.c index 78d6088e41..f7e2c17a0a 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3173, /**/ 3172, /**/ From 47bc9c333766ee3d45cb18c583a630e4ad53405a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 17 Jul 2021 21:24:56 +0200 Subject: [PATCH 34/42] patch 8.2.3174: Vim9: "legacy undo" finds "undo" variable Problem: Vim9: "legacy undo" finds "undo" variable. Solution: Do not pass lookup function to find_ex_command(). (closes #8563) --- src/testdir/test_vim9_assign.vim | 7 +++++++ src/version.c | 2 ++ src/vim9compile.c | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 3599d6c5d1..a33038c9a1 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1632,6 +1632,13 @@ def Test_script_local_in_legacy() let s:legvar = 'one' END CheckScriptFailure(lines, 'E476:', 1) + + edit! Xfile + lines =<< trim END + var edit: bool + legacy edit + END + CheckDefAndScriptSuccess(lines) enddef def Test_var_type_check() diff --git a/src/version.c b/src/version.c index f7e2c17a0a..e1421ddb4e 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3174, /**/ 3173, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 956ce44eb0..9ae11a54b1 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -9510,7 +9510,8 @@ compile_def_function( } } } - p = find_ex_command(&ea, NULL, starts_with_colon + p = find_ex_command(&ea, NULL, + starts_with_colon || (local_cmdmod.cmod_flags & CMOD_LEGACY) ? NULL : item_exists, &cctx); if (p == NULL) From c6ba2f9dde6d01c8ab356c239c2259f7d83652a4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 13:42:29 +0200 Subject: [PATCH 35/42] patch 8.2.3175: Vim9: using illegal pointer with nested lambdas. Problem: Vim9: using illegal pointer with inline function inside a lambda. Solution: Clear eval_tofree_cmdline when advancing to the next line. (closes #8578) --- src/eval.c | 5 +++++ src/testdir/test_vim9_func.vim | 16 ++++++++++++++++ src/version.c | 2 ++ 3 files changed, 23 insertions(+) diff --git a/src/eval.c b/src/eval.c index 5dc1642a16..2e8ab3d8fc 100644 --- a/src/eval.c +++ b/src/eval.c @@ -2177,6 +2177,11 @@ eval_next_line(evalarg_T *evalarg) vim_free(evalarg->eval_tofree); evalarg->eval_tofree = line; } + + // Advanced to the next line, "arg" no longer points into the previous + // line. + VIM_CLEAR(evalarg->eval_tofree_cmdline); + return skipwhite(line); } diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index c89c13e2dc..a2c4e7daed 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2265,6 +2265,22 @@ def Test_nested_inline_lambda() }) END CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + def s:func() + range(10) + ->mapnew((_, _) => ({ + key: range(10)->mapnew((_, _) => { + return ' ' + }), + })) + enddef + + defcomp + END + CheckScriptSuccess(lines) enddef def Shadowed(): list diff --git a/src/version.c b/src/version.c index e1421ddb4e..8b674d3773 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3175, /**/ 3174, /**/ From 0c35752d04f70408a3c560d5b3edbafcaddff302 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 14:43:43 +0200 Subject: [PATCH 36/42] patch 8.2.3176: Vim9: no type error for comparing number with string Problem: Vim9: no type error for comparing number with string. Solution: Add a runtime type check. (closes #8571) --- src/errors.h | 4 ++-- src/testdir/test_vim9_expr.vim | 23 +++++++++++++++++++++++ src/typval.c | 16 ++++++++++++++-- src/version.c | 2 ++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/errors.h b/src/errors.h index 46de733bc6..35d1487338 100644 --- a/src/errors.h +++ b/src/errors.h @@ -381,8 +381,8 @@ EXTERN char e_mismatched_endfunction[] INIT(= N_("E1151: Mismatched endfunction")); EXTERN char e_mismatched_enddef[] INIT(= N_("E1152: Mismatched enddef")); -EXTERN char e_invalid_operation_for_bool[] - INIT(= N_("E1153: Invalid operation for bool")); +EXTERN char e_invalid_operation_for_str[] + INIT(= N_("E1153: Invalid operation for %s")); EXTERN char e_divide_by_zero[] INIT(= N_("E1154: Divide by zero")); EXTERN char e_cannot_define_autocommands_for_all_events[] diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index cd6ffa4463..e7c08f4af0 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -660,13 +660,36 @@ def Test_expr4_equal() CheckDefExecAndScriptFailure(["var x: any = true", 'echo x == ""'], 'E1072: Cannot compare bool with string', 2) CheckDefExecAndScriptFailure2(["var x: any = 99", 'echo x == true'], 'E1138', 'E1072:', 2) CheckDefExecAndScriptFailure2(["var x: any = 'a'", 'echo x == 99'], 'E1030:', 'E1072:', 2) +enddef +def Test_expr4_wrong_type() for op in ['>', '>=', '<', '<=', '=~', '!~'] CheckDefExecAndScriptFailure([ "var a: any = 'a'", 'var b: any = true', 'echo a ' .. op .. ' b'], 'E1072:', 3) endfor + for op in ['>', '>=', '<', '<='] + CheckDefExecAndScriptFailure2([ + "var n: any = 2", + 'echo n ' .. op .. ' "3"'], 'E1030:', 'E1072:', 2) + endfor + for op in ['=~', '!~'] + CheckDefExecAndScriptFailure([ + "var n: any = 2", + 'echo n ' .. op .. ' "3"'], 'E1072:', 2) + endfor + + CheckDefAndScriptFailure([ + 'echo v:none == true'], 'E1072:', 1) + CheckDefAndScriptFailure([ + 'echo false >= true'], 'E1072:', 1) + CheckDefExecAndScriptFailure([ + "var n: any = v:none", + 'echo n == true'], 'E1072:', 2) + CheckDefExecAndScriptFailure([ + "var n: any = v:none", + 'echo n < true'], 'E1072:', 2) enddef " test != comperator diff --git a/src/typval.c b/src/typval.c index 03891c806d..9d5903f649 100644 --- a/src/typval.c +++ b/src/typval.c @@ -937,7 +937,9 @@ typval_compare( } } else if (in_vim9script() && (typ1->v_type == VAR_BOOL - || typ2->v_type == VAR_BOOL)) + || typ2->v_type == VAR_BOOL + || (typ1->v_type == VAR_SPECIAL + && typ2->v_type == VAR_SPECIAL))) { if (typ1->v_type != typ2->v_type) { @@ -955,13 +957,23 @@ typval_compare( case EXPR_ISNOT: case EXPR_NEQUAL: n1 = (n1 != n2); break; default: - emsg(_(e_invalid_operation_for_bool)); + semsg(_(e_invalid_operation_for_str), + vartype_name(typ1->v_type)); clear_tv(typ1); return FAIL; } } else { + if (in_vim9script() + && ((typ1->v_type != VAR_STRING && typ1->v_type != VAR_SPECIAL) + || (typ2->v_type != VAR_STRING && typ2->v_type != VAR_SPECIAL))) + { + semsg(_(e_cannot_compare_str_with_str), + vartype_name(typ1->v_type), vartype_name(typ2->v_type)); + clear_tv(typ1); + return FAIL; + } s1 = tv_get_string_buf(typ1, buf1); s2 = tv_get_string_buf(typ2, buf2); if (type != EXPR_MATCH && type != EXPR_NOMATCH) diff --git a/src/version.c b/src/version.c index 8b674d3773..c1a4f3f8fa 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3176, /**/ 3175, /**/ From ad2d4969e1616d3a0354c181e3a09271d5433b3d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 17:08:50 +0200 Subject: [PATCH 37/42] patch 8.2.3177: Vim9: can not use "for _ in expr" at script level Problem: Vim9: can not use "for _ in expr" at script level. Solution: Skip assignment if the loop variable is "_". --- src/eval.c | 14 ++++++++++++-- src/testdir/test_vim9_script.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/eval.c b/src/eval.c index 2e8ab3d8fc..058b2d3bed 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1784,6 +1784,8 @@ next_for_item(void *fi_void, char_u *arg) | ASSIGN_NO_MEMBER_TYPE) : 0); listitem_T *item; + int skip_assign = in_vim9script() && arg[0] == '_' + && !eval_isnamec(arg[1]); if (fi->fi_blob != NULL) { @@ -1795,6 +1797,8 @@ next_for_item(void *fi_void, char_u *arg) tv.v_lock = VAR_FIXED; tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi); ++fi->fi_bi; + if (skip_assign) + return TRUE; return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK; } @@ -1812,7 +1816,10 @@ next_for_item(void *fi_void, char_u *arg) tv.vval.v_string = vim_strnsave(fi->fi_string + fi->fi_byte_idx, len); fi->fi_byte_idx += len; ++fi->fi_bi; - result = ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, + if (skip_assign) + result = TRUE; + else + result = ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK; vim_free(tv.vval.v_string); return result; @@ -1825,7 +1832,10 @@ next_for_item(void *fi_void, char_u *arg) { fi->fi_lw.lw_item = item->li_next; ++fi->fi_bi; - result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, + if (skip_assign) + result = TRUE; + else + result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, fi->fi_varcount, flag, NULL) == OK); } return result; diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index bd06f7a2e9..592da6d0f9 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2557,6 +2557,12 @@ def Test_for_loop() dd.counter = 12 endfor assert_equal([{a: 'Cat', counter: 12}], foo) + + reslist = [] + for _ in range(3) + reslist->add('x') + endfor + assert_equal(['x', 'x', 'x'], reslist) END CheckDefAndScriptSuccess(lines) enddef diff --git a/src/version.c b/src/version.c index c1a4f3f8fa..0eb4b442b2 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3177, /**/ 3176, /**/ From 4db572eeb2b42819268e934e76c67163316d873f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 18:21:38 +0200 Subject: [PATCH 38/42] patch 8.2.3178: Vim9: the file name of an :import cannot be an expression Problem: Vim9: the file name of an :import cannot be an expression. Solution: Accept an expression that results in a string. Do not support :import in a function. --- runtime/doc/vim9.txt | 4 +++ src/testdir/test_vim9_script.vim | 49 ++++++-------------------------- src/version.c | 2 ++ src/vim9compile.c | 13 ++------- src/vim9script.c | 22 ++++++-------- 5 files changed, 25 insertions(+), 65 deletions(-) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 8b91cdd4b1..a0681d2875 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1354,6 +1354,9 @@ script file to avoid confusion. `:import` can also be used in legacy Vim script. The imported items still become script-local, even when the "s:" prefix is not given. +`:import` can not be used in a function. Imported items are intended to exist +at the script level and only imported once. + The script name after `import` can be: - A relative path, starting "." or "..". This finds a file relative to the location of the script file itself. This is useful to split up a large @@ -1363,6 +1366,7 @@ The script name after `import` can be: - A path not being relative or absolute. This will be found in the "import" subdirectories of 'runtimepath' entries. The name will usually be longer and unique, to avoid loading the wrong file. + Note that "after/import" is not used. Once a vim9 script file has been imported, the result is cached and used the next time the same script is imported. It will not be read again. diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 592da6d0f9..9baa1ff5aa 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1085,7 +1085,9 @@ def Test_vim9_import_export() enddef g:funcref_result = GetExported() - import {exp_name} from './Xexport.vim' + var dir = './' + var ext = ".vim" + import {exp_name} from dir .. 'Xexport' .. ext g:imported_name = exp_name exp_name ..= ' Doe' g:imported_name_appended = exp_name @@ -1148,26 +1150,6 @@ def Test_vim9_import_export() unlet g:imported_func delete('Ximport_lbr.vim') - # import inside :def function - var import_in_def_lines =<< trim END - vim9script - def ImportInDef() - import exported from './Xexport.vim' - g:imported = exported - exported += 7 - g:imported_added = exported - enddef - ImportInDef() - END - writefile(import_in_def_lines, 'Ximport2.vim') - source Ximport2.vim - # TODO: this should be 9879 - assert_equal(9876, g:imported) - assert_equal(9883, g:imported_added) - unlet g:imported - unlet g:imported_added - delete('Ximport2.vim') - var import_star_as_lines =<< trim END vim9script import * as Export from './Xexport.vim' @@ -1181,8 +1163,9 @@ def Test_vim9_import_export() END writefile(import_star_as_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9883, g:imported_def) - assert_equal(9883, g:imported_script) + # FIXME: this should be 9881 + assert_equal(9876, g:imported_def) + assert_equal(9876, g:imported_script) var import_star_as_lines_no_dot =<< trim END vim9script @@ -1257,7 +1240,7 @@ def Test_vim9_import_export() END writefile(import_star_as_lbr_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9883, g:imported) + assert_equal(9876, g:imported) var import_star_lines =<< trim END vim9script @@ -1345,7 +1328,7 @@ def Test_vim9_import_export() import name from Xexport.vim END writefile(import_invalid_string_lines, 'Ximport.vim') - assert_fails('source Ximport.vim', 'E1071:', '', 2, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim') var import_wrong_name_lines =<< trim END vim9script @@ -1659,22 +1642,6 @@ def Test_vim9script_reload_import() source Xreload.vim source Xreload.vim - var testlines =<< trim END - vim9script - def TheFunc() - import GetValtwo from './Xreload.vim' - assert_equal(222, GetValtwo()) - enddef - TheFunc() - END - writefile(testlines, 'Ximport.vim') - source Ximport.vim - - # Test that when not using "morelines" GetValtwo() and valtwo are still - # defined, because import doesn't reload a script. - writefile(lines, 'Xreload.vim') - source Ximport.vim - # cannot declare a var twice lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c index 0eb4b442b2..6f7864a6aa 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3178, /**/ 3177, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 9ae11a54b1..12dd19823a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4335,7 +4335,6 @@ compile_subscript( semsg(_(e_missing_paren), *arg); return FAIL; } - // TODO: base value may not be the first argument if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) return FAIL; } @@ -7293,15 +7292,6 @@ compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx) return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd; } -/* - * Compile an :import command. - */ - static char_u * -compile_import(char_u *arg, cctx_T *cctx) -{ - return handle_import(arg, &cctx->ctx_imports, 0, NULL, cctx); -} - /* * generate a jump to the ":endif"/":endfor"/":endwhile"/":finally"/":endtry". */ @@ -9638,7 +9628,8 @@ compile_def_function( break; case CMD_import: - line = compile_import(p, &cctx); + emsg(_(e_import_can_only_be_used_in_script)); + line = NULL; break; case CMD_if: diff --git a/src/vim9script.c b/src/vim9script.c index d40e334aef..85d601c7ae 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -412,6 +412,7 @@ handle_import( garray_T names; garray_T as_names; + tv.v_type = VAR_UNKNOWN; ga_init2(&names, sizeof(char_u *), 10); ga_init2(&as_names, sizeof(char_u *), 10); if (*arg == '{') @@ -496,14 +497,14 @@ handle_import( goto erret; } + // The name of the file can be an expression, which must evaluate to a + // string. arg = skipwhite_and_linebreak(arg + 4, evalarg); - tv.v_type = VAR_UNKNOWN; - // TODO: should we accept any expression? - if (*arg == '\'') - ret = eval_lit_string(&arg, &tv, TRUE); - else if (*arg == '"') - ret = eval_string(&arg, &tv, TRUE); - if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) + ret = eval0(arg, &tv, NULL, evalarg); + if (ret == FAIL) + goto erret; + if (tv.v_type != VAR_STRING + || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) { emsg(_(e_invalid_string_after_from)); goto erret; @@ -524,10 +525,7 @@ handle_import( len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2; from_name = alloc((int)len); if (from_name == NULL) - { - clear_tv(&tv); goto erret; - } vim_strncpy(from_name, si->sn_name, tail - si->sn_name); add_pathsep(from_name); STRCAT(from_name, tv.vval.v_string); @@ -550,7 +548,6 @@ handle_import( from_name = alloc((int)len); if (from_name == NULL) { - clear_tv(&tv); goto erret; } vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string); @@ -561,10 +558,8 @@ handle_import( if (res == FAIL || sid <= 0) { semsg(_(e_could_not_import_str), tv.vval.v_string); - clear_tv(&tv); goto erret; } - clear_tv(&tv); if (*arg_start == '*') { @@ -669,6 +664,7 @@ handle_import( } } erret: + clear_tv(&tv); ga_clear_strings(&names); ga_clear_strings(&as_names); return cmd_end; From 24e9316560bd5c9ea2e5a963335aedff025e7f66 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 20:40:33 +0200 Subject: [PATCH 39/42] patch 8.2.3179: Vim9: cannot assign to an imported variable at script level Problem: Vim9: cannot assign to an imported variable at script level. Solution: Lookup imported items when assigning. --- src/errors.h | 2 + src/eval.c | 3 +- src/evalvars.c | 334 +++++++++++++++++-------------- src/testdir/test_vim9_script.vim | 79 +++++--- src/version.c | 2 + 5 files changed, 243 insertions(+), 177 deletions(-) diff --git a/src/errors.h b/src/errors.h index 35d1487338..be1341adb1 100644 --- a/src/errors.h +++ b/src/errors.h @@ -506,3 +506,5 @@ EXTERN char e_list_required_for_argument_nr[] INIT(= N_("E1211: List required for argument %d")); EXTERN char e_bool_required_for_argument_nr[] INIT(= N_("E1211: Bool required for argument %d")); +EXTERN char e_redefining_imported_item_str[] + INIT(= N_("E1212: Redefining imported item %s")); diff --git a/src/eval.c b/src/eval.c index 058b2d3bed..77774b738d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1358,7 +1358,8 @@ set_var_lval( || (!var_check_ro(di->di_flags, lp->ll_name, FALSE) && !tv_check_lock(&di->di_tv, lp->ll_name, FALSE))) && tv_op(&tv, rettv, op) == OK) - set_var(lp->ll_name, &tv, FALSE); + set_var_const(lp->ll_name, NULL, &tv, FALSE, + ASSIGN_NO_DECL, 0); clear_tv(&tv); } } diff --git a/src/evalvars.c b/src/evalvars.c index 27d7328715..3f209ba216 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3201,6 +3201,7 @@ set_var_const( typval_T *tv = tv_arg; typval_T bool_tv; dictitem_T *di; + typval_T *dest_tv = NULL; char_u *varname; hashtab_T *ht; int is_script_local; @@ -3241,182 +3242,210 @@ set_var_const( di = find_var_in_ht(ht, 0, varname, TRUE); - // Search in parent scope which is possible to reference from lambda - if (di == NULL) - di = find_var_in_scoped_ht(name, TRUE); - - if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) - && var_wrong_func_name(name, di == NULL)) - goto failed; - - if (need_convert_to_bool(type, tv)) + if (di == NULL && var_in_vim9script) { - // Destination is a bool and the value is not, but it can be converted. - CLEAR_FIELD(bool_tv); - bool_tv.v_type = VAR_BOOL; - bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE; - tv = &bool_tv; - } + imported_T *import = find_imported(varname, 0, NULL); - if (di != NULL) - { - // Item already exists. Allowed to replace when reloading. - if ((di->di_flags & DI_FLAGS_RELOAD) == 0) + if (import != NULL) { - if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) - && (flags & ASSIGN_FOR_LOOP) == 0) + scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); + svar_T *sv; + + // imported variable from another script + if ((flags & ASSIGN_NO_DECL) == 0) { - emsg(_(e_cannot_mod)); + semsg(_(e_redefining_imported_item_str), name); goto failed; } + sv = ((svar_T *)si->sn_var_vals.ga_data) + + import->imp_var_vals_idx; + // TODO: check the type + // TODO: check for const and locked + dest_tv = sv->sv_tv; + } + } - if (is_script_local && vim9script - && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) + if (dest_tv == NULL) + { + // Search in parent scope which is possible to reference from lambda + if (di == NULL) + di = find_var_in_scoped_ht(name, TRUE); + + if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) + && var_wrong_func_name(name, di == NULL)) + goto failed; + + if (need_convert_to_bool(type, tv)) + { + // Destination is a bool and the value is not, but it can be converted. + CLEAR_FIELD(bool_tv); + bool_tv.v_type = VAR_BOOL; + bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE; + tv = &bool_tv; + } + + if (di != NULL) + { + // Item already exists. Allowed to replace when reloading. + if ((di->di_flags & DI_FLAGS_RELOAD) == 0) + { + if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) + && (flags & ASSIGN_FOR_LOOP) == 0) + { + emsg(_(e_cannot_mod)); + goto failed; + } + + if (is_script_local && vim9script + && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) + { + semsg(_(e_redefining_script_item_str), name); + goto failed; + } + + if (var_in_vim9script) + { + where_T where; + + // check the type and adjust to bool if needed + where.wt_index = var_idx; + where.wt_variable = TRUE; + if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL) + goto failed; + } + + if (var_check_permission(di, name) == FAIL) + goto failed; + } + else + { + // can only redefine once + di->di_flags &= ~DI_FLAGS_RELOAD; + + // A Vim9 script-local variable is also present in sn_all_vars and + // sn_var_vals. It may set "type" from "tv". + if (var_in_vim9script) + update_vim9_script_var(FALSE, di, flags, tv, &type, + (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + } + + // existing variable, need to clear the value + + // Handle setting internal di: variables separately where needed to + // prevent changing the type. + if (ht == &vimvarht) + { + if (di->di_tv.v_type == VAR_STRING) + { + VIM_CLEAR(di->di_tv.vval.v_string); + if (copy || tv->v_type != VAR_STRING) + { + char_u *val = tv_get_string(tv); + + // Careful: when assigning to v:errmsg and tv_get_string() + // causes an error message the variable will already be set. + if (di->di_tv.vval.v_string == NULL) + di->di_tv.vval.v_string = vim_strsave(val); + } + else + { + // Take over the string to avoid an extra alloc/free. + di->di_tv.vval.v_string = tv->vval.v_string; + tv->vval.v_string = NULL; + } + goto failed; + } + else if (di->di_tv.v_type == VAR_NUMBER) + { + di->di_tv.vval.v_number = tv_get_number(tv); + if (STRCMP(varname, "searchforward") == 0) + set_search_direction(di->di_tv.vval.v_number ? '/' : '?'); +#ifdef FEAT_SEARCH_EXTRA + else if (STRCMP(varname, "hlsearch") == 0) + { + no_hlsearch = !di->di_tv.vval.v_number; + redraw_all_later(SOME_VALID); + } +#endif + goto failed; + } + else if (di->di_tv.v_type != tv->v_type) + { + semsg(_("E963: setting %s to value with wrong type"), name); + goto failed; + } + } + + clear_tv(&di->di_tv); + } + else + { + // Item not found, check if a function already exists. + if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 + && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) { semsg(_(e_redefining_script_item_str), name); goto failed; } + // add a new variable + if (var_in_vim9script && (flags & ASSIGN_NO_DECL)) + { + semsg(_(e_unknown_variable_str), name); + goto failed; + } + + // Can't add "v:" or "a:" variable. + if (ht == &vimvarht || ht == get_funccal_args_ht()) + { + semsg(_(e_illvar), name); + goto failed; + } + + // Make sure the variable name is valid. In Vim9 script an autoload + // variable must be prefixed with "g:". + if (!valid_varname(varname, !vim9script + || STRNCMP(name, "g:", 2) == 0)) + goto failed; + + di = alloc(sizeof(dictitem_T) + STRLEN(varname)); + if (di == NULL) + goto failed; + STRCPY(di->di_key, varname); + if (hash_add(ht, DI2HIKEY(di)) == FAIL) + { + vim_free(di); + goto failed; + } + di->di_flags = DI_FLAGS_ALLOC; + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) + di->di_flags |= DI_FLAGS_LOCK; + + // A Vim9 script-local variable is also added to sn_all_vars and + // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) - { - where_T where; - - // check the type and adjust to bool if needed - where.wt_index = var_idx; - where.wt_variable = TRUE; - if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL) - goto failed; - } - - if (var_check_permission(di, name) == FAIL) - goto failed; - } - else - { - // can only redefine once - di->di_flags &= ~DI_FLAGS_RELOAD; - - // A Vim9 script-local variable is also present in sn_all_vars and - // sn_var_vals. It may set "type" from "tv". - if (var_in_vim9script) - update_vim9_script_var(FALSE, di, flags, tv, &type, - (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + update_vim9_script_var(TRUE, di, flags, tv, &type, + (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } - // existing variable, need to clear the value - - // Handle setting internal di: variables separately where needed to - // prevent changing the type. - if (ht == &vimvarht) - { - if (di->di_tv.v_type == VAR_STRING) - { - VIM_CLEAR(di->di_tv.vval.v_string); - if (copy || tv->v_type != VAR_STRING) - { - char_u *val = tv_get_string(tv); - - // Careful: when assigning to v:errmsg and tv_get_string() - // causes an error message the variable will already be set. - if (di->di_tv.vval.v_string == NULL) - di->di_tv.vval.v_string = vim_strsave(val); - } - else - { - // Take over the string to avoid an extra alloc/free. - di->di_tv.vval.v_string = tv->vval.v_string; - tv->vval.v_string = NULL; - } - goto failed; - } - else if (di->di_tv.v_type == VAR_NUMBER) - { - di->di_tv.vval.v_number = tv_get_number(tv); - if (STRCMP(varname, "searchforward") == 0) - set_search_direction(di->di_tv.vval.v_number ? '/' : '?'); -#ifdef FEAT_SEARCH_EXTRA - else if (STRCMP(varname, "hlsearch") == 0) - { - no_hlsearch = !di->di_tv.vval.v_number; - redraw_all_later(SOME_VALID); - } -#endif - goto failed; - } - else if (di->di_tv.v_type != tv->v_type) - { - semsg(_("E963: setting %s to value with wrong type"), name); - goto failed; - } - } - - clear_tv(&di->di_tv); - } - else - { - // Item not found, check if a function already exists. - if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 - && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) - { - semsg(_(e_redefining_script_item_str), name); - goto failed; - } - - // add a new variable - if (var_in_vim9script && (flags & ASSIGN_NO_DECL)) - { - semsg(_(e_unknown_variable_str), name); - goto failed; - } - - // Can't add "v:" or "a:" variable. - if (ht == &vimvarht || ht == get_funccal_args_ht()) - { - semsg(_(e_illvar), name); - goto failed; - } - - // Make sure the variable name is valid. In Vim9 script an autoload - // variable must be prefixed with "g:". - if (!valid_varname(varname, !vim9script - || STRNCMP(name, "g:", 2) == 0)) - goto failed; - - di = alloc(sizeof(dictitem_T) + STRLEN(varname)); - if (di == NULL) - goto failed; - STRCPY(di->di_key, varname); - if (hash_add(ht, DI2HIKEY(di)) == FAIL) - { - vim_free(di); - goto failed; - } - di->di_flags = DI_FLAGS_ALLOC; - if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) - di->di_flags |= DI_FLAGS_LOCK; - - // A Vim9 script-local variable is also added to sn_all_vars and - // sn_var_vals. It may set "type" from "tv". - if (var_in_vim9script) - update_vim9_script_var(TRUE, di, flags, tv, &type, - (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + dest_tv = &di->di_tv; } if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) - copy_tv(tv, &di->di_tv); + copy_tv(tv, dest_tv); else { - di->di_tv = *tv; - di->di_tv.v_lock = 0; + *dest_tv = *tv; + dest_tv->v_lock = 0; init_tv(tv); } if (vim9script && type != NULL) { - if (type->tt_type == VAR_DICT && di->di_tv.vval.v_dict != NULL) - di->di_tv.vval.v_dict->dv_type = alloc_type(type); - else if (type->tt_type == VAR_LIST && di->di_tv.vval.v_list != NULL) - di->di_tv.vval.v_list->lv_type = alloc_type(type); + if (type->tt_type == VAR_DICT && dest_tv->vval.v_dict != NULL) + dest_tv->vval.v_dict->dv_type = alloc_type(type); + else if (type->tt_type == VAR_LIST && dest_tv->vval.v_list != NULL) + dest_tv->vval.v_list->lv_type = alloc_type(type); } // ":const var = value" locks the value @@ -3425,8 +3454,9 @@ set_var_const( // Like :lockvar! name: lock the value and what it contains, but only // if the reference count is up to one. That locks only literal // values. - item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); + item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE); return; + failed: if (!copy) clear_tv(tv_arg); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 9baa1ff5aa..203c5c905a 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1062,6 +1062,12 @@ let s:export_script_lines =<< trim END export def Exported(): string return 'Exported' enddef + export def ExportedValue(): number + return exported + enddef + export def ExportedInc() + exported += 5 + enddef export final theList = [1] END @@ -1073,10 +1079,21 @@ enddef def Test_vim9_import_export() var import_script_lines =<< trim END vim9script - import {exported, Exported} from './Xexport.vim' - g:imported = exported + import {exported, Exported, ExportedValue} from './Xexport.vim' + g:exported1 = exported exported += 3 - g:imported_added = exported + g:exported2 = exported + g:exported3 = ExportedValue() + + import ExportedInc from './Xexport.vim' + ExportedInc() + g:exported_i1 = exported + g:exported_i2 = ExportedValue() + + exported = 11 + g:exported_s1 = exported + g:exported_s2 = ExportedValue() + g:imported_func = Exported() def GetExported(): string @@ -1091,7 +1108,7 @@ def Test_vim9_import_export() g:imported_name = exp_name exp_name ..= ' Doe' g:imported_name_appended = exp_name - g:imported_later = exported + g:exported_later = exported import theList from './Xexport.vim' theList->add(2) @@ -1105,9 +1122,17 @@ def Test_vim9_import_export() assert_equal('bobbie', g:result) assert_equal('bob', g:localname) - assert_equal(9876, g:imported) - assert_equal(9879, g:imported_added) - assert_equal(9879, g:imported_later) + assert_equal(9876, g:exported1) + assert_equal(9879, g:exported2) + assert_equal(9879, g:exported3) + + assert_equal(9884, g:exported_i1) + assert_equal(9884, g:exported_i2) + + assert_equal(11, g:exported_s1) + assert_equal(11, g:exported_s2) + assert_equal(11, g:exported_later) + assert_equal('Exported', g:imported_func) assert_equal('Exported', g:funcref_result) assert_equal('John', g:imported_name) @@ -1115,9 +1140,12 @@ def Test_vim9_import_export() assert_false(exists('g:name')) Undo_export_script_lines() - unlet g:imported - unlet g:imported_added - unlet g:imported_later + unlet g:exported1 + unlet g:exported2 + unlet g:exported3 + unlet g:exported_i1 + unlet g:exported_i2 + unlet g:exported_later unlet g:imported_func unlet g:imported_name g:imported_name_appended delete('Ximport.vim') @@ -1131,22 +1159,22 @@ def Test_vim9_import_export() } from './Xexport.vim' - g:imported = exported - exported += 5 - g:imported_added = exported + g:exported = exported + exported += 7 + g:exported_added = exported g:imported_func = Exported() END writefile(import_line_break_script_lines, 'Ximport_lbr.vim') source Ximport_lbr.vim - assert_equal(9876, g:imported) - assert_equal(9881, g:imported_added) + assert_equal(11, g:exported) + assert_equal(18, g:exported_added) assert_equal('Exported', g:imported_func) # exported script not sourced again assert_false(exists('g:result')) - unlet g:imported - unlet g:imported_added + unlet g:exported + unlet g:exported_added unlet g:imported_func delete('Ximport_lbr.vim') @@ -1154,18 +1182,20 @@ def Test_vim9_import_export() vim9script import * as Export from './Xexport.vim' def UseExport() - g:imported_def = Export.exported + g:exported_def = Export.exported enddef - g:imported_script = Export.exported + g:exported_script = Export.exported assert_equal(1, exists('Export.exported')) assert_equal(0, exists('Export.notexported')) UseExport() END writefile(import_star_as_lines, 'Ximport.vim') source Ximport.vim - # FIXME: this should be 9881 - assert_equal(9876, g:imported_def) - assert_equal(9876, g:imported_script) + + assert_equal(18, g:exported_def) + assert_equal(18, g:exported_script) + unlet g:exported_def + unlet g:exported_script var import_star_as_lines_no_dot =<< trim END vim9script @@ -1234,13 +1264,14 @@ def Test_vim9_import_export() from './Xexport.vim' def UseExport() - g:imported = Export.exported + g:exported = Export.exported enddef UseExport() END writefile(import_star_as_lbr_lines, 'Ximport.vim') source Ximport.vim - assert_equal(9876, g:imported) + assert_equal(18, g:exported) + unlet g:exported var import_star_lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c index 6f7864a6aa..48e6748aeb 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3179, /**/ 3178, /**/ From f6488547e3c7e41ff2c12dd0b93c9ef04e4c8c6f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 21:24:50 +0200 Subject: [PATCH 40/42] patch 8.2.3180: Vim9: memory leak when concatenating to an imported string Problem: Vim9: memory leak when concatenating to an imported string. Solution: Clear the destination. --- src/evalvars.c | 33 +++++++++++++++++++-------------- src/version.c | 2 ++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 3f209ba216..dcf1058dec 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3262,6 +3262,7 @@ set_var_const( // TODO: check the type // TODO: check for const and locked dest_tv = sv->sv_tv; + clear_tv(dest_tv); } } @@ -3272,12 +3273,13 @@ set_var_const( di = find_var_in_scoped_ht(name, TRUE); if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) - && var_wrong_func_name(name, di == NULL)) + && var_wrong_func_name(name, di == NULL)) goto failed; if (need_convert_to_bool(type, tv)) { - // Destination is a bool and the value is not, but it can be converted. + // Destination is a bool and the value is not, but it can be + // converted. CLEAR_FIELD(bool_tv); bool_tv.v_type = VAR_BOOL; bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE; @@ -3290,14 +3292,14 @@ set_var_const( if ((di->di_flags & DI_FLAGS_RELOAD) == 0) { if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) - && (flags & ASSIGN_FOR_LOOP) == 0) + && (flags & ASSIGN_FOR_LOOP) == 0) { emsg(_(e_cannot_mod)); goto failed; } if (is_script_local && vim9script - && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) + && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) { semsg(_(e_redefining_script_item_str), name); goto failed; @@ -3310,7 +3312,8 @@ set_var_const( // check the type and adjust to bool if needed where.wt_index = var_idx; where.wt_variable = TRUE; - if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL) + if (check_script_var_type(&di->di_tv, tv, name, where) + == FAIL) goto failed; } @@ -3322,11 +3325,11 @@ set_var_const( // can only redefine once di->di_flags &= ~DI_FLAGS_RELOAD; - // A Vim9 script-local variable is also present in sn_all_vars and - // sn_var_vals. It may set "type" from "tv". + // A Vim9 script-local variable is also present in sn_all_vars + // and sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) update_vim9_script_var(FALSE, di, flags, tv, &type, - (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } // existing variable, need to clear the value @@ -3342,8 +3345,9 @@ set_var_const( { char_u *val = tv_get_string(tv); - // Careful: when assigning to v:errmsg and tv_get_string() - // causes an error message the variable will already be set. + // Careful: when assigning to v:errmsg and + // tv_get_string() causes an error message the variable + // will already be set. if (di->di_tv.vval.v_string == NULL) di->di_tv.vval.v_string = vim_strsave(val); } @@ -3359,7 +3363,8 @@ set_var_const( { di->di_tv.vval.v_number = tv_get_number(tv); if (STRCMP(varname, "searchforward") == 0) - set_search_direction(di->di_tv.vval.v_number ? '/' : '?'); + set_search_direction(di->di_tv.vval.v_number + ? '/' : '?'); #ifdef FEAT_SEARCH_EXTRA else if (STRCMP(varname, "hlsearch") == 0) { @@ -3382,7 +3387,7 @@ set_var_const( { // Item not found, check if a function already exists. if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 - && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) + && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK) { semsg(_(e_redefining_script_item_str), name); goto failed; @@ -3405,7 +3410,7 @@ set_var_const( // Make sure the variable name is valid. In Vim9 script an autoload // variable must be prefixed with "g:". if (!valid_varname(varname, !vim9script - || STRNCMP(name, "g:", 2) == 0)) + || STRNCMP(name, "g:", 2) == 0)) goto failed; di = alloc(sizeof(dictitem_T) + STRLEN(varname)); @@ -3425,7 +3430,7 @@ set_var_const( // sn_var_vals. It may set "type" from "tv". if (var_in_vim9script) update_vim9_script_var(TRUE, di, flags, tv, &type, - (flags & ASSIGN_NO_MEMBER_TYPE) == 0); + (flags & ASSIGN_NO_MEMBER_TYPE) == 0); } dest_tv = &di->di_tv; diff --git a/src/version.c b/src/version.c index 48e6748aeb..b59eca27a6 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3180, /**/ 3179, /**/ From 9ff9c7b9741b216d3dc75603e50654088dc5f55b Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Sun, 18 Jul 2021 21:44:37 +0200 Subject: [PATCH 41/42] patch 8.2.3181: Vim9: builtin function test fails without channel feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Vim9: builtin function test fails without channel feature. Solution: Add feature checks. (Dominique Pellé, closes #8586) Make feature checks more consistent. --- src/testdir/test_vim9_builtin.vim | 50 +++++++++++++++++++++---------- src/version.c | 2 ++ 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 0668797386..638d7daa13 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -398,9 +398,13 @@ def Test_ch_close_in() enddef def Test_ch_getjob() - CheckDefAndScriptFailure2(['ch_getjob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument:') - CheckDefAndScriptFailure2(['ch_getjob({"a": 10})'], 'E1013: Argument 1: type mismatch, expected channel but got dict', 'E731: Using a Dictionary as a String') - assert_equal(0, ch_getjob(test_null_channel())) + if !has('channel') + CheckFeature channel + else + CheckDefAndScriptFailure2(['ch_getjob(1)'], 'E1013: Argument 1: type mismatch, expected channel but got number', 'E475: Invalid argument:') + CheckDefAndScriptFailure2(['ch_getjob({"a": 10})'], 'E1013: Argument 1: type mismatch, expected channel but got dict', 'E731: Using a Dictionary as a String') + assert_equal(0, ch_getjob(test_null_channel())) + endif enddef def Test_ch_info() @@ -1425,17 +1429,27 @@ def Test_items() enddef def Test_job_getchannel() - CheckDefAndScriptFailure2(['job_getchannel("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') - assert_fails('job_getchannel(test_null_job())', 'E916: not a valid job') + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_getchannel("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_getchannel(test_null_job())', 'E916: not a valid job') + endif enddef def Test_job_info() - CheckDefAndScriptFailure2(['job_info("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') - assert_fails('job_info(test_null_job())', 'E916: not a valid job') + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_info("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_fails('job_info(test_null_job())', 'E916: not a valid job') + endif enddef def Test_job_info_return_type() - if has('job') + if !has('job') + CheckFeature job + else job_start(&shell) var jobs = job_info() assert_equal('list', typename(jobs)) @@ -1445,8 +1459,12 @@ def Test_job_info_return_type() enddef def Test_job_status() - CheckDefAndScriptFailure2(['job_status("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') - assert_equal('fail', job_status(test_null_job())) + if !has('job') + CheckFeature job + else + CheckDefAndScriptFailure2(['job_status("a")'], 'E1013: Argument 1: type mismatch, expected job but got string', 'E475: Invalid argument') + assert_equal('fail', job_status(test_null_job())) + endif enddef def Test_js_decode() @@ -1877,7 +1895,9 @@ def Test_prevnonblank() enddef def Test_prompt_getprompt() - if has('channel') + if !has('channel') + CheckFeature channel + else CheckDefFailure(['prompt_getprompt([])'], 'E1013: Argument 1: type mismatch, expected string but got list') assert_equal('', prompt_getprompt('NonExistingBuf')) endif @@ -2439,7 +2459,7 @@ enddef def Test_spellsuggest() if !has('spell') - MissingFeature 'spell' + CheckFeature spell else spellsuggest('marrch', 1, true)->assert_equal(['March']) endif @@ -2496,7 +2516,7 @@ enddef def Run_str2float() if !has('float') - MissingFeature 'float' + CheckFeature float endif str2float("1.00")->assert_equal(1.00) str2float("2e-2")->assert_equal(0.02) @@ -2721,7 +2741,7 @@ enddef def Test_term_gettty() if !has('terminal') - MissingFeature 'terminal' + CheckFeature terminal else var buf = Run_shell_in_terminal({}) term_gettty(buf, true)->assert_notequal('') @@ -2754,7 +2774,7 @@ def Test_term_setrestore() enddef def Test_term_start() if !has('terminal') - MissingFeature 'terminal' + CheckFeature terminal else botright new var winnr = winnr() diff --git a/src/version.c b/src/version.c index b59eca27a6..371fdcd881 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3181, /**/ 3180, /**/ From 885971e2f5eabc4108e083086c1d6d0a31a2782f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 18 Jul 2021 22:25:29 +0200 Subject: [PATCH 42/42] patch 8.2.3182: Vim9: crash when using removing items from a constant list Problem: Vim9: crash when using removing items from a constant list. (Yegappan Lakshmanan) Solution: When a list was allocated with items copy them. --- src/list.c | 32 +++++++++++++++++++++++++------ src/testdir/test_vim9_builtin.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/list.c b/src/list.c index d138d868cd..417f735e0d 100644 --- a/src/list.c +++ b/src/list.c @@ -1566,12 +1566,32 @@ list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) vimlist_remove(l, item, item2); if (rettv_list_alloc(rettv) == OK) { - l = rettv->vval.v_list; - l->lv_first = item; - l->lv_u.mat.lv_last = item2; - item->li_prev = NULL; - item2->li_next = NULL; - l->lv_len = cnt; + list_T *rl = rettv->vval.v_list; + + if (l->lv_with_items > 0) + { + // need to copy the list items and move the value + while (item != NULL) + { + li = listitem_alloc(); + if (li == NULL) + return; + li->li_tv = item->li_tv; + init_tv(&item->li_tv); + list_append(rl, li); + if (item == item2) + break; + item = item->li_next; + } + } + else + { + rl->lv_first = item; + rl->lv_u.mat.lv_last = item2; + item->li_prev = NULL; + item2->li_next = NULL; + rl->lv_len = cnt; + } } } } diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 638d7daa13..76987b68a3 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -2083,6 +2083,12 @@ def Test_remote_startserver() CheckDefFailure(['remote_startserver({})'], 'E1013: Argument 1: type mismatch, expected string but got dict') enddef +def Test_remove_const_list() + var l: list = [1, 2, 3, 4] + assert_equal([1, 2], remove(l, 0, 1)) + assert_equal([3, 4], l) +enddef + def Test_remove_return_type() var l = remove({one: [1, 2], two: [3, 4]}, 'one') var res = 0 diff --git a/src/version.c b/src/version.c index 371fdcd881..6ae1d3bf07 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3182, /**/ 3181, /**/