Patch 8.2.2362
Problem:    Vim9: check of builtin function argument type is incomplete.
Solution:   Use need_type() instead of check_arg_type().
Files:      src/vim9compile.c, src/proto/vim9compile.pro, src/evalfunc.c,
            src/proto/evalfunc.pro, src/vim9type.c, src/proto/vim9type.pro,
            src/testdir/test_vim9_builtin.vim


*** ../vim-8.2.2361/src/vim9compile.c   2021-01-14 20:35:46.254002151 +0100
--- src/vim9compile.c   2021-01-16 15:56:19.864363365 +0100
***************
*** 878,888 ****
   * If "actual_is_const" is TRUE then the type won't change at runtime, do not
   * generate a TYPECHECK.
   */
!     static int
  need_type(
        type_T  *actual,
        type_T  *expected,
        int     offset,
        cctx_T  *cctx,
        int     silent,
        int     actual_is_const)
--- 878,889 ----
   * If "actual_is_const" is TRUE then the type won't change at runtime, do not
   * generate a TYPECHECK.
   */
!     int
  need_type(
        type_T  *actual,
        type_T  *expected,
        int     offset,
+       int     arg_idx,
        cctx_T  *cctx,
        int     silent,
        int     actual_is_const)
***************
*** 896,902 ****
        return OK;
      }
  
!     if (check_type(expected, actual, FALSE, 0) == OK)
        return OK;
  
      // If the actual type can be the expected type add a runtime check.
--- 897,903 ----
        return OK;
      }
  
!     if (check_type(expected, actual, FALSE, arg_idx) == OK)
        return OK;
  
      // If the actual type can be the expected type add a runtime check.
***************
*** 908,914 ****
      }
  
      if (!silent)
!       type_mismatch(expected, actual);
      return FAIL;
  }
  
--- 909,915 ----
      }
  
      if (!silent)
!       arg_type_mismatch(expected, actual, arg_idx);
      return FAIL;
  }
  
***************
*** 931,937 ****
        // This requires a runtime type check.
        return generate_COND2BOOL(cctx);
  
