# HG changeset patch # User Bram Moolenaar # Date 1626380103 -7200 # Node ID 1d6ff96306fc879b9941ac6ee6b5059277a109fc # Parent 19bc0f4c937949042526381e54ee29369a798695 patch 8.2.3169: Vim9: cannot handle nested inline function Commit: https://github.com/vim/vim/commit/5245beb37cb52991a745644c20d7ca1b0138ef2c Author: Bram Moolenaar Date: Thu Jul 15 22:03:50 2021 +0200 patch 8.2.3169: Vim9: cannot handle nested inline function Problem: Vim9: cannot handle nested inline function. Solution: Check for nested inline function. (closes https://github.com/vim/vim/issues/8575) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- 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 --- 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 --- 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 --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3169, +/**/ 3168, /**/ 3167,