0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

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 <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2024-04-10 17:18:19 +02:00
committed by Christian Brabandt
parent b988c7a95f
commit 7f5202143b
4 changed files with 65 additions and 23 deletions

View File

@@ -1104,6 +1104,27 @@ def Test_assignment_partial()
Ref(0) Ref(0)
END END
v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number') 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<list<number>>', typename(Fn3))
var Fn4 = (...l: list<string>) => {
return []
}
assert_equal('func(...list<string>): list<any>', typename(Fn4))
END
v9.CheckSourceSuccess(['vim9script'] + lines)
v9.CheckSourceSuccess(['def Xfunc()'] + lines + ['enddef', 'defcompile'])
enddef enddef
def Test_assignment_list_any_index() def Test_assignment_list_any_index()

View File

@@ -112,11 +112,13 @@ enddef
# :source a list of "lines" and check whether it fails with "error" # :source a list of "lines" and check whether it fails with "error"
export def CheckSourceFailure(lines: list<string>, error: string, lnum = -3) export def CheckSourceFailure(lines: list<string>, error: string, lnum = -3)
var cwd = getcwd()
new new
setline(1, lines) setline(1, lines)
try try
assert_fails('source', error, lines, lnum) assert_fails('source', error, lines, lnum)
finally finally
chdir(cwd)
bw! bw!
endtry endtry
enddef enddef
@@ -124,22 +126,26 @@ enddef
# :source a list of "lines" and check whether it fails with the list of # :source a list of "lines" and check whether it fails with the list of
# "errors" # "errors"
export def CheckSourceFailureList(lines: list<string>, errors: list<string>, lnum = -3) export def CheckSourceFailureList(lines: list<string>, errors: list<string>, lnum = -3)
var cwd = getcwd()
new new
setline(1, lines) setline(1, lines)
try try
assert_fails('source', errors, lines, lnum) assert_fails('source', errors, lines, lnum)
finally finally
chdir(cwd)
bw! bw!
endtry endtry
enddef enddef
# :source a list of "lines" and check whether it succeeds # :source a list of "lines" and check whether it succeeds
export def CheckSourceSuccess(lines: list<string>) export def CheckSourceSuccess(lines: list<string>)
var cwd = getcwd()
new new
setline(1, lines) setline(1, lines)
try try
:source :source
finally finally
chdir(cwd)
bw! bw!
endtry endtry
enddef enddef

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
299,
/**/ /**/
298, 298,
/**/ /**/

View File

@@ -417,6 +417,36 @@ type_any_or_unknown(type_T *type)
|| type->tt_type == VAR_UNKNOWN; || 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. * Get a type_T for a typval_T.
* "type_gap" is used to temporarily create types in. * "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); set_function_type(ufunc);
if (ufunc->uf_func_type != NULL) if (ufunc->uf_func_type != NULL)
{ {
if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
&& tv->vval.v_partial->pt_argc > 0) return partial_typval2type(tv, ufunc, type_gap);
{
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;
}
return ufunc->uf_func_type; 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); res = check_type_maybe(expected, actual_type, TRUE, where);
if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC 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 // If a type check is needed that means assigning "any" or
// "unknown" to a more specific type, which fails here. // "unknown" to a more specific type, which fails here.
// Except when it looks like a lambda, since they have an // 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); type_mismatch_where(expected, actual_type, where);
res = FAIL; res = FAIL;
} }