From 4b0b53e856d4df9ada397efd49bec5a78b943643 Mon Sep 17 00:00:00 2001 From: Hirohito Higashi Date: Tue, 25 Aug 2026 20:18:37 +0000 Subject: [PATCH] patch 9.2.1008: Vim9: hang when a line break is used before "->(" Problem: In Vim9 script a line break before "->(" makes Vim hang and use up memory (SectionCotangentBundle) Solution: Consume the line break for "->(" as well, and skip white space after "->" in a compiled function too (Hirohito Higashi). fixes: #21144 closes: #21147 Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- src/eval.c | 21 +++++++++++++++++---- src/testdir/test_vim9_expr.vim | 8 ++++++++ src/version.c | 2 ++ src/vim9expr.c | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/eval.c b/src/eval.c index bb6f452b0b..0d19330c7e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -7591,6 +7591,21 @@ eval_isdictc(int c) return ASCII_ISALNUM(c) || c == '_'; } +/* + * Return true when "p" points to "->" followed by a method name or a lambda. + * Only called for Vim9 script. + */ + static bool +method_call_follows(char_u *p) +{ + if (p[0] != '-' || p[1] != '>') + return false; + + char_u *after = skipwhite(p + 2); + + return ASCII_ISALPHA(*after) || *after == '('; +} + /* * Handle: * - expr[expr], expr[expr:expr] subscript @@ -7619,7 +7634,7 @@ handle_subscript( while (ret == OK) { - // When at the end of the line and ".name" or "->{" or "->X" follows in + // When at the end of the line and ".name" or a method call follows in // the next line then consume the line break. p = eval_next_non_blank(*arg, evalarg, &getnext); if (getnext @@ -7627,9 +7642,7 @@ handle_subscript( && ((rettv->v_type == VAR_DICT && eval_isdictc(p[1])) || rettv->v_type == VAR_CLASS || rettv->v_type == VAR_OBJECT)) - || (p[0] == '-' && p[1] == '>' && (p[2] == '{' - || ASCII_ISALPHA(in_vim9script() ? *skipwhite(p + 2) - : p[2]))))) + || method_call_follows(p))) { *arg = eval_next_line(*arg, evalarg); p = *arg; diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 1062df185d..3613c1a2ea 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -3964,6 +3964,14 @@ def Test_expr9_method_call() var sorted = [3, 1, 2] -> sort() assert_equal([1, 2, 3], sorted) + + var nrs = [1, 2] + ->((x) => x)() + assert_equal([1, 2], nrs) + + nrs = [3, 4] + -> ((x) => x)() + assert_equal([3, 4], nrs) END v9.CheckDefAndScriptSuccess(lines) diff --git a/src/version.c b/src/version.c index 218ee0cc8c..80a2f16869 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1008, /**/ 1007, /**/ diff --git a/src/vim9expr.c b/src/vim9expr.c index 87a872f58c..46d978d443 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -2550,7 +2550,7 @@ compile_subscript( if (next != NULL && ((next[0] == '-' && next[1] == '>' && (next[2] == '{' - || next[2] == '(' + || *skipwhite(next + 2) == '(' || ASCII_ISALPHA(*skipwhite(next + 2)))) || (next[0] == '.' && eval_isdictc(next[1])))) {