Patch 9.0.1540
Problem: reverse() on string doesn't work in compiled function.
Solution: Accept string in argument type check. (Yegappan Lakshmanan,
closes #12377)
Files: src/evalfunc.c, src/list.c, src/optionstr.c,
src/testdir/test_functions.vim, src/testdir/test_listdict.vim,
src/testdir/test_method.vim, src/testdir/test_vim9_builtin.vim
*** ../vim-9.0.1539/src/evalfunc.c 2023-04-27 16:24:03.592501355 +0100
--- src/evalfunc.c 2023-05-11 14:58:51.187438722 +0100
***************
*** 757,762 ****
--- 757,773 ----
}
/*
+ * Check "type" is a modifiable list of 'any' or a blob or a string.
+ */
+ static int
+ arg_string_list_or_blob_mod(type_T *type, type_T *decl_type, argcontext_T *context)
+ {
+ if (arg_string_list_or_blob(type, decl_type, context) == FAIL)
+ return FAIL;
+ return arg_type_modifiable(type, context->arg_idx + 1);
+ }
+
+ /*
* Check "type" is a job.
*/
static int
***************
*** 1010,1016 ****
static argcheck_T arg1_job[] = {arg_job};
static argcheck_T arg1_list_any[] = {arg_list_any};
static argcheck_T arg1_list_number[] = {arg_list_number};
! static argcheck_T arg1_list_or_blob_mod[] = {arg_list_or_blob_mod};
static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict};
static argcheck_T arg1_list_string[] = {arg_list_string};
static argcheck_T arg1_string_or_list_or_dict[] = {arg_string_or_list_or_dict};
--- 1021,1027 ----
static argcheck_T arg1_job[] = {arg_job};
static argcheck_T arg1_list_any[] = {arg_list_any};
static argcheck_T arg1_list_number[] = {arg_list_number};
! static argcheck_T arg1_string_or_list_or_blob_mod[] = {arg_string_list_or_blob_mod};
static argcheck_T arg1_list_or_dict[] = {arg_list_or_dict};
static argcheck_T arg1_list_string[] = {arg_list_string};
static argcheck_T arg1_string_or_list_or_dict[] = {arg_string_or_list_or_dict};
***************
*** 2413,2419 ****
ret_repeat, f_repeat},
{"resolve", 1, 1, FEARG_1, arg1_string,
ret_string, f_resolve},
! {"reverse", 1, 1, FEARG_1, arg1_list_or_blob_mod,
ret_first_arg, f_reverse},
{"round", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, f_round},
--- 2424,2430 ----
ret_repeat, f_repeat},
{"resolve", 1, 1, FEARG_1, arg1_string,
ret_string, f_resolve},
! {"reverse", 1, 1, FEARG_1, arg1_string_or_list_or_blob_mod,
ret_first_arg, f_reverse},
{"round", 1, 1, FEARG_1, arg1_float_or_nr,
ret_float, f_round},
*** ../vim-9.0.1539/src/list.c 2023-05-06 14:08:10.139045046 +0100
--- src/list.c 2023-05-11 14:58:51.187438722 +0100
***************
*** 2994,3009 ****
void
f_reverse(typval_T *argvars, typval_T *rettv)
{
! if (in_vim9script() && check_for_list_or_blob_arg(argvars, 0) == FAIL)
return;
if (argvars[0].v_type == VAR_BLOB)
blob_reverse(argvars[0].vval.v_blob, rettv);
else if (argvars[0].v_type == VAR_STRING)
string_reverse(argvars[0].vval.v_string, rettv);
! else if (argvars[0].v_type != VAR_LIST)
! semsg(_(e_argument_of_str_must_be_list_or_blob), "reverse()");
! else
list_reverse(argvars[0].vval.v_list, rettv);
}
--- 2994,3007 ----
void
f_reverse(typval_T *argvars, typval_T *rettv)
{
! if (check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL)
return;
if (argvars[0].v_type == VAR_BLOB)
blob_reverse(argvars[0].vval.v_blob, rettv);
else if (argvars[0].v_type == VAR_STRING)
string_reverse(argvars[0].vval.v_string, rettv);
! else if (argvars[0].v_type == VAR_LIST)
list_reverse(argvars[0].vval.v_list, rettv);
}
*** ../vim-9.0.1539/src/optionstr.c 2023-04-23 17:50:14.857935970 +0100
--- src/optionstr.c 2023-05-11 14:58:51.187438722 +0100
***************
*** 134,140 ****
(void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, TRUE);
}
! #if defined(FEAT_EVAL)
/*
* Trigger the OptionSet autocommand.
* "opt_idx" is the index of the option being set.
--- 134,140 ----
(void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, TRUE);
}
! #if defined(FEAT_EVAL) || defined(PROTO)
/*
* Trigger the OptionSet autocommand.
* "opt_idx" is the index of the option being set.
*** ../vim-9.0.1539/src/testdir/test_functions.vim 2023-05-08 15:31:34.247545088 +0100
--- src/testdir/test_functions.vim 2023-05-11 14:58:51.191438722 +0100
***************
*** 3475,3487 ****
" Test for the reverse() function with a string
func Test_string_reverse()
! call assert_equal('', reverse(test_null_string()))
! for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'],
! \ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'],
! \ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'],
! \ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']]
! call assert_equal(s2, reverse(s1))
! endfor
" test in latin1 encoding
let save_enc = &encoding
--- 3475,3490 ----
" Test for the reverse() function with a string
func Test_string_reverse()
! let lines =<< trim END
! call assert_equal('', reverse(test_null_string()))
! for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'],
! \ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'],
! \ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'],
! \ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']]
! call assert_equal(s2, reverse(s1))
! endfor
! END
! call v9.CheckLegacyAndVim9Success(lines)
" test in latin1 encoding
let save_enc = &encoding
*** ../vim-9.0.1539/src/testdir/test_listdict.vim 2023-05-06 14:08:10.143045044 +0100
--- src/testdir/test_listdict.vim 2023-05-11 14:58:51.191438722 +0100
***************
*** 981,987 ****
END
call v9.CheckLegacyAndVim9Success(lines)
! call assert_fails('call reverse({})', 'E899:')
call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:")
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
--- 981,987 ----
END
call v9.CheckLegacyAndVim9Success(lines)
! call assert_fails('call reverse({})', 'E1252:')
call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:")
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
*** ../vim-9.0.1539/src/testdir/test_method.vim 2023-01-28 19:18:56.729720605 +0000
--- src/testdir/test_method.vim 2023-05-11 14:58:51.191438722 +0100
***************
*** 62,68 ****
call assert_equal(2, d->remove("two"))
let d.two = 2
call assert_fails('let x = d->repeat(2)', 'E731:')
! call assert_fails('let x = d->reverse()', 'E899:')
call assert_fails('let x = d->sort()', 'E686:')
call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string())
call assert_equal(v:t_dict, d->type())
--- 62,68 ----
call assert_equal(2, d->remove("two"))
let d.two = 2
call assert_fails('let x = d->repeat(2)', 'E731:')
! call assert_fails('let x = d->reverse()', 'E1252:')
call assert_fails('let x = d->sort()', 'E686:')
call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string())
call assert_equal(v:t_dict, d->type())
*** ../vim-9.0.1539/src/testdir/test_vim9_builtin.vim 2023-03-05 19:27:43.646982550 +0000
--- src/testdir/test_vim9_builtin.vim 2023-05-11 14:58:51.191438722 +0100
***************
*** 3459,3466 ****
enddef
def Test_reverse()
! v9.CheckDefAndScriptFailure(['reverse(10)'], ['E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1226: List or Blob required for argument 1'])
! v9.CheckDefAndScriptFailure(['reverse("abc")'], ['E1013: Argument 1: type mismatch, expected list<any> but got string', 'E1226: List or Blob required for argument 1'])
enddef
def Test_reverse_return_type()
--- 3459,3465 ----
enddef
def Test_reverse()
! v9.CheckDefAndScriptFailure(['reverse(10)'], ['E1013: Argument 1: type mismatch, expected list<any> but got number', 'E1252: String, List or Blob required for argument 1'])
enddef
def Test_reverse_return_type()
*** ../vim-9.0.1539/src/version.c 2023-05-10 22:01:51.308844691 +0100
--- src/version.c 2023-05-11 15:00:34.455443234 +0100
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1540,
/**/
--
How To Keep A Healthy Level Of Insanity:
10. Ask people what sex they are. Laugh hysterically after they answer.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///