# HG changeset patch # User Christian Brabandt # Date 1711134006 -3600 # Node ID 7ff3c277377fbee24b88d00743d819bddae9fae6 # Parent 624afe8100835c527a100cb32740e442fe217905 patch 9.1.0198: Vim9: compound operators broken for lambdas in an object Commit: https://github.com/vim/vim/commit/d990bf08d85d83e14fc51fd99a66ebe2f36d2fcd Author: Yegappan Lakshmanan Date: Fri Mar 22 19:56:17 2024 +0100 patch 9.1.0198: Vim9: compound operators broken for lambdas in an object Problem: Vim9: compound operators broken for lambdas in an object (girishji) Solution: When using an object from the outer scope, use the LOADOUTER instruction to load the object (Yegappan Lakshmanan). fixes: #14236 closes: #14266 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt 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 @@ -10349,4 +10349,75 @@ def Test_Ref_Class_Within_Same_Class() v9.CheckScriptFailure(lines, 'E1347: Not a valid interface: A', 3) enddef +" Test for using a compound operator from a lambda function in an object method +def Test_compound_op_in_objmethod_lambda() + # Test using the "+=" operator + var lines =<< trim END + vim9script + class A + var n: number = 10 + def Foo() + var Fn = () => { + this.n += 1 + } + Fn() + enddef + endclass + + var a = A.new() + a.Foo() + assert_equal(11, a.n) + END + v9.CheckScriptSuccess(lines) + + # Test using the "..=" operator + lines =<< trim END + vim9script + class A + var s: string = "a" + def Foo() + var Fn = () => { + this.s ..= "a" + } + Fn() + enddef + endclass + + var a = A.new() + a.Foo() + a.Foo() + assert_equal("aaa", a.s) + END + v9.CheckScriptSuccess(lines) +enddef + +" call a lambda function in one object from another object +def Test_lambda_invocation_across_classes() + var lines =<< trim END + vim9script + class A + var s: string = "foo" + def GetFn(): func + var Fn = (): string => { + return this.s + } + return Fn + enddef + endclass + + class B + var s: string = "bar" + def GetFn(): func + var a = A.new() + return a.GetFn() + enddef + endclass + + var b = B.new() + var Fn = b.GetFn() + assert_equal("foo", Fn()) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -3436,4 +3436,36 @@ def Test_disassemble_object_len() unlet g:instr enddef +" Disassemble instructions for using a compound operator in a closure +def Test_disassemble_compound_op_in_closure() + var lines =<< trim END + vim9script + class A + var foo: number = 1 + def Foo(): func + var Fn = () => { + this.foo += 1 + } + return Fn + enddef + endclass + var a = A.new() + var Lambda = a.Foo() + var num = matchstr(string(Lambda), '\d\+') + g:instr = execute($'disassemble {num}') + END + v9.CheckScriptSuccess(lines) + assert_match('\d\+\_s*' .. + 'this.foo += 1\_s*' .. + '0 LOADOUTER level 0 $0\_s*' .. + '1 OBJ_MEMBER 0\_s*' .. + '2 PUSHNR 1\_s*' .. + '3 OPNR +\_s*' .. + '4 PUSHNR 0\_s*' .. + '5 LOADOUTER level 0 $0\_s*' .. + '6 STOREINDEX object\_s*' .. + '7 RETURN void', g:instr) + unlet g:instr +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 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 */ /**/ + 198, +/**/ 197, /**/ 196, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2285,7 +2285,17 @@ compile_load_lhs_with_index(lhs_T *lhs, if (dot - var_start == 4 && STRNCMP(var_start, "this", 4) == 0) { // load "this" - if (generate_LOAD(cctx, ISN_LOAD, 0, NULL, lhs->lhs_type) == FAIL) + lvar_T *lvar = lhs->lhs_lvar; + int rc; + + if (lvar->lv_from_outer > 0) + rc = generate_LOADOUTER(cctx, lvar->lv_idx, + lvar->lv_from_outer, lvar->lv_loop_depth, + lvar->lv_loop_idx, type); + else + rc = generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); + + if (rc == FAIL) return FAIL; } else