Patch 8.2.0508
Problem:    Vim9: func and partial types not done yet
Solution:   Fill in details about func declaration, drop a separate partial
            declaration.
Files:      runtime/doc/vim9.txt, src/vim9compile.c, src/globals.h,
            src/structs.h, src/evalfunc.c, src/testdir/test_vim9_expr.vim,
            src/testdir/test_vim9_script.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.0507/runtime/doc/vim9.txt        2020-02-29 22:06:25.647709244 
+0100
--- runtime/doc/vim9.txt        2020-04-03 20:52:01.541368955 +0200
***************
*** 213,219 ****
        blob            non-empty
        list            non-empty (different from JavaScript)
        dictionary      non-empty (different from JavaScript)
!       funcref         when not NULL
        partial         when not NULL
        special         v:true
        job             when not NULL
--- 213,219 ----
        blob            non-empty
        list            non-empty (different from JavaScript)
        dictionary      non-empty (different from JavaScript)
!       func            when not NULL
        partial         when not NULL
        special         v:true
        job             when not NULL
***************
*** 249,256 ****
                        the function follows in the next lines, until the
                        matching `:enddef`.
  
!                       When {return-type} is omitted the function is not
!                       expected to return anything.
                        
                        {arguments} is a sequence of zero or more argument
                        declarations.  There are three forms:
--- 249,256 ----
                        the function follows in the next lines, until the
                        matching `:enddef`.
  
!                       When {return-type} is omitted or is "void" the
!                       function is not expected to return anything.
                        
                        {arguments} is a sequence of zero or more argument
                        declarations.  There are three forms:
***************
*** 296,322 ****
        float
        string
        blob
!       list<type>
!       dict<type>
!       (a: type, b: type): type
        job
        channel
  
  Not supported yet:
!       tuple<a: type, b: type, ...>
  
! These types can be used in declarations, but no variable will have this type:
!       type|type
        void
        any
  
! There is no array type, use list<type> instead.  For a list constant an
  efficient implementation is used that avoids allocating lot of small pieces of
  memory.
  
! A function defined with `:def` must declare the return type.  If there is no
! type then the function doesn't return anything.  "void" is used in type
! declarations.
  
  Custom types can be defined with `:type`: >
        :type MyList list<string>
--- 296,335 ----
        float
        string
        blob
!       list<{type}>
!       dict<{type}>
        job
        channel
+       func
+       func({type}, ...)
+       func({type}, ...): {type}
  
  Not supported yet:
!       tuple<a: {type}, b: {type}, ...>
  
! These types can be used in declarations, but no value will have this type:
!       {type}|{type}
        void
        any
  
! There is no array type, use list<{type}> instead.  For a list constant an
  efficient implementation is used that avoids allocating lot of small pieces of
  memory.
  
! A partial and function can be declared in more or less specific ways:
! func                          any kind of function reference, no type
!                               checking
! func: {type}                  any number and type of arguments with specific
!                               return type
! func({type} ...)              function with argument types, does not return
!                               a value
! func({type} ...): {type}      function with argument types and return type
! 
! If the return type is "void" the function does not return a value.
! 
! The reference can also be a |Partial|, in which case it stores extra arguments
! and/or a dictionary, which are not visible to the caller.  Since they are
! called in the same way the declaration is the same.
  
  Custom types can be defined with `:type`: >
        :type MyList list<string>
*** ../vim-8.2.0507/src/vim9compile.c   2020-04-02 22:57:32.331945116 +0200
--- src/vim9compile.c   2020-04-03 21:29:53.848485949 +0200
***************
*** 224,230 ****
  }
  
      static type_T *
! get_list_type(type_T *member_type, garray_T *type_list)
  {
      type_T *type;
  
--- 224,230 ----
  }
  
      static type_T *
