# HG changeset patch # User Christian Brabandt # Date 1715193007 -7200 # Node ID f2b94f240b7ddd73761f99402ab6b6f6db94d5b5 # Parent ebb2a0e14e621e42426a267742c1938fe434fb00 patch 9.1.0398: Vim9: imported vars are not properly type checked Commit: https://github.com/vim/vim/commit/9937d8b61922a02311509fb3352583d9e8c54885 Author: Yegappan Lakshmanan Date: Wed May 8 20:24:33 2024 +0200 patch 9.1.0398: Vim9: imported vars are not properly type checked Problem: Vim9: imported vars are not properly type checked Solution: Check the imported variable type properly (Yegappan Lakshmanan) closes: #14729 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1170,12 +1170,10 @@ get_lval_check_access( static char_u * get_lval_imported( lval_T *lp, - typval_T *rettv, scid_T imp_sid, char_u *p, dictitem_T **dip, - int fne_flags, - int vim9script) + int fne_flags) { ufunc_T *ufunc; type_T *type = NULL; @@ -1197,16 +1195,6 @@ get_lval_imported( TRUE) == -1) goto failed; - if (vim9script && type != NULL) - { - where_T where = WHERE_INIT; - - // In a vim9 script, do type check and make sure the variable is - // writable. - if (check_typval_type(type, rettv, where) == FAIL) - goto failed; - } - // Get the typval for the exported item hashtab_T *ht = &SCRIPT_VARS(imp_sid); if (ht == NULL) @@ -1232,6 +1220,7 @@ get_lval_imported( goto failed; lp->ll_tv = &di->di_tv; + lp->ll_valtype = type; success: rc = OK; @@ -1410,8 +1399,7 @@ get_lval( if (import != NULL) { p++; // skip '.' - p = get_lval_imported(lp, rettv, import->imp_sid, p, &v, - fne_flags, vim9script); + p = get_lval_imported(lp, import->imp_sid, p, &v, fne_flags); if (p == NULL) return NULL; } @@ -1754,6 +1742,12 @@ get_lval( == FAIL) return NULL; } + + if (!lp->ll_range) + // Indexing a single byte in a blob. So the rhs type is a + // number. + lp->ll_valtype = &t_number; + lp->ll_blob = lp->ll_tv->vval.v_blob; lp->ll_tv = NULL; break; @@ -1782,7 +1776,7 @@ get_lval( return NULL; } - if (lp->ll_valtype != NULL) + if (lp->ll_valtype != NULL && !lp->ll_range) // use the type of the member lp->ll_valtype = lp->ll_valtype->tt_member; @@ -1896,6 +1890,17 @@ get_lval( } } + if (vim9script && lp->ll_valtype != NULL && rettv != NULL) + { + where_T where = WHERE_INIT; + + // In a vim9 script, do type check and make sure the variable is + // writable. + if (check_typval_type(lp->ll_valtype, rettv, where) == FAIL) + return NULL; + } + + clear_tv(&var1); lp->ll_name_end = p; return p; diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -97,6 +97,18 @@ func Test_blob_assign() let lines =<< trim END VAR b = 0zDEADBEEF + LET b[0 : 1] = 0x1122 + END + call v9.CheckLegacyAndVim9Failure(lines, ['E709:', 'E1012:', 'E709:']) + + let lines =<< trim END + VAR b = 0zDEADBEEF + LET b[0] = 0z11 + END + call v9.CheckLegacyAndVim9Failure(lines, ['E974:', 'E974:', 'E1012:']) + + let lines =<< trim END + VAR b = 0zDEADBEEF LET b ..= 0z33 END call v9.CheckLegacyAndVim9Failure(lines, ['E734:', 'E1019:', 'E734:']) diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -650,7 +650,7 @@ def Test_assign_index() var bl = 0z11 bl[1] = g:val END - v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"') + v9.CheckDefExecAndScriptFailure(lines, ['E1030: Using a String as a Number: "22"', 'E1012: Type mismatch; expected number but got string']) # should not read the next line when generating "a.b" var a = {} diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim --- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -3222,4 +3222,65 @@ def Test_autoload_import_dict_func() &rtp = save_rtp enddef +" Test for changing the value of an imported Dict item +def Test_set_imported_dict_item() + var lines =<< trim END + vim9script + export var dict1: dict = {bflag: false} + export var dict2: dict> = {x: {bflag: false}} + END + writefile(lines, 'XimportedDict.vim', 'D') + + lines =<< trim END + vim9script + import './XimportedDict.vim' + assert_equal(XimportedDict.dict1.bflag, false) + XimportedDict.dict1.bflag = true + assert_equal(XimportedDict.dict1.bflag, true) + XimportedDict.dict2.x.bflag = true + assert_equal(XimportedDict.dict2.x.bflag, true) + assert_equal('bool', typename(XimportedDict.dict1.bflag)) + assert_equal('bool', typename(XimportedDict.dict2.x.bflag)) + assert_equal('bool', typename(XimportedDict.dict2['x'].bflag)) + assert_equal('bool', typename(XimportedDict.dict2.x['bflag'])) + + assert_equal(XimportedDict.dict1['bflag'], true) + XimportedDict.dict1['bflag'] = false + assert_equal(XimportedDict.dict1.bflag, false) + XimportedDict.dict2['x']['bflag'] = false + assert_equal(XimportedDict.dict2['x'].bflag, false) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + import './XimportedDict.vim' + XimportedDict.dict2.x.bflag = [] + END + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected bool but got list', 3) +enddef + +" Test for changing the value of an imported class member +def Test_set_imported_class_member() + var lines =<< trim END + vim9script + export class Config + public static var option = false + endclass + END + writefile(lines, 'XimportedClass.vim', 'D') + + lines =<< trim END + vim9script + import './XimportedClass.vim' as foo + type FooConfig = foo.Config + assert_equal(false, FooConfig.option) + assert_equal(false, foo.Config.option) + foo.Config.option = true + assert_equal(true, foo.Config.option) + assert_equal(true, FooConfig.option) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 398, +/**/ 397, /**/ 396,