Patch 8.2.0512
Problem:    Vim9: no optional arguments in func type.
Solution:   Check for question mark after type.  Find function reference
            without function().
Files:      src/vim9compile.c, src/vim9execute.c, src/structs.h,
            src/globals.h, src/vim.h, src/vim9.h, src/userfunc.c,
            src/testdir/Make_all.mak, src/testdir/test_vim9_script.vim,
            src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_func.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.0511/src/vim9compile.c   2020-04-03 21:59:29.329665634 +0200
--- src/vim9compile.c   2020-04-05 17:05:23.371164554 +0200
***************
*** 120,126 ****
      scope_T   *ctx_scope;         // current scope, NULL at toplevel
  
      garray_T  ctx_type_stack;     // type of each item on the stack
!     garray_T  *ctx_type_list;     // space for adding types
  };
  
  static char e_var_notfound[] = N_("E1001: variable not found: %s");
--- 120,126 ----
      scope_T   *ctx_scope;         // current scope, NULL at toplevel
  
      garray_T  ctx_type_stack;     // type of each item on the stack
!     garray_T  *ctx_type_list;     // list of pointers to allocated types
  };
  
  static char e_var_notfound[] = N_("E1001: variable not found: %s");
***************
*** 223,228 ****
--- 223,248 ----
      return OK;
  }
  
+ /*
+  * Allocate memory for a type_T and add the pointer to type_gap, so that it 
can
+  * be freed later.
+  */
+     static type_T *
+ alloc_type(garray_T *type_gap)
+ {
+     type_T *type;
+ 
+     if (ga_grow(type_gap, 1) == FAIL)
+       return NULL;
+     type = ALLOC_CLEAR_ONE(type_T);
+     if (type != NULL)
+     {
+       ((type_T **)type_gap->ga_data)[type_gap->ga_len] = type;
+       ++type_gap->ga_len;
+     }
+     return type;
+ }
+ 
      static type_T *
  get_list_type(type_T *member_type, garray_T *type_gap)
  {
***************
*** 241,250 ****
        return &t_list_string;
  
      // Not a common type, create a new entry.
!     if (ga_grow(type_gap, 1) == FAIL)
        return &t_any;
-     type = ((type_T *)type_gap->ga_data) + type_gap->ga_len;
-     ++type_gap->ga_len;
      type->tt_type = VAR_LIST;
      type->tt_member = member_type;
      type->tt_argcount = 0;
--- 261,269 ----
        return &t_list_string;
  
      // Not a common type, create a new entry.
!     type = alloc_type(type_gap);
!     if (type == NULL)
        return &t_any;
      type->tt_type = VAR_LIST;
      type->tt_member = member_type;
      type->tt_argcount = 0;
***************
*** 270,279 ****
        return &t_dict_string;
  
      // Not a common type, create a new entry.
!     if (ga_grow(type_gap, 1) == FAIL)
        return &t_any;
-     type = ((type_T *)type_gap->ga_data) + type_gap->ga_len;
-     ++type_gap->ga_len;
      type->tt_type = VAR_DICT;
      type->tt_member = member_type;
      type->tt_argcount = 0;
--- 289,297 ----
        return &t_dict_string;
  
      // Not a common type, create a new entry.
!     type = alloc_type(type_gap);
!     if (type == NULL)
        return &t_any;
      type->tt_type = VAR_DICT;
      type->tt_member = member_type;
      type->tt_argcount = 0;
***************
*** 325,334 ****
      }
  
      // Not a common type or has arguments, create a new entry.
!     if (ga_grow(type_gap, 1) == FAIL)
        return &t_any;
-     type = ((type_T *)type_gap->ga_data) + type_gap->ga_len;
-     ++type_gap->ga_len;
      type->tt_type = VAR_FUNC;
      type->tt_member = ret_type;
      type->tt_args = NULL;
--- 343,351 ----
      }
  
      // Not a common type or has arguments, create a new entry.
!     type = alloc_type(type_gap);
!     if (type == NULL)
        return &t_any;
      type->tt_type = VAR_FUNC;
      type->tt_member = ret_type;
      type->tt_args = NULL;
***************
*** 336,341 ****
--- 353,381 ----
  }
  
  /*
+  * For a function type, reserve space for "argcount" argument types.
+  */
+     static int
+ func_type_add_arg_types(
+       type_T      *functype,
+       int         argcount,
+       int         min_argcount,
+       garray_T    *type_gap)
+ {
+     if (ga_grow(type_gap, 1) == FAIL)
+       return FAIL;
+     functype->tt_args = ALLOC_CLEAR_MULT(type_T *, argcount);
+     if (functype->tt_args == NULL)
+       return FAIL;
+     ((type_T **)type_gap->ga_data)[type_gap->ga_len] = (void 
*)functype->tt_args;
+     ++type_gap->ga_len;
+ 
+     functype->tt_argcount = argcount;
+     functype->tt_min_argcount = min_argcount;
+     return OK;
+ }
+ 
+ /*
   * Return the type_T for a typval.  Only for primitive types.
   */
      static type_T *
***************
*** 810,821 ****
   * Consumes "name".
   */
      static int
! generate_PUSHFUNC(cctx_T *cctx, char_u *name)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, &t_func_void)) == NULL)
        return FAIL;
      isn->isn_arg.string = name;
  
--- 850,861 ----
   * Consumes "name".
   */
      static int
! generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
  {
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, type)) == NULL)
        return FAIL;
      isn->isn_arg.string = name;
  
***************
*** 1010,1016 ****
      // drop the value types
      stack->ga_len -= count;
  
!     // Use the first value type for the list member type.  Use "void" for an
      // empty list.
      if (count > 0)
        member = ((type_T **)stack->ga_data)[stack->ga_len];
--- 1050,1056 ----
      // drop the value types
      stack->ga_len -= count;
  
!     // Use the first value type for the list member type.  Use "any" for an
      // empty list.
      if (count > 0)
        member = ((type_T **)stack->ga_data)[stack->ga_len];
***************
*** 1533,1554 ****
                *arg += len;
                return &t_float;
  #else
!               emsg(_("E1055: This Vim is not compiled with float support"));
                return &t_any;
  #endif
            }
            if (len == 4 && STRNCMP(*arg, "func", len) == 0)
            {
                type_T  *type;
!               type_T  *ret_type = &t_void;
                int     argcount = -1;
                int     flags = 0;
                type_T  *arg_type[MAX_FUNC_ARGS + 1];
  
                // func({type}, ...): {type}
                *arg += len;
                if (**arg == '(')
                {
                    p = ++*arg;
                    argcount = 0;
                    while (*p != NUL && *p != ')')
--- 1573,1599 ----
                *arg += len;
                return &t_float;
  #else
!               emsg(_("E1076: This Vim is not compiled with float support"));
                return &t_any;
  #endif
            }
            if (len == 4 && STRNCMP(*arg, "func", len) == 0)
            {
                type_T  *type;
!               type_T  *ret_type = &t_any;
                int     argcount = -1;
                int     flags = 0;
+               int     first_optional = -1;
                type_T  *arg_type[MAX_FUNC_ARGS + 1];
  
                // func({type}, ...): {type}
                *arg += len;
                if (**arg == '(')
                {
+                   // "func" may or may not return a value, "func()" does
+                   // not return a value.
+                   ret_type = &t_void;
+ 
                    p = ++*arg;
                    argcount = 0;
                    while (*p != NUL && *p != ')')
***************
*** 1560,1565 ****
--- 1605,1622 ----
                        }
                        arg_type[argcount++] = parse_type(&p, type_gap);
  
+                       if (*p == '?')
+                       {
+                           if (first_optional == -1)
+                               first_optional = argcount;
+                           ++p;
+                       }
+                       else if (first_optional != -1)
+                       {
+                           emsg(_("E1007: mandatory argument after optional 
argument"));
+                           return &t_any;
+                       }
+ 
                        if (*p != ',' && *skipwhite(p) == ',')
                        {
                            semsg(_(e_no_white_before), ",");
***************
*** 1596,1619 ****
                    *arg = skipwhite(*arg);
                    ret_type = parse_type(arg, type_gap);
                }
!               type = get_func_type(ret_type, flags == 0 ? argcount : 99,
                                                                    type_gap);
                if (flags != 0)
                    type->tt_flags = flags;
                if (argcount > 0)
                {
!                   int type_ptr_cnt = (sizeof(type_T *) * argcount
!                                       + sizeof(type_T) - 1) / sizeof(type_T);
! 
!                   type->tt_argcount = argcount;
!                   // Get space from "type_gap" to avoid having to keep track
!                   // of the pointer and freeing it.
!                   ga_grow(type_gap, type_ptr_cnt);
!                   if (ga_grow(type_gap, type_ptr_cnt) == FAIL)
                        return &t_any;
-                   type->tt_args =
-                            ((type_T **)type_gap->ga_data) + type_gap->ga_len;
-                   type_gap->ga_len += type_ptr_cnt;
                    mch_memmove(type->tt_args, arg_type,
                                                  sizeof(type_T *) * argcount);
                }
--- 1653,1669 ----
                    *arg = skipwhite(*arg);
                    ret_type = parse_type(arg, type_gap);
                }
!               type = get_func_type(ret_type,
!                           flags == 0 && first_optional == -1 ? argcount : 99,
                                                                    type_gap);
                if (flags != 0)
                    type->tt_flags = flags;
                if (argcount > 0)
                {
!                   if (func_type_add_arg_types(type, argcount,
!                           first_optional == -1 ? argcount : first_optional,
!                                                            type_gap) == FAIL)
                        return &t_any;
                    mch_memmove(type->tt_args, arg_type,
                                                  sizeof(type_T *) * argcount);
                }
***************
*** 1775,1781 ****
            return *tofree;
        }
      }
!     // TODO: function and partial argument types
  
      return name;
  }
