mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.2.1865: Vim9: add() does not check type of argument
Problem: Vim9: add() does not check type of argument. Solution: Inline the add() call. (closes #7160)
This commit is contained in:
@@ -282,4 +282,6 @@ EXTERN char e_endblock_without_block[]
|
|||||||
INIT(= N_("E1128: } without {"));
|
INIT(= N_("E1128: } without {"));
|
||||||
EXTERN char e_throw_with_empty_string[]
|
EXTERN char e_throw_with_empty_string[]
|
||||||
INIT(= N_("E1129: Throw with empty string"));
|
INIT(= N_("E1129: Throw with empty string"));
|
||||||
|
EXTERN char e_cannot_add_to_null_list[]
|
||||||
|
INIT(= N_("E1130: Cannot add to null list"));
|
||||||
#endif
|
#endif
|
||||||
|
@@ -273,6 +273,34 @@ def Test_disassemble_list_assign()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def s:ListAdd()
|
||||||
|
var l: list<number> = []
|
||||||
|
add(l, 123)
|
||||||
|
add(l, g:aNumber)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_list_add()
|
||||||
|
var res = execute('disass s:ListAdd')
|
||||||
|
assert_match('<SNR>\d*_ListAdd\_s*' ..
|
||||||
|
'var l: list<number> = []\_s*' ..
|
||||||
|
'\d NEWLIST size 0\_s*' ..
|
||||||
|
'\d STORE $0\_s*' ..
|
||||||
|
'add(l, 123)\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d PUSHNR 123\_s*' ..
|
||||||
|
'\d LISTAPPEND\_s*' ..
|
||||||
|
'\d DROP\_s*' ..
|
||||||
|
'add(l, g:aNumber)\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d\+ LOADG g:aNumber\_s*' ..
|
||||||
|
'\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
|
||||||
|
'\d\+ LISTAPPEND\_s*' ..
|
||||||
|
'\d\+ DROP\_s*' ..
|
||||||
|
'\d\+ PUSHNR 0\_s*' ..
|
||||||
|
'\d\+ RETURN',
|
||||||
|
res)
|
||||||
|
enddef
|
||||||
|
|
||||||
def s:ScriptFuncUnlet()
|
def s:ScriptFuncUnlet()
|
||||||
g:somevar = "value"
|
g:somevar = "value"
|
||||||
unlet g:somevar
|
unlet g:somevar
|
||||||
@@ -803,7 +831,7 @@ def Test_disassemble_for_loop()
|
|||||||
'res->add(i)\_s*' ..
|
'res->add(i)\_s*' ..
|
||||||
'\d LOAD $0\_s*' ..
|
'\d LOAD $0\_s*' ..
|
||||||
'\d LOAD $2\_s*' ..
|
'\d LOAD $2\_s*' ..
|
||||||
'\d\+ BCALL add(argc 2)\_s*' ..
|
'\d\+ LISTAPPEND\_s*' ..
|
||||||
'\d\+ DROP\_s*' ..
|
'\d\+ DROP\_s*' ..
|
||||||
'endfor\_s*' ..
|
'endfor\_s*' ..
|
||||||
'\d\+ JUMP -> \d\+\_s*' ..
|
'\d\+ JUMP -> \d\+\_s*' ..
|
||||||
|
@@ -1772,6 +1772,24 @@ def Test_list2str_str2list_utf8()
|
|||||||
list2str(l, true)->assert_equal(s)
|
list2str(l, true)->assert_equal(s)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_list_add()
|
||||||
|
var l: list<number> # defaults to empty list
|
||||||
|
add(l, 9)
|
||||||
|
assert_equal([9], l)
|
||||||
|
|
||||||
|
var lines =<< trim END
|
||||||
|
var l: list<number>
|
||||||
|
add(l, "x")
|
||||||
|
END
|
||||||
|
CheckDefFailure(lines, 'E1012:', 2)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var l: list<number> = test_null_list()
|
||||||
|
add(l, 123)
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1130:', 2)
|
||||||
|
enddef
|
||||||
|
|
||||||
def SID(): number
|
def SID(): number
|
||||||
return expand('<SID>')
|
return expand('<SID>')
|
||||||
->matchstr('<SNR>\zs\d\+\ze_$')
|
->matchstr('<SNR>\zs\d\+\ze_$')
|
||||||
|
@@ -750,6 +750,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 */
|
||||||
|
/**/
|
||||||
|
1865,
|
||||||
/**/
|
/**/
|
||||||
1864,
|
1864,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -96,8 +96,8 @@ typedef enum {
|
|||||||
ISN_ENDTRY, // take entry off from ec_trystack
|
ISN_ENDTRY, // take entry off from ec_trystack
|
||||||
|
|
||||||
// more expression operations
|
// more expression operations
|
||||||
ISN_ADDLIST,
|
ISN_ADDLIST, // add two lists
|
||||||
ISN_ADDBLOB,
|
ISN_ADDBLOB, // add two blobs
|
||||||
|
|
||||||
// operation with two arguments; isn_arg.op.op_type is exptype_T
|
// operation with two arguments; isn_arg.op.op_type is exptype_T
|
||||||
ISN_OPNR,
|
ISN_OPNR,
|
||||||
@@ -120,6 +120,7 @@ typedef enum {
|
|||||||
ISN_CONCAT,
|
ISN_CONCAT,
|
||||||
ISN_STRINDEX, // [expr] string index
|
ISN_STRINDEX, // [expr] string index
|
||||||
ISN_STRSLICE, // [expr:expr] string slice
|
ISN_STRSLICE, // [expr:expr] string slice
|
||||||
|
ISN_LISTAPPEND, // append to a list, like add()
|
||||||
ISN_LISTINDEX, // [expr] list index
|
ISN_LISTINDEX, // [expr] list index
|
||||||
ISN_LISTSLICE, // [expr:expr] list slice
|
ISN_LISTSLICE, // [expr:expr] list slice
|
||||||
ISN_ANYINDEX, // [expr] runtime index
|
ISN_ANYINDEX, // [expr] runtime index
|
||||||
|
@@ -1494,6 +1494,32 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_LISTAPPEND instruction. Works like add().
|
||||||
|
* Argument count is already checked.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
generate_LISTAPPEND(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type_T *list_type;
|
||||||
|
type_T *item_type;
|
||||||
|
type_T *expected;
|
||||||
|
|
||||||
|
// Caller already checked that list_type is a list.
|
||||||
|
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
||||||
|
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
|
expected = list_type->tt_member;
|
||||||
|
if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
--stack->ga_len; // drop the argument
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate an ISN_DCALL or ISN_UCALL instruction.
|
* Generate an ISN_DCALL or ISN_UCALL instruction.
|
||||||
* Return FAIL if the number of arguments is wrong.
|
* Return FAIL if the number of arguments is wrong.
|
||||||
@@ -2536,8 +2562,26 @@ compile_call(
|
|||||||
|
|
||||||
// builtin function
|
// builtin function
|
||||||
idx = find_internal_func(name);
|
idx = find_internal_func(name);
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
if (STRCMP(name, "add") == 0 && argcount == 2)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type_T *type = ((type_T **)stack->ga_data)[
|
||||||
|
stack->ga_len - 2];
|
||||||
|
|
||||||
|
// TODO: also check for VAR_BLOB
|
||||||
|
if (type->tt_type == VAR_LIST)
|
||||||
|
{
|
||||||
|
// inline "add(list, item)" so that the type can be checked
|
||||||
|
res = generate_LISTAPPEND(cctx);
|
||||||
|
idx = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
|
res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
semsg(_(e_unknownfunc), namebuf);
|
semsg(_(e_unknownfunc), namebuf);
|
||||||
goto theend;
|
goto theend;
|
||||||
@@ -7656,6 +7700,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_FOR:
|
case ISN_FOR:
|
||||||
case ISN_GETITEM:
|
case ISN_GETITEM:
|
||||||
case ISN_JUMP:
|
case ISN_JUMP:
|
||||||
|
case ISN_LISTAPPEND:
|
||||||
case ISN_LISTINDEX:
|
case ISN_LISTINDEX:
|
||||||
case ISN_LISTSLICE:
|
case ISN_LISTSLICE:
|
||||||
case ISN_LOAD:
|
case ISN_LOAD:
|
||||||
|
@@ -2095,6 +2095,7 @@ call_def_function(
|
|||||||
|| *skipwhite(tv->vval.v_string) == NUL)
|
|| *skipwhite(tv->vval.v_string) == NUL)
|
||||||
{
|
{
|
||||||
vim_free(tv->vval.v_string);
|
vim_free(tv->vval.v_string);
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
emsg(_(e_throw_with_empty_string));
|
emsg(_(e_throw_with_empty_string));
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
@@ -2282,6 +2283,7 @@ call_def_function(
|
|||||||
typval_T *tv1 = STACK_TV_BOT(-2);
|
typval_T *tv1 = STACK_TV_BOT(-2);
|
||||||
typval_T *tv2 = STACK_TV_BOT(-1);
|
typval_T *tv2 = STACK_TV_BOT(-1);
|
||||||
|
|
||||||
|
// add two lists or blobs
|
||||||
if (iptr->isn_type == ISN_ADDLIST)
|
if (iptr->isn_type == ISN_ADDLIST)
|
||||||
eval_addlist(tv1, tv2);
|
eval_addlist(tv1, tv2);
|
||||||
else
|
else
|
||||||
@@ -2291,6 +2293,25 @@ call_def_function(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ISN_LISTAPPEND:
|
||||||
|
{
|
||||||
|
typval_T *tv1 = STACK_TV_BOT(-2);
|
||||||
|
typval_T *tv2 = STACK_TV_BOT(-1);
|
||||||
|
list_T *l = tv1->vval.v_list;
|
||||||
|
|
||||||
|
// add an item to a list
|
||||||
|
if (l == NULL)
|
||||||
|
{
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
emsg(_(e_cannot_add_to_null_list));
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
if (list_append_tv(l, tv2) == FAIL)
|
||||||
|
goto failed;
|
||||||
|
--ectx.ec_stack.ga_len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// Computation with two arguments of unknown type
|
// Computation with two arguments of unknown type
|
||||||
case ISN_OPANY:
|
case ISN_OPANY:
|
||||||
{
|
{
|
||||||
@@ -3410,6 +3431,7 @@ ex_disassemble(exarg_T *eap)
|
|||||||
case ISN_CONCAT: smsg("%4d CONCAT", current); break;
|
case ISN_CONCAT: smsg("%4d CONCAT", current); break;
|
||||||
case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
|
case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
|
||||||
case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
|
case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
|
||||||
|
case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break;
|
||||||
case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
|
case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
|
||||||
case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
|
case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
|
||||||
case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
|
case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
|
||||||
|
Reference in New Issue
Block a user