diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2023-09-18 19:56:49 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2023-09-18 19:56:49 +0200 |
commit | 00cd18222ee1551c65228e9556c158624507fc7a (patch) | |
tree | 2686d05c81b58786e4f0c5b7f284f9e6d9158f8b /src | |
parent | d25021cf036c63d539f845a1ee05b03ea21d61ff (diff) |
patch 9.0.1909: Vim9: problem calling class method from other classv9.0.1909
Problem: Vim9: problem calling class method from other class
Solution: Fix this problem, fix readonly object access, update error
messages.
Calling a class method from another method without the class name prefix
doesn't work properly.
A readonly object variable is modifiable outside the class using a
nested object assignment.
Remove the unused E1338 error message.
Update error messages.
closes: #13116
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/errors.h | 11 | ||||
-rw-r--r-- | src/eval.c | 8 | ||||
-rw-r--r-- | src/proto/vim9class.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_class.vim | 172 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9class.c | 37 | ||||
-rw-r--r-- | src/vim9compile.c | 85 | ||||
-rw-r--r-- | src/vim9expr.c | 9 | ||||
-rw-r--r-- | src/vim9instr.c | 10 |
9 files changed, 208 insertions, 128 deletions
diff --git a/src/errors.h b/src/errors.h index 1db70786b3..f1373a42c4 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3418,8 +3418,7 @@ EXTERN char e_internal_error_shortmess_too_long[] #ifdef FEAT_EVAL EXTERN char e_class_member_str_not_found_in_class_str[] INIT(= N_("E1337: Class member \"%s\" not found in class \"%s\"")); -EXTERN char e_interface_static_direct_access_str[] - INIT(= N_("E1338: Cannot directly access interface \"%s\" static member \"%s\"")); +// E1338 unused #endif #ifdef FEAT_PROP_POPUP EXTERN char e_cannot_add_textprop_with_text_after_using_textprop_with_negative_id[] @@ -3506,11 +3505,11 @@ EXTERN char e_object_member_str_accessible_only_using_object_str[] INIT(= N_("E1376: Object member \"%s\" accessible only using class \"%s\" object")); EXTERN char e_method_str_of_class_str_has_different_access[] INIT(= N_("E1377: Access level of method \"%s\" is different in class \"%s\"")); -EXTERN char e_static_cannot_be_used_in_interface[] - INIT(= N_("E1378: Static cannot be used in an interface")); -EXTERN char e_private_variable_str_in_interface[] +EXTERN char e_static_member_not_supported_in_interface[] + INIT(= N_("E1378: Static member not supported in an interface")); +EXTERN char e_private_variable_not_supported_in_interface[] INIT(= N_("E1379: Private variable not supported in an interface")); -EXTERN char e_private_method_str_in_interface[] +EXTERN char e_private_method_not_supported_in_interface[] INIT(= N_("E1380: Private method not supported in an interface")); EXTERN char e_interface_cannot_use_implements[] INIT(= N_("E1381: Interface cannot use \"implements\"")); diff --git a/src/eval.c b/src/eval.c index 523546957e..0f952ee3e6 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1180,14 +1180,6 @@ get_lval( return NULL; lp->ll_tv = &v->di_tv; } - if (vim9script && writing && lp->ll_tv->v_type == VAR_CLASS - && (lp->ll_tv->vval.v_class->class_flags & CLASS_INTERFACE) != 0) - { - if (!quiet) - semsg(_(e_interface_static_direct_access_str), - lp->ll_tv->vval.v_class->class_name, lp->ll_name); - return NULL; - } if (vim9script && (flags & GLV_NO_DECL) == 0) { diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro index 1448f19159..d09f654570 100644 --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -1,7 +1,7 @@ /* vim9class.c */ int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl, int is_static); void ex_class(exarg_T *eap); -type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx, ocmember_T **m); +type_T *class_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx); void ex_enum(exarg_T *eap); void ex_type(exarg_T *eap); int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose); diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index 5e3b945591..fa621b25ac 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -4,12 +4,14 @@ source check.vim import './vim9.vim' as v9 def Test_class_basic() + # Class supported only in "vim9script" var lines =<< trim END class NotWorking endclass END v9.CheckSourceFailure(lines, 'E1316:') + # First character in a class name should be capitalized. lines =<< trim END vim9script class notWorking @@ -17,6 +19,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1314:') + # Only alphanumeric characters are supported in a class name lines =<< trim END vim9script class Not@working @@ -24,6 +27,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1315:') + # Unsupported keyword (instead of class) lines =<< trim END vim9script abstract noclass Something @@ -31,6 +35,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E475:') + # Only the completed word "class" should be recognized lines =<< trim END vim9script abstract classy Something @@ -38,6 +43,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E475:') + # The complete "endclass" should be specified. lines =<< trim END vim9script class Something @@ -45,6 +51,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1065:') + # Additional words after "endclass" lines =<< trim END vim9script class Something @@ -52,6 +59,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E488:') + # Additional commands after "endclass" lines =<< trim END vim9script class Something @@ -59,6 +67,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E488:') + # Use "this" without any member variable name lines =<< trim END vim9script class Something @@ -67,6 +76,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1317:') + # Use "this." without any member variable name lines =<< trim END vim9script class Something @@ -75,6 +85,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1317:') + # Space between "this" and ".<variable>" lines =<< trim END vim9script class Something @@ -83,6 +94,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1317:') + # Space between "this." and the member variable name lines =<< trim END vim9script class Something @@ -91,6 +103,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1317:') + # Use "that" instead of "this" lines =<< trim END vim9script class Something @@ -100,6 +113,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1318: Not a valid command in a class: that.count') + # Member variable without a type or initialization lines =<< trim END vim9script class Something @@ -108,6 +122,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1022:') + # Use a non-existing member variable in new() lines =<< trim END vim9script class Something @@ -117,8 +132,9 @@ def Test_class_basic() endclass var obj = Something.new() END - v9.CheckSourceFailure(lines, 'E1089:') + v9.CheckSourceFailure(lines, 'E1326: Member not found on object "Something": state') + # Space before ":" in a member variable declaration lines =<< trim END vim9script class Something @@ -127,6 +143,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1059:') + # No space after ":" in a member variable declaration lines =<< trim END vim9script class Something @@ -204,6 +221,8 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E1324: Using an object as a String') + # Test creating a class with member variables and methods, calling a object + # method. Check for using type() and typename() with a class and an object. lines =<< trim END vim9script @@ -270,6 +289,7 @@ def Test_class_basic() END v9.CheckSourceFailure(lines, 'E15:') + # Use a multi-line initialization for a member variable lines =<< trim END vim9script class A @@ -347,6 +367,7 @@ def Test_class_interface_wrong_end() enddef def Test_object_not_set() + # Use an uninitialized object in script context var lines =<< trim END vim9script @@ -360,6 +381,7 @@ def Test_object_not_set() END v9.CheckSourceFailure(lines, 'E1360:') + # Use an uninitialized object from a def function lines =<< trim END vim9script @@ -378,6 +400,8 @@ def Test_object_not_set() END v9.CheckSourceFailure(lines, 'E1360:') + # Pass an uninitialized object variable to a "new" function and try to call an + # object method. lines =<< trim END vim9script @@ -418,6 +442,7 @@ def Test_object_not_set() v9.CheckSourceFailure(lines, 'E1363:') enddef +" Null object assignment and comparison def Test_null_object_assign_compare() var lines =<< trim END vim9script @@ -458,6 +483,7 @@ def Test_null_object_assign_compare() v9.CheckSourceSuccess(lines) enddef +" Test for object member initialization and disassembly def Test_class_member_initializer() var lines =<< trim END vim9script @@ -517,32 +543,6 @@ def Test_member_any_used_as_object() END v9.CheckSourceSuccess(lines) - lines =<< trim END - vim9script - - class Inner - this.value: number = 0 - endclass - - class Outer - this.inner: Inner - endclass - - def F(outer: Outer) - outer.inner.value = 1 - enddef - - def Test_assign_to_nested_typed_member() - var inner = Inner.new(0) - var outer = Outer.new(inner) - F(outer) - assert_equal(1, inner.value) - enddef - - Test_assign_to_nested_typed_member() - END - v9.CheckSourceSuccess(lines) - # Try modifying a private variable using an "any" object lines =<< trim END vim9script @@ -588,7 +588,37 @@ def Test_member_any_used_as_object() v9.CheckSourceFailure(lines, 'E1326: Member not found on object "Inner": someval') enddef +" Nested assignment to a object variable which is of another class type +def Test_assignment_nested_type() + var lines =<< trim END + vim9script + + class Inner + public this.value: number = 0 + endclass + + class Outer + this.inner: Inner + endclass + + def F(outer: Outer) + outer.inner.value = 1 + enddef + + def Test_assign_to_nested_typed_member() + var inner = Inner.new(0) + var outer = Outer.new(inner) + F(outer) + assert_equal(1, inner.value) + enddef + + Test_assign_to_nested_typed_member() + END + v9.CheckSourceSuccess(lines) +enddef + def Test_assignment_with_operator() + # Use "+=" to assign to a object variable var lines =<< trim END vim9script @@ -762,7 +792,6 @@ def Test_class_default_new() v9.CheckSourceFailure(lines, "E1328: Constructor default value must be v:none: = 'a'") enddef - def Test_class_new_with_object_member() var lines =<< trim END vim9script @@ -1677,7 +1706,7 @@ func Test_interface_garbagecollect() call v9.CheckSourceSuccess(lines) endfunc -def Test_class_function() +def Test_class_method() var lines =<< trim END vim9script class Value @@ -1713,6 +1742,29 @@ def Test_class_function() endclass END v9.CheckSourceFailure(lines, 'E1318:') + + # Test for calling a class method from another class method without the class + # name prefix. + lines =<< trim END + vim9script + class A + static myList: list<number> = [1] + static def Foo(n: number) + myList->add(n) + enddef + static def Bar() + Foo(2) + enddef + def Baz() + Foo(3) + enddef + endclass + A.Bar() + var a = A.new() + a.Baz() + assert_equal([1, 2, 3], A.myList) + END + v9.CheckSourceSuccess(lines) enddef def Test_class_defcompile() @@ -2343,7 +2395,6 @@ def Test_call_interface_method() END v9.CheckSourceSuccess(lines) - # No class that implements the interface. lines =<< trim END vim9script @@ -2685,7 +2736,6 @@ def Test_using_base_class() v9.CheckSourceSuccess(lines) enddef - def Test_class_import() var lines =<< trim END vim9script @@ -3651,7 +3701,7 @@ def Test_private_class_method() return 1234 enddef def Bar() - assert_equal(1234, A._Foo()) + assert_equal(1234, _Foo()) enddef endclass var a = A.new() @@ -3659,7 +3709,8 @@ def Test_private_class_method() END v9.CheckSourceSuccess(lines) - # Use a class private method from another class private method + # Use a class private method from another class private method without the + # class name prefix. lines =<< trim END vim9script @@ -3668,10 +3719,10 @@ def Test_private_class_method() return 1234 enddef static def _Foo2() - assert_equal(1234, A._Foo1()) + assert_equal(1234, _Foo1()) enddef def Bar() - A._Foo2() + _Foo2() enddef endclass var a = A.new() @@ -4063,7 +4114,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckSourceFailure(lines, 'E1089: Unknown variable: _a') + v9.CheckSourceFailure(lines, 'E1326: Member not found on object "A": _a') # private static member variable lines =<< trim END @@ -4091,7 +4142,7 @@ def Test_private_member_access_outside_class() enddef T() END - v9.CheckSourceFailure(lines, 'E1374: Class member "_val" accessible only inside class "A"') + v9.CheckSourceFailure(lines, 'E1375: Class member "_val" accessible only using class "A"') # private static class variable lines =<< trim END @@ -4265,7 +4316,7 @@ def Test_class_variable_access_using_object() enddef T() END - v9.CheckSourceFailure(lines, 'E1374: Class member "svar2" accessible only inside class "A"') + v9.CheckSourceFailure(lines, 'E1375: Class member "svar2" accessible only using class "A"') enddef " Test for using a interface method using a child object @@ -4711,7 +4762,7 @@ def Test_class_variable() enddef T() END - v9.CheckSourceFailure(lines, 'E1374: Class member "val" accessible only inside class "A"') + v9.CheckSourceFailure(lines, 'E1375: Class member "val" accessible only using class "A"') # Reading a class variable using an object at function level lines =<< trim END @@ -4977,7 +5028,7 @@ def Test_interface_with_unsupported_members() static num: number endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -4985,7 +5036,7 @@ def Test_interface_with_unsupported_members() static _num: number endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -4993,7 +5044,7 @@ def Test_interface_with_unsupported_members() public static num: number endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -5001,7 +5052,7 @@ def Test_interface_with_unsupported_members() public static _num: number endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -5009,7 +5060,7 @@ def Test_interface_with_unsupported_members() static def Foo(d: dict<any>): list<string> endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -5017,7 +5068,7 @@ def Test_interface_with_unsupported_members() static def _Foo(d: dict<any>): list<string> endinterface END - v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface') + v9.CheckSourceFailure(lines, 'E1378: Static member not supported in an interface') lines =<< trim END vim9script @@ -5402,4 +5453,35 @@ def Test_implements_using_var_type_any() v9.CheckSourceFailure(lines, 'E1382: Member "val": type mismatch, expected list<dict<string>> but got dict<number>') enddef +" Test for assigning to a member variable in a nested class +def Test_nested_object_assignment() + var lines =<< trim END + vim9script + + class A + this.value: number + endclass + + class B + this.a: A = A.new() + endclass + + class C + this.b: B = B.new() + endclass + + class D + this.c: C = C.new() + endclass + + def T(da: D) + da.c.b.a.value = 10 + enddef + + var d = D.new() + T(d) + END + v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "value"') +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 18c12fae5f..7670cddde6 100644 --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1909, +/**/ 1908, /**/ 1907, diff --git a/src/vim9class.c b/src/vim9class.c index 394589b02b..da862f2667 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -1592,7 +1592,7 @@ early_ret: if (!is_class) { - emsg(_(e_static_cannot_be_used_in_interface)); + emsg(_(e_static_member_not_supported_in_interface)); break; } has_static = TRUE; @@ -1623,7 +1623,8 @@ early_ret: if (!is_class && *varname == '_') { // private variables are not supported in an interface - semsg(_(e_private_variable_str_in_interface), varname); + semsg(_(e_private_variable_not_supported_in_interface), + varname); break; } @@ -1689,7 +1690,8 @@ early_ret: if (!is_class && *name == '_') { // private variables are not supported in an interface - semsg(_(e_private_method_str_in_interface), name); + semsg(_(e_private_method_not_supported_in_interface), + name); func_clear_free(uf, FALSE); break; } @@ -2010,8 +2012,7 @@ class_member_type( int is_object, char_u *name, char_u *name_end, - int *member_idx, - ocmember_T **p_m) + int *member_idx) { size_t len = name_end - name; ocmember_T *m; @@ -2022,27 +2023,11 @@ class_member_type( member_idx); if (m == NULL) { - char_u *varname = vim_strnsave(name, len); - if (varname != NULL) - { - if (is_object && class_member_idx(cl, name, len) >= 0) - // A class variable with this name is present - semsg(_(e_class_member_str_accessible_only_inside_class_str), - varname, cl->class_name); - else if (!is_object && object_member_idx(cl, name, len) >= 0) - // An instance variable with this name is present - semsg(_(e_object_member_str_accessible_only_using_object_str), - varname, cl->class_name); - else - semsg(_(e_unknown_variable_str), varname); - } - vim_free(varname); + member_not_found_msg(cl, is_object ? VAR_OBJECT : VAR_CLASS, name, + len); return &t_any; } - if (p_m != NULL) - *p_m = m; - return m->ocm_type; } @@ -2250,12 +2235,6 @@ class_object_index( semsg(_(e_cannot_access_private_member_str), m->ocm_name); return FAIL; } - if ((cl->class_flags & CLASS_INTERFACE) != 0) - { - semsg(_(e_interface_static_direct_access_str), - cl->class_name, m->ocm_name); - return FAIL; - } typval_T *tv = &cl->class_members_tv[m_idx]; copy_tv(tv, rettv); diff --git a/src/vim9compile.c b/src/vim9compile.c index 7de1b6253e..ab063f9ff2 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1579,6 +1579,47 @@ is_decl_command(cmdidx_T cmdidx) } /* + * Returns TRUE if the class or object variable in "lhs" is modifiable. + * "var_start" points to the start of the variable name and "lhs->lhs_varlen" + * has the total length. Note that the "lhs" can be nested an object reference + * (e.g. a.b.c.d.var). + */ + static int +lhs_class_member_modifiable(lhs_T *lhs, char_u *var_start, cctx_T *cctx) +{ + size_t varlen = lhs->lhs_varlen; + class_T *cl = lhs->lhs_type->tt_class; + int is_object = lhs->lhs_type->tt_type == VAR_OBJECT; + char_u *name = var_start + varlen + 1; + size_t namelen = lhs->lhs_end - var_start - varlen - 1; + ocmember_T *m; + + m = member_lookup(cl, lhs->lhs_type->tt_type, name, namelen, NULL); + if (m == NULL) + { + member_not_found_msg(cl, lhs->lhs_type->tt_type, name, namelen); + return FALSE; + } + + // If it is private member variable, then accessing it outside the + // class is not allowed. + // If it is a read only class variable, then it can be modified + // only inside the class where it is defined. + if ((m->ocm_access != VIM_ACCESS_ALL) && + ((is_object && !inside_class(cctx, cl)) + || (!is_object && cctx->ctx_ufunc->uf_class != cl))) + { + char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE) + ? e_cannot_access_private_member_str + : e_cannot_change_readonly_variable_str; + semsg(_(msg), m->ocm_name); + return FALSE; + } + + return TRUE; +} + +/* * Figure out the LHS type and other properties for an assignment or one item * of ":unlet" with an index. * Returns OK or FAIL. @@ -1691,9 +1732,9 @@ compile_lhs( { if (is_decl) { - // if we come here with what looks like an assignment like .= - // but which has been reject by assignment_len() from may_compile_assignment - // give a better error message + // if we come here with what looks like an assignment like + // .= but which has been reject by assignment_len() from + // may_compile_assignment give a better error message char_u *p = skipwhite(lhs->lhs_end); if (p[0] == '.' && p[1] == '=') emsg(_(e_dot_equal_not_supported_with_script_version_two)); @@ -1959,36 +2000,17 @@ compile_lhs( { // for an object or class member get the type of the member class_T *cl = lhs->lhs_type->tt_class; - ocmember_T *m; int is_object = lhs->lhs_type->tt_type == VAR_OBJECT; + if (!lhs_class_member_modifiable(lhs, var_start, cctx)) + return FAIL; + lhs->lhs_member_type = class_member_type(cl, is_object, after + 1, lhs->lhs_end, - &lhs->lhs_member_idx, &m); + &lhs->lhs_member_idx); if (lhs->lhs_member_idx < 0) return FAIL; - if ((cl->class_flags & CLASS_INTERFACE) != 0 - && lhs->lhs_type->tt_type == VAR_CLASS) - { - semsg(_(e_interface_static_direct_access_str), - cl->class_name, m->ocm_name); - return FAIL; - } - // If it is private member variable, then accessing it outside the - // class is not allowed. - // If it is a read only class variable, then it can be modified - // only inside the class where it is defined. - if ((m->ocm_access != VIM_ACCESS_ALL) && - ((is_object && !inside_class(cctx, cl)) - || (!is_object && cctx->ctx_ufunc->uf_class != cl))) - { - char *msg = (m->ocm_access == VIM_ACCESS_PRIVATE) - ? e_cannot_access_private_member_str - : e_cannot_change_readonly_variable_str; - semsg(_(msg), m->ocm_name); - return FAIL; - } } else { @@ -2163,6 +2185,14 @@ compile_load_lhs( lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void : get_type_on_stack(cctx, 0); + + if (lhs->lhs_type->tt_type == VAR_OBJECT) + { + // Check whether the object variable is modifiable + if (!lhs_class_member_modifiable(lhs, var_start, cctx)) + return FAIL; + } + // Now we can properly check the type. The variable is indexed, thus // we need the member type. For a class or object we don't know the // type yet, it depends on what member is used. @@ -2198,8 +2228,7 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx) class_T *cl = lhs->lhs_type->tt_class; type_T *type = class_member_type(cl, TRUE, dot + 1, - lhs->lhs_end, &lhs->lhs_member_idx, - NULL); + lhs->lhs_end, &lhs->lhs_member_idx); if (lhs->lhs_member_idx < 0) return FAIL; diff --git a/src/vim9expr.c b/src/vim9expr.c index a158f31ae7..bcad79ca17 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -439,12 +439,6 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type) if (m != NULL) { // Note: type->tt_type = VAR_CLASS - if ((cl->class_flags & CLASS_INTERFACE) != 0) - { - semsg(_(e_interface_static_direct_access_str), - cl->class_name, m->ocm_name); - return FAIL; - } // A private class variable can be accessed only in the class where // it is defined. if (*name == '_' && cctx->ctx_ufunc->uf_class != cl) @@ -1152,9 +1146,6 @@ compile_call( // the class where the function is defined. if (cctx->ctx_ufunc->uf_defclass == cl) { - // The generate_CALL() function expects the class type at the - // top of the stack. So push the class type to the stack. - push_type_stack(cctx, &t_class); res = generate_CALL(cctx, cl->class_class_functions[mi], NULL, 0, type, argcount); } diff --git a/src/vim9instr.c b/src/vim9instr.c index ccec0bcc38..b9bbfd09bd 100644 --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -1899,9 +1899,15 @@ generate_CALL( // drop the argument types cctx->ctx_type_stack.ga_len -= argcount; - // For an object or class method call, drop the object/class type + // For an object or class method call, drop the object/class type. if (ufunc->uf_class != NULL) - cctx->ctx_type_stack.ga_len--; + { + // When a class method is called without the class name prefix, then + // the type will not be in the stack. + type_T *stype = get_type_on_stack(cctx, 0); + if (stype->tt_type == VAR_CLASS || stype->tt_type == VAR_OBJECT) + cctx->ctx_type_stack.ga_len--; + } // add return type return push_type_stack(cctx, ufunc->uf_ret_type); |