From f4af331d084b4f2c63710179a2f1fa360cc7d74b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 4 Jul 2024 13:43:12 +0200 Subject: patch 9.1.0520: Vim9: incorrect type checking for modifying lists Problem: Vim9: incorrect type checking for modifying lists Solution: Correctly assign the member declared types and generate typechecks, add disassembly test (LemonBoy) fixes: #15090 closes: #15094 Signed-off-by: LemonBoy Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt --- src/testdir/test_vim9_class.vim | 33 +++++++++++++++++++++++++++++++++ src/testdir/test_vim9_disassemble.vim | 22 ++++++++++++++++++++++ src/version.c | 2 ++ src/vim9class.c | 1 + src/vim9compile.c | 11 ++++++++++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index a043f8c699..f0c27de99b 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -10776,4 +10776,37 @@ def Test_class_object_index() v9.CheckScriptFailure(lines, 'E689: Index not allowed after a object: a[10] = 1', 5) enddef +def Test_class_member_init_typecheck() + # Ensure the class member is assigned its declared type. + var lines =<< trim END + vim9script + class S + static var l: list = [] + endclass + S.l->add(123) + END + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 5) + + # Ensure the initializer value and the declared type match. + lines =<< trim END + vim9script + class S + var l: list = [1, 2, 3] + endclass + var o = S.new() + END + v9.CheckScriptFailure(lines, 'E1382: Variable "l": type mismatch, expected list but got list') + + # Ensure the class member is assigned its declared type. + lines =<< trim END + vim9script + class S + var l: list = [] + endclass + var o = S.new() + o.l->add(123) + END + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 6) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index c74cce4482..89dcceed57 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -3496,4 +3496,26 @@ def Test_disassemble_compound_op_in_closure() unlet g:instr enddef +def Test_disassemble_member_initializer() + var lines =<< trim END + vim9script + class A + var l: list = [] + var d: dict = {} + endclass + g:instr = execute('disassemble A.new') + END + v9.CheckScriptSuccess(lines) + # Ensure SETTYPE is emitted and that matches the declared type. + assert_match('new\_s*' .. + '0 NEW A size \d\+\_s*' .. + '1 NEWLIST size 0\_s*' .. + '2 SETTYPE list\_s*' .. + '3 STORE_THIS 0\_s*' .. + '4 NEWDICT size 0\_s*' .. + '5 SETTYPE dict\_s*' .. + '6 STORE_THIS 1', g:instr) + unlet g:instr +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 966088de22..ec993ab6bb 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 520, /**/ 519, /**/ diff --git a/src/vim9class.c b/src/vim9class.c index 5d68459de8..cf2af61325 100644 --- a/src/vim9class.c +++ b/src/vim9class.c @@ -1280,6 +1280,7 @@ add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap) tv->v_type = m->ocm_type->tt_type; tv->vval.v_string = NULL; } + set_tv_type(tv, m->ocm_type); if (m->ocm_flags & OCMFLAG_CONST) item_lock(tv, DICT_MAXNEST, TRUE, TRUE); } diff --git a/src/vim9compile.c b/src/vim9compile.c index 8e6f6e23fd..61fefa767e 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3315,7 +3315,7 @@ obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx) // the initialization expression type. m->ocm_type = type; } - else if (m->ocm_type->tt_type != type->tt_type) + else { // The type of the member initialization expression is // determined at run time. Add a runtime type check. @@ -3330,6 +3330,15 @@ obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx) else push_default_value(cctx, m->ocm_type->tt_type, FALSE, NULL); + if ((m->ocm_type->tt_type == VAR_DICT + || m->ocm_type->tt_type == VAR_LIST) + && m->ocm_type->tt_member != NULL + && m->ocm_type->tt_member != &t_any + && m->ocm_type->tt_member != &t_unknown) + // Set the type in the list or dict, so that it can be checked, + // also in legacy script. + generate_SETTYPE(cctx, m->ocm_type); + generate_STORE_THIS(cctx, i); } -- cgit v1.2.3