--- 1825,1886 ----
            return *tofree;
        }
      }
!     if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
!     {
!       garray_T    ga;
!       int         i;
! 
!       ga_init2(&ga, 1, 100);
!       if (ga_grow(&ga, 20) == FAIL)
!           return "[unknown]";
!       *tofree = ga.ga_data;
!       STRCPY(ga.ga_data, "func(");
!       ga.ga_len += 5;
! 
!       for (i = 0; i < type->tt_argcount; ++i)
!       {
!           char *arg_free;
!           char *arg_type = type_name(type->tt_args[i], &arg_free);
!           int  len;
! 
!           if (i > 0)
!           {
!               STRCPY(ga.ga_data + ga.ga_len, ", ");
!               ga.ga_len += 2;
!           }
!           len = (int)STRLEN(arg_type);
!           if (ga_grow(&ga, len + 6) == FAIL)
!           {
!               vim_free(arg_free);
!               return "[unknown]";
!           }
!           *tofree = ga.ga_data;
!           STRCPY(ga.ga_data + ga.ga_len, arg_type);
!           ga.ga_len += len;
!           vim_free(arg_free);
!       }
! 
!       if (type->tt_member == &t_void)
!           STRCPY(ga.ga_data + ga.ga_len, ")");
!       else
!       {
!           char *ret_free;
!           char *ret_name = type_name(type->tt_member, &ret_free);
!           int  len;
! 
!           len = (int)STRLEN(ret_name) + 4;
!           if (ga_grow(&ga, len) == FAIL)
!           {
!               vim_free(ret_free);
!               return "[unknown]";
!           }
!           *tofree = ga.ga_data;
!           STRCPY(ga.ga_data + ga.ga_len, "): ");
!           STRCPY(ga.ga_data + ga.ga_len + 3, ret_name);
!           vim_free(ret_free);
!       }
!       return ga.ga_data;
!     }
  
      return name;
  }
***************
*** 1868,1874 ****
  }
  
  /*
!  * Generate an instruction to load script-local variable "name".
   */
      static int
  compile_load_scriptvar(
--- 1973,1981 ----
  }
  
  /*
!  * Generate an instruction to load script-local variable "name", without the
!  * leading "s:".
!  * Also finds imported variables.
   */
      static int
  compile_load_scriptvar(
***************
*** 1933,1939 ****
        }
        else
        {
!           // TODO: check this is a variable, not a function
            generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
                    import->imp_sid,
                    import->imp_var_vals_idx,
--- 2040,2046 ----
        }
        else
        {
!           // TODO: check this is a variable, not a function?
            generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
                    import->imp_sid,
                    import->imp_var_vals_idx,
***************
*** 1947,1952 ****
--- 2054,2070 ----
      return FAIL;
  }
  
