# HG changeset patch # User Christian Brabandt # Date 1712260804 -7200 # Node ID af48c532bd88f99f754f5602b39784e97ce53630 # Parent cd738b9a790a44af4ad541d771bf108f31259be7 patch 9.1.0263: Vim9: Problem with lambda blocks in enums and classes Commit: https://github.com/vim/vim/commit/3fa8f7728a47822e4efd106ab30c83c28f198b3c Author: Yegappan Lakshmanan Date: Thu Apr 4 21:42:07 2024 +0200 patch 9.1.0263: Vim9: Problem with lambda blocks in enums and classes Problem: Vim9: Problem with lambda blocks in enums and classes (Aliaksei Budavei) Solution: Support evaluating lambda blocks from a string, skip over comments (Yegappan Lakshmanan) fixes: #14350 closes: #14405 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -549,6 +549,7 @@ skip_expr_concatenate( ((char_u **)gap->ga_data)[gap->ga_len - 1]; ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL; ga_clear_strings(gap); + ga_clear(freegap); } else { @@ -1203,7 +1204,7 @@ get_lval_imported( dictitem_T *di = find_var_in_ht(ht, 0, lp->ll_name, TRUE); if (di == NULL) - // variable is not found + // script is autoloaded. So variable will be found later goto success; *dip = di; diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -10553,4 +10553,34 @@ def Test_protected_funcref() v9.CheckScriptFailure(lines, 'E1333: Cannot access protected variable "_Id" in class "Test2"', 5) enddef +" Test for using lambda block in classes +def Test_lambda_block_in_class() + # This used to crash Vim + var lines =<< trim END + vim9script + class IdClass1 + const Id: func(number): number = (num: number): number => { + # Return a ID + return num * 10 + } + endclass + var id = IdClass1.new() + assert_equal(20, id.Id(2)) + END + v9.CheckScriptSuccess(lines) + + # This used to crash Vim + lines =<< trim END + vim9script + class IdClass2 + static const Id: func(number): number = (num: number): number => { + # Return a ID + return num * 2 + } + endclass + assert_equal(16, IdClass2.Id(8)) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_enum.vim b/src/testdir/test_vim9_enum.vim --- a/src/testdir/test_vim9_enum.vim +++ b/src/testdir/test_vim9_enum.vim @@ -1503,4 +1503,35 @@ def Test_use_enum_values_in_class_variab v9.CheckSourceSuccess(lines) enddef +" Test for using lambda block in enums +def Test_lambda_block_in_enum() + # This used to crash Vim + var lines =<< trim END + vim9script + enum IdEnum1 + ID1 + const Id: func(number): number = (num: number): number => { + # Return a ID + return num / 2 + } + endenum + assert_equal(5, IdEnum1.ID1.Id(10)) + END + v9.CheckScriptSuccess(lines) + + # This used to crash Vim + lines =<< trim END + vim9script + enum IdEnum2 + ID1 + static const Id: func(number): number = (num: number): number => { + # Return a ID + return num + 2 + } + endenum + assert_equal(12, IdEnum2.Id(10)) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim --- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -2993,4 +2993,30 @@ def Test_import_autloaded_script() &rtp = save_rtp enddef +" Test for autoloading an imported dict func +def Test_autoload_import_dict_func() + mkdir('Xdir/autoload', 'pR') + var lines =<< trim END + vim9script + export var al_exported_nr: number = 33 + def Al_AddNum(n: number) + al_exported_nr += n + enddef + export var al_exportedDict: dict = {Fn: Al_AddNum} + END + writefile(lines, 'Xdir/autoload/Xdictfunc.vim') + + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdir' + lines =<< trim END + import './Xdir/autoload/Xdictfunc.vim' + call Xdictfunc#al_exportedDict.Fn(5) + call assert_equal(38, Xdictfunc#al_exported_nr) + call call(Xdictfunc#al_exportedDict.Fn, [3]) + call assert_equal(41, Xdictfunc#al_exported_nr) + END + v9.CheckScriptSuccess(lines) + &rtp = save_rtp +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4931,6 +4931,16 @@ def Test_for_empty_line_after_lambda() v9.CheckSourceSuccess(lines) enddef +" Test for evaluating a lambda block from a string +def Test_eval_lambda_block() + var lines =<< trim END + vim9script + var Fn = eval("(x: number): number => {\nreturn x * 2\n}") + assert_equal(6, Fn(3)) + END + v9.CheckSourceSuccess(lines) +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1335,6 +1335,7 @@ lambda_function_body( char_u *name; int lnum_save = -1; linenr_T sourcing_lnum_top = SOURCING_LNUM; + char_u *line_arg = NULL; *arg = skipwhite(*arg + 1); if (**arg == '|' || !ends_excmd2(start, *arg)) @@ -1343,6 +1344,12 @@ lambda_function_body( return FAIL; } + // When there is a line break use what follows for the lambda body. + // Makes lambda body initializers work for object and enum member + // variables. + if (**arg == '\n') + line_arg = *arg + 1; + CLEAR_FIELD(eap); eap.cmdidx = CMD_block; eap.forceit = FALSE; @@ -1357,7 +1364,7 @@ lambda_function_body( } ga_init2(&newlines, sizeof(char_u *), 10); - if (get_function_body(&eap, &newlines, NULL, + if (get_function_body(&eap, &newlines, line_arg, &evalarg->eval_tofree_ga) == FAIL) goto erret; @@ -1372,7 +1379,12 @@ lambda_function_body( for (idx = 0; idx < newlines.ga_len; ++idx) { - char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]); + char_u *p = ((char_u **)newlines.ga_data)[idx]; + if (p == NULL) + // comment line in the lambda body + continue; + + p = skipwhite(p); if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL) goto erret; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 263, +/**/ 262, /**/ 261,