diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-04-09 20:24:31 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-04-09 20:24:31 +0200 |
commit | 2a38908b05c1d3973a8edbeb5b3e05a11332faf0 (patch) | |
tree | 493740a34e6d0267647145fe571355e09743f295 | |
parent | 767034c5b82ba8999d9fed2f997436e6e3e99419 (diff) | |
download | vim-git-2a38908b05c1d3973a8edbeb5b3e05a11332faf0.tar.gz |
patch 8.2.2740: Vim9: lambda with varargs doesn't workv8.2.2740
Problem: Vim9: lambda with varargs doesn't work.
Solution: Make "...name" work. Require type to be a list.
-rw-r--r-- | src/errors.h | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_func.vim | 21 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 6 | ||||
-rw-r--r-- | src/userfunc.c | 61 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 5 | ||||
-rw-r--r-- | src/vim9execute.c | 2 |
7 files changed, 68 insertions, 31 deletions
diff --git a/src/errors.h b/src/errors.h index 0225531cb..e4836bc4a 100644 --- a/src/errors.h +++ b/src/errors.h @@ -395,3 +395,5 @@ EXTERN char e_cannot_lock_unlock_local_variable[] 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")); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index b0669fe65..d48cab452 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -791,10 +791,18 @@ def Test_call_funcref_wrong_args() 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)()') - var lines =<< trim END + lines =<< trim END var Ref = (x: number, y: number) => x + y echo Ref(1, 'x') END @@ -923,7 +931,7 @@ def Test_call_def_varargs() lines =<< trim END vim9script - def Func(...l: any) + def Func(...l: list<any>) echo l enddef Func(0) @@ -932,6 +940,15 @@ def Test_call_def_varargs() 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<string>) echo _l enddef diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 98f40bb8f..7155e8f3b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -3644,7 +3644,7 @@ enddef def Test_catch_exception_in_callback() var lines =<< trim END vim9script - def Callback(...l: any) + def Callback(...l: list<any>) try var x: string var y: string @@ -3669,10 +3669,10 @@ def Test_no_unknown_error_after_error() var lines =<< trim END vim9script var source: list<number> - def Out_cb(...l: any) + def Out_cb(...l: list<any>) eval [][0] enddef - def Exit_cb(...l: any) + def Exit_cb(...l: list<any>) sleep 1m source += l enddef diff --git a/src/userfunc.c b/src/userfunc.c index 81a73e280..8d06b4916 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -68,6 +68,7 @@ one_function_arg( garray_T *argtypes, int types_optional, evalarg_T *evalarg, + int is_vararg, int skip) { char_u *p = arg; @@ -155,7 +156,8 @@ one_function_arg( { if (type == NULL && types_optional) // lambda arguments default to "any" type - type = vim_strsave((char_u *)"any"); + type = vim_strsave((char_u *) + (is_vararg ? "list<any>" : "any")); ((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type; } } @@ -250,7 +252,7 @@ get_function_args( arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, - evalarg, skip); + evalarg, TRUE, skip); if (p == arg) break; if (*skipwhite(p) == '=') @@ -264,7 +266,7 @@ get_function_args( { arg = p; p = one_function_arg(p, newargs, argtypes, types_optional, - evalarg, skip); + evalarg, FALSE, skip); if (p == arg) break; @@ -360,12 +362,14 @@ err_ret: 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. - int len = argtypes->ga_len - (varargs ? 1 : 0); + len = argtypes->ga_len - (varargs ? 1 : 0); if (len > 0) fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len); @@ -388,25 +392,35 @@ parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs) fp->uf_arg_types[i] = type; } } - if (varargs) + } + + 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 { - 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) + 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,7 +1250,8 @@ get_lambda_tv( ga_init(&fp->uf_def_args); if (types_optional) { - if (parse_argument_types(fp, &argtypes, FALSE) == FAIL) + if (parse_argument_types(fp, &argtypes, + in_vim9script() && varargs) == FAIL) goto errret; if (ret_type != NULL) { @@ -1264,8 +1279,8 @@ get_lambda_tv( 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(); + // 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,7 +3205,7 @@ list_func_head(ufunc_T *fp, int indent) msg_puts(", "); msg_puts("..."); msg_puts((char *)fp->uf_va_name); - if (fp->uf_va_type) + if (fp->uf_va_type != NULL) { char *tofree; diff --git a/src/version.c b/src/version.c index a2bd55869..74a0ae6e7 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2740, +/**/ 2739, /**/ 2738, diff --git a/src/vim9compile.c b/src/vim9compile.c index 00a8f5646..2cfc12798 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1856,7 +1856,8 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) continue; expected = ufunc->uf_arg_types[i]; } - else if (ufunc->uf_va_type == NULL || ufunc->uf_va_type == &t_any) + else if (ufunc->uf_va_type == NULL + || ufunc->uf_va_type == &t_list_any) // possibly a lambda or "...: any" expected = &t_any; else @@ -9069,7 +9070,7 @@ set_function_type(ufunc_T *ufunc) if (varargs) { ufunc->uf_func_type->tt_args[argcount] = - ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; + ufunc->uf_va_type == NULL ? &t_list_any : ufunc->uf_va_type; ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; } } diff --git a/src/vim9execute.c b/src/vim9execute.c index d6c476488..eddb90f9f 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1374,7 +1374,7 @@ call_def_function( // 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 != &t_list_any && ufunc->uf_va_type->tt_member != &t_any && tv->vval.v_list != NULL) { |