!     return need_type(type, &t_bool, -1, cctx, FALSE, FALSE);
  }
  
  /*
--- 932,938 ----
        // This requires a runtime type check.
        return generate_COND2BOOL(cctx);
  
!     return need_type(type, &t_bool, -1, 0, cctx, FALSE, FALSE);
  }
  
  /*
***************
*** 1613,1619 ****
      {
        // Check the types of the arguments.
        argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
!       if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
            return FAIL;
        if (internal_func_is_map(func_idx))
            maptype = *argtypes;
--- 1614,1621 ----
      {
        // Check the types of the arguments.
        argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
!       if (internal_func_check_arg_types(argtypes, func_idx, argcount,
!                                                                cctx) == FAIL)
            return FAIL;
        if (internal_func_is_map(func_idx))
            maptype = *argtypes;
***************
*** 1656,1662 ****
      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)
--- 1658,1664 ----
      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, 0, cctx, FALSE, FALSE) == FAIL)
        return FAIL;
  
      if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
***************
*** 1678,1684 ****
  
      // Caller already checked that blob_type is a blob.
      item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
!     if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
        return FAIL;
  
      if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
--- 1680,1686 ----
  
      // Caller already checked that blob_type is a blob.
      item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
!     if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
        return FAIL;
  
      if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
***************
*** 1733,1739 ****
            else
                expected = ufunc->uf_va_type->tt_member;
            actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
!           if (need_type(actual, expected, -argcount + i, cctx,
                                                          TRUE, FALSE) == FAIL)
            {
                arg_type_mismatch(expected, actual, i + 1);
--- 1735,1741 ----
            else
                expected = ufunc->uf_va_type->tt_member;
            actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
!           if (need_type(actual, expected, -argcount + i, 0, cctx,
                                                          TRUE, FALSE) == FAIL)
            {
                arg_type_mismatch(expected, actual, i + 1);
***************
*** 1850,1856 ****
                                             type->tt_argcount - 1]->tt_member;
                    else
                        expected = type->tt_args[i];
!                   if (need_type(actual, expected, offset,
                                                    cctx, TRUE, FALSE) == FAIL)
                    {
                        arg_type_mismatch(expected, actual, i + 1);
--- 1852,1858 ----
                                             type->tt_argcount - 1]->tt_member;
                    else
                        expected = type->tt_args[i];
!                   if (need_type(actual, expected, offset, 0,
                                                    cctx, TRUE, FALSE) == FAIL)
                    {
                        arg_type_mismatch(expected, actual, i + 1);
***************
*** 3135,3141 ****
            {
                type_T *keytype = ((type_T **)stack->ga_data)
                                                       [stack->ga_len - 1];
!               if (need_type(keytype, &t_string, -1, cctx,
                                                     FALSE, FALSE) == FAIL)
                    return FAIL;
            }
--- 3137,3143 ----
            {
                type_T *keytype = ((type_T **)stack->ga_data)
                                                       [stack->ga_len - 1];
!               if (need_type(keytype, &t_string, -1, 0, cctx,
                                                     FALSE, FALSE) == FAIL)
                    return FAIL;
            }
***************
*** 3808,3820 ****
                vtype = VAR_DICT;
            if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
            {
!               if (need_type(valtype, &t_number, -1, cctx,
                                                         FALSE, 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, FALSE) == FAIL)
                        return FAIL;
                }
--- 3810,3822 ----
                vtype = VAR_DICT;
            if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
            {
!               if (need_type(valtype, &t_number, -1, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
                    return FAIL;
                if (is_slice)
                {
                    valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
!                   if (need_type(valtype, &t_number, -2, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
                        return FAIL;
                }
***************
*** 3836,3842 ****
                }
                else
                {
!                   if (need_type(*typep, &t_dict_any, -2, cctx,
                                                         FALSE, FALSE) == FAIL)
                        return FAIL;
                    *typep = &t_any;
--- 3838,3844 ----
                }
                else
                {
!                   if (need_type(*typep, &t_dict_any, -2, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
                        return FAIL;
                    *typep = &t_any;
***************
*** 4235,4241 ****
        actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
        if (check_type(want_type, actual, FALSE, 0) == FAIL)
        {
!           if (need_type(actual, want_type, -1, cctx, FALSE, FALSE) == FAIL)
                return FAIL;
        }
      }
--- 4237,4243 ----
        actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
        if (check_type(want_type, actual, FALSE, 0) == FAIL)
        {
!           if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
                return FAIL;
        }
      }
***************
*** 4917,4923 ****
                    return NULL;
                }
                if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
!                                                  cctx, FALSE, FALSE) == FAIL)
                    return NULL;
            }
        }
--- 4919,4925 ----
                    return NULL;
                }
                if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
!                                               0, cctx, FALSE, FALSE) == FAIL)
                    return NULL;
            }
        }
***************
*** 5831,5837 ****
                  : ((type_T **)stack->ga_data)[stack->ga_len - 1];
        // now we can properly check the type
        if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
!               && need_type(rhs_type, lhs->lhs_type->tt_member, -2, cctx,
                                                         FALSE, FALSE) == FAIL)
            return FAIL;
      }
--- 5833,5839 ----
                  : ((type_T **)stack->ga_data)[stack->ga_len - 1];
        // now we can properly check the type
        if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
!               && need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
            return FAIL;
      }
***************
*** 5976,5982 ****
                emsg(_(e_cannot_use_void_value));
                goto theend;
            }
!           if (need_type(stacktype, &t_list_any, -1, cctx,
                                                         FALSE, FALSE) == FAIL)
                goto theend;
            // TODO: check the length of a constant list here
--- 5978,5984 ----
                emsg(_(e_cannot_use_void_value));
                goto theend;
            }
!           if (need_type(stacktype, &t_list_any, -1, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
                goto theend;
            // TODO: check the length of a constant list here
***************
*** 6123,6135 ****
                        // without operator check type here, otherwise below
                        if (lhs.lhs_has_index)
                            use_type = lhs.lhs_member_type;
!                       if (need_type(rhs_type, use_type, -1, cctx,
                                                      FALSE, is_const) == FAIL)
                            goto theend;
                    }
                }
                else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
!                                              -1, cctx, FALSE, FALSE) == FAIL)
                    goto theend;
            }
            else if (cmdidx == CMD_final)
--- 6125,6137 ----
                        // without operator check type here, otherwise below
                        if (lhs.lhs_has_index)
                            use_type = lhs.lhs_member_type;
!                       if (need_type(rhs_type, use_type, -1, 0, cctx,
                                                      FALSE, is_const) == FAIL)
                            goto theend;
                    }
                }
                else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
!                                           -1, 0, cctx, FALSE, FALSE) == FAIL)
                    goto theend;
            }
            else if (cmdidx == CMD_final)
***************
*** 6216,6222 ****
                // If variable is float operation with number is OK.
                !(expected == &t_float && stacktype == &t_number) &&
  #endif
!                   need_type(stacktype, expected, -1, cctx,
                                                         FALSE, FALSE) == FAIL)
                goto theend;
  
--- 6218,6224 ----
                // If variable is float operation with number is OK.
                !(expected == &t_float && stacktype == &t_number) &&
  #endif
!                   need_type(stacktype, expected, -1, 0, cctx,
                                                         FALSE, FALSE) == FAIL)
                goto theend;
  
***************
*** 6925,6931 ****
      // Now that we know the type of "var", check that it is a list, now or at
      // runtime.
      vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
!     if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL)
      {
        drop_scope(cctx);
        return NULL;
--- 6927,6933 ----
      // Now that we know the type of "var", check that it is a list, now or at
      // runtime.
      vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
!     if (need_type(vartype, &t_list_any, -1, 0, cctx, FALSE, FALSE) == FAIL)
      {
        drop_scope(cctx);
        return NULL;
*** ../vim-8.2.2361/src/proto/vim9compile.pro   2021-01-09 15:45:20.353451132 
+0100
--- src/proto/vim9compile.pro   2021-01-16 15:41:13.938984124 +0100
***************
*** 2,7 ****
--- 2,8 ----
  int check_defined(char_u *p, size_t len, cctx_T *cctx);
  int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
  int use_typecheck(type_T *actual, type_T *expected);
+ int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
  int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T 
*cctx);
  imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
  imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
*** ../vim-8.2.2361/src/evalfunc.c      2021-01-13 21:46:53.832589880 +0100
--- src/evalfunc.c      2021-01-16 15:59:15.951901386 +0100
***************
*** 275,280 ****
--- 275,281 ----
      int               arg_count;      // actual argument count
      type_T    **arg_types;    // list of argument types
      int               arg_idx;        // current argument index (first arg is 
zero)
+     cctx_T    *arg_cctx;
  } argcontext_T;
  
  // A function to check one argument type.  The first argument is the type to
***************
*** 283,288 ****
--- 284,305 ----
  typedef int (*argcheck_T)(type_T *, argcontext_T *);
  
  /*
+  * Call need_type() to check an argument type.
+  */
+     static int
+ check_arg_type(
+       type_T          *expected,
+       type_T          *actual,
+       argcontext_T    *context)
+ {
+     // TODO: would be useful to know if "actual" is a constant and pass it to
+     // need_type() to get a compile time error if possible.
+     return need_type(actual, expected,
+           context->arg_idx - context->arg_count, context->arg_idx + 1,
+           context->arg_cctx, FALSE, FALSE);
+ }
+ 
+ /*
   * Check "type" is a float or a number.
   */
      static int
