Skip to content

Commit

Permalink
patch 9.0.2043: Vim9: issue with funcref assignmentand varargs
Browse files Browse the repository at this point in the history
Problem:  Vim9: issue with funcref assignmentand varargs
Solution: Fix funcref type checking

closes: #13351

Signed-off-by: Christian Brabandt <[email protected]>
Co-authored-by: Ernie Rael <[email protected]>
  • Loading branch information
errael authored and chrisbra committed Oct 17, 2023
1 parent c290009 commit 96952b2
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
56 changes: 56 additions & 0 deletions src/testdir/test_vim9_assign.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
63 changes: 63 additions & 0 deletions src/testdir/test_vim9_class.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/testdir/test_vim9_func.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2043,
/**/
2042,
/**/
Expand Down
5 changes: 5 additions & 0 deletions src/vim9type.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 96952b2

Please sign in to comment.