summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-08-16 14:48:19 +0200
committerBram Moolenaar <Bram@vim.org>2020-08-16 14:48:19 +0200
commit56acb0943ede35cd9d2f6667cde2442819ccbf59 (patch)
treed35aa5928ec6d46f07ea1ed4f1e5fb2f00bfa7dc
parent829ac868b7615d73dbfb536f7fcd44fc7c5b7c1d (diff)
patch 8.2.1465: Vim9: subscript not handled properlyv8.2.1465
Problem: Vim9: subscript not handled properly. Solution: Adjust error message. Remove dead code. Disallow string to number conversion in scripts.
-rw-r--r--src/errors.h4
-rw-r--r--src/eval.c4
-rw-r--r--src/list.c5
-rw-r--r--src/testdir/test_vim9_expr.vim35
-rw-r--r--src/testdir/test_vim9_script.vim9
-rw-r--r--src/typval.c15
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c26
-rw-r--r--src/vim9execute.c38
9 files changed, 71 insertions, 67 deletions
diff --git a/src/errors.h b/src/errors.h
index 3f96071469..0622042a81 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -228,8 +228,8 @@ EXTERN char e_one_argument_too_many[]
INIT(= N_("E1106: one argument too many"));
EXTERN char e_nr_arguments_too_many[]
INIT(= N_("E1106: %d arguments too many"));
-EXTERN char e_list_dict_or_blob_required[]
- INIT(= N_("E1107: List, Dict or Blob required"));
+EXTERN char e_string_list_dict_or_blob_required[]
+ INIT(= N_("E1107: String, List, Dict or Blob required"));
EXTERN char e_item_not_found_str[]
INIT(= N_("E1108: Item not found: %s"));
#endif
diff --git a/src/eval.c b/src/eval.c
index 8f685eda47..02b5623fc6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2142,7 +2142,9 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
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;
clear_tv(rettv);
if (error)
diff --git a/src/list.c b/src/list.c
index 955272c37b..b09e87f5fd 100644
--- a/src/list.c
+++ b/src/list.c
@@ -1909,7 +1909,10 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
int error = FALSE;
// 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);
// On type error, nothing has been removed; return FAIL to stop the
// loop. The error message was given by tv_get_number_chk().
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index 6f3cedf902..720f2307f1 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -384,12 +384,14 @@ func Test_expr3_fails()
call CheckDefFailure(["let x = 1&& 2"], msg)
endfunc
+" global variables to use for tests with the "any" type
let atrue = v:true
let afalse = v:false
let anone = v:none
let anull = v:null
let anint = 10
-let alsoint = 4
+let theone = 1
+let thefour = 4
if has('float')
let afloat = 0.1
endif
@@ -901,17 +903,17 @@ def Test_expr5()
assert_equal(66, 60 + 6)
assert_equal(70, 60 +
g:anint)
- assert_equal(9, g:alsoint
+ assert_equal(9, g:thefour
+ 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(54, 60 - 6)
assert_equal(50, 60 -
g:anint)
- assert_equal(-1, g:alsoint
+ assert_equal(-1, g:thefour
- 5)
- assert_equal(-6, g:alsoint - g:anint)
+ assert_equal(-6, g:thefour - g:anint)
assert_equal('hello', 'hel' .. 'lo')
assert_equal('hello 123', 'hello ' ..
@@ -1136,24 +1138,24 @@ endfunc
def Test_expr6()
assert_equal(36, 6 * 6)
assert_equal(24, 6 *
- g:alsoint)
- assert_equal(24, g:alsoint
+ g:thefour)
+ assert_equal(24, g:thefour
* 6)
- assert_equal(40, g:anint * g:alsoint)
+ assert_equal(40, g:anint * g:thefour)
assert_equal(10, 60 / 6)
assert_equal(6, 60 /
g:anint)
assert_equal(1, g:anint / 6)
assert_equal(2, g:anint
- / g:alsoint)
+ / g:thefour)
assert_equal(5, 11 % 6)
assert_equal(4, g:anint % 6)
assert_equal(3, 13 %
g:anint)
assert_equal(2, g:anint
- % g:alsoint)
+ % g:thefour)
assert_equal(4, 6 * 4 / 6)
@@ -1323,7 +1325,7 @@ let $TESTVAR = 'testvar'
" type casts
def Test_expr7t()
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
assert_equal(234, nr)
@@ -1448,13 +1450,15 @@ def Test_expr7_list()
let mixed: list<any> = [1, 'b', false,]
assert_equal(g:list_mixed, mixed)
- assert_equal('b', g:list_mixed[1])
+ assert_equal('b', mixed[1])
echo [1,
2] [3,
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 = [1,2,3]"], 'E1069:')
@@ -2136,6 +2140,7 @@ def Test_expr7_list_subscript()
assert_equal([4], list[4:-1])
assert_equal([], list[5:-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], list[0:0])
@@ -2147,6 +2152,10 @@ def Test_expr7_list_subscript()
END
CheckDefSuccess(lines)
CheckScriptSuccess(['vim9script'] + lines)
+
+ lines = ['let l = [0, 1, 2]', 'echo l[g:astring : g:theone]']
+ CheckDefExecFailure(lines, 'E1029:')
+ CheckScriptFailure(['vim9script'] + lines, 'E1030:')
enddef
def Test_expr7_subscript_linebreak()
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 832835ec50..1e265be0d7 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -793,19 +793,20 @@ def Test_try_catch()
endtry
assert_equal(99, n)
+ # TODO: this will change when index on "any" works
try
n = g:astring[3]
- catch /E714:/
+ catch /E1029:/
n = 77
endtry
assert_equal(77, n)
try
n = l[g:astring]
- catch /E39:/
- n = 77
+ catch /E1029:/
+ n = 88
endtry
- assert_equal(77, n)
+ assert_equal(88, n)
try
n = s:does_not_exist
diff --git a/src/typval.c b/src/typval.c
index e87f91096e..406a193be3 100644
--- a/src/typval.c
+++ b/src/typval.c
@@ -204,6 +204,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
emsg(_("E703: Using a Funcref as a Number"));
break;
case VAR_STRING:
+ if (in_vim9script())
+ {
+ emsg(_(e_using_string_as_number));
+ break;
+ }
if (varp->vval.v_string != NULL)
vim_str2nr(varp->vval.v_string, NULL, NULL,
STR2NR_ALL, &n, NULL, 0, FALSE);
@@ -216,6 +221,11 @@ tv_get_number_chk(typval_T *varp, int *denote)
break;
case VAR_BOOL:
case VAR_SPECIAL:
+ if (in_vim9script())
+ {
+ emsg(_("E611: Using a Special as a Number"));
+ break;
+ }
return varp->vval.v_number == VVAL_TRUE ? 1 : 0;
case VAR_JOB:
#ifdef FEAT_JOB_CHANNEL
@@ -1461,9 +1471,10 @@ eval_env_var(char_u **arg, typval_T *rettv, int evaluate)
linenr_T
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()
{
int fnum;
diff --git a/src/version.c b/src/version.c
index 4554fc4bbf..7a6fcbfff6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1465,
+/**/
1464,
/**/
1463,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index da44770f3e..cdc63cfe19 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -3067,6 +3067,7 @@ compile_subscript(
{
garray_T *stack = &cctx->ctx_type_stack;
type_T **typep;
+ type_T *valtype;
vartype_T vtype;
int is_slice = FALSE;
@@ -3127,13 +3128,22 @@ compile_subscript(
typep = ((type_T **)stack->ga_data) + stack->ga_len
- (is_slice ? 3 : 2);
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)
- [stack->ga_len - 1];
- if (valtype == &t_string)
- vtype = VAR_DICT;
+ if (need_type(valtype, &t_number, -1, cctx, FALSE) == FAIL)
+ return FAIL;
+ if (is_slice)
+ {
+ 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 (is_slice)
@@ -3169,6 +3179,10 @@ compile_subscript(
}
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 (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
@@ -3184,7 +3198,7 @@ compile_subscript(
}
else
{
- emsg(_(e_list_dict_or_blob_required));
+ emsg(_(e_string_list_dict_or_blob_required));
return FAIL;
}
}
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 5670a7c3c0..02a895ecb7 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2241,33 +2241,13 @@ call_def_function(
// string index: string is at stack-2, index at stack-1
// string slice: string is at stack-3, first index at
// 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)
{
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;
}
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;
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
// stack-1
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;
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;
clear_tv(tv);
if (is_slice)
{
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;
clear_tv(tv);
}