To: vim_dev@googlegroups.com Subject: Patch 8.2.0508 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 ! dict ! (a: type, b: type): type job channel Not supported yet: ! tuple ! 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 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 --- 296,335 ---- float string blob ! list<{type}> ! dict<{type}> job channel + func + func({type}, ...) + func({type}, ...): {type} Not supported yet: ! tuple ! 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 *** ../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: "" 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: "" 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 ")); 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 ")); 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', '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', '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 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 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 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 '], 'E1007:') call CheckDefFailure(['let var: dict'], 'E1068:') call CheckDefFailure(['let var: dict33} == {->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 -- Bram@Moolenaar.net -- 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 ///