forked from aniani/vim
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 <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
c7a8eb5ff2
commit
9937d8b619
37
src/eval.c
37
src/eval.c
@@ -1170,12 +1170,10 @@ get_lval_check_access(
|
|||||||
static char_u *
|
static char_u *
|
||||||
get_lval_imported(
|
get_lval_imported(
|
||||||
lval_T *lp,
|
lval_T *lp,
|
||||||
typval_T *rettv,
|
|
||||||
scid_T imp_sid,
|
scid_T imp_sid,
|
||||||
char_u *p,
|
char_u *p,
|
||||||
dictitem_T **dip,
|
dictitem_T **dip,
|
||||||
int fne_flags,
|
int fne_flags)
|
||||||
int vim9script)
|
|
||||||
{
|
{
|
||||||
ufunc_T *ufunc;
|
ufunc_T *ufunc;
|
||||||
type_T *type = NULL;
|
type_T *type = NULL;
|
||||||
@@ -1197,16 +1195,6 @@ get_lval_imported(
|
|||||||
TRUE) == -1)
|
TRUE) == -1)
|
||||||
goto failed;
|
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
|
// Get the typval for the exported item
|
||||||
hashtab_T *ht = &SCRIPT_VARS(imp_sid);
|
hashtab_T *ht = &SCRIPT_VARS(imp_sid);
|
||||||
if (ht == NULL)
|
if (ht == NULL)
|
||||||
@@ -1232,6 +1220,7 @@ get_lval_imported(
|
|||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
lp->ll_tv = &di->di_tv;
|
lp->ll_tv = &di->di_tv;
|
||||||
|
lp->ll_valtype = type;
|
||||||
|
|
||||||
success:
|
success:
|
||||||
rc = OK;
|
rc = OK;
|
||||||
@@ -1410,8 +1399,7 @@ get_lval(
|
|||||||
if (import != NULL)
|
if (import != NULL)
|
||||||
{
|
{
|
||||||
p++; // skip '.'
|
p++; // skip '.'
|
||||||
p = get_lval_imported(lp, rettv, import->imp_sid, p, &v,
|
p = get_lval_imported(lp, import->imp_sid, p, &v, fne_flags);
|
||||||
fne_flags, vim9script);
|
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1754,6 +1742,12 @@ get_lval(
|
|||||||
== FAIL)
|
== FAIL)
|
||||||
return NULL;
|
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_blob = lp->ll_tv->vval.v_blob;
|
||||||
lp->ll_tv = NULL;
|
lp->ll_tv = NULL;
|
||||||
break;
|
break;
|
||||||
@@ -1782,7 +1776,7 @@ get_lval(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lp->ll_valtype != NULL)
|
if (lp->ll_valtype != NULL && !lp->ll_range)
|
||||||
// use the type of the member
|
// use the type of the member
|
||||||
lp->ll_valtype = lp->ll_valtype->tt_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);
|
clear_tv(&var1);
|
||||||
lp->ll_name_end = p;
|
lp->ll_name_end = p;
|
||||||
return p;
|
return p;
|
||||||
|
@@ -95,6 +95,18 @@ func Test_blob_assign()
|
|||||||
END
|
END
|
||||||
call v9.CheckLegacyAndVim9Failure(lines, 'E979:')
|
call v9.CheckLegacyAndVim9Failure(lines, 'E979:')
|
||||||
|
|
||||||
|
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
|
let lines =<< trim END
|
||||||
VAR b = 0zDEADBEEF
|
VAR b = 0zDEADBEEF
|
||||||
LET b ..= 0z33
|
LET b ..= 0z33
|
||||||
|
@@ -650,7 +650,7 @@ def Test_assign_index()
|
|||||||
var bl = 0z11
|
var bl = 0z11
|
||||||
bl[1] = g:val
|
bl[1] = g:val
|
||||||
END
|
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"
|
# should not read the next line when generating "a.b"
|
||||||
var a = {}
|
var a = {}
|
||||||
|
@@ -3222,4 +3222,65 @@ def Test_autoload_import_dict_func()
|
|||||||
&rtp = save_rtp
|
&rtp = save_rtp
|
||||||
enddef
|
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<bool> = {bflag: false}
|
||||||
|
export var dict2: dict<dict<bool>> = {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<any>', 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
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -704,6 +704,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 */
|
||||||
|
/**/
|
||||||
|
398,
|
||||||
/**/
|
/**/
|
||||||
397,
|
397,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user