patch 9.1.0850: Vim9: cannot access nested object inside objects
Problem: Vim9: cannot access nested object inside objects
(lifepillar, 91khr, mawkish)
Solution: Add support for accessing an object member using a "any"
variable type (Yegappan Lakshmanan)
fixes: #11822
fixes: #12024
fixes: #12196
fixes: #12198
closes: #16029
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/vim9class.c b/src/vim9class.c
index 87b4d45..d0ddcb8 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -2777,12 +2777,13 @@
* "rettv". If "is_object" is TRUE, then the object member variable table is
* searched. Otherwise the class member variable table is searched.
*/
- static int
+ int
get_member_tv(
class_T *cl,
int is_object,
char_u *name,
size_t namelen,
+ class_T *current_class,
typval_T *rettv)
{
ocmember_T *m;
@@ -2793,7 +2794,8 @@
if (m == NULL)
return FAIL;
- if (*name == '_')
+ if (*name == '_' && (current_class == NULL ||
+ !class_instance_of(current_class, cl)))
{
emsg_var_cl_define(e_cannot_access_protected_variable_str,
m->ocm_name, 0, cl);
@@ -2873,7 +2875,7 @@
if (ocm == NULL && *fp->uf_name == '_')
{
- // Cannot access a private method outside of a class
+ // Cannot access a protected method outside of a class
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
return FAIL;
}
@@ -2917,6 +2919,33 @@
}
/*
+ * Create a partial typval for "obj.obj_method" and store it in "rettv".
+ * Returns OK on success and FAIL on memory allocation failure.
+ */
+ int
+obj_method_to_partial_tv(object_T *obj, ufunc_T *obj_method, typval_T *rettv)
+{
+ partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
+ if (pt == NULL)
+ return FAIL;
+
+ pt->pt_refcount = 1;
+ if (obj != NULL)
+ {
+ pt->pt_obj = obj;
+ ++pt->pt_obj->obj_refcount;
+ }
+ pt->pt_auto = TRUE;
+ pt->pt_func = obj_method;
+ func_ptr_ref(pt->pt_func);
+
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+
+ return OK;
+}
+
+/*
* Evaluate what comes after a class:
* - class member: SomeClass.varname
* - class function: SomeClass.SomeMethod()
@@ -2978,7 +3007,7 @@
// Search in the object member variable table and the class member
// variable table.
int is_object = rettv->v_type == VAR_OBJECT;
- if (get_member_tv(cl, is_object, name, len, rettv) == OK)
+ if (get_member_tv(cl, is_object, name, len, NULL, rettv) == OK)
{
*arg = name_end;
return OK;
@@ -2989,28 +3018,17 @@
ufunc_T *fp = method_lookup(cl, rettv->v_type, name, len, &fidx);
if (fp != NULL)
{
- // Private methods are not accessible outside the class
+ // Protected methods are not accessible outside the class
if (*name == '_')
{
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
return FAIL;
}
- partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
- if (pt == NULL)
+ if (obj_method_to_partial_tv(is_object ? rettv->vval.v_object :
+ NULL, fp, rettv) == FAIL)
return FAIL;
- pt->pt_refcount = 1;
- if (is_object)
- {
- pt->pt_obj = rettv->vval.v_object;
- ++pt->pt_obj->obj_refcount;
- }
- pt->pt_auto = TRUE;
- pt->pt_func = fp;
- func_ptr_ref(pt->pt_func);
- rettv->v_type = VAR_PARTIAL;
- rettv->vval.v_partial = pt;
*arg = name_end;
return OK;
}