mirror of
https://github.com/vim/vim.git
synced 2025-09-27 04:14:06 -04:00
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 <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
committed by
Christian Brabandt
parent
23c92d93c1
commit
342f4f626e
@@ -7,6 +7,7 @@ void ex_type(exarg_T *eap);
|
|||||||
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
|
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
|
||||||
ufunc_T *find_class_func(char_u **arg);
|
ufunc_T *find_class_func(char_u **arg);
|
||||||
int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
|
int class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
|
||||||
|
int class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx);
|
||||||
int inside_class(cctx_T *cctx_arg, class_T *cl);
|
int inside_class(cctx_T *cctx_arg, class_T *cl);
|
||||||
void copy_object(typval_T *from, typval_T *to);
|
void copy_object(typval_T *from, typval_T *to);
|
||||||
void object_unref(object_T *obj);
|
void object_unref(object_T *obj);
|
||||||
|
@@ -4248,8 +4248,6 @@ def Test_private_member_access_outside_class()
|
|||||||
T()
|
T()
|
||||||
END
|
END
|
||||||
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
|
v9.CheckScriptFailure(lines, 'E1333: Cannot access private member: _val')
|
||||||
|
|
||||||
|
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
" Test for changing the member access of an interface in a implementation class
|
" Test for changing the member access of an interface in a implementation class
|
||||||
@@ -4613,4 +4611,65 @@ def Test_abstract_method()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for calling a class method using an object in a def function context and
|
||||||
|
" script context.
|
||||||
|
def Test_class_method_call_using_object()
|
||||||
|
# script context
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static def Foo(): list<string>
|
||||||
|
return ['a', 'b']
|
||||||
|
enddef
|
||||||
|
def Bar()
|
||||||
|
assert_equal(['a', 'b'], A.Foo())
|
||||||
|
assert_equal(['a', 'b'], Foo())
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
def T()
|
||||||
|
assert_equal(['a', 'b'], A.Foo())
|
||||||
|
var t_a = A.new()
|
||||||
|
t_a.Bar()
|
||||||
|
enddef
|
||||||
|
|
||||||
|
assert_equal(['a', 'b'], A.Foo())
|
||||||
|
var a = A.new()
|
||||||
|
a.Bar()
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
# script context
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static def Foo(): string
|
||||||
|
return 'foo'
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var a = A.new()
|
||||||
|
assert_equal('foo', a.Foo())
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()')
|
||||||
|
|
||||||
|
# def function context
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class A
|
||||||
|
static def Foo(): string
|
||||||
|
return 'foo'
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
def T()
|
||||||
|
var a = A.new()
|
||||||
|
assert_equal('foo', a.Foo())
|
||||||
|
enddef
|
||||||
|
T()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1325: Method not found on class "A": Foo()')
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -699,6 +699,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1888,
|
||||||
/**/
|
/**/
|
||||||
1887,
|
1887,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2090,6 +2090,33 @@ class_member_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If "name[len]" is a class method in cctx->ctx_ufunc->uf_class return the
|
||||||
|
* index in class.class_class_functions[].
|
||||||
|
* If "cl_ret" is not NULL set it to the class.
|
||||||
|
* Otherwise return -1.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
class_method_index(char_u *name, size_t len, class_T **cl_ret, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||||
|
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||||
|
return -1;
|
||||||
|
class_T *cl = cctx->ctx_ufunc->uf_class;
|
||||||
|
|
||||||
|
for (int i = 0; i < cl->class_class_function_count; ++i)
|
||||||
|
{
|
||||||
|
ufunc_T *fp = cl->class_class_functions[i];
|
||||||
|
if (STRNCMP(name, fp->uf_name, len) == 0 && fp->uf_name[len] == NUL)
|
||||||
|
{
|
||||||
|
if (cl_ret != NULL)
|
||||||
|
*cl_ret = cl;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE if current context "cctx_arg" is inside class "cl".
|
* Return TRUE if current context "cctx_arg" is inside class "cl".
|
||||||
* Return FALSE if not.
|
* Return FALSE if not.
|
||||||
|
@@ -775,6 +775,8 @@ compile_load(
|
|||||||
}
|
}
|
||||||
else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0)
|
else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0)
|
||||||
{
|
{
|
||||||
|
// Referencing a class member without the class name. Infer
|
||||||
|
// the class from the def function context.
|
||||||
res = generate_CLASSMEMBER(cctx, TRUE, cl, idx);
|
res = generate_CLASSMEMBER(cctx, TRUE, cl, idx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1118,6 +1120,9 @@ compile_call(
|
|||||||
if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
|
if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
|
||||||
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
|
&& arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
|
||||||
{
|
{
|
||||||
|
class_T *cl = NULL;
|
||||||
|
int mi = 0;
|
||||||
|
|
||||||
// If we can find the function by name generate the right call.
|
// If we can find the function by name generate the right call.
|
||||||
// Skip global functions here, a local funcref takes precedence.
|
// Skip global functions here, a local funcref takes precedence.
|
||||||
ufunc = find_func(name, FALSE);
|
ufunc = find_func(name, FALSE);
|
||||||
@@ -1136,6 +1141,16 @@ compile_call(
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((mi = class_method_index(name, varlen, &cl, cctx)) >= 0)
|
||||||
|
{
|
||||||
|
// Class method invocation without the class name. 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);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the name is a variable, load it and use PCALL.
|
// If the name is a variable, load it and use PCALL.
|
||||||
|
Reference in New Issue
Block a user