***************
*** 301,307 ****
      static int
  arg_number(type_T *type, argcontext_T *context)
  {
!     return check_arg_type(&t_number, type, context->arg_idx + 1);
  }
  
  /*
--- 318,324 ----
      static int
  arg_number(type_T *type, argcontext_T *context)
  {
!     return check_arg_type(&t_number, type, context);
  }
  
  /*
***************
*** 310,316 ****
      static int
  arg_string(type_T *type, argcontext_T *context)
  {
!     return check_arg_type(&t_string, type, context->arg_idx + 1);
  }
  
  /*
--- 327,333 ----
      static int
  arg_string(type_T *type, argcontext_T *context)
  {
!     return check_arg_type(&t_string, type, context);
  }
  
  /*
***************
*** 348,354 ****
  {
      type_T *prev_type = context->arg_types[context->arg_idx - 1];
  
!     return check_arg_type(prev_type, type, context->arg_idx + 1);
  }
  
  /*
--- 365,371 ----
  {
      type_T *prev_type = context->arg_types[context->arg_idx - 1];
  
!     return check_arg_type(prev_type, type, context);
  }
  
  /*
***************
*** 362,368 ****
      type_T *prev_type = context->arg_types[context->arg_idx - 1];
  
      if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
!       return check_arg_type(prev_type, type, context->arg_idx + 1);
      return OK;
  }
  
--- 379,385 ----
      type_T *prev_type = context->arg_types[context->arg_idx - 1];
  
      if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
!       return check_arg_type(prev_type, type, context);
      return OK;
  }
  
***************
*** 384,390 ****
        // probably VAR_ANY, can't check
        return OK;
  
!     return check_arg_type(expected, type, context->arg_idx + 1);
  }
  
  /*
--- 401,407 ----
        // probably VAR_ANY, can't check
        return OK;
  
!     return check_arg_type(expected, type, context);
  }
  
  /*
***************
*** 1931,1937 ****
   * Return FAIL and gives an error message when a type is wrong.
   */
      int
