Mirror of the Vim source from https://github.com/vim/vim
Revision | 6589dae9696ca885fffe441205be849230e9750f (tree) |
---|---|
Time | 2020-10-20 02:15:04 |
Author | Bram Moolenaar <Bram@vim....> |
Commiter | Bram Moolenaar |
patch 8.2.1865: Vim9: add() does not check type of argument
Commit: https://github.com/vim/vim/commit/1dcae59957301b6b19aef49af648715f911a1378
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Oct 19 19:02:42 2020 +0200
@@ -282,4 +282,6 @@ | ||
282 | 282 | INIT(= N_("E1128: } without {")); |
283 | 283 | EXTERN char e_throw_with_empty_string[] |
284 | 284 | INIT(= N_("E1129: Throw with empty string")); |
285 | +EXTERN char e_cannot_add_to_null_list[] | |
286 | + INIT(= N_("E1130: Cannot add to null list")); | |
285 | 287 | #endif |
@@ -273,6 +273,34 @@ | ||
273 | 273 | res) |
274 | 274 | enddef |
275 | 275 | |
276 | +def s:ListAdd() | |
277 | + var l: list<number> = [] | |
278 | + add(l, 123) | |
279 | + add(l, g:aNumber) | |
280 | +enddef | |
281 | + | |
282 | +def Test_disassemble_list_add() | |
283 | + var res = execute('disass s:ListAdd') | |
284 | + assert_match('<SNR>\d*_ListAdd\_s*' .. | |
285 | + 'var l: list<number> = []\_s*' .. | |
286 | + '\d NEWLIST size 0\_s*' .. | |
287 | + '\d STORE $0\_s*' .. | |
288 | + 'add(l, 123)\_s*' .. | |
289 | + '\d LOAD $0\_s*' .. | |
290 | + '\d PUSHNR 123\_s*' .. | |
291 | + '\d LISTAPPEND\_s*' .. | |
292 | + '\d DROP\_s*' .. | |
293 | + 'add(l, g:aNumber)\_s*' .. | |
294 | + '\d LOAD $0\_s*' .. | |
295 | + '\d\+ LOADG g:aNumber\_s*' .. | |
296 | + '\d\+ CHECKTYPE number stack\[-1\]\_s*' .. | |
297 | + '\d\+ LISTAPPEND\_s*' .. | |
298 | + '\d\+ DROP\_s*' .. | |
299 | + '\d\+ PUSHNR 0\_s*' .. | |
300 | + '\d\+ RETURN', | |
301 | + res) | |
302 | +enddef | |
303 | + | |
276 | 304 | def s:ScriptFuncUnlet() |
277 | 305 | g:somevar = "value" |
278 | 306 | unlet g:somevar |
@@ -803,7 +831,7 @@ | ||
803 | 831 | 'res->add(i)\_s*' .. |
804 | 832 | '\d LOAD $0\_s*' .. |
805 | 833 | '\d LOAD $2\_s*' .. |
806 | - '\d\+ BCALL add(argc 2)\_s*' .. | |
834 | + '\d\+ LISTAPPEND\_s*' .. | |
807 | 835 | '\d\+ DROP\_s*' .. |
808 | 836 | 'endfor\_s*' .. |
809 | 837 | '\d\+ JUMP -> \d\+\_s*' .. |
@@ -1772,6 +1772,24 @@ | ||
1772 | 1772 | list2str(l, true)->assert_equal(s) |
1773 | 1773 | enddef |
1774 | 1774 | |
1775 | +def Test_list_add() | |
1776 | + var l: list<number> # defaults to empty list | |
1777 | + add(l, 9) | |
1778 | + assert_equal([9], l) | |
1779 | + | |
1780 | + var lines =<< trim END | |
1781 | + var l: list<number> | |
1782 | + add(l, "x") | |
1783 | + END | |
1784 | + CheckDefFailure(lines, 'E1012:', 2) | |
1785 | + | |
1786 | + lines =<< trim END | |
1787 | + var l: list<number> = test_null_list() | |
1788 | + add(l, 123) | |
1789 | + END | |
1790 | + CheckDefExecFailure(lines, 'E1130:', 2) | |
1791 | +enddef | |
1792 | + | |
1775 | 1793 | def SID(): number |
1776 | 1794 | return expand('<SID>') |
1777 | 1795 | ->matchstr('<SNR>\zs\d\+\ze_$') |
@@ -751,6 +751,8 @@ | ||
751 | 751 | static int included_patches[] = |
752 | 752 | { /* Add new patch number below this line */ |
753 | 753 | /**/ |
754 | + 1865, | |
755 | +/**/ | |
754 | 756 | 1864, |
755 | 757 | /**/ |
756 | 758 | 1863, |
@@ -96,8 +96,8 @@ | ||
96 | 96 | ISN_ENDTRY, // take entry off from ec_trystack |
97 | 97 | |
98 | 98 | // more expression operations |
99 | - ISN_ADDLIST, | |
100 | - ISN_ADDBLOB, | |
99 | + ISN_ADDLIST, // add two lists | |
100 | + ISN_ADDBLOB, // add two blobs | |
101 | 101 | |
102 | 102 | // operation with two arguments; isn_arg.op.op_type is exptype_T |
103 | 103 | ISN_OPNR, |
@@ -120,6 +120,7 @@ | ||
120 | 120 | ISN_CONCAT, |
121 | 121 | ISN_STRINDEX, // [expr] string index |
122 | 122 | ISN_STRSLICE, // [expr:expr] string slice |
123 | + ISN_LISTAPPEND, // append to a list, like add() | |
123 | 124 | ISN_LISTINDEX, // [expr] list index |
124 | 125 | ISN_LISTSLICE, // [expr:expr] list slice |
125 | 126 | ISN_ANYINDEX, // [expr] runtime index |
@@ -1495,6 +1495,32 @@ | ||
1495 | 1495 | } |
1496 | 1496 | |
1497 | 1497 | /* |
1498 | + * Generate an ISN_LISTAPPEND instruction. Works like add(). | |
1499 | + * Argument count is already checked. | |
1500 | + */ | |
1501 | + static int | |
1502 | +generate_LISTAPPEND(cctx_T *cctx) | |
1503 | +{ | |
1504 | + garray_T *stack = &cctx->ctx_type_stack; | |
1505 | + type_T *list_type; | |
1506 | + type_T *item_type; | |
1507 | + type_T *expected; | |
1508 | + | |
1509 | + // Caller already checked that list_type is a list. | |
1510 | + list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2]; | |
1511 | + item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | |
1512 | + expected = list_type->tt_member; | |
1513 | + if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL) | |
1514 | + return FAIL; | |
1515 | + | |
1516 | + if (generate_instr(cctx, ISN_LISTAPPEND) == NULL) | |
1517 | + return FAIL; | |
1518 | + | |
1519 | + --stack->ga_len; // drop the argument | |
1520 | + return OK; | |
1521 | +} | |
1522 | + | |
1523 | +/* | |
1498 | 1524 | * Generate an ISN_DCALL or ISN_UCALL instruction. |
1499 | 1525 | * Return FAIL if the number of arguments is wrong. |
1500 | 1526 | */ |
@@ -2537,7 +2563,25 @@ | ||
2537 | 2563 | // builtin function |
2538 | 2564 | idx = find_internal_func(name); |
2539 | 2565 | if (idx >= 0) |
2540 | - res = generate_BCALL(cctx, idx, argcount, argcount_init == 1); | |
2566 | + { | |
2567 | + if (STRCMP(name, "add") == 0 && argcount == 2) | |
2568 | + { | |
2569 | + garray_T *stack = &cctx->ctx_type_stack; | |
2570 | + type_T *type = ((type_T **)stack->ga_data)[ | |
2571 | + stack->ga_len - 2]; | |
2572 | + | |
2573 | + // TODO: also check for VAR_BLOB | |
2574 | + if (type->tt_type == VAR_LIST) | |
2575 | + { | |
2576 | + // inline "add(list, item)" so that the type can be checked | |
2577 | + res = generate_LISTAPPEND(cctx); | |
2578 | + idx = -1; | |
2579 | + } | |
2580 | + } | |
2581 | + | |
2582 | + if (idx >= 0) | |
2583 | + res = generate_BCALL(cctx, idx, argcount, argcount_init == 1); | |
2584 | + } | |
2541 | 2585 | else |
2542 | 2586 | semsg(_(e_unknownfunc), namebuf); |
2543 | 2587 | goto theend; |
@@ -7656,6 +7700,7 @@ | ||
7656 | 7700 | case ISN_FOR: |
7657 | 7701 | case ISN_GETITEM: |
7658 | 7702 | case ISN_JUMP: |
7703 | + case ISN_LISTAPPEND: | |
7659 | 7704 | case ISN_LISTINDEX: |
7660 | 7705 | case ISN_LISTSLICE: |
7661 | 7706 | case ISN_LOAD: |
@@ -2095,6 +2095,7 @@ | ||
2095 | 2095 | || *skipwhite(tv->vval.v_string) == NUL) |
2096 | 2096 | { |
2097 | 2097 | vim_free(tv->vval.v_string); |
2098 | + SOURCING_LNUM = iptr->isn_lnum; | |
2098 | 2099 | emsg(_(e_throw_with_empty_string)); |
2099 | 2100 | goto failed; |
2100 | 2101 | } |
@@ -2282,6 +2283,7 @@ | ||
2282 | 2283 | typval_T *tv1 = STACK_TV_BOT(-2); |
2283 | 2284 | typval_T *tv2 = STACK_TV_BOT(-1); |
2284 | 2285 | |
2286 | + // add two lists or blobs | |
2285 | 2287 | if (iptr->isn_type == ISN_ADDLIST) |
2286 | 2288 | eval_addlist(tv1, tv2); |
2287 | 2289 | else |
@@ -2291,6 +2293,25 @@ | ||
2291 | 2293 | } |
2292 | 2294 | break; |
2293 | 2295 | |
2296 | + case ISN_LISTAPPEND: | |
2297 | + { | |
2298 | + typval_T *tv1 = STACK_TV_BOT(-2); | |
2299 | + typval_T *tv2 = STACK_TV_BOT(-1); | |
2300 | + list_T *l = tv1->vval.v_list; | |
2301 | + | |
2302 | + // add an item to a list | |
2303 | + if (l == NULL) | |
2304 | + { | |
2305 | + SOURCING_LNUM = iptr->isn_lnum; | |
2306 | + emsg(_(e_cannot_add_to_null_list)); | |
2307 | + goto on_error; | |
2308 | + } | |
2309 | + if (list_append_tv(l, tv2) == FAIL) | |
2310 | + goto failed; | |
2311 | + --ectx.ec_stack.ga_len; | |
2312 | + } | |
2313 | + break; | |
2314 | + | |
2294 | 2315 | // Computation with two arguments of unknown type |
2295 | 2316 | case ISN_OPANY: |
2296 | 2317 | { |
@@ -3410,6 +3431,7 @@ | ||
3410 | 3431 | case ISN_CONCAT: smsg("%4d CONCAT", current); break; |
3411 | 3432 | case ISN_STRINDEX: smsg("%4d STRINDEX", current); break; |
3412 | 3433 | case ISN_STRSLICE: smsg("%4d STRSLICE", current); break; |
3434 | + case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break; | |
3413 | 3435 | case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break; |
3414 | 3436 | case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break; |
3415 | 3437 | case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break; |