summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2024-04-10 17:18:19 +0200
committerChristian Brabandt <cb@256bit.org>2024-04-10 17:18:19 +0200
commit7f5202143b2c84ec12e709272d90dd79621d14ca (patch)
tree2aeb0df82a0773db12da800e684dc1a79a440d49
parentb988c7a95f5ddb1f665a3fc7f0bcf2b08145693b (diff)
patch 9.1.0299: Vim9: return type not set for a lambda assigned to script varv9.1.0299
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>
-rw-r--r--src/testdir/test_vim9_assign.vim21
-rw-r--r--src/testdir/vim9.vim6
-rw-r--r--src/version.c2
-rw-r--r--src/vim9type.c59
4 files changed, 65 insertions, 23 deletions
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<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
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<string>, 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<string>, errors: list<string>, 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<string>)
+ 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
@@ -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
index 4d93ba7277..691c26bf8e 100644
--- 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, 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;
}