Patch 8.2.1865
Problem:    Vim9: add() does not check type of argument.
Solution:   Inline the add() call. (closes #7160)
Files:      src/vim9.h, src/vim9compile.c, src/vim9execute.c, src/errors.h,
            src/testdir/test_vim9_func.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.1864/src/vim9.h  2020-10-03 22:51:42.890813408 +0200
--- src/vim9.h  2020-10-19 18:14:27.963998794 +0200
***************
*** 96,103 ****
      ISN_ENDTRY,           // take entry off from ec_trystack
  
      // more expression operations
!     ISN_ADDLIST,
!     ISN_ADDBLOB,
  
      // operation with two arguments; isn_arg.op.op_type is exptype_T
      ISN_OPNR,
--- 96,103 ----
      ISN_ENDTRY,           // take entry off from ec_trystack
  
      // more expression operations
!     ISN_ADDLIST,    // add two lists
!     ISN_ADDBLOB,    // add two blobs
  
      // operation with two arguments; isn_arg.op.op_type is exptype_T
      ISN_OPNR,
***************
*** 120,125 ****
--- 120,126 ----
      ISN_CONCAT,
      ISN_STRINDEX,   // [expr] string index
      ISN_STRSLICE,   // [expr:expr] string slice
+     ISN_LISTAPPEND, // append to a list, like add()
      ISN_LISTINDEX,  // [expr] list index
      ISN_LISTSLICE,  // [expr:expr] list slice
      ISN_ANYINDEX,   // [expr] runtime index
*** ../vim-8.2.1864/src/vim9compile.c   2020-10-19 16:07:37.193322741 +0200
--- src/vim9compile.c   2020-10-19 18:35:28.577344915 +0200
***************
*** 1495,1500 ****
--- 1495,1526 ----
  }
  
  /*
+  * 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.
   * Return FAIL if the number of arguments is wrong.
   */
***************
*** 2537,2543 ****
        // builtin function
        idx = find_internal_func(name);
        if (idx >= 0)
!           res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
        else
            semsg(_(e_unknownfunc), namebuf);
        goto theend;
--- 2563,2587 ----
        // builtin function
        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)
!               res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
!       }
        else
            semsg(_(e_unknownfunc), namebuf);
        goto theend;
***************
*** 7656,7661 ****
--- 7700,7706 ----
        case ISN_FOR:
        case ISN_GETITEM:
        case ISN_JUMP:
+       case ISN_LISTAPPEND:
        case ISN_LISTINDEX:
        case ISN_LISTSLICE:
        case ISN_LOAD:
*** ../vim-8.2.1864/src/vim9execute.c   2020-10-17 22:58:17.913317608 +0200
--- src/vim9execute.c   2020-10-19 18:59:06.617794199 +0200
***************
*** 2095,2100 ****
--- 2095,2101 ----
                                       || *skipwhite(tv->vval.v_string) == NUL)
                {
                    vim_free(tv->vval.v_string);
+                   SOURCING_LNUM = iptr->isn_lnum;
                    emsg(_(e_throw_with_empty_string));
                    goto failed;
                }
***************
*** 2282,2287 ****
--- 2283,2289 ----
                    typval_T *tv1 = STACK_TV_BOT(-2);
                    typval_T *tv2 = STACK_TV_BOT(-1);
  
+                   // add two lists or blobs
                    if (iptr->isn_type == ISN_ADDLIST)
                        eval_addlist(tv1, tv2);
                    else
***************
*** 2291,2296 ****
--- 2293,2317 ----
                }
                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
            case ISN_OPANY:
                {
***************
*** 3410,3415 ****
--- 3431,3437 ----
            case ISN_CONCAT: smsg("%4d CONCAT", current); break;
            case ISN_STRINDEX: smsg("%4d STRINDEX", 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_LISTSLICE: smsg("%4d LISTSLICE", current); break;
            case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
*** ../vim-8.2.1864/src/errors.h        2020-10-16 23:16:43.459258200 +0200
--- src/errors.h        2020-10-19 18:36:55.749148167 +0200
***************
*** 282,285 ****
--- 282,287 ----
        INIT(= N_("E1128: } without {"));
  EXTERN char e_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
*** ../vim-8.2.1864/src/testdir/test_vim9_func.vim      2020-10-17 
19:29:47.526935795 +0200
--- src/testdir/test_vim9_func.vim      2020-10-19 18:58:15.089922991 +0200
***************
*** 1772,1777 ****
--- 1772,1795 ----
    list2str(l, true)->assert_equal(s)
  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
    return expand('<SID>')
            ->matchstr('<SNR>\zs\d\+\ze_$')
*** ../vim-8.2.1864/src/testdir/test_vim9_disassemble.vim       2020-10-10 
14:12:58.024646147 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-10-19 18:53:39.646630997 
+0200
***************
*** 273,278 ****
--- 273,306 ----
          res)
  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()
    g:somevar = "value"
    unlet g:somevar
***************
*** 803,809 ****
          'res->add(i)\_s*' ..
          '\d LOAD $0\_s*' ..
          '\d LOAD $2\_s*' ..
!         '\d\+ BCALL add(argc 2)\_s*' ..
          '\d\+ DROP\_s*' ..
          'endfor\_s*' ..
          '\d\+ JUMP -> \d\+\_s*' ..
--- 831,837 ----
          'res->add(i)\_s*' ..
          '\d LOAD $0\_s*' ..
          '\d LOAD $2\_s*' ..
!         '\d\+ LISTAPPEND\_s*' ..
          '\d\+ DROP\_s*' ..
          'endfor\_s*' ..
          '\d\+ JUMP -> \d\+\_s*' ..
*** ../vim-8.2.1864/src/version.c       2020-10-19 16:07:37.193322741 +0200
--- src/version.c       2020-10-19 18:24:34.546489681 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1865,
  /**/

-- 
The primary purpose of the DATA statement is to give names to constants;
instead of referring to pi as 3.141592653589793 at every appearance, the
variable PI can be given that value with a DATA statement and used instead
of the longer form of the constant.  This also simplifies modifying the
program, should the value of pi change.
        -- FORTRAN manual for Xerox Computers

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202010191703.09JH3iKN1188460%40masaka.moolenaar.net.

Raspunde prin e-mail lui