1
0
forked from aniani/vim

patch 8.2.4302: Vim9: return type of getline() is too strict

Problem:    Vim9: return type of getline() is too strict.
Solution:   Make the declared type list<any>.  Also do this for other
            functions returning a list of a specific type.
This commit is contained in:
Bram Moolenaar
2022-02-05 18:12:34 +00:00
parent e0c2b2ceaa
commit 82e46e5d31
3 changed files with 67 additions and 20 deletions

View File

@@ -1049,47 +1049,43 @@ ret_list_any(int argcount UNUSED,
} }
static type_T * static type_T *
ret_list_number(int argcount UNUSED, ret_list_number(int argcount UNUSED,
type2_T *argtypes UNUSED,
type_T **decl_type UNUSED)
{
return &t_list_number;
}
static type_T *
ret_range(int argcount UNUSED,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type) type_T **decl_type)
{ {
// returning a list<number>, but it's not declared as such
*decl_type = &t_list_any; *decl_type = &t_list_any;
return &t_list_number; return &t_list_number;
} }
static type_T * static type_T *
ret_list_string(int argcount UNUSED, ret_list_string(int argcount UNUSED,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
*decl_type = &t_list_any;
return &t_list_string; return &t_list_string;
} }
static type_T * static type_T *
ret_list_dict_any(int argcount UNUSED, ret_list_dict_any(int argcount UNUSED,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
*decl_type = &t_list_any;
return &t_list_dict_any; return &t_list_dict_any;
} }
static type_T * static type_T *
ret_list_items(int argcount UNUSED, ret_list_items(int argcount UNUSED,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
*decl_type = &t_list_any;
return &t_list_list_any; return &t_list_list_any;
} }
static type_T * static type_T *
ret_list_string_items(int argcount UNUSED, ret_list_string_items(int argcount UNUSED,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
*decl_type = &t_list_any;
return &t_list_list_string; return &t_list_list_string;
} }
static type_T * static type_T *
@@ -1102,10 +1098,13 @@ ret_dict_any(int argcount UNUSED,
static type_T * static type_T *
ret_job_info(int argcount, ret_job_info(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
if (argcount == 0) if (argcount == 0)
{
*decl_type = &t_list_any;
return &t_list_job; return &t_list_job;
}
return &t_dict_any; return &t_dict_any;
} }
static type_T * static type_T *
@@ -1252,7 +1251,10 @@ ret_getline(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type UNUSED)
{ {
return argcount == 1 ? &t_string : &t_list_string; if (argcount == 1)
return &t_string;
*decl_type = &t_list_any;
return &t_list_string;
} }
// for finddir() // for finddir()
static type_T * static type_T *
@@ -1273,10 +1275,11 @@ ret_finddir(int argcount,
static type_T * static type_T *
ret_list_or_dict_0(int argcount, ret_list_or_dict_0(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
if (argcount > 0) if (argcount > 0)
return &t_dict_any; return &t_dict_any;
*decl_type = &t_list_any;
return &t_list_dict_any; return &t_list_dict_any;
} }
@@ -1287,21 +1290,25 @@ ret_list_or_dict_0(int argcount,
static type_T * static type_T *
ret_list_or_dict_1(int argcount, ret_list_or_dict_1(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
if (argcount > 1) if (argcount > 1)
return &t_dict_any; return &t_dict_any;
*decl_type = &t_list_any;
return &t_list_dict_any; return &t_list_dict_any;
} }
static type_T * static type_T *
ret_argv(int argcount, ret_argv(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
// argv() returns list of strings // argv() returns list of strings
if (argcount == 0) if (argcount == 0)
{
*decl_type = &t_list_any;
return &t_list_string; return &t_list_string;
}
// argv(0) returns a string, but argv(-1] returns a list // argv(0) returns a string, but argv(-1] returns a list
return &t_any; return &t_any;
@@ -1331,11 +1338,14 @@ ret_remove(int argcount,
static type_T * static type_T *
ret_getreg(int argcount, ret_getreg(int argcount,
type2_T *argtypes UNUSED, type2_T *argtypes UNUSED,
type_T **decl_type UNUSED) type_T **decl_type)
{ {
// Assume that if the third argument is passed it's non-zero // Assume that if the third argument is passed it's non-zero
if (argcount == 3) if (argcount == 3)
{
*decl_type = &t_list_any;
return &t_list_string; return &t_list_string;
}
return &t_string; return &t_string;
} }
@@ -2124,7 +2134,7 @@ static funcentry_T global_functions[] =
{"rand", 0, 1, FEARG_1, arg1_list_number, {"rand", 0, 1, FEARG_1, arg1_list_number,
ret_number, f_rand}, ret_number, f_rand},
{"range", 1, 3, FEARG_1, arg3_number, {"range", 1, 3, FEARG_1, arg3_number,
ret_range, f_range}, ret_list_number, f_range},
{"readblob", 1, 1, FEARG_1, arg1_string, {"readblob", 1, 1, FEARG_1, arg1_string,
ret_blob, f_readblob}, ret_blob, f_readblob},
{"readdir", 1, 3, FEARG_1, arg3_string_any_dict, {"readdir", 1, 3, FEARG_1, arg3_string_any_dict,

View File

@@ -313,6 +313,7 @@ def Test_balloon_split()
enddef enddef
def Test_blob2list() def Test_blob2list()
assert_equal(['x', 'x'], blob2list(0z1234)->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['blob2list(10)'], ['E1013: Argument 1: type mismatch, expected blob but got number', 'E1238: Blob required for argument 1']) v9.CheckDefAndScriptFailure(['blob2list(10)'], ['E1013: Argument 1: type mismatch, expected blob but got number', 'E1238: Blob required for argument 1'])
enddef enddef
@@ -1529,6 +1530,8 @@ def Test_getbufline()
getbufline(-1, '$', '$')->assert_equal([]) getbufline(-1, '$', '$')->assert_equal([])
getbufline(-1, 1, '$')->assert_equal([]) getbufline(-1, 1, '$')->assert_equal([])
assert_equal([7, 7, 7], getbufline('#', 1, '$')->map((_, _) => 7))
assert_fails('getbufline("", "$a", "$b")', ['E1030: Using a String as a Number: "$a"', 'E1030: Using a String as a Number: "$a"']) assert_fails('getbufline("", "$a", "$b")', ['E1030: Using a String as a Number: "$a"', 'E1030: Using a String as a Number: "$a"'])
assert_fails('getbufline("", "$", "$b")', ['E1030: Using a String as a Number: "$b"', 'E1030: Using a String as a Number: "$b"']) assert_fails('getbufline("", "$", "$b")', ['E1030: Using a String as a Number: "$b"', 'E1030: Using a String as a Number: "$b"'])
bwipe! bwipe!
@@ -1561,6 +1564,8 @@ def Test_getchar()
enddef enddef
def Test_getcharpos() def Test_getcharpos()
assert_equal(['x', 'x', 'x', 'x'], getcharpos('.')->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['getcharpos(true)'], ['E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['getcharpos(true)'], ['E1013: Argument 1: type mismatch, expected string but got bool', 'E1174: String required for argument 1'])
v9.CheckDefAndScriptFailure(['getcharpos(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['getcharpos(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckDefExecAndScriptFailure(['getcharpos("")'], 'E1209: Invalid value for a line number') v9.CheckDefExecAndScriptFailure(['getcharpos("")'], 'E1209: Invalid value for a line number')
@@ -1584,10 +1589,14 @@ def Test_getcompletion()
enddef enddef
def Test_getcurpos() def Test_getcurpos()
assert_equal(['x', 'x', 'x', 'x', 'x'], getcurpos()->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['getcurpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['getcurpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
enddef enddef
def Test_getcursorcharpos() def Test_getcursorcharpos()
assert_equal(['x', 'x', 'x', 'x', 'x'], getcursorcharpos()->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['getcursorcharpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['getcursorcharpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
enddef enddef
@@ -1664,6 +1673,8 @@ def Test_getline()
normal 2Gvjv normal 2Gvjv
assert_equal('there', getline("'<")) assert_equal('there', getline("'<"))
assert_equal('again', getline("'>")) assert_equal('again', getline("'>"))
assert_equal([3, 3, 3], getline(1, 3)->map((_, _) => 3))
END END
v9.CheckDefAndScriptSuccess(lines) v9.CheckDefAndScriptSuccess(lines)
@@ -1700,6 +1711,8 @@ def Test_getmatches()
enddef enddef
def Test_getpos() def Test_getpos()
assert_equal(['x', 'x', 'x', 'x'], getpos('.')->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['getpos(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['getpos(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
assert_equal([0, 1, 1, 0], getpos('.')) assert_equal([0, 1, 1, 0], getpos('.'))
v9.CheckDefExecFailure(['getpos("a")'], 'E1209:') v9.CheckDefExecFailure(['getpos("a")'], 'E1209:')
@@ -1723,6 +1736,8 @@ def Test_getreg()
var lines = ['aaa', 'bbb', 'ccc'] var lines = ['aaa', 'bbb', 'ccc']
setreg('a', lines) setreg('a', lines)
getreg('a', true, true)->assert_equal(lines) getreg('a', true, true)->assert_equal(lines)
assert_equal([7, 7, 7], getreg('a', true, true)->map((_, _) => 7))
assert_fails('getreg("ab")', 'E1162:') assert_fails('getreg("ab")', 'E1162:')
v9.CheckDefAndScriptFailure(['getreg(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['getreg(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckDefAndScriptFailure(['getreg(".", 2)'], ['E1013: Argument 2: type mismatch, expected bool but got number', 'E1212: Bool required for argument 2']) v9.CheckDefAndScriptFailure(['getreg(".", 2)'], ['E1013: Argument 2: type mismatch, expected bool but got number', 'E1212: Bool required for argument 2'])
@@ -1786,6 +1801,8 @@ def Test_getwininfo()
enddef enddef
def Test_getwinpos() def Test_getwinpos()
assert_equal(['x', 'x'], getwinpos()->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['getwinpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['getwinpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
enddef enddef
@@ -2020,6 +2037,7 @@ def Test_items()
v9.CheckDefFailure(['[]->items()'], 'E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>') v9.CheckDefFailure(['[]->items()'], 'E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>')
assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items()) assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items())
assert_equal([], {}->items()) assert_equal([], {}->items())
assert_equal(['x', 'x'], {'a': 10, 'b': 20}->items()->map((_, _) => 'x'))
enddef enddef
def Test_job_getchannel() def Test_job_getchannel()
@@ -2089,6 +2107,8 @@ def Test_json_decode()
enddef enddef
def Test_keys() def Test_keys()
assert_equal([7, 7], keys({a: 1, b: 2})->map((_, _) => 7))
v9.CheckDefAndScriptFailure(['keys([])'], ['E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 1']) v9.CheckDefAndScriptFailure(['keys([])'], ['E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 1'])
assert_equal(['a'], {a: 'v'}->keys()) assert_equal(['a'], {a: 'v'}->keys())
assert_equal([], {}->keys()) assert_equal([], {}->keys())
@@ -2881,6 +2901,7 @@ def Test_readfile()
writefile(text, 'Xreadfile') writefile(text, 'Xreadfile')
var read: list<string> = readfile('Xreadfile') var read: list<string> = readfile('Xreadfile')
assert_equal(text, read) assert_equal(text, read)
assert_equal([7, 7, 7], readfile('Xreadfile')->map((_, _) => 7))
var lines =<< trim END var lines =<< trim END
var read: dict<string> = readfile('Xreadfile') var read: dict<string> = readfile('Xreadfile')
@@ -3089,6 +3110,8 @@ def Test_screenchar()
enddef enddef
def Test_screenchars() def Test_screenchars()
assert_equal(['x'], screenchars(1, 1)->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['screenchars("x", 1)'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['screenchars("x", 1)'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
v9.CheckDefAndScriptFailure(['screenchars(1, "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) v9.CheckDefAndScriptFailure(['screenchars(1, "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2'])
enddef enddef
@@ -3189,6 +3212,8 @@ def Test_searchpair()
assert_equal(0, searchpair('', '', '')) assert_equal(0, searchpair('', '', ''))
assert_equal([0, 0], searchpairpos('', '', '')) assert_equal([0, 0], searchpairpos('', '', ''))
assert_equal(['x', 'x'], searchpairpos('', '', '')->map((_, _) => 'x'))
var lines =<< trim END var lines =<< trim END
vim9script vim9script
setline(1, '()') setline(1, '()')
@@ -3247,6 +3272,8 @@ def Test_searchpair()
enddef enddef
def Test_searchpos() def Test_searchpos()
assert_equal(['x', 'x'], searchpos('.')->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['searchpos(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['searchpos(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckDefAndScriptFailure(['searchpos("a", 2)'], ['E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2']) v9.CheckDefAndScriptFailure(['searchpos("a", 2)'], ['E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2'])
v9.CheckDefAndScriptFailure(['searchpos("a", "b", "c")'], ['E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3']) v9.CheckDefAndScriptFailure(['searchpos("a", "b", "c")'], ['E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3'])
@@ -3685,6 +3712,9 @@ def Test_split()
enddef enddef
def Test_srand() def Test_srand()
var expected = srand()->len()->range()->map((_, _) => 'x')
assert_equal(expected, srand()->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['srand("a")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['srand("a")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
type(srand(100))->assert_equal(v:t_list) type(srand(100))->assert_equal(v:t_list)
enddef enddef
@@ -3707,6 +3737,8 @@ def Test_str2float()
enddef enddef
def Test_str2list() def Test_str2list()
assert_equal(['x', 'x', 'x'], str2list('abc')->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['str2list(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['str2list(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckDefAndScriptFailure(['str2list("a", 2)'], ['E1013: Argument 2: type mismatch, expected bool but got number', 'E1212: Bool required for argument 2']) v9.CheckDefAndScriptFailure(['str2list("a", 2)'], ['E1013: Argument 2: type mismatch, expected bool but got number', 'E1212: Bool required for argument 2'])
assert_equal([97], str2list('a')) assert_equal([97], str2list('a'))
@@ -3914,6 +3946,7 @@ def Test_tabpagebuflist()
v9.CheckDefAndScriptFailure(['tabpagebuflist("t")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['tabpagebuflist("t")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
assert_equal([bufnr('')], tabpagebuflist()) assert_equal([bufnr('')], tabpagebuflist())
assert_equal([bufnr('')], tabpagebuflist(1)) assert_equal([bufnr('')], tabpagebuflist(1))
assert_equal(['x'], tabpagebuflist()->map((_, _) => 'x'))
enddef enddef
def Test_tabpagenr() def Test_tabpagenr()
@@ -4293,6 +4326,8 @@ def Test_win_id2win()
enddef enddef
def Test_win_screenpos() def Test_win_screenpos()
assert_equal(['x', 'x'], win_screenpos(1)->map((_, _) => 'x'))
v9.CheckDefAndScriptFailure(['win_screenpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1']) v9.CheckDefAndScriptFailure(['win_screenpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
enddef enddef

View File

@@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4302,
/**/ /**/
4301, 4301,
/**/ /**/