From 7f5202143b2c84ec12e709272d90dd79621d14ca Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Wed, 10 Apr 2024 17:18:19 +0200 Subject: 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 --- src/testdir/test_vim9_assign.vim | 21 ++++++++++++++ src/testdir/vim9.vim | 6 ++++ src/version.c | 2 ++ src/vim9type.c | 59 ++++++++++++++++++++++++---------------- 4 files changed, 65 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 82dc3e5ca9..0d6d783ed8 100644 --- 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 index 782809bde8..764b6119db 100644 --- 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 index 520b7e9c2b..db892ab487 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 299, /**/ 298, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index 4d93ba7277..691c26bf8e 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -417,6 +417,36 @@ type_any_or_unknown(type_T *type) || type->tt_type == VAR_UNKNOWN; } +/* + * 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. @@ -569,27 +599,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags) 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, typval_T *actual_tv, where_T where) { 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; } -- cgit v1.2.3