]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2043: Vim9: issue with funcref assignmentand varargs v9.0.2043
authorErnie Rael <errael@raelity.com>
Tue, 17 Oct 2023 16:15:01 +0000 (18:15 +0200)
committerChristian Brabandt <cb@256bit.org>
Tue, 17 Oct 2023 16:15:01 +0000 (18:15 +0200)
Problem:  Vim9: issue with funcref assignmentand varargs
Solution: Fix funcref type checking

closes: #13351

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ernie Rael <errael@raelity.com>
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_class.vim
src/testdir/test_vim9_func.vim
src/version.c
src/vim9type.c

index 3a187774ec2a449af78bc7fa97f8ec98ce16ae7a..bff9c9f8f1e788d2dff7d0887739da4e1c893f07 100644 (file)
@@ -1863,6 +1863,62 @@ def Test_assign_lambda()
   v9.CheckDefAndScriptFailure(lines, 'E1051:')
 enddef
 
+def Test_assign_funcref_args()
+  # unspecified arguments match everything, including varargs
+  var lines =<< trim END
+    vim9script
+
+    var FuncUnknown: func: number
+
+    FuncUnknown = (v): number => v
+    assert_equal(5, FuncUnknown(5))
+
+    FuncUnknown = (v1, v2): number => v1 + v2
+    assert_equal(7, FuncUnknown(3, 4))
+
+    FuncUnknown = (...v1): number => v1[0] + v1[1] + len(v1) * 1000
+    assert_equal(4007, FuncUnknown(3, 4, 5, 6))
+
+    FuncUnknown = (v: list<any>): number => v[0] + v[1] + len(v) * 1000
+    assert_equal(5009, FuncUnknown([4, 5, 6, 7, 8]))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # varargs must match
+  lines =<< trim END
+    vim9script
+    var FuncAnyVA: func(...any): number
+    FuncAnyVA = (v): number => v
+  END
+  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(any): number')
+
+  # varargs must match
+  lines =<< trim END
+    vim9script
+    var FuncAnyVA: func(...any): number
+    FuncAnyVA = (v1, v2): number => v1 + v2
+  END
+  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(any, any): number')
+
+  # varargs must match
+  lines =<< trim END
+    vim9script
+    var FuncAnyVA: func(...any): number
+    FuncAnyVA = (v1: list<any>): number => 3
+  END
+  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(...any): number but got func(list<any>): number')
+enddef
+
+def Test_assign_funcref_arg_any()
+  var lines =<< trim END
+    vim9script
+    var FuncAnyVA: func(any): number
+    FuncAnyVA = (v): number => v
+  END
+  # TODO: Verify this should succeed.
+  v9.CheckScriptSuccess(lines)
+enddef
+
 def Test_heredoc()
   # simple heredoc
   var lines =<< trim END
index 8b08dc1b2d70539c57d21e0fdf22b99f3fc1de4f..01cf3e128fdf64e3fde6c9c2f5f18be55cbda6e0 100644 (file)
@@ -6953,6 +6953,21 @@ def Test_extended_obj_method_type_check()
     endclass
   END
   v9.CheckSourceFailure(lines, 'E1383: Method "Doit": type mismatch, expected func(object<B>): object<B> but got func(object<B>): object<A>', 20)
+
+  # check varargs type mismatch
+  lines =<< trim END
+    vim9script
+
+    class B
+      def F(...xxx: list<any>)
+      enddef
+    endclass
+    class C extends B
+      def F(xxx: list<any>)
+      enddef
+    endclass
+  END
+  v9.CheckSourceFailure(lines, 'E1383: Method "F": type mismatch, expected func(...list<any>) but got func(list<any>)', 10)
 enddef
 
 " Test type checking for class variable in assignments
@@ -7431,6 +7446,54 @@ def Test_funcref_argtype_returntype_check()
   v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected func(object<A>): object<A> but got func(object<B>): object<B>', 1)
 enddef
 
+def Test_funcref_argtype_invariance_check()
+  var lines =<< trim END
+    vim9script
+
+    class A
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+    endclass
+
+    var Func: func(B): number
+    Func = (o: B): number => 3
+    assert_equal(3, Func(B.new()))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+
+    class A
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+    endclass
+
+    var Func: func(B): number
+    Func = (o: A): number => 3
+  END
+  v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected func(object<B>): number but got func(object<A>): number', 11)
+
+  lines =<< trim END
+    vim9script
+
+    class A
+    endclass
+    class B extends A
+    endclass
+    class C extends B
+    endclass
+
+    var Func: func(B): number
+    Func = (o: C): number => 3
+  END
+  v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected func(object<B>): number but got func(object<C>): number', 11)
+enddef
+
 " Test for using an operator (e.g. +) with an assignment
 def Test_op_and_assignment()
   # Using += with a class variable
index 597a10c581882c180a1f96a5ae1000680c2edeb0..701a2f085dd3a13a8d58e75f6c3ee8700d00c112 100644 (file)
@@ -1995,7 +1995,7 @@ def Test_varargs_mismatch()
       var res = Map((v) => str2nr(v))
       assert_equal(12, res)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected func(...any): number but got func(any): number')
 enddef
 
 def Test_using_var_as_arg()
index 0b1bf3138e97642890f6a353bb0b67c4ac9bee10..bad07e6446f3f60abd54def27f375ca3c7cc2105 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2043,
 /**/
     2042,
 /**/
index 00ee76b487c6d47ad0eaaa521091c99001fefd5c..6a5848792bc90dea11c8dcf59fbb85e98695e729 100644 (file)
@@ -884,6 +884,11 @@ check_type_maybe(
                else
                    ret = MAYBE;
            }
+           if (ret != FAIL
+                   && ((expected->tt_flags & TTFLAG_VARARGS)
+                       != (actual->tt_flags & TTFLAG_VARARGS))
+                   && expected->tt_argcount != -1)
+               ret = FAIL;
            if (ret != FAIL && expected->tt_argcount != -1
                    && actual->tt_min_argcount != -1
                    && (actual->tt_argcount == -1