# HG changeset patch # User Christian Brabandt # Date 1712763004 -7200 # Node ID 3f9d9ee5cb7c1e420420f8e7ca556084e4ec63ba # Parent 6e66a52748d0a2e338917c3eb43d74e833a14a76 patch 9.1.0299: Vim9: return type not set for a lambda assigned to script var Commit: https://github.com/vim/vim/commit/7f5202143b2c84ec12e709272d90dd79621d14ca Author: Yegappan Lakshmanan Date: Wed Apr 10 17:18:19 2024 +0200 patch 9.1.0299: Vim9: return type not set for a lambda assigned to script var Problem: Vim9: return type not set for a lambda assigned to script var (Ernie Rael) Solution: Correctly determine the return type (Yegappan Lakshmanan) fixes: #14445 closes: #14473 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1104,6 +1104,27 @@ def Test_assignment_partial() Ref(0) END v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number') + + lines =<< trim END + var Fn1 = () => { + return 10 + } + assert_equal('func(): number', typename(Fn1)) + var Fn2 = () => { + return "a" + } + assert_equal('func(): string', typename(Fn2)) + var Fn3 = () => { + return {a: [1]} + } + assert_equal('func(): dict>', typename(Fn3)) + var Fn4 = (...l: list) => { + return [] + } + assert_equal('func(...list): list', typename(Fn4)) + END + v9.CheckSourceSuccess(['vim9script'] + lines) + v9.CheckSourceSuccess(['def Xfunc()'] + lines + ['enddef', 'defcompile']) enddef def Test_assignment_list_any_index() diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -112,11 +112,13 @@ enddef # :source a list of "lines" and check whether it fails with "error" export def CheckSourceFailure(lines: list, error: string, lnum = -3) + var cwd = getcwd() new setline(1, lines) try assert_fails('source', error, lines, lnum) finally + chdir(cwd) bw! endtry enddef @@ -124,22 +126,26 @@ enddef # :source a list of "lines" and check whether it fails with the list of # "errors" export def CheckSourceFailureList(lines: list, errors: list, lnum = -3) + var cwd = getcwd() new setline(1, lines) try assert_fails('source', errors, lines, lnum) finally + chdir(cwd) bw! endtry enddef # :source a list of "lines" and check whether it succeeds export def CheckSourceSuccess(lines: list) + var cwd = getcwd() new setline(1, lines) try :source finally + chdir(cwd) bw! endtry enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 299, +/**/ 298, /**/ 297, diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -418,6 +418,36 @@ type_any_or_unknown(type_T *type) } /* + * Get a type_T for a partial typval in "tv". + */ + static type_T * +partial_typval2type(typval_T *tv, ufunc_T *ufunc, garray_T *type_gap) +{ + partial_T *pt = tv->vval.v_partial; + type_T *type; + + type = get_type_ptr(type_gap); + if (type == NULL) + return NULL; + + *type = *ufunc->uf_func_type; + if (type->tt_argcount >= 0 && pt->pt_argc > 0) + { + type->tt_argcount -= pt->pt_argc; + type->tt_min_argcount -= pt->pt_argc; + if (type->tt_argcount > 0 && func_type_add_arg_types(type, + type->tt_argcount, type_gap) == OK) + for (int i = 0; i < type->tt_argcount; ++i) + type->tt_args[i] = + ufunc->uf_func_type->tt_args[i + pt->pt_argc]; + } + if (pt->pt_func != NULL) + type->tt_member = pt->pt_func->uf_ret_type; + + return type; +} + +/* * Get a type_T for a typval_T. * "type_gap" is used to temporarily create types in. * When "flags" has TVTT_DO_MEMBER also get the member type, otherwise use @@ -569,27 +599,8 @@ typval2type_int(typval_T *tv, int copyID set_function_type(ufunc); if (ufunc->uf_func_type != NULL) { - if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL - && tv->vval.v_partial->pt_argc > 0) - { - type = get_type_ptr(type_gap); - if (type == NULL) - return NULL; - *type = *ufunc->uf_func_type; - if (type->tt_argcount >= 0) - { - type->tt_argcount -= tv->vval.v_partial->pt_argc; - type->tt_min_argcount -= tv->vval.v_partial->pt_argc; - if (type->tt_argcount > 0 - && func_type_add_arg_types(type, - type->tt_argcount, type_gap) == OK) - for (int i = 0; i < type->tt_argcount; ++i) - type->tt_args[i] = - ufunc->uf_func_type->tt_args[ - i + tv->vval.v_partial->pt_argc]; - } - return type; - } + if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) + return partial_typval2type(tv, ufunc, type_gap); return ufunc->uf_func_type; } } @@ -737,12 +748,14 @@ check_typval_type(type_T *expected, typv { res = check_type_maybe(expected, actual_type, TRUE, where); if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC - && actual_type->tt_member == &t_unknown)) + && (actual_type->tt_member == &t_unknown + || actual_type->tt_member == NULL))) { // If a type check is needed that means assigning "any" or // "unknown" to a more specific type, which fails here. // Except when it looks like a lambda, since they have an - // incomplete type. + // incomplete type. A legacy lambda function has a NULL return + // type. type_mismatch_where(expected, actual_type, where); res = FAIL; }