]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0299: Vim9: return type not set for a lambda assigned to script var v9.1.0299
authorYegappan Lakshmanan <yegappan@yahoo.com>
Wed, 10 Apr 2024 15:18:19 +0000 (17:18 +0200)
committerChristian Brabandt <cb@256bit.org>
Wed, 10 Apr 2024 15:18:19 +0000 (17:18 +0200)
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>
src/testdir/test_vim9_assign.vim
src/testdir/vim9.vim
src/version.c
src/vim9type.c

index 82dc3e5ca98f0720d52f9ca513241a8e7c42d367..0d6d783ed847d41803f78d8799baff01fe88bc70 100644 (file)
@@ -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()
index 782809bde89c47eb9b9bf8f435ce8feb6d1efe3f..764b6119db66820fc87936f257272d5f2c2ab435 100644 (file)
@@ -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
index 520b7e9c2b40c5753582f89b82b2bd749eebcfed..db892ab487972e7b670054fc4e7aa45528b2bebf 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    299,
 /**/
     298,
 /**/
index 4d93ba72775528bd23fd770a1981baaa502951ef..691c26bf8e8b55a155c865dc59dc19b443673a85 100644 (file)
@@ -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;
        }