mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.1465: Vim9: subscript not handled properly
Problem: Vim9: subscript not handled properly. Solution: Adjust error message. Remove dead code. Disallow string to number conversion in scripts.
This commit is contained in:
parent
829ac868b7
commit
56acb0943e
@ -228,8 +228,8 @@ EXTERN char e_one_argument_too_many[]
|
|||||||
INIT(= N_("E1106: one argument too many"));
|
INIT(= N_("E1106: one argument too many"));
|
||||||
EXTERN char e_nr_arguments_too_many[]
|
EXTERN char e_nr_arguments_too_many[]
|
||||||
INIT(= N_("E1106: %d arguments too many"));
|
INIT(= N_("E1106: %d arguments too many"));
|
||||||
EXTERN char e_list_dict_or_blob_required[]
|
EXTERN char e_string_list_dict_or_blob_required[]
|
||||||
INIT(= N_("E1107: List, Dict or Blob required"));
|
INIT(= N_("E1107: String, List, Dict or Blob required"));
|
||||||
EXTERN char e_item_not_found_str[]
|
EXTERN char e_item_not_found_str[]
|
||||||
INIT(= N_("E1108: Item not found: %s"));
|
INIT(= N_("E1108: Item not found: %s"));
|
||||||
#endif
|
#endif
|
||||||
|
@ -2142,7 +2142,9 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
{
|
{
|
||||||
int error = FALSE;
|
int error = FALSE;
|
||||||
|
|
||||||
if (tv_get_number_chk(rettv, &error) != 0)
|
if (in_vim9script())
|
||||||
|
result = tv2bool(rettv);
|
||||||
|
else if (tv_get_number_chk(rettv, &error) != 0)
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
clear_tv(rettv);
|
clear_tv(rettv);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -1909,7 +1909,10 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
|
|||||||
int error = FALSE;
|
int error = FALSE;
|
||||||
|
|
||||||
// filter(): when expr is zero remove the item
|
// filter(): when expr is zero remove the item
|
||||||
*remp = (tv_get_number_chk(&rettv, &error) == 0);
|
if (in_vim9script())
|
||||||
|
*remp = !tv2bool(&rettv);
|
||||||
|
else
|
||||||
|
*remp = (tv_get_number_chk(&rettv, &error) == 0);
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
// On type error, nothing has been removed; return FAIL to stop the
|
// On type error, nothing has been removed; return FAIL to stop the
|
||||||
// loop. The error message was given by tv_get_number_chk().
|
// loop. The error message was given by tv_get_number_chk().
|
||||||
|
@ -384,12 +384,14 @@ func Test_expr3_fails()
|
|||||||
call CheckDefFailure(["let x = 1&& 2"], msg)
|
call CheckDefFailure(["let x = 1&& 2"], msg)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" global variables to use for tests with the "any" type
|
||||||
let atrue = v:true
|
let atrue = v:true
|
||||||
let afalse = v:false
|
let afalse = v:false
|
||||||
let anone = v:none
|
let anone = v:none
|
||||||
let anull = v:null
|
let anull = v:null
|
||||||
let anint = 10
|
let anint = 10
|
||||||
let alsoint = 4
|
let theone = 1
|
||||||
|
let thefour = 4
|
||||||
if has('float')
|
if has('float')
|
||||||
let afloat = 0.1
|
let afloat = 0.1
|
||||||
endif
|
endif
|
||||||
@ -901,17 +903,17 @@ def Test_expr5()
|
|||||||
assert_equal(66, 60 + 6)
|
assert_equal(66, 60 + 6)
|
||||||
assert_equal(70, 60 +
|
assert_equal(70, 60 +
|
||||||
g:anint)
|
g:anint)
|
||||||
assert_equal(9, g:alsoint
|
assert_equal(9, g:thefour
|
||||||
+ 5)
|
+ 5)
|
||||||
assert_equal(14, g:alsoint + g:anint)
|
assert_equal(14, g:thefour + g:anint)
|
||||||
assert_equal([1, 2, 3, 4], [1] + g:alist)
|
assert_equal([1, 2, 3, 4], [1] + g:alist)
|
||||||
|
|
||||||
assert_equal(54, 60 - 6)
|
assert_equal(54, 60 - 6)
|
||||||
assert_equal(50, 60 -
|
assert_equal(50, 60 -
|
||||||
g:anint)
|
g:anint)
|
||||||
assert_equal(-1, g:alsoint
|
assert_equal(-1, g:thefour
|
||||||
- 5)
|
- 5)
|
||||||
assert_equal(-6, g:alsoint - g:anint)
|
assert_equal(-6, g:thefour - g:anint)
|
||||||
|
|
||||||
assert_equal('hello', 'hel' .. 'lo')
|
assert_equal('hello', 'hel' .. 'lo')
|
||||||
assert_equal('hello 123', 'hello ' ..
|
assert_equal('hello 123', 'hello ' ..
|
||||||
@ -1136,24 +1138,24 @@ endfunc
|
|||||||
def Test_expr6()
|
def Test_expr6()
|
||||||
assert_equal(36, 6 * 6)
|
assert_equal(36, 6 * 6)
|
||||||
assert_equal(24, 6 *
|
assert_equal(24, 6 *
|
||||||
g:alsoint)
|
g:thefour)
|
||||||
assert_equal(24, g:alsoint
|
assert_equal(24, g:thefour
|
||||||
* 6)
|
* 6)
|
||||||
assert_equal(40, g:anint * g:alsoint)
|
assert_equal(40, g:anint * g:thefour)
|
||||||
|
|
||||||
assert_equal(10, 60 / 6)
|
assert_equal(10, 60 / 6)
|
||||||
assert_equal(6, 60 /
|
assert_equal(6, 60 /
|
||||||
g:anint)
|
g:anint)
|
||||||
assert_equal(1, g:anint / 6)
|
assert_equal(1, g:anint / 6)
|
||||||
assert_equal(2, g:anint
|
assert_equal(2, g:anint
|
||||||
/ g:alsoint)
|
/ g:thefour)
|
||||||
|
|
||||||
assert_equal(5, 11 % 6)
|
assert_equal(5, 11 % 6)
|
||||||
assert_equal(4, g:anint % 6)
|
assert_equal(4, g:anint % 6)
|
||||||
assert_equal(3, 13 %
|
assert_equal(3, 13 %
|
||||||
g:anint)
|
g:anint)
|
||||||
assert_equal(2, g:anint
|
assert_equal(2, g:anint
|
||||||
% g:alsoint)
|
% g:thefour)
|
||||||
|
|
||||||
assert_equal(4, 6 * 4 / 6)
|
assert_equal(4, 6 * 4 / 6)
|
||||||
|
|
||||||
@ -1323,7 +1325,7 @@ let $TESTVAR = 'testvar'
|
|||||||
" type casts
|
" type casts
|
||||||
def Test_expr7t()
|
def Test_expr7t()
|
||||||
let ls: list<string> = ['a', <string>g:string_empty]
|
let ls: list<string> = ['a', <string>g:string_empty]
|
||||||
let ln: list<number> = [<number>g:anint, <number>g:alsoint]
|
let ln: list<number> = [<number>g:anint, <number>g:thefour]
|
||||||
let nr = <number>234
|
let nr = <number>234
|
||||||
assert_equal(234, nr)
|
assert_equal(234, nr)
|
||||||
|
|
||||||
@ -1448,13 +1450,15 @@ def Test_expr7_list()
|
|||||||
|
|
||||||
let mixed: list<any> = [1, 'b', false,]
|
let mixed: list<any> = [1, 'b', false,]
|
||||||
assert_equal(g:list_mixed, mixed)
|
assert_equal(g:list_mixed, mixed)
|
||||||
assert_equal('b', g:list_mixed[1])
|
assert_equal('b', mixed[1])
|
||||||
|
|
||||||
echo [1,
|
echo [1,
|
||||||
2] [3,
|
2] [3,
|
||||||
4]
|
4]
|
||||||
|
|
||||||
call CheckDefExecFailure(["let x = g:anint[3]"], 'E714:')
|
call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
|
||||||
|
call CheckDefExecFailure(["let x = g:anint[3]"], 'E1029:')
|
||||||
|
|
||||||
call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
|
call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
|
||||||
|
|
||||||
call CheckDefFailure(["let x = [1,2,3]"], 'E1069:')
|
call CheckDefFailure(["let x = [1,2,3]"], 'E1069:')
|
||||||
@ -2136,6 +2140,7 @@ def Test_expr7_list_subscript()
|
|||||||
assert_equal([4], list[4:-1])
|
assert_equal([4], list[4:-1])
|
||||||
assert_equal([], list[5:-1])
|
assert_equal([], list[5:-1])
|
||||||
assert_equal([], list[999:-1])
|
assert_equal([], list[999:-1])
|
||||||
|
assert_equal([1, 2, 3, 4], list[g:theone:g:thefour])
|
||||||
|
|
||||||
assert_equal([0, 1, 2, 3], list[0:3])
|
assert_equal([0, 1, 2, 3], list[0:3])
|
||||||
assert_equal([0], list[0:0])
|
assert_equal([0], list[0:0])
|
||||||
@ -2147,6 +2152,10 @@ def Test_expr7_list_subscript()
|
|||||||
END
|
END
|
||||||
CheckDefSuccess(lines)
|
CheckDefSuccess(lines)
|
||||||
CheckScriptSuccess(['vim9script'] + lines)
|
CheckScriptSuccess(['vim9script'] + lines)
|
||||||
|
|
||||||
|
lines = ['let l = [0, 1, 2]', 'echo l[g:astring : g:theone]']
|
||||||
|
CheckDefExecFailure(lines, 'E1029:')
|
||||||
|
CheckScriptFailure(['vim9script'] + lines, 'E1030:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_expr7_subscript_linebreak()
|
def Test_expr7_subscript_linebreak()
|
||||||
|
@ -793,19 +793,20 @@ def Test_try_catch()
|
|||||||
endtry
|
endtry
|
||||||
assert_equal(99, n)
|
assert_equal(99, n)
|
||||||
|
|
||||||
|
# TODO: this will change when index on "any" works
|
||||||
try
|
try
|
||||||
n = g:astring[3]
|
n = g:astring[3]
|
||||||
catch /E714:/
|
catch /E1029:/
|
||||||
n = 77
|
n = 77
|
||||||
endtry
|
endtry
|
||||||
assert_equal(77, n)
|
assert_equal(77, n)
|
||||||
|
|
||||||
try
|
try
|
||||||
n = l[g:astring]
|
n = l[g:astring]
|
||||||
catch /E39:/
|
catch /E1029:/
|
||||||
n = 77
|
n = 88
|
||||||
endtry
|
endtry
|
||||||
assert_equal(77, n)
|
assert_equal(88, n)
|
||||||
|
|
||||||
try
|
try
|
||||||
n = s:does_not_exist
|
n = s:does_not_exist
|
||||||
|
15
src/typval.c
15
src/typval.c
@ -204,6 +204,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
|
|||||||
emsg(_("E703: Using a Funcref as a Number"));
|
emsg(_("E703: Using a Funcref as a Number"));
|
||||||
break;
|
break;
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
|
if (in_vim9script())
|
||||||
|
{
|
||||||
|
emsg(_(e_using_string_as_number));
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (varp->vval.v_string != NULL)
|
if (varp->vval.v_string != NULL)
|
||||||
vim_str2nr(varp->vval.v_string, NULL, NULL,
|
vim_str2nr(varp->vval.v_string, NULL, NULL,
|
||||||
STR2NR_ALL, &n, NULL, 0, FALSE);
|
STR2NR_ALL, &n, NULL, 0, FALSE);
|
||||||
@ -216,6 +221,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
|
|||||||
break;
|
break;
|
||||||
case VAR_BOOL:
|
case VAR_BOOL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
|
if (in_vim9script())
|
||||||
|
{
|
||||||
|
emsg(_("E611: Using a Special as a Number"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
|
return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
@ -1461,9 +1471,10 @@ eval_env_var(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
linenr_T
|
linenr_T
|
||||||
tv_get_lnum(typval_T *argvars)
|
tv_get_lnum(typval_T *argvars)
|
||||||
{
|
{
|
||||||
linenr_T lnum;
|
linenr_T lnum = 0;
|
||||||
|
|
||||||
lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
|
if (argvars[0].v_type != VAR_STRING || !in_vim9script())
|
||||||
|
lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
|
||||||
if (lnum == 0) // no valid number, try using arg like line()
|
if (lnum == 0) // no valid number, try using arg like line()
|
||||||
{
|
{
|
||||||
int fnum;
|
int fnum;
|
||||||
|
@ -754,6 +754,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 */
|
||||||
|
/**/
|
||||||
|
1465,
|
||||||
/**/
|
/**/
|
||||||
1464,
|
1464,
|
||||||
/**/
|
/**/
|
||||||
|
@ -3067,6 +3067,7 @@ compile_subscript(
|
|||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
type_T **typep;
|
type_T **typep;
|
||||||
|
type_T *valtype;
|
||||||
vartype_T vtype;
|
vartype_T vtype;
|
||||||
int is_slice = FALSE;
|
int is_slice = FALSE;
|
||||||
|
|
||||||
@ -3127,13 +3128,22 @@ compile_subscript(
|
|||||||
typep = ((type_T **)stack->ga_data) + stack->ga_len
|
typep = ((type_T **)stack->ga_data) + stack->ga_len
|
||||||
- (is_slice ? 3 : 2);
|
- (is_slice ? 3 : 2);
|
||||||
vtype = (*typep)->tt_type;
|
vtype = (*typep)->tt_type;
|
||||||
if (*typep == &t_any)
|
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
|
// If the index is a string, the variable must be a Dict.
|
||||||
|
if (*typep == &t_any && valtype == &t_string)
|
||||||
|
vtype = VAR_DICT;
|
||||||
|
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
|
||||||
{
|
{
|
||||||
type_T *valtype = ((type_T **)stack->ga_data)
|
if (need_type(valtype, &t_number, -1, cctx, FALSE) == FAIL)
|
||||||
[stack->ga_len - 1];
|
return FAIL;
|
||||||
if (valtype == &t_string)
|
if (is_slice)
|
||||||
vtype = VAR_DICT;
|
{
|
||||||
|
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
||||||
|
if (need_type(valtype, &t_number, -2, cctx, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtype == VAR_DICT)
|
if (vtype == VAR_DICT)
|
||||||
{
|
{
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
@ -3169,6 +3179,10 @@ compile_subscript(
|
|||||||
}
|
}
|
||||||
else if (vtype == VAR_LIST || *typep == &t_any)
|
else if (vtype == VAR_LIST || *typep == &t_any)
|
||||||
{
|
{
|
||||||
|
// TODO: any requires runtime code
|
||||||
|
if (*typep == &t_any && need_type(*typep, &t_list_any,
|
||||||
|
is_slice ? -3 : -2, cctx, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
if (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
|
if (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
|
||||||
@ -3184,7 +3198,7 @@ compile_subscript(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emsg(_(e_list_dict_or_blob_required));
|
emsg(_(e_string_list_dict_or_blob_required));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2241,33 +2241,13 @@ call_def_function(
|
|||||||
// string index: string is at stack-2, index at stack-1
|
// string index: string is at stack-2, index at stack-1
|
||||||
// string slice: string is at stack-3, first index at
|
// string slice: string is at stack-3, first index at
|
||||||
// stack-2, second index at stack-1
|
// stack-2, second index at stack-1
|
||||||
tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
|
|
||||||
if (tv->v_type != VAR_STRING)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_stringreq));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
tv = STACK_TV_BOT(-2);
|
tv = STACK_TV_BOT(-2);
|
||||||
if (tv->v_type != VAR_NUMBER)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_number_exp));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
n1 = tv->vval.v_number;
|
n1 = tv->vval.v_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
if (tv->v_type != VAR_NUMBER)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_number_exp));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
n2 = tv->vval.v_number;
|
n2 = tv->vval.v_number;
|
||||||
|
|
||||||
ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
|
ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
|
||||||
@ -2296,33 +2276,15 @@ call_def_function(
|
|||||||
// list slice: list is at stack-3, indexes at stack-2 and
|
// list slice: list is at stack-3, indexes at stack-2 and
|
||||||
// stack-1
|
// stack-1
|
||||||
tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
|
tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
|
||||||
if (tv->v_type != VAR_LIST)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_listreq));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
list = tv->vval.v_list;
|
list = tv->vval.v_list;
|
||||||
|
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
if (tv->v_type != VAR_NUMBER)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_number_exp));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
n1 = n2 = tv->vval.v_number;
|
n1 = n2 = tv->vval.v_number;
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
|
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
tv = STACK_TV_BOT(-2);
|
tv = STACK_TV_BOT(-2);
|
||||||
if (tv->v_type != VAR_NUMBER)
|
|
||||||
{
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
|
||||||
emsg(_(e_number_exp));
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
n1 = tv->vval.v_number;
|
n1 = tv->vval.v_number;
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user