! get_list_type(type_T *member_type, garray_T *type_gap)
  {
      type_T *type;
  
***************
*** 241,257 ****
        return &t_list_string;
  
      // Not a common type, create a new entry.
!     if (ga_grow(type_list, 1) == FAIL)
        return &t_any;
!     type = ((type_T *)type_list->ga_data) + type_list->ga_len;
!     ++type_list->ga_len;
      type->tt_type = VAR_LIST;
      type->tt_member = member_type;
      return type;
  }
  
      static type_T *
! get_dict_type(type_T *member_type, garray_T *type_list)
  {
      type_T *type;
  
--- 241,259 ----
        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;
+     type->tt_args = NULL;
      return type;
  }
  
      static type_T *
! get_dict_type(type_T *member_type, garray_T *type_gap)
  {
      type_T *type;
  
***************
*** 268,279 ****
        return &t_dict_string;
  
      // Not a common type, create a new entry.
!     if (ga_grow(type_list, 1) == FAIL)
        return &t_any;
!     type = ((type_T *)type_list->ga_data) + type_list->ga_len;
!     ++type_list->ga_len;
      type->tt_type = VAR_DICT;
      type->tt_member = member_type;
      return type;
  }
  
--- 270,337 ----
        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;
+     type->tt_args = NULL;
+     return type;
+ }
+ 
+ /*
+  * Get a function type, based on the return type "ret_type".
+  * If "argcount" is -1 or 0 a predefined type can be used.
+  * If "argcount" > 0 always create a new type, so that arguments can be added.
+  */
+     static type_T *
+ get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
+ {
+     type_T *type;
+ 
+     // recognize commonly used types
+     if (argcount <= 0)
+     {
+       if (ret_type == &t_void)
+       {
+           if (argcount == 0)
+               return &t_func_0_void;
+           else
+               return &t_func_void;
+       }
+       if (ret_type == &t_any)
+       {
+           if (argcount == 0)
+               return &t_func_0_any;
+           else
+               return &t_func_any;
+       }
+       if (ret_type == &t_number)
+       {
+           if (argcount == 0)
+               return &t_func_0_number;
+           else
+               return &t_func_number;
+       }
+       if (ret_type == &t_string)
+       {
+           if (argcount == 0)
+               return &t_func_0_string;
+           else
+               return &t_func_string;
+       }
+     }
+ 
+     // 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;
      return type;
  }
  
***************
*** 774,781 ****
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL,
!                                                     &t_partial_any)) == NULL)
        return FAIL;
      isn->isn_arg.partial = part;
  
--- 832,838 ----
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, &t_func_any)) == 
NULL)
        return FAIL;
      isn->isn_arg.partial = part;
  