+     static int
+ generate_funcref(cctx_T *cctx, char_u *name)
+ {
+     ufunc_T *ufunc = find_func(name, cctx);
+ 
+     if (ufunc == NULL)
+       return FAIL;
+ 
+     return generate_PUSHFUNC(cctx, vim_strsave(name), ufunc->uf_func_type);
+ }
+ 
  /*
   * Compile a variable name into a load instruction.
   * "end" points to just after the name.
***************
*** 2051,2060 ****
                        || (len == 5 && STRNCMP("false", *arg, 5) == 0))
                    res = generate_PUSHBOOL(cctx, **arg == 't'
                                                     ? VVAL_TRUE : VVAL_FALSE);
!               else if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
!                                                       == SCRIPT_VERSION_VIM9)
!                   // in Vim9 script "var" can be script-local.
!                  res = compile_load_scriptvar(cctx, name, *arg, &end, error);
            }
        }
        if (gen_load)
--- 2169,2189 ----
                        || (len == 5 && STRNCMP("false", *arg, 5) == 0))
                    res = generate_PUSHBOOL(cctx, **arg == 't'
                                                     ? VVAL_TRUE : VVAL_FALSE);
!               else
!               {
!                   // "var" can be script-local even without using "s:" if it
!                   // already exists.
!                   if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
!                                                       == SCRIPT_VERSION_VIM9
!                               || lookup_script(*arg, len) == OK)
!                      res = compile_load_scriptvar(cctx, name, *arg, &end,
!                                                                       FALSE);
! 
!                   // When the name starts with an uppercase letter or "x:" it
!                   // can be a user defined function.
!                   if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':'))
!                       res = generate_funcref(cctx, name);
!               }
            }
        }
        if (gen_load)
***************
*** 2149,2159 ****
        // builtin function
        idx = find_internal_func(name);
        if (idx >= 0)
-       {
            res = generate_BCALL(cctx, idx, argcount);
!           goto theend;
!       }
!       semsg(_(e_unknownfunc), namebuf);
      }
  
      // If we can find the function by name generate the right call.
--- 2278,2287 ----
        // builtin function
        idx = find_internal_func(name);
        if (idx >= 0)
            res = generate_BCALL(cctx, idx, argcount);
!       else
!           semsg(_(e_unknownfunc), namebuf);
!       goto theend;
      }
  
      // If we can find the function by name generate the right call.
***************
*** 2264,2269 ****
--- 2392,2399 ----
      static int
  check_type(type_T *expected, type_T *actual, int give_msg)
  {
+     int ret = OK;
+ 
      if (expected->tt_type != VAR_UNKNOWN)
      {
        if (expected->tt_type != actual->tt_type)
***************
*** 2274,2290 ****
        }
        if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST)
        {
-           int ret;
- 
            // void is used for an empty list or dict
!           if (actual->tt_member == &t_void)
!               ret = OK;
!           else
                ret = check_type(expected->tt_member, actual->tt_member, FALSE);
-           if (ret == FAIL && give_msg)
-               type_mismatch(expected, actual);
-           return ret;
        }
      }
      return OK;
  }
--- 2404,2424 ----
        }
        if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST)
        {
            // void is used for an empty list or dict
!           if (actual->tt_member != &t_void)
                ret = check_type(expected->tt_member, actual->tt_member, FALSE);
        }
+       else if (expected->tt_type == VAR_FUNC)
+       {
+           if (expected->tt_member != &t_any)
+               ret = check_type(expected->tt_member, actual->tt_member, FALSE);
+           if (ret == OK && expected->tt_argcount != -1
+                   && (actual->tt_argcount < expected->tt_min_argcount
+                       || actual->tt_argcount > expected->tt_argcount))
+                   ret = FAIL;
+       }
+       if (ret == FAIL && give_msg)
+           type_mismatch(expected, actual);
      }
      return OK;
  }
***************
*** 2357,2362 ****
--- 2491,2497 ----
      ufunc = rettv.vval.v_partial->pt_func;
      ++ufunc->uf_refcount;
      clear_tv(&rettv);
+     ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
  
      // The function will have one line: "return {expr}".
      // Compile it into instructions.
***************
*** 2401,2406 ****
--- 2536,2542 ----
      ufunc = rettv.vval.v_partial->pt_func;
      ++ufunc->uf_refcount;
      clear_tv(&rettv);
+     ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
  
      // The function will have one line: "return {expr}".
      // Compile it into instructions.
***************
*** 3679,3685 ****
            type = &t_string;
            if (is_decl)
            {
!               semsg(_("E1065: Cannot declare an environment variable: %s"), 
name);
                goto theend;
            }
        }
--- 3815,3822 ----
            type = &t_string;
            if (is_decl)
            {
!               semsg(_("E1065: Cannot declare an environment variable: %s"),
!                                                                        name);
                goto theend;
            }
        }
***************
*** 3761,3767 ****
                if (is_decl)
                {
                    semsg(_("E1054: Variable already declared in the script: 
%s"),
!                                                                            
name);
                    goto theend;
                }
            }
--- 3898,3904 ----
                if (is_decl)
                {
                    semsg(_("E1054: Variable already declared in the script: 
%s"),
!                                                                        name);
                    goto theend;
                }
            }
***************
*** 3803,3819 ****
        goto theend;
      }
  
-     // +=, /=, etc. require an existing variable
      if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
      {
        if (oplen > 1 && !heredoc)
        {
            semsg(_("E1020: cannot use an operator on a new variable: %s"),
                                                                         name);
            goto theend;
        }
  
        // new local variable
        idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
        if (idx < 0)
            goto theend;
--- 3940,3959 ----
        goto theend;
      }
  
      if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
      {
        if (oplen > 1 && !heredoc)
        {
+           // +=, /=, etc. require an existing variable
            semsg(_("E1020: cannot use an operator on a new variable: %s"),
                                                                         name);
            goto theend;
        }
  
        // new local variable
+       if ((type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
+                                           && var_check_func_name(name, TRUE))
+           goto theend;
        idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
        if (idx < 0)
            goto theend;
***************
*** 3897,3903 ****
        if (idx >= 0 && (is_decl || !has_type))
        {
            lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
!           if (!has_type)
            {
                if (stacktype->tt_type == VAR_VOID)
                {
--- 4037,4043 ----
        if (idx >= 0 && (is_decl || !has_type))
        {
            lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
!           if (new_local && !has_type)
            {
                if (stacktype->tt_type == VAR_VOID)
                {
***************
*** 3905,3915 ****
                    goto theend;
                }
                else
!                   lvar->lv_type = stacktype;
            }
!           else
!               if (check_type(lvar->lv_type, stacktype, TRUE) == FAIL)
!                   goto theend;
        }
        else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
            goto theend;
--- 4045,4063 ----
                    goto theend;
                }
                else
!               {
!                   // An empty list or dict has a &t_void member, for a
!                   // variable that implies &t_any.
!                   if (stacktype == &t_list_empty)
!                       lvar->lv_type = &t_list_any;
!                   else if (stacktype == &t_dict_empty)
!                       lvar->lv_type = &t_dict_any;
!                   else
!                       lvar->lv_type = stacktype;
!               }
            }
!           else if (check_type(lvar->lv_type, stacktype, TRUE) == FAIL)
!               goto theend;
        }
        else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
            goto theend;
***************
*** 3946,3952 ****
                generate_PUSHBLOB(cctx, NULL);
                break;
            case VAR_FUNC:
!               generate_PUSHFUNC(cctx, NULL);
                break;
            case VAR_PARTIAL:
                generate_PUSHPARTIAL(cctx, NULL);
--- 4094,4100 ----
                generate_PUSHBLOB(cctx, NULL);
                break;
            case VAR_FUNC:
!               generate_PUSHFUNC(cctx, NULL, &t_func_void);
                break;
            case VAR_PARTIAL:
                generate_PUSHPARTIAL(cctx, NULL);
***************
*** 4039,4045 ****
                idx = get_script_item_idx(sid, rawname, TRUE);
                // TODO: specific type
                if (idx < 0)
!                   generate_OLDSCRIPT(cctx, ISN_STORES, name, sid, &t_any);
                else
                    generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
                                                             sid, idx, &t_any);
--- 4187,4210 ----
                idx = get_script_item_idx(sid, rawname, TRUE);
                // TODO: specific type
                if (idx < 0)
!               {
!                   char_u *name_s = name;
! 
!                   // Include s: in the name for store_var()
!                   if (name[1] != ':')
!                   {
!                       int len = (int)STRLEN(name) + 3;
! 
!                       name_s = alloc(len);
!                       if (name_s == NULL)
!                           name_s = name;
!                       else
!                           vim_snprintf((char *)name_s, len, "s:%s", name);
!                   }
!                   generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid, &t_any);
!                   if (name_s != name)
!                       vim_free(name_s);
!               }
                else
                    generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
                                                             sid, idx, &t_any);
***************
*** 5357,5369 ****
      {
        int     is_ex_command;
  
        if (line != NULL && *line == '|')
            // the line continues after a '|'
            ++line;
        else if (line != NULL && *line != NUL)
        {
!           if (emsg_before == called_emsg)
!               semsg(_("E488: Trailing characters: %s"), line);
            goto erret;
        }
        else
--- 5522,5538 ----
      {
        int     is_ex_command;
  
+       // Bail out on the first error to avoid a flood of errors and report
+       // the right line number when inside try/catch.
+       if (emsg_before != called_emsg)
+           goto erret;
+ 
        if (line != NULL && *line == '|')
            // the line continues after a '|'
            ++line;
        else if (line != NULL && *line != NUL)
        {
!           semsg(_("E488: Trailing characters: %s"), line);
            goto erret;
        }
        else
***************
*** 5653,5658 ****
--- 5822,5858 ----
        dfunc->df_varcount = cctx.ctx_max_local;
      }
  
+     {
+       int argcount = ufunc->uf_args.ga_len
+                                        + (ufunc->uf_va_name == NULL ? 0 : 1);
+ 
+       // Create a type for the function, with the return type and any
+       // argument types.
+       ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type, argcount,
+                                                        &ufunc->uf_type_list);
+       if (argcount > 0)
+       {
+           if (func_type_add_arg_types(ufunc->uf_func_type, argcount,
+                       argcount - ufunc->uf_def_args.ga_len,
+                                                &ufunc->uf_type_list) == FAIL)
+           {
+               ret = FAIL;
+               goto erret;
+           }
+           if (ufunc->uf_arg_types == NULL)
+           {
+               int i;
+ 
+               // lambda does not have argument types.
+               for (i = 0; i < argcount; ++i)
+                   ufunc->uf_func_type->tt_args[i] = &t_any;
+           }
+           else
+               mch_memmove(ufunc->uf_func_type->tt_args,
+                            ufunc->uf_arg_types, sizeof(type_T *) * argcount);
+       }
+     }
+ 
      ret = OK;
  
  erret:
*** ../vim-8.2.0511/src/vim9execute.c   2020-04-01 22:10:56.428201257 +0200
--- src/vim9execute.c   2020-04-05 16:52:32.150189604 +0200
***************
*** 377,383 ****
      funccal_entry_T entry;
  
      save_funccal(&entry);
!     set_var_const(name, NULL, tv, FALSE, 0);
      restore_funccal();
  }
  
--- 377,383 ----
      funccal_entry_T entry;
  
      save_funccal(&entry);
!     set_var_const(name, NULL, tv, FALSE, LET_NO_COMMAND);
      restore_funccal();
  }
  
***************
*** 739,745 ****
  
                    --ectx.ec_stack.ga_len;
                    if (di == NULL)
!                       store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
                    else
                    {
                        clear_tv(&di->di_tv);
--- 739,745 ----
  
                    --ectx.ec_stack.ga_len;
                    if (di == NULL)
!                       store_var(name, STACK_TV_BOT(0));
                    else
                    {
                        clear_tv(&di->di_tv);
***************
*** 1828,1834 ****
                                               iptr->isn_arg.loadstore.ls_sid);
  
                    smsg("%4d LOADS s:%s from %s", current,
!                                           iptr->isn_arg.string, si->sn_name);
                }
                break;
            case ISN_LOADG:
--- 1828,1834 ----
                                               iptr->isn_arg.loadstore.ls_sid);
  
                    smsg("%4d LOADS s:%s from %s", current,
!                                iptr->isn_arg.loadstore.ls_name, si->sn_name);
                }
                break;
            case ISN_LOADG:
***************
*** 1865,1871 ****
                                               iptr->isn_arg.loadstore.ls_sid);
  
                    smsg("%4d STORES %s in %s", current,
!                                           iptr->isn_arg.string, si->sn_name);
                }
                break;
            case ISN_STORESCRIPT:
--- 1865,1871 ----
                                               iptr->isn_arg.loadstore.ls_sid);
  
                    smsg("%4d STORES %s in %s", current,
!                                iptr->isn_arg.loadstore.ls_name, si->sn_name);
                }
                break;
            case ISN_STORESCRIPT:
*** ../vim-8.2.0511/src/structs.h       2020-04-03 21:59:29.329665634 +0200
--- src/structs.h       2020-04-05 16:13:46.967427310 +0200
***************
*** 1341,1350 ****
  typedef struct type_S type_T;
  struct type_S {
      vartype_T     tt_type;
!     short         tt_argcount;    // for func, partial, -1 for unknown
!     short         tt_flags;       // TTFLAG_ values
      type_T        *tt_member;     // for list, dict, func return type
!     type_T        **tt_args;      // func arguments, allocated
  };
  
  #define TTFLAG_VARARGS        1           // func args ends with "..."
--- 1341,1351 ----
  typedef struct type_S type_T;
  struct type_S {
      vartype_T     tt_type;
!     char          tt_argcount;    // for func, -1 for unknown
!     char          tt_min_argcount; // number of non-optional arguments
!     char          tt_flags;       // TTFLAG_ values
      type_T        *tt_member;     // for list, dict, func return type
!     type_T        **tt_args;      // func argument types, allocated
  };
  
  #define TTFLAG_VARARGS        1           // func args ends with "..."
***************
*** 1520,1526 ****
      int               uf_calls;       // nr of active calls
      int               uf_cleared;     // func_clear() was already called
      int               uf_dfunc_idx;   // >= 0 for :def function only
!     garray_T  uf_args;        // arguments
      garray_T  uf_def_args;    // default argument expressions
  
      // for :def (for :function uf_ret_type is NULL)
--- 1521,1527 ----
      int               uf_calls;       // nr of active calls
      int               uf_cleared;     // func_clear() was already called
      int               uf_dfunc_idx;   // >= 0 for :def function only
!     garray_T  uf_args;        // arguments, including optional arguments
      garray_T  uf_def_args;    // default argument expressions
  
      // for :def (for :function uf_ret_type is NULL)
***************
*** 1531,1536 ****
--- 1532,1538 ----
                                // uf_def_args; length: uf_def_args.ga_len + 1
      char_u    *uf_va_name;    // name from "...name" or NULL
      type_T    *uf_va_type;    // type from "...name: type" or NULL
+     type_T    *uf_func_type;  // type of the function, &t_func_any if unknown
  
      garray_T  uf_lines;       // function lines
  # ifdef FEAT_PROFILE
*** ../vim-8.2.0511/src/globals.h       2020-04-03 21:59:29.329665634 +0200
--- src/globals.h       2020-04-03 22:18:25.446684305 +0200
***************
*** 379,417 ****
  
  
  // Commonly used types.
! EXTERN type_T t_any INIT5(VAR_UNKNOWN, 0, 0, NULL, NULL);
! EXTERN type_T t_void INIT5(VAR_VOID, 0, 0, NULL, NULL);
! EXTERN type_T t_bool INIT5(VAR_BOOL, 0, 0, NULL, NULL);
! EXTERN type_T t_special INIT5(VAR_SPECIAL, 0, 0, NULL, NULL);
! EXTERN type_T t_number INIT5(VAR_NUMBER, 0, 0, NULL, NULL);
! EXTERN type_T t_float INIT5(VAR_FLOAT, 0, 0, NULL, NULL);
! EXTERN type_T t_string INIT5(VAR_STRING, 0, 0, NULL, NULL);
! EXTERN type_T t_blob INIT5(VAR_BLOB, 0, 0, NULL, NULL);
! EXTERN type_T t_job INIT5(VAR_JOB, 0, 0, NULL, NULL);
! EXTERN type_T t_channel INIT5(VAR_CHANNEL, 0, 0, NULL, NULL);
! 
! EXTERN type_T t_func_void INIT5(VAR_FUNC, -1, 0, &t_void, NULL);
! EXTERN type_T t_func_any INIT5(VAR_FUNC, -1, 0, &t_any, NULL);
! EXTERN type_T t_func_number INIT5(VAR_FUNC, -1, 0, &t_number, NULL);
! EXTERN type_T t_func_string INIT5(VAR_FUNC, -1, 0, &t_string, NULL);
! EXTERN type_T t_func_0_void INIT5(VAR_FUNC, 0, 0, &t_void, NULL);
! EXTERN type_T t_func_0_any INIT5(VAR_FUNC, 0, 0, &t_any, NULL);
! EXTERN type_T t_func_0_number INIT5(VAR_FUNC, 0, 0, &t_number, NULL);
! EXTERN type_T t_func_0_string INIT5(VAR_FUNC, 0, 0, &t_string, NULL);
! 
! EXTERN type_T t_list_any INIT5(VAR_LIST, 0, 0, &t_any, NULL);
! EXTERN type_T t_dict_any INIT5(VAR_DICT, 0, 0, &t_any, NULL);
! EXTERN type_T t_list_empty INIT5(VAR_LIST, 0, 0, &t_void, NULL);
! EXTERN type_T t_dict_empty INIT5(VAR_DICT, 0, 0, &t_void, NULL);
! 
! EXTERN type_T t_list_bool INIT5(VAR_LIST, 0, 0, &t_bool, NULL);
! EXTERN type_T t_list_number INIT5(VAR_LIST, 0, 0, &t_number, NULL);
! EXTERN type_T t_list_string INIT5(VAR_LIST, 0, 0, &t_string, NULL);
! EXTERN type_T t_list_dict_any INIT5(VAR_LIST, 0, 0, &t_dict_any, NULL);
! 
! EXTERN type_T t_dict_bool INIT5(VAR_DICT, 0, 0, &t_bool, NULL);
! EXTERN type_T t_dict_number INIT5(VAR_DICT, 0, 0, &t_number, NULL);
! EXTERN type_T t_dict_string INIT5(VAR_DICT, 0, 0, &t_string, NULL);
  
  
  #endif
--- 379,417 ----
  
  
  // Commonly used types.
! EXTERN type_T t_any INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, 0, NULL, NULL);
! EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, 0, NULL, NULL);
! 
! EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, 0, &t_void, NULL);
! EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, 0, &t_any, NULL);
! EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, 0, &t_number, NULL);
! EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, 0, &t_string, NULL);
! EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, 0, &t_void, NULL);
! EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, 0, &t_any, NULL);
! EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, 0, &t_number, NULL);
! EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, 0, &t_string, NULL);
! 
! EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, 0, &t_any, NULL);
! EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, 0, &t_any, NULL);
! EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_void, NULL);
! EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_void, NULL);
! 
! EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, 0, &t_bool, NULL);
! EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, 0, &t_number, NULL);
! EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, 0, &t_string, NULL);
! EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, 0, &t_dict_any, NULL);
! 
! EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, 0, &t_bool, NULL);
! EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, 0, &t_number, NULL);
! EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, 0, &t_string, NULL);
  
  
  #endif
*** ../vim-8.2.0511/src/vim.h   2020-02-28 22:19:38.310023356 +0100
--- src/vim.h   2020-04-03 22:21:55.937968185 +0200
***************
*** 1751,1756 ****
--- 1751,1757 ----
  # define INIT3(a, b, c)
  # define INIT4(a, b, c, d)
  # define INIT5(a, b, c, d, e)
+ # define INIT6(a, b, c, d, e, f)
  #else
  # ifndef INIT
  #  define INIT(x) x
***************
*** 1758,1763 ****
--- 1759,1765 ----
  #  define INIT3(a, b, c) = {a, b, c}
  #  define INIT4(a, b, c, d) = {a, b, c, d}
  #  define INIT5(a, b, c, d, e) = {a, b, c, d, e}
+ #  define INIT6(a, b, c, d, e, f) = {a, b, c, d, e, f}
  #  define DO_INIT
  # endif
  #endif
*** ../vim-8.2.0511/src/vim9.h  2020-03-31 23:32:27.042315928 +0200
--- src/vim9.h  2020-04-05 16:51:13.266502318 +0200
***************
*** 29,36 ****
      ISN_STORE,            // pop into local variable isn_arg.number
      ISN_STOREV,           // pop into v: variable isn_arg.number
      ISN_STOREG,           // pop into global variable isn_arg.string
!     ISN_STORES,           // pop into scirpt variable isn_arg.loadstore
!     ISN_STORESCRIPT, // pop into scirpt variable isn_arg.script
      ISN_STOREOPT,   // pop into option isn_arg.string
      ISN_STOREENV,    // pop into environment variable isn_arg.string
      ISN_STOREREG,    // pop into register isn_arg.number
--- 29,36 ----
      ISN_STORE,            // pop into local variable isn_arg.number
      ISN_STOREV,           // pop into v: variable isn_arg.number
      ISN_STOREG,           // pop into global variable isn_arg.string
!     ISN_STORES,           // pop into script variable isn_arg.loadstore
!     ISN_STORESCRIPT, // pop into script variable isn_arg.script
      ISN_STOREOPT,   // pop into option isn_arg.string
      ISN_STOREENV,    // pop into environment variable isn_arg.string
      ISN_STOREREG,    // pop into register isn_arg.number
***************
*** 191,197 ****
  
  // arguments to ISN_LOADS and ISN_STORES
  typedef struct {
!     char_u    *ls_name;       // variable name
      int               ls_sid;         // script ID
  } loadstore_T;
  
--- 191,197 ----
  
  // arguments to ISN_LOADS and ISN_STORES
  typedef struct {
!     char_u    *ls_name;       // variable name (with s: for ISN_STORES)
      int               ls_sid;         // script ID
  } loadstore_T;
  
*** ../vim-8.2.0511/src/userfunc.c      2020-04-03 18:13:54.446315826 +0200
--- src/userfunc.c      2020-04-04 22:05:20.769521548 +0200
***************
*** 951,956 ****
--- 951,959 ----
      VIM_CLEAR(fp->uf_arg_types);
      VIM_CLEAR(fp->uf_def_arg_idx);
      VIM_CLEAR(fp->uf_va_name);
+     while (fp->uf_type_list.ga_len > 0)
+       vim_free(((type_T **)fp->uf_type_list.ga_data)
+                                                 [--fp->uf_type_list.ga_len]);
      ga_clear(&fp->uf_type_list);
  #ifdef FEAT_PROFILE
      VIM_CLEAR(fp->uf_tml_count);
***************
*** 3013,3018 ****
--- 3016,3022 ----
      fp->uf_args = newargs;
      fp->uf_def_args = default_args;
      fp->uf_ret_type = &t_any;
+     fp->uf_func_type = &t_func_any;
  
      if (eap->cmdidx == CMD_def)
      {
***************
*** 3022,3028 ****
        SOURCING_LNUM = sourcing_lnum_top;
  
        // parse the argument types
!       ga_init2(&fp->uf_type_list, sizeof(type_T), 5);
  
        if (argtypes.ga_len > 0)
        {
--- 3026,3032 ----
        SOURCING_LNUM = sourcing_lnum_top;
  
        // parse the argument types
!       ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
  
        if (argtypes.ga_len > 0)
        {
*** ../vim-8.2.0511/src/testdir/Make_all.mak    2020-03-22 14:08:27.317399676 
+0100
--- src/testdir/Make_all.mak    2020-04-03 22:32:56.115554815 +0200
***************
*** 274,279 ****
--- 274,280 ----
        test_vartabs \
        test_vim9_disassemble \
        test_vim9_expr \
+       test_vim9_func \
        test_vim9_script \
        test_viminfo \
        test_vimscript \
***************
*** 483,488 ****
--- 484,490 ----
        test_vartabs.res \
        test_vim9_disassemble.res \
        test_vim9_expr.res \
+       test_vim9_func.res \
        test_vim9_script.res \
        test_viminfo.res \
        test_vimscript.res \
*** ../vim-8.2.0511/src/testdir/test_vim9_script.vim    2020-04-03 
21:59:29.333665628 +0200
--- src/testdir/test_vim9_script.vim    2020-04-05 14:40:11.205454801 +0200
***************
*** 21,33 ****
    let other: list<string> = ['asdf']
  enddef
  
- func Test_def_basic()
-   def SomeFunc(): string
-     return 'yes'
-   enddef
-   call assert_equal('yes', SomeFunc())
- endfunc
- 
  let s:appendToMe = 'xxx'
  let s:addToMe = 111
  let g:existing = 'yes'
--- 21,26 ----
***************
*** 66,74 ****
    if has('float')
      let float1: float = 3.4
    endif
!   let funky1: func
!   let funky2: func = function('len')
!   let party2: func = funcref('Test_syntax')
  
    " type becomes list<any>
    let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
--- 59,67 ----
    if has('float')
      let float1: float = 3.4
    endif
!   let Funky1: func
!   let Funky2: func = function('len')
!   let Party2: func = funcref('Test_syntax')
  
    " type becomes list<any>
    let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
***************
*** 134,139 ****
--- 127,135 ----
    assert_equal('noneagain', v:errmsg)
    call CheckDefFailure(['v:errmsg += "more"'], 'E1013:')
    call CheckDefFailure(['v:errmsg += 123'], 'E1013:')
+ enddef
+ 
+ def Test_assignment_default()
  
    " Test default values.
    let thebool: bool
***************
*** 153,160 ****
    let theblob: blob
    assert_equal(0z, theblob)
  
!   let thefunc: func
!   assert_equal(test_null_function(), thefunc)
  
    let thelist: list<any>
    assert_equal([], thelist)
--- 149,156 ----
    let theblob: blob
    assert_equal(0z, theblob)
  
!   let Thefunc: func
!   assert_equal(test_null_function(), Thefunc)
  
    let thelist: list<any>
    assert_equal([], thelist)
***************
*** 264,420 ****
  enddef
  
  
- def ReturnString(): string
-   return 'string'
- enddef
- 
- def ReturnNumber(): number
-   return 123
- enddef
- 
- let g:notNumber = 'string'
- 
- def ReturnGlobal(): number
-   return g:notNumber
- enddef
- 
- def Test_return_something()
-   assert_equal('string', ReturnString())
-   assert_equal(123, ReturnNumber())
-   assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
- enddef
- 
- let s:nothing = 0
- def ReturnNothing()
-   s:nothing = 1
-   if true
-     return
-   endif
-   s:nothing = 2
- enddef
- 
- def Test_return_nothing()
-   ReturnNothing()
-   assert_equal(1, s:nothing)
- enddef
- 
- func Increment()
-   let g:counter += 1
- endfunc
- 
- def Test_call_ufunc_count()
-   g:counter = 1
-   Increment()
-   Increment()
-   Increment()
-   " works with and without :call
-   assert_equal(4, g:counter)
-   call assert_equal(4, g:counter)
-   unlet g:counter
- enddef
- 
- def MyVarargs(arg: string, ...rest: list<string>): string
-   let res = arg
-   for s in rest
-     res ..= ',' .. s
-   endfor
-   return res
- enddef
- 
- def Test_call_varargs()
-   assert_equal('one', MyVarargs('one'))
-   assert_equal('one,two', MyVarargs('one', 'two'))
-   assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
- enddef
- 
- def MyDefaultArgs(name = 'string'): string
-   return name
- enddef
- 
- def Test_call_default_args()
-   assert_equal('string', MyDefaultArgs())
-   assert_equal('one', MyDefaultArgs('one'))
-   assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
- 
-   call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 
'E1001:')
- enddef
- 
- func Test_call_default_args_from_func()
-   call assert_equal('string', MyDefaultArgs())
-   call assert_equal('one', MyDefaultArgs('one'))
-   call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
- endfunc
- 
- func TakesOneArg(arg)
-   echo a:arg
- endfunc
- 
- def Test_call_wrong_args()
-   call CheckDefFailure(['TakesOneArg()'], 'E119:')
-   call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
-   call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
- enddef
- 
- " Default arg and varargs
- def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
-   let res = one .. ',' .. two
-   for s in rest
-     res ..= ',' .. s
-   endfor
-   return res
- enddef
- 
- def Test_call_def_varargs()
-   call assert_fails('call MyDefVarargs()', 'E119:')
-   assert_equal('one,foo', MyDefVarargs('one'))
-   assert_equal('one,two', MyDefVarargs('one', 'two'))
-   assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
- enddef
- 
- def Test_using_var_as_arg()
-   call writefile(['def Func(x: number)',  'let x = 234', 'enddef'], 'Xdef')
-   call assert_fails('so Xdef', 'E1006:')
-   call delete('Xdef')
- enddef
- 
- def Test_call_func_defined_later()
-   call assert_equal('one', DefinedLater('one'))
-   call assert_fails('call NotDefined("one")', 'E117:')
- enddef
- 
- func DefinedLater(arg)
-   return a:arg
- endfunc
- 
- def FuncWithForwardCall()
-   return DefinedEvenLater("yes")
- enddef
- 
- def DefinedEvenLater(arg: string): string
-   return arg
- enddef
- 
- def Test_error_in_nested_function()
-   " Error in called function requires unwinding the call stack.
-   assert_fails('call FuncWithForwardCall()', 'E1029')
- enddef
- 
- def Test_return_type_wrong()
-   CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 
'expected number but got string')
-   CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected 
string but got number')
-   CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected 
void but got string')
-   CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void 
but got string')
- 
-   CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
- 
-   CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
-   CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
- enddef
- 
- def Test_arg_type_wrong()
-   CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 
'E1008: Missing <type>')
- enddef
- 
  def Test_try_catch()
    let l = []
    try
--- 260,265 ----
***************
*** 732,813 ****
    assert_fails('export something', 'E1042')
  enddef
  
- def Test_vim9script_call()
-   let lines =<< trim END
-     vim9script
-     let var = ''
-     def MyFunc(arg: string)
-        var = arg
-     enddef
-     MyFunc('foobar')
-     assert_equal('foobar', var)
- 
-     let str = 'barfoo'
-     str->MyFunc()
-     assert_equal('barfoo', var)
- 
-     let g:value = 'value'
-     g:value->MyFunc()
-     assert_equal('value', var)
- 
-     let listvar = []
-     def ListFunc(arg: list<number>)
-        listvar = arg
-     enddef
-     [1, 2, 3]->ListFunc()
-     assert_equal([1, 2, 3], listvar)
- 
-     let dictvar = {}
-     def DictFunc(arg: dict<number>)
-        dictvar = arg
-     enddef
-     {'a': 1, 'b': 2}->DictFunc()
-     assert_equal(#{a: 1, b: 2}, dictvar)
-     def CompiledDict()
-       {'a': 3, 'b': 4}->DictFunc()
-     enddef
-     CompiledDict()
-     assert_equal(#{a: 3, b: 4}, dictvar)
- 
-     #{a: 3, b: 4}->DictFunc()
-     assert_equal(#{a: 3, b: 4}, dictvar)
- 
-     ('text')->MyFunc()
-     assert_equal('text', var)
-     ("some")->MyFunc()
-     assert_equal('some', var)
-   END
-   writefile(lines, 'Xcall.vim')
-   source Xcall.vim
-   delete('Xcall.vim')
- enddef
- 
- def Test_vim9script_call_fail_decl()
-   let lines =<< trim END
-     vim9script
-     let var = ''
-     def MyFunc(arg: string)
-        let var = 123
-     enddef
-   END
-   writefile(lines, 'Xcall_decl.vim')
-   assert_fails('source Xcall_decl.vim', 'E1054:')
-   delete('Xcall_decl.vim')
- enddef
- 
- def Test_vim9script_call_fail_const()
-   let lines =<< trim END
-     vim9script
-     const var = ''
-     def MyFunc(arg: string)
-        var = 'asdf'
-     enddef
-   END
-   writefile(lines, 'Xcall_const.vim')
-   assert_fails('source Xcall_const.vim', 'E46:')
-   delete('Xcall_const.vim')
- enddef
- 
  def Test_vim9script_reload()
    let lines =<< trim END
      vim9script
--- 577,582 ----
***************
*** 926,942 ****
    assert_equal([2, 99, 3, 4, 5], l)
  enddef
  
- " Test that inside :function a Python function can be defined, :def is not
- " recognized.
- func Test_function_python()
-   CheckFeature python3
-   let py = 'python3'
-   execute py "<< EOF"
- def do_something():
-   return 1
- EOF
- endfunc
- 
  def IfElse(what: number): string
    let res = ''
    if what == 1
--- 695,700 ----
***************
*** 1087,1113 ****
    call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
  enddef
  
- def Test_delfunc()
-   let lines =<< trim END
-     vim9script
-     def GoneSoon()
-       echo 'hello'
-     enddef
- 
-     def CallGoneSoon()
-       GoneSoon()
-     enddef
- 
-     delfunc GoneSoon
-     CallGoneSoon()
-   END
-   writefile(lines, 'XToDelFunc')
-   assert_fails('so XToDelFunc', 'E933')
-   assert_fails('so XToDelFunc', 'E933')
- 
-   delete('XToDelFunc')
- enddef
- 
  def Test_execute_cmd()
    new
    setline(1, 'default')
--- 845,850 ----
***************
*** 1222,1304 ****
    assert_true(caught, 'should have caught an exception')
  enddef
  
- def Test_redef_failure()
-   call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
-   so Xdef
-   call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
-   so Xdef
-   call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
-   call assert_fails('so Xdef', 'E1027:')
-   call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
-   so Xdef
-   call delete('Xdef')
- 
-   call assert_equal(0, Func0())
-   call assert_equal('Func1', Func1())
-   call assert_equal('Func2', Func2())
- 
-   delfunc! Func0
-   delfunc! Func1
-   delfunc! Func2
- enddef
- 
- " Test for internal functions returning different types
- func Test_InternalFuncRetType()
-   let lines =<< trim END
-     def RetFloat(): float
-       return ceil(1.456)
-     enddef
- 
-     def RetListAny(): list<any>
-       return items({'k' : 'v'})
-     enddef
- 
-     def RetListString(): list<string>
-       return split('a:b:c', ':')
-     enddef
- 
-     def RetListDictAny(): list<dict<any>>
-       return getbufinfo()
-     enddef
- 
-     def RetDictNumber(): dict<number>
-       return wordcount()
-     enddef
- 
-     def RetDictString(): dict<string>
-       return environ()
-     enddef
-   END
-   call writefile(lines, 'Xscript')
-   source Xscript
- 
-   call assert_equal(2.0, RetFloat())
-   call assert_equal([['k', 'v']], RetListAny())
-   call assert_equal(['a', 'b', 'c'], RetListString())
-   call assert_notequal([], RetListDictAny())
-   call assert_notequal({}, RetDictNumber())
-   call assert_notequal({}, RetDictString())
-   call delete('Xscript')
- endfunc
- 
- " Test for passing too many or too few arguments to internal functions
- func Test_internalfunc_arg_error()
-   let l =<< trim END
-     def! FArgErr(): float
-       return ceil(1.1, 2)
-     enddef
-   END
-   call writefile(l, 'Xinvalidarg')
-   call assert_fails('so Xinvalidarg', 'E118:')
-   let l =<< trim END
-     def! FArgErr(): float
-       return ceil()
-     enddef
-   END
-   call writefile(l, 'Xinvalidarg')
-   call assert_fails('so Xinvalidarg', 'E119:')
-   call delete('Xinvalidarg')
- endfunc
  
  " Keep this last, it messes up highlighting.
  def Test_substitute_cmd()
--- 959,964 ----
*** ../vim-8.2.0511/src/testdir/test_vim9_expr.vim      2020-04-03 
21:59:29.329665634 +0200
--- src/testdir/test_vim9_expr.vim      2020-04-04 22:29:19.048946562 +0200
***************
*** 460,467 ****
  
    call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == 
chan'], 'Cannot compare job with channel')
    call CheckDefFailureMult(['let j: job', 'let x: list<any>', 'let r = j == 
x'], 'Cannot compare job with list')
!   call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 
'Cannot compare job with func')
!   call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 
'Cannot compare job with func')
  endfunc
  
  " test addition, subtraction, concatenation
--- 460,467 ----
  
    call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == 
chan'], 'Cannot compare job with channel')
    call CheckDefFailureMult(['let j: job', 'let x: list<any>', 'let r = j == 
x'], 'Cannot compare job with list')
!   call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 
'Cannot compare job with func')
!   call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 
'Cannot compare job with func')
  endfunc
  
  " test addition, subtraction, concatenation
*** ../vim-8.2.0511/src/testdir/test_vim9_func.vim      2020-04-05 
17:04:23.551397938 +0200
--- src/testdir/test_vim9_func.vim      2020-04-05 16:08:12.572796447 +0200
***************
*** 0 ****
--- 1,400 ----
+ " Test various aspects of the Vim9 script language.
+ 
+ source check.vim
+ source view_util.vim
+ 
+ " Check that "lines" inside ":def" results in an "error" message.
+ func CheckDefFailure(lines, error)
+   call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
+   call assert_fails('so Xdef', a:error, a:lines)
+   call delete('Xdef')
+ endfunc
+ 
+ func CheckScriptFailure(lines, error)
+   call writefile(a:lines, 'Xdef')
+   call assert_fails('so Xdef', a:error, a:lines)
+   call delete('Xdef')
+ endfunc
+ 
+ func Test_def_basic()
+   def SomeFunc(): string
+     return 'yes'
+   enddef
+   call assert_equal('yes', SomeFunc())
+ endfunc
+ 
+ def ReturnString(): string
+   return 'string'
+ enddef
+ 
+ def ReturnNumber(): number
+   return 123
+ enddef
+ 
+ let g:notNumber = 'string'
+ 
+ def ReturnGlobal(): number
+   return g:notNumber
+ enddef
+ 
+ def Test_return_something()
+   assert_equal('string', ReturnString())
+   assert_equal(123, ReturnNumber())
+   assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
+ enddef
+ 
+ let s:nothing = 0
+ def ReturnNothing()
+   s:nothing = 1
+   if true
+     return
+   endif
+   s:nothing = 2
+ enddef
+ 
+ def Test_return_nothing()
+   ReturnNothing()
+   assert_equal(1, s:nothing)
+ enddef
+ 
+ func Increment()
+   let g:counter += 1
+ endfunc
+ 
+ def Test_call_ufunc_count()
+   g:counter = 1
+   Increment()
+   Increment()
+   Increment()
+   " works with and without :call
+   assert_equal(4, g:counter)
+   call assert_equal(4, g:counter)
+   unlet g:counter
+ enddef
+ 
+ def MyVarargs(arg: string, ...rest: list<string>): string
+   let res = arg
+   for s in rest
+     res ..= ',' .. s
+   endfor
+   return res
+ enddef
+ 
+ def Test_call_varargs()
+   assert_equal('one', MyVarargs('one'))
+   assert_equal('one,two', MyVarargs('one', 'two'))
+   assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
+ enddef
+ 
+ def MyDefaultArgs(name = 'string'): string
+   return name
+ enddef
+ 
+ def Test_call_default_args()
+   assert_equal('string', MyDefaultArgs())
+   assert_equal('one', MyDefaultArgs('one'))
+   assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
+ 
+   call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 
'E1001:')
+ enddef
+ 
+ func Test_call_default_args_from_func()
+   call assert_equal('string', MyDefaultArgs())
+   call assert_equal('one', MyDefaultArgs('one'))
+   call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
+ endfunc
+ 
+ func TakesOneArg(arg)
+   echo a:arg
+ endfunc
+ 
+ def Test_call_wrong_args()
+   call CheckDefFailure(['TakesOneArg()'], 'E119:')
+   call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
+   call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
+ enddef
+ 
+ " Default arg and varargs
+ def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
+   let res = one .. ',' .. two
+   for s in rest
+     res ..= ',' .. s
+   endfor
+   return res
+ enddef
+ 
+ def Test_call_def_varargs()
+   call assert_fails('call MyDefVarargs()', 'E119:')
+   assert_equal('one,foo', MyDefVarargs('one'))
+   assert_equal('one,two', MyDefVarargs('one', 'two'))
+   assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
+ enddef
+ 
+ def Test_using_var_as_arg()
+   call writefile(['def Func(x: number)',  'let x = 234', 'enddef'], 'Xdef')
+   call assert_fails('so Xdef', 'E1006:')
+   call delete('Xdef')
+ enddef
+ 
+ def Test_call_func_defined_later()
+   call assert_equal('one', DefinedLater('one'))
+   call assert_fails('call NotDefined("one")', 'E117:')
+ enddef
+ 
+ func DefinedLater(arg)
+   return a:arg
+ endfunc
+ 
+ def FuncWithForwardCall()
+   return DefinedEvenLater("yes")
+ enddef
+ 
+ def DefinedEvenLater(arg: string): string
+   return arg
+ enddef
+ 
+ def Test_error_in_nested_function()
+   " Error in called function requires unwinding the call stack.
+   assert_fails('call FuncWithForwardCall()', 'E1029')
+ enddef
+ 
+ def Test_return_type_wrong()
+   CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 
'expected number but got string')
+   CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected 
string but got number')
+   CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected 
void but got string')
+   CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void 
but got string')
+ 
+   CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
+ 
+   CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
+   CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
+ enddef
+ 
+ def Test_arg_type_wrong()
+   CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 
'E1008: Missing <type>')
+ enddef
+ 
+ def Test_vim9script_call()
+   let lines =<< trim END
+     vim9script
+     let var = ''
+     def MyFunc(arg: string)
+        var = arg
+     enddef
+     MyFunc('foobar')
+     assert_equal('foobar', var)
+ 
+     let str = 'barfoo'
+     str->MyFunc()
+     assert_equal('barfoo', var)
+ 
+     let g:value = 'value'
+     g:value->MyFunc()
+     assert_equal('value', var)
+ 
+     let listvar = []
+     def ListFunc(arg: list<number>)
+        listvar = arg
+     enddef
+     [1, 2, 3]->ListFunc()
+     assert_equal([1, 2, 3], listvar)
+ 
+     let dictvar = {}
+     def DictFunc(arg: dict<number>)
+        dictvar = arg
+     enddef
+     {'a': 1, 'b': 2}->DictFunc()
+     assert_equal(#{a: 1, b: 2}, dictvar)
+     def CompiledDict()
+       {'a': 3, 'b': 4}->DictFunc()
+     enddef
+     CompiledDict()
+     assert_equal(#{a: 3, b: 4}, dictvar)
+ 
+     #{a: 3, b: 4}->DictFunc()
+     assert_equal(#{a: 3, b: 4}, dictvar)
+ 
+     ('text')->MyFunc()
+     assert_equal('text', var)
+     ("some")->MyFunc()
+     assert_equal('some', var)
+   END
+   writefile(lines, 'Xcall.vim')
+   source Xcall.vim
+   delete('Xcall.vim')
+ enddef
+ 
+ def Test_vim9script_call_fail_decl()
+   let lines =<< trim END
+     vim9script
+     let var = ''
+     def MyFunc(arg: string)
+        let var = 123
+     enddef
+   END
+   writefile(lines, 'Xcall_decl.vim')
+   assert_fails('source Xcall_decl.vim', 'E1054:')
+   delete('Xcall_decl.vim')
+ enddef
+ 
+ def Test_vim9script_call_fail_const()
+   let lines =<< trim END
+     vim9script
+     const var = ''
+     def MyFunc(arg: string)
+        var = 'asdf'
+     enddef
+   END
+   writefile(lines, 'Xcall_const.vim')
+   assert_fails('source Xcall_const.vim', 'E46:')
+   delete('Xcall_const.vim')
+ enddef
+ 
+ " Test that inside :function a Python function can be defined, :def is not
+ " recognized.
+ func Test_function_python()
+   CheckFeature python3
+   let py = 'python3'
+   execute py "<< EOF"
+ def do_something():
+   return 1
+ EOF
+ endfunc
+ 
+ def Test_delfunc()
+   let lines =<< trim END
+     vim9script
+     def GoneSoon()
+       echo 'hello'
+     enddef
+ 
+     def CallGoneSoon()
+       GoneSoon()
+     enddef
+ 
+     delfunc GoneSoon
+     CallGoneSoon()
+   END
+   writefile(lines, 'XToDelFunc')
+   assert_fails('so XToDelFunc', 'E933')
+   assert_fails('so XToDelFunc', 'E933')
+ 
+   delete('XToDelFunc')
+ enddef
+ 
+ def Test_redef_failure()
+   call writefile(['def Func0(): string',  'return "Func0"', 'enddef'], 'Xdef')
+   so Xdef
+   call writefile(['def Func1(): string',  'return "Func1"', 'enddef'], 'Xdef')
+   so Xdef
+   call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
+   call assert_fails('so Xdef', 'E1027:')
+   call writefile(['def Func2(): string',  'return "Func2"', 'enddef'], 'Xdef')
+   so Xdef
+   call delete('Xdef')
+ 
+   call assert_equal(0, Func0())
+   call assert_equal('Func1', Func1())
+   call assert_equal('Func2', Func2())
+ 
+   delfunc! Func0
+   delfunc! Func1
+   delfunc! Func2
+ enddef
+ 
+ " Test for internal functions returning different types
+ func Test_InternalFuncRetType()
+   let lines =<< trim END
+     def RetFloat(): float
+       return ceil(1.456)
+     enddef
+ 
+     def RetListAny(): list<any>
+       return items({'k' : 'v'})
+     enddef
+ 
+     def RetListString(): list<string>
+       return split('a:b:c', ':')
+     enddef
+ 
+     def RetListDictAny(): list<dict<any>>
+       return getbufinfo()
+     enddef
+ 
+     def RetDictNumber(): dict<number>
+       return wordcount()
+     enddef
+ 
+     def RetDictString(): dict<string>
+       return environ()
+     enddef
+   END
+   call writefile(lines, 'Xscript')
+   source Xscript
+ 
+   call assert_equal(2.0, RetFloat())
+   call assert_equal([['k', 'v']], RetListAny())
+   call assert_equal(['a', 'b', 'c'], RetListString())
+   call assert_notequal([], RetListDictAny())
+   call assert_notequal({}, RetDictNumber())
+   call assert_notequal({}, RetDictString())
+   call delete('Xscript')
+ endfunc
+ 
+ " Test for passing too many or too few arguments to internal functions
+ func Test_internalfunc_arg_error()
+   let l =<< trim END
+     def! FArgErr(): float
+       return ceil(1.1, 2)
+     enddef
+   END
+   call writefile(l, 'Xinvalidarg')
+   call assert_fails('so Xinvalidarg', 'E118:')
+   let l =<< trim END
+     def! FArgErr(): float
+       return ceil()
+     enddef
+   END
+   call writefile(l, 'Xinvalidarg')
+   call assert_fails('so Xinvalidarg', 'E119:')
+   call delete('Xinvalidarg')
+ endfunc
+ 
+ let s:funcResult = 0
+ 
+ def FuncNoArgNoRet()
+   funcResult = 11
+ enddef
+ 
+ def FuncNoArgRetNumber(): number
+   funcResult = 22
+   return 1234
+ enddef
+ 
+ def FuncOneArgNoRet(arg: number)
+   funcResult = arg
+ enddef
+ 
+ def FuncOneArgRetNumber(arg: number): number
+   funcResult = arg
+   return arg
+ enddef
+ 
+ def Test_func_type()
+   let Ref1: func()
+   funcResult = 0
+   Ref1 = FuncNoArgNoRet
+   Ref1()
+   assert_equal(11, funcResult)
+ enddef
+ 
+ def Test_func_type_fails()
+   CheckDefFailure(['let ref1: func()'], 'E704:')
+ 
+   CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: 
type mismatch, expected func() but got func(): number')
+   CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: 
type mismatch, expected func() but got func(number)')
+   CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: 
type mismatch, expected func() but got func(number): number')
+ enddef
+ 
+ 
+ " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-8.2.0511/src/testdir/test_vim9_disassemble.vim       2020-04-03 
21:59:29.333665628 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-04-05 16:38:21.993652926 
+0200
***************
*** 87,94 ****
--- 87,96 ----
  def Test_disassemble_store()
    let res = execute('disass s:ScriptFuncStore')
    assert_match('<SNR>\d*_ScriptFuncStore.*'
+         \ .. 'let localnr = 1.*'
          \ .. 'localnr = 2.*'
          \ .. ' STORE 2 in $0.*'
+         \ .. 'let localstr = ''abc''.*'
          \ .. 'localstr = ''xyz''.*'
          \ .. ' STORE $1.*'
          \ .. 'v:char = ''abc''.*'
***************
*** 360,381 ****
  enddef
  
  def WithFunc()
!   let funky1: func
!   let funky2: func = function("len")
!   let party2: func = funcref("UserFunc")
  enddef
  
  def Test_disassemble_function()
    let instr = execute('disassemble WithFunc')
    assert_match('WithFunc.*'
!         \ .. 'let funky1: func.*'
          \ .. '0 PUSHFUNC "\[none]".*'
          \ .. '1 STORE $0.*'
!         \ .. 'let funky2: func = function("len").*'
          \ .. '2 PUSHS "len".*'
          \ .. '3 BCALL function(argc 1).*'
          \ .. '4 STORE $1.*'
!         \ .. 'let party2: func = funcref("UserFunc").*'
          \ .. '\d PUSHS "UserFunc".*'
          \ .. '\d BCALL funcref(argc 1).*'
          \ .. '\d STORE $2.*'
--- 362,383 ----
  enddef
  
  def WithFunc()
!   let Funky1: func
!   let Funky2: func = function("len")
!   let Party2: func = funcref("UserFunc")
  enddef
  
  def Test_disassemble_function()
    let instr = execute('disassemble WithFunc')
    assert_match('WithFunc.*'
!         \ .. 'let Funky1: func.*'
          \ .. '0 PUSHFUNC "\[none]".*'
          \ .. '1 STORE $0.*'
!         \ .. 'let Funky2: func = function("len").*'
          \ .. '2 PUSHS "len".*'
          \ .. '3 BCALL function(argc 1).*'
          \ .. '4 STORE $1.*'
!         \ .. 'let Party2: func = funcref("UserFunc").*'
          \ .. '\d PUSHS "UserFunc".*'
          \ .. '\d BCALL funcref(argc 1).*'
          \ .. '\d STORE $2.*'
*** ../vim-8.2.0511/src/version.c       2020-04-05 15:36:13.023853428 +0200
--- src/version.c       2020-04-05 17:01:41.692030123 +0200
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     512,
  /**/

-- 
Every exit is an entrance into something else.

 /// 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/202004051508.035F8tG1003260%40masaka.moolenaar.net.

Raspunde prin e-mail lui