Skip to content

Commit 342f4f6

Browse files
yegappanchrisbra
authored andcommitted
patch 9.0.1888: Vim9: Problem trying to invoke class method
Problem: Vim9: Problem trying to invoke class method Solution: Lookup the class method insider other classes closes: #13055 Signed-off-by: Christian Brabandt <[email protected]> Co-authored-by: Yegappan Lakshmanan <[email protected]>
1 parent 23c92d9 commit 342f4f6

5 files changed

Lines changed: 106 additions & 2 deletions

File tree

src/proto/vim9class.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ void ex_type(exarg_T *eap);
77
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
88
ufunc_T *find_class_func(char_u **arg);
99
int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
10+
int class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
1011
int inside_class(cctx_T *cctx_arg, class_T *cl);
1112
void copy_object(typval_T *from, typval_T *to);
1213
void object_unref(object_T *obj);

src/testdir/test_vim9_class.vim

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4248,8 +4248,6 @@ def Test_private_member_access_outside_class()
42484248
T()
42494249
END
42504250
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
4251-
4252-
42534251
enddef
42544252

42554253
" Test for changing the member access of an interface in a implementation class
@@ -4613,4 +4611,65 @@ def Test_abstract_method()
46134611
v9.CheckScriptSuccess(lines)
46144612
enddef
46154613

4614+
" Test for calling a class method using an object in a def function context and
4615+
" script context.
4616+
def Test_class_method_call_using_object()
4617+
# script context
4618+
var lines =<< trim END
4619+
vim9script
4620+
class A
4621+
static def Foo(): list<string>
4622+
return ['a', 'b']
4623+
enddef
4624+
def Bar()
4625+
assert_equal(['a', 'b'], A.Foo())
4626+
assert_equal(['a', 'b'], Foo())
4627+
enddef
4628+
endclass
4629+
4630+
def T()
4631+
assert_equal(['a', 'b'], A.Foo())
4632+
var t_a = A.new()
4633+
t_a.Bar()
4634+
enddef
4635+
4636+
assert_equal(['a', 'b'], A.Foo())
4637+
var a = A.new()
4638+
a.Bar()
4639+
T()
4640+
END
4641+
v9.CheckScriptSuccess(lines)
4642+
4643+
# script context
4644+
lines =<< trim END
4645+
vim9script
4646+
class A
4647+
static def Foo(): string
4648+
return 'foo'
4649+
enddef
4650+
endclass
4651+
4652+
var a = A.new()
4653+
assert_equal('foo', a.Foo())
4654+
END
4655+
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()')
4656+
4657+
# def function context
4658+
lines =<< trim END
4659+
vim9script
4660+
class A
4661+
static def Foo(): string
4662+
return 'foo'
4663+
enddef
4664+
endclass
4665+
4666+
def T()
4667+
var a = A.new()
4668+
assert_equal('foo', a.Foo())
4669+
enddef
4670+
T()
4671+
END
4672+
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()')
4673+
enddef
4674+
46164675
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
1888,
702704
/**/
703705
1887,
704706
/**/

src/vim9class.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,33 @@ class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
20902090
return -1;
20912091
}
20922092

2093+
/*
2094+
* If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the
2095+
* index in class.class_class_functions[].
2096+
* If "cl_ret" is not NULL set it to the class.
2097+
* Otherwise return -1.
2098+
*/
2099+
int
2100+
class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
2101+
{
2102+
if (cctx == NULL || cctx->ctx_ufunc == NULL
2103+
|| cctx->ctx_ufunc->uf_class == NULL)
2104+
return -1;
2105+
class_T *cl = cctx->ctx_ufunc->uf_class;
2106+
2107+
for (int i = 0; i < cl->class_class_function_count; ++i)
2108+
{
2109+
ufunc_T *fp = cl->class_class_functions[i];
2110+
if (STRNCMP(name, fp->uf_name, len) == 0 && fp->uf_name[len] == NUL)
2111+
{
2112+
if (cl_ret != NULL)
2113+
*cl_ret = cl;
2114+
return i;
2115+
}
2116+
}
2117+
return -1;
2118+
}
2119+
20932120
/*
20942121
* Return TRUE if current context "cctx_arg" is inside class "cl".
20952122
* Return FALSE if not.

src/vim9expr.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,8 @@ compile_load(
775775
}
776776
else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0)
777777
{
778+
// Referencing a class member without the class name. Infer
779+
// the class from the def function context.
778780
res = generate_CLASSMEMBER(cctx, TRUE, cl, idx);
779781
}
780782
else
@@ -1118,6 +1120,9 @@ compile_call(
11181120
if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
11191121
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
11201122
{
1123+
class_T *cl = NULL;
1124+
int mi = 0;
1125+
11211126
// If we can find the function by name generate the right call.
11221127
// Skip global functions here, a local funcref takes precedence.
11231128
ufunc = find_func(name, FALSE);
@@ -1136,6 +1141,16 @@ compile_call(
11361141
goto theend;
11371142
}
11381143
}
1144+
else if ((mi = class_method_index(name, varlen, &cl, cctx)) >= 0)
1145+
{
1146+
// Class method invocation without the class name. The
1147+
// generate_CALL() function expects the class type at the top of
1148+
// the stack. So push the class type to the stack.
1149+
push_type_stack(cctx, &t_class);
1150+
res = generate_CALL(cctx, cl->class_class_functions[mi], NULL, 0,
1151+
type, argcount);
1152+
goto theend;
1153+
}
11391154
}
11401155

11411156
// If the name is a variable, load it and use PCALL.

0 commit comments

Comments
 (0)