***************
*** 942,948 ****
  {
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
-     garray_T  *type_list = cctx->ctx_type_list;
      type_T    *type;
      type_T    *member;
  
--- 999,1004 ----
***************
*** 960,966 ****
        member = ((type_T **)stack->ga_data)[stack->ga_len];
      else
        member = &t_void;
!     type = get_list_type(member, type_list);
  
      // add the list type to the type stack
      if (ga_grow(stack, 1) == FAIL)
--- 1016,1022 ----
        member = ((type_T **)stack->ga_data)[stack->ga_len];
      else
        member = &t_void;
!     type = get_list_type(member, cctx->ctx_type_list);
  
      // add the list type to the type stack
      if (ga_grow(stack, 1) == FAIL)
***************
*** 979,985 ****
  {
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
-     garray_T  *type_list = cctx->ctx_type_list;
      type_T    *type;
      type_T    *member;
  
--- 1035,1040 ----
***************
*** 997,1003 ****
        member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
      else
        member = &t_void;
!     type = get_dict_type(member, type_list);
  
      // add the dict type to the type stack
      if (ga_grow(stack, 1) == FAIL)
--- 1052,1058 ----
        member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
      else
        member = &t_void;
!     type = get_dict_type(member, cctx->ctx_type_list);
  
      // add the dict type to the type stack
      if (ga_grow(stack, 1) == FAIL)
***************
*** 1024,1030 ****
  
      if (ga_grow(stack, 1) == FAIL)
        return FAIL;
!     ((type_T **)stack->ga_data)[stack->ga_len] = &t_partial_any;
      // TODO: argument and return types
      ++stack->ga_len;
  
--- 1079,1085 ----
  
      if (ga_grow(stack, 1) == FAIL)
        return FAIL;
!     ((type_T **)stack->ga_data)[stack->ga_len] = &t_func_any;
      // TODO: argument and return types
      ++stack->ga_len;
  
***************
*** 1298,1303 ****
--- 1353,1360 ----
  
  static char e_white_both[] =
                        N_("E1004: white space required before and after '%s'");
+ static char e_white_after[] = N_("E1069: white space required after '%s'");
+ static char e_no_white_before[] = N_("E1068: No white space allowed before 
'%s'");
  
  /*
   * Reserve space for a local variable.
***************
*** 1385,1395 ****
  
  /*
   * Parse the member type: "<type>" and return "type" with the member set.
!  * Use "type_list" if a new type needs to be added.
   * Returns NULL in case of failure.
   */
      static type_T *
! parse_type_member(char_u **arg, type_T *type, garray_T *type_list)
  {
      type_T  *member_type;
      int           prev_called_emsg = called_emsg;
--- 1442,1452 ----
  
  /*
   * Parse the member type: "<type>" and return "type" with the member set.
!  * Use "type_gap" if a new type needs to be added.
   * Returns NULL in case of failure.
   */
      static type_T *
! parse_type_member(char_u **arg, type_T *type, garray_T *type_gap)
  {
      type_T  *member_type;
      int           prev_called_emsg = called_emsg;
***************
*** 1397,1410 ****
      if (**arg != '<')
      {
        if (*skipwhite(*arg) == '<')
!           emsg(_("E1007: No white space allowed before <"));
        else
            emsg(_("E1008: Missing <type>"));
        return type;
      }
      *arg = skipwhite(*arg + 1);
  
!     member_type = parse_type(arg, type_list);
  
      *arg = skipwhite(*arg);
      if (**arg != '>' && called_emsg == prev_called_emsg)
--- 1454,1467 ----
      if (**arg != '<')
      {
        if (*skipwhite(*arg) == '<')
!           semsg(_(e_no_white_before), "<");
        else
            emsg(_("E1008: Missing <type>"));
        return type;
      }
      *arg = skipwhite(*arg + 1);
  
!     member_type = parse_type(arg, type_gap);
  
      *arg = skipwhite(*arg);
      if (**arg != '>' && called_emsg == prev_called_emsg)
***************
*** 1415,1422 ****
      ++*arg;
  
      if (type->tt_type == VAR_LIST)
!       return get_list_type(member_type, type_list);
!     return get_dict_type(member_type, type_list);
  }
  
  /*
--- 1472,1479 ----
      ++*arg;
  
      if (type->tt_type == VAR_LIST)
!       return get_list_type(member_type, type_gap);
!     return get_dict_type(member_type, type_gap);
  }
  
  /*
***************
*** 1424,1430 ****
   * Return &t_any for failure.
   */
      type_T *
! parse_type(char_u **arg, garray_T *type_list)
  {
      char_u  *p = *arg;
      size_t  len;
--- 1481,1487 ----
   * Return &t_any for failure.
   */
      type_T *
! parse_type(char_u **arg, garray_T *type_gap)
  {
      char_u  *p = *arg;
      size_t  len;
***************
*** 1466,1472 ****
            if (len == 4 && STRNCMP(*arg, "dict", len) == 0)
            {
                *arg += len;
!               return parse_type_member(arg, &t_dict_any, type_list);
            }
            break;
        case 'f':
--- 1523,1529 ----
            if (len == 4 && STRNCMP(*arg, "dict", len) == 0)
            {
                *arg += len;
!               return parse_type_member(arg, &t_dict_any, type_gap);
            }
            break;
        case 'f':
***************
*** 1482,1490 ****
            }
            if (len == 4 && STRNCMP(*arg, "func", len) == 0)
            {
                *arg += len;
!               // TODO: arguments and return type
!               return &t_func_any;
            }
            break;
        case 'j':
--- 1539,1623 ----
            }
            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 != ')')
!                   {
!                       if (STRNCMP(p, "...", 3) == 0)
!                       {
!                           flags |= TTFLAG_VARARGS;
!                           break;
!                       }
!                       arg_type[argcount++] = parse_type(&p, type_gap);
! 
!                       if (*p != ',' && *skipwhite(p) == ',')
!                       {
!                           semsg(_(e_no_white_before), ",");
!                           return &t_any;
!                       }
!                       if (*p == ',')
!                       {
!                           ++p;
!                           if (!VIM_ISWHITE(*p))
!                               semsg(_(e_white_after), ",");
!                       }
!                       p = skipwhite(p);
!                       if (argcount == MAX_FUNC_ARGS)
!                       {
!                           emsg(_("E740: Too many argument types"));
!                           return &t_any;
!                       }
!                   }
! 
!                   p = skipwhite(p);
!                   if (*p != ')')
!                   {
!                       emsg(_(e_missing_close));
!                       return &t_any;
!                   }
!                   *arg = p + 1;
!               }
!               if (**arg == ':')
!               {
!                   // parse return type
!                   ++*arg;
!                   if (!VIM_ISWHITE(*p))
!                       semsg(_(e_white_after), ":");
!                   *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);
!               }
!               return type;
            }
            break;
        case 'j':
