patch 9.0.2043: Vim9: issue with funcref assignmentand varargs
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>
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 3a18777..bff9c9f 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -1863,6 +1863,62 @@
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
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 8b08dc1..01cf3e1 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -6953,6 +6953,21 @@
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 @@
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
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 597a10c..701a2f0 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
Binary files differ
diff --git a/src/version.c b/src/version.c
index 0b1bf31..bad07e6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2043,
+/**/
2042,
/**/
2041,
diff --git a/src/vim9type.c b/src/vim9type.c
index 00ee76b..6a58487 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -884,6 +884,11 @@
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