patch 9.2.1130: Vim9: assigning a Number to $VAR or @r is not an error
Problem: Vim9: assigning a non-String value to an environment
variable, a register or a String v: variable at the script
level converts the value, while a :def function gives E1012.
Solution: Also check the type at the script level and give E1012
Using "@#" still takes a Number with "=".
Add Test_assign_string_only(), which checks that these fail with E1012
both in a :def function and at the script level: "= 123", "..= 123"
and "= true" on $XSTRING_ONLY, @a and v:errmsg, "@# ..= 1" and
"[$XSTRING_ONLY, @a] = [1, 2]". It also checks that legacy :let still
converts a Number to a String for these three targets.
closes: #21364
Assisted-by: Claude
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
1 parent
7c16e2127f
commit
12ff5ce7fd
5 files changed
+72
-1
No files matched your search
@@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 9.2. Last change: 2026 Sep 24
|
||||
*vim9.txt* For Vim version 9.2. Last change: 2026 Sep 25
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -4620,6 +4620,12 @@ in Vim9 script.
|
||||
echo filter([1, 2], 0)
|
||||
vim9cmd echo filter([1, 2], 0) # E1024: Using a Number as a String
|
||||
<
|
||||
- Assigning a number to an environment variable, a register or a String
|
||||
v: variable:
|
||||
>vim
|
||||
let $FOO = 123
|
||||
vim9cmd $FOO = 123 # E1012: Type mismatch; expected string but ...
|
||||
<
|
||||
- Not using a number where a number is expected:
|
||||
>vim
|
||||
" In this example, legacy Vim script treats v:false as 0
|
||||
|
||||
+14
@@ -2417,6 +2417,20 @@ set_var_lval(
|
||||
return;
|
||||
}
|
||||
|
||||
// In Vim9 script a String v: variable only takes a String.
|
||||
if (in_vim9script() && STRNCMP(lp->ll_name, "v:", 2) == 0
|
||||
&& tv.v_type == VAR_STRING)
|
||||
{
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
if (check_typval_type(&t_string, rettv, where) == FAIL)
|
||||
{
|
||||
clear_tv(&tv);
|
||||
*endp = cc;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((di == NULL
|
||||
|| (!var_check_ro(di->di_flags, lp->ll_name, FALSE)
|
||||
&& !tv_check_lock(&di->di_tv, lp->ll_name, FALSE)))
|
||||
|
||||
@@ -1991,6 +1991,18 @@ ex_let_one(
|
||||
if (check_typval_is_value(tv) == FAIL)
|
||||
return NULL;
|
||||
|
||||
// In Vim9 script an environment variable and a register only take a
|
||||
// String. "@#" also takes a buffer number.
|
||||
if (in_vim9script() && (*arg == '$' || *arg == '@')
|
||||
&& !(*arg == '@' && arg[1] == '#' && tv->v_type == VAR_NUMBER
|
||||
&& (op == NULL || *op == '=')))
|
||||
{
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
if (check_typval_type(&t_string, tv, where) == FAIL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*arg == '$')
|
||||
{
|
||||
// ":let $VAR = expr": Set environment variable.
|
||||
@@ -4327,6 +4339,16 @@ set_var_const(
|
||||
|
||||
// existing variable, need to clear the value
|
||||
|
||||
// In Vim9 script a String v: variable only takes a String.
|
||||
if (ht == &vimvarht && di->di_tv.v_type == VAR_STRING
|
||||
&& in_vim9script())
|
||||
{
|
||||
where_T where = WHERE_INIT;
|
||||
|
||||
if (check_typval_type(&t_string, tv, where) == FAIL)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// Handle setting internal v: variables separately where needed to
|
||||
// prevent changing the type.
|
||||
int type_error = FALSE;
|
||||
|
||||
@@ -308,6 +308,33 @@ def Test_assign_register()
|
||||
v9.CheckDefFailure(['@a += 123'], 'E1012:')
|
||||
enddef
|
||||
|
||||
" An environment variable, a register and a String v: variable only take a
|
||||
" String.
|
||||
def Test_assign_string_only()
|
||||
for target in ['$XSTRING_ONLY', '@a', 'v:errmsg']
|
||||
v9.CheckDefAndScriptFailure([target .. ' = 123'],
|
||||
'E1012: Type mismatch; expected string but got number', 1)
|
||||
v9.CheckDefAndScriptFailure([target .. ' ..= 123'],
|
||||
'E1012: Type mismatch; expected string but got number', 1)
|
||||
v9.CheckDefAndScriptFailure([target .. ' = true'],
|
||||
'E1012: Type mismatch; expected string but got bool', 1)
|
||||
endfor
|
||||
v9.CheckDefAndScriptFailure(['[$XSTRING_ONLY, @a] = [1, 2]'],
|
||||
'E1012: Type mismatch; expected string but got number', 1)
|
||||
v9.CheckDefAndScriptFailure(['@# ..= 1'],
|
||||
'E1012: Type mismatch; expected string but got number', 1)
|
||||
v9.CheckDefAndScriptSuccess(['@# = bufnr()'])
|
||||
|
||||
# Legacy script converts the value.
|
||||
legacy let $XSTRING_ONLY = 123
|
||||
legacy let @a = 456
|
||||
legacy let v:errmsg = 789
|
||||
assert_equal('123', $XSTRING_ONLY)
|
||||
assert_equal('456', @a)
|
||||
assert_equal('789', v:errmsg)
|
||||
unlet $XSTRING_ONLY
|
||||
enddef
|
||||
|
||||
def Test_reserved_name()
|
||||
var more_names = ['null_job', 'null_channel']
|
||||
if !has('job')
|
||||
|
||||
@@ -763,6 +763,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1130,
|
||||
/**/
|
||||
1129,
|
||||
/**/
|
||||
|
||||
Reference in new issue
Block a user