Patch 8.2.1931
Problem:    Vim9: arguments of extend() not checked at compile time.
Solution:   Add argument type checking for extend().
Files:      src/evalfunc.c, src/testdir/test_vim9_builtin.vim


*** ../vim-8.2.1930/src/evalfunc.c      2020-10-22 12:31:45.841100292 +0200
--- src/evalfunc.c      2020-10-31 19:18:16.478754547 +0100
***************
*** 276,281 ****
--- 276,284 ----
  // E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
  typedef int (*argcheck_T)(type_T *, argcontext_T *);
  
+ /*
+  * Check "type" is a float or a number.
+  */
      static int
  arg_float_or_nr(type_T *type, argcontext_T *context)
  {
***************
*** 286,297 ****
--- 289,315 ----
      return FAIL;
  }
  
+ /*
+  * Check "type" is a number.
+  */
      static int
  arg_number(type_T *type, argcontext_T *context)
  {
      return check_type(&t_number, type, TRUE, context->arg_idx + 1);
  }
  
+ /*
+  * Check "type" is a string.
+  */
+     static int
+ arg_string(type_T *type, argcontext_T *context)
+ {
+     return check_type(&t_string, type, TRUE, context->arg_idx + 1);
+ }
+ 
+ /*
+  * Check "type" is a list or a blob.
+  */
      static int
  arg_list_or_blob(type_T *type, argcontext_T *context)
  {
***************
*** 303,309 ****
  }
  
  /*
!  * Check the type is an item of the list or blob of the previous arg.
   * Must not be used for the first argcheck_T entry.
   */
      static int
--- 321,352 ----
  }
  
  /*
!  * Check "type" is a list or a dict.
!  */
!     static int
! arg_list_or_dict(type_T *type, argcontext_T *context)
! {
!     if (type->tt_type == VAR_ANY
!                    || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
!       return OK;
!     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
!     return FAIL;
! }
! 
! /*
!  * Check "type" is the same type as the previous argument
!  * Must not be used for the first argcheck_T entry.
!  */
!     static int
! arg_same_as_prev(type_T *type, argcontext_T *context)
! {
!     type_T *prev_type = context->arg_types[context->arg_idx - 1];
! 
!     return check_type(prev_type, type, TRUE, context->arg_idx + 1);
! }
! 
! /*
!  * Check "type" is an item of the list or blob of the previous arg.
   * Must not be used for the first argcheck_T entry.
   */
      static int
***************
*** 324,332 ****
--- 367,393 ----
  }
  
  /*
+  * Check "type" which is the third argument of extend().
+  */
+     static int
+ arg_extend3(type_T *type, argcontext_T *context)
+ {
+     type_T *first_type = context->arg_types[context->arg_idx - 2];
+ 
+     if (first_type->tt_type == VAR_LIST)
+       return arg_number(type, context);
+     if (first_type->tt_type == VAR_DICT)
+       return arg_string(type, context);
+     return OK;
+ }
+ 
+ 
+ /*
   * Lists of functions that check the argument types of a builtin function.
   */
  argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
+ argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
+ argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
  argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
  
  /*
***************
*** 567,573 ****
                        ret_any,            FLOAT_FUNC(f_abs)},
      {"acos",          1, 1, FEARG_1,      NULL,
                        ret_float,          FLOAT_FUNC(f_acos)},
!     {"add",           2, 2, FEARG_1,      NULL,
                        ret_first_arg,      f_add},
      {"and",           2, 2, FEARG_1,      NULL,
                        ret_number,         f_and},
--- 628,634 ----
                        ret_any,            FLOAT_FUNC(f_abs)},
      {"acos",          1, 1, FEARG_1,      NULL,
                        ret_float,          FLOAT_FUNC(f_acos)},
!     {"add",           2, 2, FEARG_1,      NULL /* arg2_listblob_item */,
                        ret_first_arg,      f_add},
      {"and",           2, 2, FEARG_1,      NULL,
                        ret_number,         f_and},
***************
*** 793,799 ****
                        ret_any,            f_expand},
      {"expandcmd",     1, 1, FEARG_1,      NULL,
                        ret_string,         f_expandcmd},
!     {"extend",                2, 3, FEARG_1,      NULL,
                        ret_first_arg,      f_extend},
      {"feedkeys",      1, 2, FEARG_1,      NULL,
                        ret_void,           f_feedkeys},
--- 854,860 ----
                        ret_any,            f_expand},
      {"expandcmd",     1, 1, FEARG_1,      NULL,
                        ret_string,         f_expandcmd},
!     {"extend",                2, 3, FEARG_1,      arg23_extend,
                        ret_first_arg,      f_extend},
      {"feedkeys",      1, 2, FEARG_1,      NULL,
                        ret_void,           f_feedkeys},
*** ../vim-8.2.1930/src/testdir/test_vim9_builtin.vim   2020-10-22 
18:23:34.429289412 +0200
--- src/testdir/test_vim9_builtin.vim   2020-10-31 19:29:19.728469511 +0100
***************
*** 191,196 ****
--- 191,214 ----
    close
  enddef
  
+ def Test_extend_arg_types()
+   assert_equal([1, 2, 3], extend([1, 2], [3]))
+   assert_equal([3, 1, 2], extend([1, 2], [3], 0))
+   assert_equal([1, 3, 2], extend([1, 2], [3], 1))
+ 
+   assert_equal(#{a: 1, b: 2, c: 3}, extend(#{a: 1, b: 2}, #{c: 3}))
+   assert_equal(#{a: 1, b: 4}, extend(#{a: 1, b: 2}, #{b: 4}))
+   assert_equal(#{a: 1, b: 2}, extend(#{a: 1, b: 2}, #{b: 4}, 'keep'))
+ 
+   CheckDefFailure(['extend([1, 2], 3)'], 'E1013: Argument 2: type mismatch, 
expected list<number> but got number')
+   CheckDefFailure(['extend([1, 2], ["x"])'], 'E1013: Argument 2: type 
mismatch, expected list<number> but got list<string>')
+   CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type 
mismatch, expected number but got string')
+ 
+   CheckDefFailure(['extend(#{a: 1}, 42)'], 'E1013: Argument 2: type mismatch, 
expected dict<number> but got number')
+   CheckDefFailure(['extend(#{a: 1}, #{b: "x"})'], 'E1013: Argument 2: type 
mismatch, expected dict<number> but got dict<string>')
+   CheckDefFailure(['extend(#{a: 1}, #{b: 2}, 1)'], 'E1013: Argument 3: type 
mismatch, expected string but got number')
+ enddef
+ 
  def Test_extend_return_type()
    var l = extend([1, 2], [3])
    var res = 0
*** ../vim-8.2.1930/src/version.c       2020-10-31 16:33:42.847372387 +0100
--- src/version.c       2020-10-31 17:22:20.908239569 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1931,
  /**/

-- 
You're as much use as a condom machine at the Vatican.
                  -- Rimmer to Holly in Red Dwarf 'Queeg'

 /// 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/202010311834.09VIY5Yb3032653%40masaka.moolenaar.net.

Raspunde prin e-mail lui