Commit: patch 9.2.0975: Vim9: assignment to a member of an object member fails
Christian Brabandt <[email protected]>
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <[email protected]> |
patch 9.2.0975: Vim9: assignment to a member of an object member fails Commit: https://github.com/vim/vim/commit/44a92018a5a9e6d947845c748ab3add7b2d8e7c3 Author: Hirohito Higashi <[email protected]> Date: Tue Aug 18 20:50:15 2026 +0000 patch 9.2.0975: Vim9: assignment to a member of an object member fails Problem: Using an operator on a member of an object that is itself a member of an object gives E909, and a plain assignment to it stores the value in the wrong member (Mao-Yining). Solution: When the last index is split off from the name, forget the member index found for the first name. The index is compiled before the variable, thus do not use the type that loading the variable produced. Load the member of an object like an expression does instead of indexing it (Hirohito Higashi). fixes: #21084 closes: #21085 Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Signed-off-by: Hirohito Higashi <[email protected]> Signed-off-by: Christian Brabandt <[email protected]> diff --git a/src/proto/vim9expr.pro b/src/proto/vim9expr.pro index 4de143917..055723ce4 100644 --- a/src/proto/vim9expr.pro +++ b/src/proto/vim9expr.pro @@ -2,6 +2,7 @@ int generate_ppconst(cctx_T *cctx, ppconst_T *ppconst); void clear_ppconst(ppconst_T *ppconst); int compile_member(int is_slice, int *keeping_dict, cctx_T *cctx); +int compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type); int compile_load_scriptvar(cctx_T *cctx, char_u *name, char_u *start, char_u **end, imported_T *import); int compile_load(char_u **arg, size_t namelen, char_u *end_arg, cctx_T *cctx, int is_expr, int error); int compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, ca_special_T special_fn); diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index eb108bcb9..5875f6426 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -11904,4 +11904,65 @@ def Test_class_member_closure() v9.CheckSourceSuccess(lines) enddef +" Using a compound operator on an object variable of an object variable. +def Test_nested_object_member_op_assign() + var lines =<< trim END + vim9script + class A + public var n = 1 + public var s = 'x' + endclass + class B + var a: A = A.new() + def Add() + this.a.n += 2 + this.a.s ..= 'y' + enddef + endclass + var b = B.new() + b.Add() + assert_equal(3, b.a.n) + assert_equal('xy', b.a.s) + END + v9.CheckSourceSuccess(lines) + + # Also when the object is in a local variable. + lines =<< trim END + vim9script + class A + public var n = 1 + endclass + class B + var a: A = A.new() + endclass + def F(): number + var b = B.new() + b.a.n += 2 + return b.a.n + enddef + assert_equal(3, F()) + END + v9.CheckSourceSuccess(lines) + + # A plain assignment must use the last name, not the first one. + lines =<< trim END + vim9script + class A + public var n = 1 + public var s = 'x' + endclass + class B + var a: A = A.new() + def Set() + this.a.s = 'y' + enddef + endclass + var b = B.new() + b.Set() + assert_equal(1, b.a.n) + assert_equal('y', b.a.s) + END + v9.CheckSourceSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 2341e6991..fcb088bdb 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 */ +/**/ + 975, /**/ 974, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 2aeef4095..5f51fdf6d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2265,8 +2265,10 @@ compile_lhs_set_member_type( lhs->lhs_varlen = after - var_start; lhs->lhs_dest = dest_expr; // We don't know the type before evaluating the expression, - // use "any" until then. + // use "any" until then. The member index is for the first name, + // not for the last index. lhs->lhs_type = &t_any; + lhs->lhs_member_idx = -1; } int use_class = lhs->lhs_type != NULL @@ -2623,7 +2625,17 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx) if (lhs->lhs_has_index) { - int range = FALSE; + int range = FALSE; + type_T *type = get_type_on_stack(cctx, 0); + + // A member of an object or class is not obtained by indexing it. + if (type->tt_type == VAR_CLASS + || (type->tt_type == VAR_OBJECT && type != &t_object_any)) + { + char_u *p = var_start + lhs->lhs_varlen; + + return compile_class_object_index(cctx, &p, type); + } // Get member from list or dict. First compile the // index value. @@ -2673,7 +2685,10 @@ compile_assign_unlet( return FAIL; } - if (lhs->lhs_type == NULL || lhs->lhs_type == &t_any) + // For "expr[idx]" the index is compiled before the expression, thus the + // resulting type cannot be used here. + if (lhs->lhs_dest == dest_expr + || lhs->lhs_type == NULL || lhs->lhs_type == &t_any) { // Index on variable of unknown type: check at runtime. dest_type = VAR_ANY; diff --git a/src/vim9expr.c b/src/vim9expr.c index 7f47d82fb..87a872f58 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -347,7 +347,7 @@ inside_class_hierarchy(cctx_T *cctx_arg, class_T *cl) /* * Compile ".member" coming after an object or class. */ - static int + int compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) { int m_idx; -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wwQuk-00AkBl-VI%40256bit.org.