***************
*** 1498,1504 ****
            if (len == 4 && STRNCMP(*arg, "list", len) == 0)
            {
                *arg += len;
!               return parse_type_member(arg, &t_list_any, type_list);
            }
            break;
        case 'n':
--- 1631,1637 ----
            if (len == 4 && STRNCMP(*arg, "list", len) == 0)
            {
                *arg += len;
!               return parse_type_member(arg, &t_list_any, type_gap);
            }
            break;
        case 'n':
***************
*** 1508,1521 ****
                return &t_number;
            }
            break;
-       case 'p':
-           if (len == 7 && STRNCMP(*arg, "partial", len) == 0)
-           {
-               *arg += len;
-               // TODO: arguments and return type
-               return &t_partial_any;
-           }
-           break;
        case 's':
            if (len == 6 && STRNCMP(*arg, "string", len) == 0)
            {
--- 1641,1646 ----
***************
*** 1574,1580 ****
   * "type2" and "dest" may be the same.
   */
      static void
! common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_list)
  {
      if (equal_type(type1, type2))
      {
--- 1699,1705 ----
   * "type2" and "dest" may be the same.
   */
      static void
! common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
  {
      if (equal_type(type1, type2))
      {
***************
*** 1588,1598 ****
        {
            type_T *common;
  
!           common_type(type1->tt_member, type2->tt_member, &common, type_list);
            if (type1->tt_type == VAR_LIST)
!               *dest = get_list_type(common, type_list);
            else
!               *dest = get_dict_type(common, type_list);
            return;
        }
        // TODO: VAR_FUNC and VAR_PARTIAL
--- 1713,1723 ----
        {
            type_T *common;
  
!           common_type(type1->tt_member, type2->tt_member, &common, type_gap);
            if (type1->tt_type == VAR_LIST)
!               *dest = get_list_type(common, type_gap);
            else
!               *dest = get_dict_type(common, type_gap);
            return;
        }
        // TODO: VAR_FUNC and VAR_PARTIAL
***************
*** 1962,1975 ****
  
        if (*p != ',' && *skipwhite(p) == ',')
        {
!           emsg(_("E1068: No white space allowed before ,"));
            p = skipwhite(p);
        }
        if (*p == ',')
        {
            ++p;
            if (!VIM_ISWHITE(*p))
!               emsg(_("E1069: white space required after ,"));
        }
        p = skipwhite(p);
      }
--- 2087,2100 ----
  
        if (*p != ',' && *skipwhite(p) == ',')
        {
!           semsg(_(e_no_white_before), ",");
            p = skipwhite(p);
        }
        if (*p == ',')
        {
            ++p;
            if (!VIM_ISWHITE(*p))
!               semsg(_(e_white_after), ",");
        }
        p = skipwhite(p);
      }
*** ../vim-8.2.0507/src/globals.h       2020-04-02 18:50:42.419773128 +0200
--- src/globals.h       2020-04-03 21:31:30.596059891 +0200
***************
*** 379,414 ****
  
  
  // Commonly used types.
! EXTERN type_T t_any INIT4(VAR_UNKNOWN, 0, NULL, NULL);
! EXTERN type_T t_void INIT4(VAR_VOID, 0, NULL, NULL);
! EXTERN type_T t_bool INIT4(VAR_BOOL, 0, NULL, NULL);
! EXTERN type_T t_special INIT4(VAR_SPECIAL, 0, NULL, NULL);
! EXTERN type_T t_number INIT4(VAR_NUMBER, 0, NULL, NULL);
! EXTERN type_T t_float INIT4(VAR_FLOAT, 0, NULL, NULL);
! EXTERN type_T t_string INIT4(VAR_STRING, 0, NULL, NULL);
! EXTERN type_T t_blob INIT4(VAR_BLOB, 0, NULL, NULL);
! EXTERN type_T t_job INIT4(VAR_JOB, 0, NULL, NULL);
! EXTERN type_T t_channel INIT4(VAR_CHANNEL, 0, NULL, NULL);
! 
! EXTERN type_T t_func_void INIT4(VAR_FUNC, -1, &t_void, NULL);
! EXTERN type_T t_func_any INIT4(VAR_FUNC, -1, &t_any, NULL);
! 
! EXTERN type_T t_partial_void INIT4(VAR_PARTIAL, -1, &t_void, NULL);
! EXTERN type_T t_partial_any INIT4(VAR_PARTIAL, -1, &t_any, NULL);
! 
! EXTERN type_T t_list_any INIT4(VAR_LIST, 0, &t_any, NULL);
! EXTERN type_T t_dict_any INIT4(VAR_DICT, 0, &t_any, NULL);
! EXTERN type_T t_list_empty INIT4(VAR_LIST, 0, &t_void, NULL);
! EXTERN type_T t_dict_empty INIT4(VAR_DICT, 0, &t_void, NULL);
! 
! EXTERN type_T t_list_bool INIT4(VAR_LIST, 0, &t_bool, NULL);
! EXTERN type_T t_list_number INIT4(VAR_LIST, 0, &t_number, NULL);
! EXTERN type_T t_list_string INIT4(VAR_LIST, 0, &t_string, NULL);
! EXTERN type_T t_list_dict_any INIT4(VAR_LIST, 0, &t_dict_any, NULL);
! 
! EXTERN type_T t_dict_bool INIT4(VAR_DICT, 0, &t_bool, NULL);
! EXTERN type_T t_dict_number INIT4(VAR_DICT, 0, &t_number, NULL);
! EXTERN type_T t_dict_string INIT4(VAR_DICT, 0, &t_string, NULL);
  
  
  #endif
--- 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
*** ../vim-8.2.0507/src/structs.h       2020-03-26 20:33:20.995063766 +0100
--- src/structs.h       2020-04-03 21:20:22.703051055 +0200
***************
*** 1342,1351 ****
  struct type_S {
      vartype_T     tt_type;
      short         tt_argcount;    // for func, partial, -1 for unknown
      type_T        *tt_member;     // for list, dict, func return type
!     type_T        *tt_args;       // func arguments
  };
  
  /*
   * Structure to hold an internal variable without a name.
   */
--- 1342,1355 ----
  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 "..."
+ #define TTFLAG_OPTARG 2           // func arg type with "?"
+ 
  /*
   * Structure to hold an internal variable without a name.
   */
*** ../vim-8.2.0507/src/evalfunc.c      2020-04-02 18:50:42.419773128 +0200
--- src/evalfunc.c      2020-04-03 21:14:25.256444458 +0200
***************
*** 336,346 ****
      return &t_func_any;
  }
      static type_T *
- ret_partial_any(int argcount UNUSED, type_T **argtypes UNUSED)
- {
-     return &t_partial_any;
- }
-     static type_T *
  ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
  {
      return &t_channel;
--- 336,341 ----
***************
*** 564,570 ****
      {"foldtext",      0, 0, 0,          ret_string,   f_foldtext},
      {"foldtextresult",        1, 1, FEARG_1,    ret_string,   
f_foldtextresult},
      {"foreground",    0, 0, 0,          ret_void,     f_foreground},
!     {"funcref",               1, 3, FEARG_1,    ret_partial_any, f_funcref},
      {"function",      1, 3, FEARG_1,    ret_f_function, f_function},
      {"garbagecollect",        0, 1, 0,          ret_void,     
f_garbagecollect},
      {"get",           2, 3, FEARG_1,    ret_any,      f_get},
--- 559,565 ----
      {"foldtext",      0, 0, 0,          ret_string,   f_foldtext},
      {"foldtextresult",        1, 1, FEARG_1,    ret_string,   
f_foldtextresult},
      {"foreground",    0, 0, 0,          ret_void,     f_foreground},
!     {"funcref",               1, 3, FEARG_1,    ret_func_any, f_funcref},
      {"function",      1, 3, FEARG_1,    ret_f_function, f_function},
      {"garbagecollect",        0, 1, 0,          ret_void,     
f_garbagecollect},
      {"get",           2, 3, FEARG_1,    ret_any,      f_get},
***************
*** 961,967 ****
      {"test_null_function", 0, 0, 0,     ret_func_any, f_test_null_function},
      {"test_null_job", 0, 0, 0,          ret_job,      
JOB_FUNC(f_test_null_job)},
      {"test_null_list",        0, 0, 0,          ret_list_any, 
f_test_null_list},
!     {"test_null_partial", 0, 0, 0,      ret_partial_any, f_test_null_partial},
      {"test_null_string", 0, 0, 0,       ret_string,   f_test_null_string},
      {"test_option_not_set", 1, 1, FEARG_1,ret_void,    f_test_option_not_set},
      {"test_override", 2, 2, FEARG_2,    ret_void,     f_test_override},
--- 956,962 ----
      {"test_null_function", 0, 0, 0,     ret_func_any, f_test_null_function},
      {"test_null_job", 0, 0, 0,          ret_job,      
JOB_FUNC(f_test_null_job)},
      {"test_null_list",        0, 0, 0,          ret_list_any, 
f_test_null_list},
!     {"test_null_partial", 0, 0, 0,      ret_func_any, f_test_null_partial},
      {"test_null_string", 0, 0, 0,       ret_string,   f_test_null_string},
      {"test_option_not_set", 1, 1, FEARG_1,ret_void,    f_test_option_not_set},
      {"test_override", 2, 2, FEARG_2,    ret_void,     f_test_override},
***************
*** 2902,2908 ****
  {
      if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
        return &t_func_any;
!     return &t_partial_void;
  }
  
  /*
--- 2897,2903 ----
  {
      if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
        return &t_func_any;
!     return &t_func_void;
  }
  
  /*
*** ../vim-8.2.0507/src/testdir/test_vim9_expr.vim      2020-04-01 
21:17:17.268409971 +0200
--- src/testdir/test_vim9_expr.vim      2020-04-03 21:41:49.053439350 +0200
***************
*** 461,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: partial', 'let r = j == 
x'], 'Cannot compare job with partial')
  endfunc
  
  " test addition, subtraction, concatenation
--- 461,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
*** ../vim-8.2.0507/src/testdir/test_vim9_script.vim    2020-04-02 
22:33:17.868287352 +0200
--- src/testdir/test_vim9_script.vim    2020-04-03 21:43:59.008901654 +0200
***************
*** 68,75 ****
    endif
    let funky1: func
    let funky2: func = function('len')
!   let party1: partial
!   let party2: partial = funcref('Test_syntax')
  
    " type becomes list<any>
    let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
--- 68,74 ----
    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']
***************
*** 157,165 ****
    let thefunc: func
    assert_equal(test_null_function(), thefunc)
  
-   let thepartial: partial
-   assert_equal(test_null_partial(), thepartial)
- 
    let thelist: list<any>
    assert_equal([], thelist)
  
--- 156,161 ----
***************
*** 213,219 ****
    call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:')
    call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number 
but got void')
  
!   call CheckDefFailure(['let var: dict <number>'], 'E1007:')
    call CheckDefFailure(['let var: dict<number'], 'E1009:')
  endfunc
  
--- 209,215 ----
    call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:')
    call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number 
but got void')
  
!   call CheckDefFailure(['let var: dict <number>'], 'E1068:')
    call CheckDefFailure(['let var: dict<number'], 'E1009:')
  endfunc
  
*** ../vim-8.2.0507/src/testdir/test_vim9_disassemble.vim       2020-04-02 
21:13:21.396362396 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-04-03 21:49:34.439523652 
+0200
***************
*** 362,369 ****
  def WithFunc()
    let funky1: func
    let funky2: func = function("len")
!   let party1: partial
!   let party2: partial = funcref("UserFunc")
  enddef
  
  def Test_disassemble_function()
--- 362,368 ----
  def WithFunc()
    let funky1: func
    let funky2: func = function("len")
!   let party2: func = funcref("UserFunc")
  enddef
  
  def Test_disassemble_function()
***************
*** 376,390 ****
          \ .. '2 PUSHS "len".*'
          \ .. '3 BCALL function(argc 1).*'
          \ .. '4 STORE $1.*'
!         \ .. 'let party1: partial.*'
!         \ .. '5 PUSHPARTIAL "\[none]".*'
!         \ .. '6 STORE $2.*'
!         \ .. 'let party2: partial = funcref("UserFunc").*'
!         \ .. '7 PUSHS "UserFunc".*'
!         \ .. '8 BCALL funcref(argc 1).*'
!         \ .. '9 STORE $3.*'
!         \ .. '10 PUSHNR 0.*'
!         \ .. '11 RETURN.*'
          \, instr)
  enddef
  
--- 375,386 ----
          \ .. '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.*'
!         \ .. '\d PUSHNR 0.*'
!         \ .. '\d RETURN.*'
          \, instr)
  enddef
  
***************
*** 753,762 ****
          \ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
          \ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
          \
!         \ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
!         \ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
!         \ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
!         \ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
          \
          \ ['77 == g:xx', 'COMPAREANY =='],
          \ ['77 != g:xx', 'COMPAREANY !='],
--- 749,758 ----
          \ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
          \ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
          \
!         \ ['{->33} == {->44}', 'COMPAREFUNC =='],
!         \ ['{->33} != {->44}', 'COMPAREFUNC !='],
!         \ ['{->33} is {->44}', 'COMPAREFUNC is'],
!         \ ['{->33} isnot {->44}', 'COMPAREFUNC isnot'],
          \
          \ ['77 == g:xx', 'COMPAREANY =='],
          \ ['77 != g:xx', 'COMPAREANY !='],
*** ../vim-8.2.0507/src/version.c       2020-04-03 18:43:31.886980756 +0200
--- src/version.c       2020-04-03 21:49:54.083443302 +0200
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     508,
  /**/

-- 
ARTHUR:  No, hang on!  Just answer the five questions ...
GALAHAD: Three questions ...
ARTHUR:  Three questions ...  And we shall watch ... and pray.
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// 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/202004032000.033K0UbK029149%40masaka.moolenaar.net.

Raspunde prin e-mail lui