Patch 9.0.1127
Problem: No error if function argument shadows class member.
Solution: Give an error for shadowing a class member.
Files: src/vim9expr.c, src/vim9class.c, src/proto/
vim9class.pro,
src/vim9compile.c, src/testdir/test_vim9_class.vim
*** ../vim-9.0.1126/src/vim9expr.c 2023-01-01 12:58:29.474417546 +0000
--- src/vim9expr.c 2023-01-01 18:59:31.950852320 +0000
***************
*** 603,609 ****
else
gen_load = TRUE;
}
! else if (class_member_exists(name, &cl, &idx, cctx))
{
res = generate_CLASSMEMBER(cctx, TRUE, cl, idx);
}
--- 603,609 ----
else
gen_load = TRUE;
}
! else if ((idx = class_member_index(*arg, len, &cl, cctx)) >= 0)
{
res = generate_CLASSMEMBER(cctx, TRUE, cl, idx);
}
*** ../vim-9.0.1126/src/vim9class.c 2023-01-01 14:11:23.358483466 +0000
--- src/vim9class.c 2023-01-01 19:17:18.623906933 +0000
***************
*** 358,374 ****
ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE);
ga_clear_strings(&lines_to_free);
! // TODO: how about errors?
! int is_new = STRNCMP(uf->uf_name, "new", 3) == 0;
! garray_T *fgap = has_static || is_new
! ? &classfunctions : &objmethods;
! if (uf != NULL && ga_grow(fgap, 1) == OK)
{
! if (is_new)
! uf->uf_flags |= FC_NEW;
! ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
! ++fgap->ga_len;
}
}
--- 358,376 ----
ufunc_T *uf = define_function(&ea, NULL, &lines_to_free, TRUE);
ga_clear_strings(&lines_to_free);
! if (uf != NULL)
{
! int is_new = STRNCMP(uf->uf_name, "new", 3) == 0;
! garray_T *fgap = has_static || is_new
! ? &classfunctions : &objmethods;
! if (ga_grow(fgap, 1) == OK)
! {
! if (is_new)
! uf->uf_flags |= FC_NEW;
! ((ufunc_T **)fgap->ga_data)[fgap->ga_len] = uf;
! ++fgap->ga_len;
! }
}
}
***************
*** 863,894 ****
}
/*
! * If "cctx->ctx_ufunc" indicates we are in a class, check if "name" is a class
! * member. If it is then return TRUE and set "cl_ret" and "idx_ret".
*/
int
! class_member_exists(
! char_u *name,
! class_T **cl_ret,
! int *idx_ret,
! cctx_T *cctx)
{
! if (cctx->ctx_ufunc == NULL || cctx->ctx_ufunc->uf_class == NULL)
! return FALSE;
class_T *cl = cctx->ctx_ufunc->uf_class;
! for (int idx = 0; idx < cl->class_class_member_count; ++idx)
{
! ocmember_T *m = &cl->class_class_members[idx];
! if (STRCMP(m->ocm_name, name) == 0)
{
! *cl_ret = cl;
! *idx_ret = idx;
! return TRUE;
}
}
!
! return FALSE;
}
/*
--- 865,894 ----
}
/*
! * If "name[len]" is a class member in cctx->ctx_ufunc->uf_class return the
! * index in class.class_class_members[].
! * If "cl_ret" is not NULL set it to the class.
! * Otherwise return -1;
*/
int
! class_member_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_member_count; ++i)
{
! ocmember_T *m = &cl->class_class_members[i];
! if (STRNCMP(name, m->ocm_name, len) == 0 && m->ocm_name[len] == NUL)
{
! if (cl_ret != NULL)
! *cl_ret = cl;
! return i;
}
}
! return -1;
}
/*
*** ../vim-9.0.1126/src/proto/
vim9class.pro 2023-01-01 12:58:29.470417543 +0000
--- src/proto/
vim9class.pro 2023-01-01 19:05:25.757452321 +0000
***************
*** 6,12 ****
void ex_type(exarg_T *eap);
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
ufunc_T *find_class_func(char_u **arg);
! int class_member_exists(char_u *name, class_T **cl_ret, int *idx_ret, cctx_T *cctx);
void copy_object(typval_T *from, typval_T *to);
void object_unref(object_T *obj);
void copy_class(typval_T *from, typval_T *to);
--- 6,12 ----
void ex_type(exarg_T *eap);
int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
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);
void copy_object(typval_T *from, typval_T *to);
void object_unref(object_T *obj);
void copy_class(typval_T *from, typval_T *to);
*** ../vim-9.0.1126/src/vim9compile.c 2022-12-29 20:56:20.021538298 +0000
--- src/vim9compile.c 2023-01-01 19:48:15.002633479 +0000
***************
*** 302,329 ****
}
/*
- * If "name" is a class member in cctx->ctx_ufunc->uf_class return the index in
- * class.class_class_members[].
- * Otherwise return -1;
- */
- static int
- class_member_index(char_u *name, size_t len, 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_member_count; ++i)
- {
- ocmember_T *m = &cl->class_class_members[i];
- if (STRNCMP(name, m->ocm_name, len) == 0
- && m->ocm_name[len] == NUL)
- return i;
- }
- return -1;
- }
-
- /*
* Return TRUE if "name" is a local variable, argument, script variable or
* imported.
*/
--- 302,307 ----
***************
*** 338,344 ****
&& (cctx->ctx_ufunc->uf_flags & FC_OBJECT)
&& STRNCMP(name, "this", 4) == 0)))
|| script_var_exists(name, len, cctx, NULL) == OK
! || class_member_index(name, len, cctx) >= 0
|| find_imported(name, len, FALSE) != NULL;
}
--- 316,322 ----
&& (cctx->ctx_ufunc->uf_flags & FC_OBJECT)
&& STRNCMP(name, "this", 4) == 0)))
|| script_var_exists(name, len, cctx, NULL) == OK
! || class_member_index(name, len, NULL, cctx) >= 0
|| find_imported(name, len, FALSE) != NULL;
}
***************
*** 376,384 ****
if (len == 1 && *p == '_')
return OK;
- if (class_member_index(p, len, cctx) >= 0)
- return OK;
-
if (script_var_exists(p, len, cctx, cstack) == OK)
{
if (is_arg)
--- 354,359 ----
***************
*** 388,393 ****
--- 363,377 ----
return FAIL;
}
+ if (class_member_index(p, len, NULL, cctx) >= 0)
+ {
+ if (is_arg)
+ semsg(_(e_argument_already_declared_in_class_str), p);
+ else
+ semsg(_(e_variable_already_declared_in_class_str), p);
+ return FAIL;
+ }
+
p[len] = NUL;
if ((cctx != NULL
&& (lookup_local(p, len, NULL, cctx) == OK
***************
*** 1592,1599 ****
}
}
else if ((lhs->lhs_classmember_idx = class_member_index(
! var_start, lhs->lhs_varlen, cctx)) >= 0)
{
lhs->lhs_dest = dest_class_member;
lhs->lhs_class = cctx->ctx_ufunc->uf_class;
}
--- 1576,1589 ----
}
}
else if ((lhs->lhs_classmember_idx = class_member_index(
! var_start, lhs->lhs_varlen, NULL, cctx)) >= 0)
{
+ if (is_decl)
+ {
+ semsg(_(e_variable_already_declared_in_class_str),
+ lhs->lhs_name);
+ return FAIL;
+ }
lhs->lhs_dest = dest_class_member;
lhs->lhs_class = cctx->ctx_ufunc->uf_class;
}
***************
*** 2264,2270 ****
CLEAR_FIELD(lhs);
long start_lnum = SOURCING_LNUM;
! int has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0;
if (has_arg_is_set_prefix)
{
arg += 11;
--- 2254,2260 ----
CLEAR_FIELD(lhs);
long start_lnum = SOURCING_LNUM;
! int has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0;
if (has_arg_is_set_prefix)
{
arg += 11;
*** ../vim-9.0.1126/src/testdir/test_vim9_class.vim 2023-01-01 12:58:29.474417546 +0000
--- src/testdir/test_vim9_class.vim 2023-01-01 19:50:20.110562669 +0000
***************
*** 367,373 ****
v9.CheckScriptFailure(lines, 'E1041:')
enddef
! def Test_class_member_access()
var lines =<< trim END
vim9script
class TextPos
--- 367,374 ----
v9.CheckScriptFailure(lines, 'E1041:')
enddef
! def Test_class_member()
! # check access rules
var lines =<< trim END
vim9script
class TextPos
***************
*** 401,406 ****
--- 402,439 ----
assert_equal(17, TextPos.anybody)
END
v9.CheckScriptSuccess(lines)
+
+ # check shadowing
+ lines =<< trim END
+ vim9script
+
+ class Some
+ static count = 0
+ def Method(count: number)
+ echo count
+ enddef
+ endclass
+
+ var s = Some.new()
+ s.Method(7)
+ END
+ v9.CheckScriptFailure(lines, 'E1340: Argument already declared in the class: count')
+
+ lines =<< trim END
+ vim9script
+
+ class Some
+ static count = 0
+ def Method(arg: number)
+ var count = 3
+ echo arg count
+ enddef
+ endclass
+
+ var s = Some.new()
+ s.Method(7)
+ END
+ v9.CheckScriptFailure(lines, 'E1341: Variable already declared in the class: count')
enddef
def Test_class_function()
*** ../vim-9.0.1126/src/version.c 2023-01-01 18:03:55.476613184 +0000
--- src/version.c 2023-01-01 19:51:20.590526047 +0000
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1127,
/**/
--
INSPECTOR END OF FILM: Move along. There's nothing to see! Keep moving!
[Suddenly he notices the cameras.]
INSPECTOR END OF FILM: (to Camera) All right, put that away sonny.
[He walks over to it and puts his hand over the lens.]
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///