To: vim_dev@googlegroups.com Subject: Patch 8.2.2740 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2740 Problem: Vim9: lambda with varargs doesn't work. Solution: Make "...name" work. Require type to be a list. Files: src/userfunc.c, src/vim9compile.c, src/vim9execute.c, src/errors.h, src/testdir/test_vim9_func.vim, src/testdir/test_vim9_script.vim *** ../vim-8.2.2739/src/userfunc.c 2021-04-09 17:24:48.575828504 +0200 --- src/userfunc.c 2021-04-09 20:15:56.545331719 +0200 *************** *** 68,73 **** --- 68,74 ---- garray_T *argtypes, int types_optional, evalarg_T *evalarg, + int is_vararg, int skip) { char_u *p = arg; *************** *** 155,161 **** { if (type == NULL && types_optional) // lambda arguments default to "any" type ! type = vim_strsave((char_u *)"any"); ((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type; } } --- 156,163 ---- { if (type == NULL && types_optional) // lambda arguments default to "any" type ! type = vim_strsave((char_u *) ! (is_vararg ? "list" : "any")); ((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type; } } *************** *** 250,256 **** arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, ! evalarg, skip); if (p == arg) break; if (*skipwhite(p) == '=') --- 252,258 ---- arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, ! evalarg, TRUE, skip); if (p == arg) break; if (*skipwhite(p) == '=') *************** *** 264,270 **** { arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, ! evalarg, skip); if (p == arg) break; --- 266,272 ---- { arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, ! evalarg, FALSE, skip); if (p == arg) break; *************** *** 360,371 **** static int parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs) { ga_init2(&fp->uf_type_list, sizeof(type_T *), 10); if (argtypes->ga_len > 0) { // When "varargs" is set the last name/type goes into uf_va_name // and uf_va_type. ! int len = argtypes->ga_len - (varargs ? 1 : 0); if (len > 0) fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len); --- 362,375 ---- static int parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs) { + int len = 0; + ga_init2(&fp->uf_type_list, sizeof(type_T *), 10); if (argtypes->ga_len > 0) { // When "varargs" is set the last name/type goes into uf_va_name // and uf_va_type. ! len = argtypes->ga_len - (varargs ? 1 : 0); if (len > 0) fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len); *************** *** 388,412 **** fp->uf_arg_types[i] = type; } } ! if (varargs) ! { ! char_u *p; ! // Move the last argument "...name: type" to uf_va_name and ! // uf_va_type. ! fp->uf_va_name = ((char_u **)fp->uf_args.ga_data) ! [fp->uf_args.ga_len - 1]; ! --fp->uf_args.ga_len; ! p = ((char_u **)argtypes->ga_data)[len]; ! if (p == NULL) ! // todo: get type from default value ! fp->uf_va_type = &t_any; ! else ! fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE); ! if (fp->uf_va_type == NULL) return FAIL; } } return OK; } --- 392,426 ---- fp->uf_arg_types[i] = type; } } ! } ! if (varargs) ! { ! char_u *p; ! ! // Move the last argument "...name: type" to uf_va_name and ! // uf_va_type. ! fp->uf_va_name = ((char_u **)fp->uf_args.ga_data) ! [fp->uf_args.ga_len - 1]; ! --fp->uf_args.ga_len; ! p = ((char_u **)argtypes->ga_data)[len]; ! if (p == NULL) ! // TODO: get type from default value ! fp->uf_va_type = &t_list_any; ! else ! { ! fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE); ! if (fp->uf_va_type != NULL && fp->uf_va_type->tt_type != VAR_LIST) ! { ! semsg(_(e_variable_arguments_type_must_be_list_str), ! ((char_u **)argtypes->ga_data)[len]); return FAIL; + } } + if (fp->uf_va_type == NULL) + return FAIL; } + return OK; } *************** *** 1236,1242 **** ga_init(&fp->uf_def_args); if (types_optional) { ! if (parse_argument_types(fp, &argtypes, FALSE) == FAIL) goto errret; if (ret_type != NULL) { --- 1250,1257 ---- ga_init(&fp->uf_def_args); if (types_optional) { ! if (parse_argument_types(fp, &argtypes, ! in_vim9script() && varargs) == FAIL) goto errret; if (ret_type != NULL) { *************** *** 1264,1271 **** if (sandbox) flags |= FC_SANDBOX; // In legacy script a lambda can be called with more args than ! // uf_args.ga_len. ! fp->uf_varargs = !in_vim9script(); fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; --- 1279,1286 ---- if (sandbox) flags |= FC_SANDBOX; // In legacy script a lambda can be called with more args than ! // uf_args.ga_len. In Vim9 script "...name" has to be used. ! fp->uf_varargs = !in_vim9script() || varargs; fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; *************** *** 3190,3196 **** msg_puts(", "); msg_puts("..."); msg_puts((char *)fp->uf_va_name); ! if (fp->uf_va_type) { char *tofree; --- 3205,3211 ---- msg_puts(", "); msg_puts("..."); msg_puts((char *)fp->uf_va_name); ! if (fp->uf_va_type != NULL) { char *tofree; *** ../vim-8.2.2739/src/vim9compile.c 2021-04-07 21:58:13.199566858 +0200 --- src/vim9compile.c 2021-04-09 19:36:29.513747654 +0200 *************** *** 1856,1862 **** continue; expected = ufunc->uf_arg_types[i]; } ! else if (ufunc->uf_va_type == NULL || ufunc->uf_va_type == &t_any) // possibly a lambda or "...: any" expected = &t_any; else --- 1856,1863 ---- continue; expected = ufunc->uf_arg_types[i]; } ! else if (ufunc->uf_va_type == NULL ! || ufunc->uf_va_type == &t_list_any) // possibly a lambda or "...: any" expected = &t_any; else *************** *** 9069,9075 **** if (varargs) { ufunc->uf_func_type->tt_args[argcount] = ! ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; } } --- 9070,9076 ---- if (varargs) { ufunc->uf_func_type->tt_args[argcount] = ! ufunc->uf_va_type == NULL ? &t_list_any : ufunc->uf_va_type; ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; } } *** ../vim-8.2.2739/src/vim9execute.c 2021-04-08 18:04:58.865044553 +0200 --- src/vim9execute.c 2021-04-09 19:38:57.897237585 +0200 *************** *** 1374,1380 **** // Check the type of the list items. tv = STACK_TV_BOT(-1); if (ufunc->uf_va_type != NULL ! && ufunc->uf_va_type != &t_any && ufunc->uf_va_type->tt_member != &t_any && tv->vval.v_list != NULL) { --- 1374,1380 ---- // Check the type of the list items. tv = STACK_TV_BOT(-1); if (ufunc->uf_va_type != NULL ! && ufunc->uf_va_type != &t_list_any && ufunc->uf_va_type->tt_member != &t_any && tv->vval.v_list != NULL) { *** ../vim-8.2.2739/src/errors.h 2021-03-29 21:06:01.171475448 +0200 --- src/errors.h 2021-04-09 20:16:08.221267788 +0200 *************** *** 395,397 **** --- 395,399 ---- INIT(= N_("E1178: Cannot lock or unlock a local variable")); EXTERN char e_failed_to_extract_pwd_from_str_check_your_shell_config[] INIT(= N_("E1179: Failed to extract PWD from %s, check your shell's config related to OSC 7")); + EXTERN char e_variable_arguments_type_must_be_list_str[] + INIT(= N_("E1180: Variable arguments type must be a list: %s")); *** ../vim-8.2.2739/src/testdir/test_vim9_func.vim 2021-04-09 17:24:48.575828504 +0200 --- src/testdir/test_vim9_func.vim 2021-04-09 20:19:09.712338328 +0200 *************** *** 791,800 **** enddef def Test_call_lambda_args() CheckDefFailure(['echo ((i) => 0)()'], 'E119: Not enough arguments for function: ((i) => 0)()') ! var lines =<< trim END var Ref = (x: number, y: number) => x + y echo Ref(1, 'x') END --- 791,808 ---- enddef def Test_call_lambda_args() + var lines =<< trim END + var Callback = (..._) => 'anything' + assert_equal('anything', Callback()) + assert_equal('anything', Callback(1)) + assert_equal('anything', Callback('a', 2)) + END + CheckDefAndScriptSuccess(lines) + CheckDefFailure(['echo ((i) => 0)()'], 'E119: Not enough arguments for function: ((i) => 0)()') ! lines =<< trim END var Ref = (x: number, y: number) => x + y echo Ref(1, 'x') END *************** *** 923,929 **** lines =<< trim END vim9script ! def Func(...l: any) echo l enddef Func(0) --- 931,937 ---- lines =<< trim END vim9script ! def Func(...l: list) echo l enddef Func(0) *************** *** 932,937 **** --- 940,954 ---- lines =<< trim END vim9script + def Func(...l: any) + echo l + enddef + Func(0) + END + CheckScriptFailure(lines, 'E1180:', 2) + + lines =<< trim END + vim9script def Func(..._l: list) echo _l enddef *** ../vim-8.2.2739/src/testdir/test_vim9_script.vim 2021-04-09 17:24:48.575828504 +0200 --- src/testdir/test_vim9_script.vim 2021-04-09 20:20:55.787841142 +0200 *************** *** 3644,3650 **** def Test_catch_exception_in_callback() var lines =<< trim END vim9script ! def Callback(...l: any) try var x: string var y: string --- 3644,3650 ---- def Test_catch_exception_in_callback() var lines =<< trim END vim9script ! def Callback(...l: list) try var x: string var y: string *************** *** 3669,3678 **** var lines =<< trim END vim9script var source: list ! def Out_cb(...l: any) eval [][0] enddef ! def Exit_cb(...l: any) sleep 1m source += l enddef --- 3669,3678 ---- var lines =<< trim END vim9script var source: list ! def Out_cb(...l: list) eval [][0] enddef ! def Exit_cb(...l: list) sleep 1m source += l enddef *** ../vim-8.2.2739/src/version.c 2021-04-09 17:24:48.575828504 +0200 --- src/version.c 2021-04-09 19:32:38.226528348 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2740, /**/ -- From "know your smileys": ~#:-( I just washed my hair, and I can't do nuthin' with it. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///