! internal_func_check_arg_types(type_T **types, int idx, int argcount)
  {
      argcheck_T        *argchecks = global_functions[idx].f_argcheck;
      int               i;
--- 1948,1958 ----
   * Return FAIL and gives an error message when a type is wrong.
   */
      int
! internal_func_check_arg_types(
!       type_T  **types,
!       int     idx,
!       int     argcount,
!       cctx_T  *cctx)
  {
      argcheck_T        *argchecks = global_functions[idx].f_argcheck;
      int               i;
***************
*** 1942,1947 ****
--- 1963,1969 ----
  
        context.arg_count = argcount;
        context.arg_types = types;
+       context.arg_cctx = cctx;
        for (i = 0; i < argcount; ++i)
            if (argchecks[i] != NULL)
            {
*** ../vim-8.2.2361/src/proto/evalfunc.pro      2021-01-10 22:42:46.916847071 
+0100
--- src/proto/evalfunc.pro      2021-01-16 15:48:51.973585991 +0100
***************
*** 4,10 ****
  int find_internal_func(char_u *name);
  int has_internal_func(char_u *name);
  char *internal_func_name(int idx);
! int internal_func_check_arg_types(type_T **types, int idx, int argcount);
  type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
  int internal_func_is_map(int idx);
  int check_internal_func(int idx, int argcount);
--- 4,10 ----
  int find_internal_func(char_u *name);
  int has_internal_func(char_u *name);
  char *internal_func_name(int idx);
! int internal_func_check_arg_types(type_T **types, int idx, int argcount, 
cctx_T *cctx);
  type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
  int internal_func_is_map(int idx);
  int check_internal_func(int idx, int argcount);
*** ../vim-8.2.2361/src/vim9type.c      2021-01-12 21:48:55.879131998 +0100
--- src/vim9type.c      2021-01-16 15:55:18.936525110 +0100
***************
*** 514,538 ****
  }
  
  /*
-  * Like check_type() but also allow for a runtime type check. E.g. "any" can 
be
-  * used for "number".
-  */
-     int
- check_arg_type(type_T *expected, type_T *actual, int argidx)
- {
-     if (check_type(expected, actual, FALSE, 0) == OK
-                                           || use_typecheck(actual, expected))
-       return OK;
-     // TODO: should generate a TYPECHECK instruction.
-     return check_type(expected, actual, TRUE, argidx);
- }
- 
- /*
   * Check that the arguments of "type" match "argvars[argcount]".
   * Return OK/FAIL.
   */
      int
! check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u 
*name)
  {
      int           varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
      int           i;
--- 514,528 ----
  }
  
  /*
   * Check that the arguments of "type" match "argvars[argcount]".
   * Return OK/FAIL.
   */
      int
! check_argument_types(
!       type_T      *type,
!       typval_T    *argvars,
!       int         argcount,
!       char_u      *name)
  {
      int           varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
      int           i;
*** ../vim-8.2.2361/src/proto/vim9type.pro      2021-01-12 21:48:55.879131998 
+0100
--- src/proto/vim9type.pro      2021-01-16 15:48:56.185574013 +0100
***************
*** 15,21 ****
  void type_mismatch(type_T *expected, type_T *actual);
  void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
  int check_type(type_T *expected, type_T *actual, int give_msg, int argidx);
- int check_arg_type(type_T *expected, type_T *actual, int argidx);
  int check_argument_types(type_T *type, typval_T *argvars, int argcount, 
char_u *name);
  char_u *skip_type(char_u *start, int optional);
  type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
--- 15,20 ----
*** ../vim-8.2.2361/src/testdir/test_vim9_builtin.vim   2021-01-13 
21:46:53.832589880 +0100
--- src/testdir/test_vim9_builtin.vim   2021-01-16 16:04:27.403098215 +0100
***************
*** 241,246 ****
--- 241,249 ----
    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')
+ 
+   CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, 
expected list<number> but got list<string>')
+   CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1012: Type mismatch; 
expected list<number> but got list<any>')
  enddef
  
  def Test_extendnew()
*** ../vim-8.2.2361/src/version.c       2021-01-16 14:34:42.219758927 +0100
--- src/version.c       2021-01-16 15:34:23.844532727 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2362,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
164. You got out to buy software, instead of going out for a beer.

 /// 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/202101161507.10GF7Ttf299688%40masaka.moolenaar.net.

Raspunde prin e-mail lui