Skip to content

Commit 32517c4

Browse files
committed
patch 9.0.1203: return type of values() is always list<any>
Problem: Return type of values() is always list<any>. Solution: Use the member type if possible. (issue #11822)
1 parent f450804 commit 32517c4

6 files changed

Lines changed: 62 additions & 5 deletions

File tree

src/evalfunc.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,8 @@ static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string,
11361136
static argcheck_T arg23_writefile[] = {arg_list_or_blob, arg_string, arg_string};
11371137
static argcheck_T arg24_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number};
11381138

1139+
// Can be used by functions called through "f_retfunc" to create new types.
1140+
static garray_T *current_type_gap = NULL;
11391141

11401142
/*
11411143
* Functions that return the return type of a builtin function.
@@ -1438,6 +1440,29 @@ ret_finddir(int argcount,
14381440
// Depending on the count would be a string or a list of strings.
14391441
return &t_any;
14401442
}
1443+
// for values(): list of member of first argument
1444+
static type_T *
1445+
ret_list_member(int argcount,
1446+
type2_T *argtypes,
1447+
type_T **decl_type)
1448+
{
1449+
if (argcount > 0)
1450+
{
1451+
type_T *t = argtypes[0].type_decl;
1452+
if (current_type_gap != NULL
1453+
&& (t->tt_type == VAR_DICT || t->tt_type == VAR_LIST))
1454+
t = get_list_type(t->tt_member, current_type_gap);
1455+
else
1456+
t = &t_list_any;
1457+
*decl_type = t;
1458+
1459+
t = argtypes[0].type_curr;
1460+
if (current_type_gap != NULL
1461+
&& (t->tt_type == VAR_DICT || t->tt_type == VAR_LIST))
1462+
return get_list_type(t->tt_member, current_type_gap);
1463+
}
1464+
return &t_list_any;
1465+
}
14411466

14421467
/*
14431468
* Used for getqflist(): returns list if there is no argument, dict if there is
@@ -2759,7 +2784,7 @@ static funcentry_T global_functions[] =
27592784
{"uniq", 1, 3, FEARG_1, arg13_sortuniq,
27602785
ret_first_arg, f_uniq},
27612786
{"values", 1, 1, FEARG_1, arg1_dict_any,
2762-
ret_list_any, f_values},
2787+
ret_list_member, f_values},
27632788
{"virtcol", 1, 2, FEARG_1, arg2_string_or_list_bool,
27642789
ret_virtcol, f_virtcol},
27652790
{"virtcol2col", 3, 3, FEARG_1, arg3_number,
@@ -2993,14 +3018,17 @@ internal_func_ret_type(
29933018
int idx,
29943019
int argcount,
29953020
type2_T *argtypes,
2996-
type_T **decl_type)
3021+
type_T **decl_type,
3022+
garray_T *type_gap)
29973023
{
29983024
type_T *ret;
29993025

3026+
current_type_gap = type_gap;
30003027
*decl_type = NULL;
30013028
ret = global_functions[idx].f_retfunc(argcount, argtypes, decl_type);
30023029
if (*decl_type == NULL)
30033030
*decl_type = ret;
3031+
current_type_gap = NULL;
30043032
return ret;
30053033
}
30063034

src/proto/evalfunc.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ int has_internal_func(char_u *name);
77
char *internal_func_name(int idx);
88
int internal_func_check_arg_types(type2_T *types, int idx, int argcount, cctx_T *cctx);
99
void internal_func_get_argcount(int idx, int *argcount, int *min_argcount);
10-
type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes, type_T **decl_type);
10+
type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes, type_T **decl_type, garray_T *type_gap);
1111
int internal_func_is_map(int idx);
1212
int check_internal_func(int idx, int argcount);
1313
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);

src/testdir/test_vim9_builtin.vim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4740,6 +4740,31 @@ def Test_values()
47404740
v9.CheckDefAndScriptFailure(['values([])'], ['E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 1'])
47414741
assert_equal([], {}->values())
47424742
assert_equal(['sun'], {star: 'sun'}->values())
4743+
4744+
# the return type of values() is list<member>
4745+
var lines =<< trim END
4746+
vim9script
4747+
4748+
class Foo
4749+
this.val: number
4750+
def Add()
4751+
echo this.val
4752+
enddef
4753+
endclass
4754+
4755+
def Process(FooDict: dict<Foo>)
4756+
for foo in values(FooDict)
4757+
foo.Add()
4758+
endfor
4759+
enddef
4760+
4761+
disas Process
4762+
4763+
var D = {'x': Foo.new(22)}
4764+
4765+
Process(D)
4766+
END
4767+
v9.CheckScriptSuccess(lines)
47434768
enddef
47444769

47454770
def Test_virtcol()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
1203,
698700
/**/
699701
1202,
700702
/**/

src/vim9instr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1619,7 +1619,8 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
16191619

16201620
// Drop the argument types and push the return type.
16211621
stack->ga_len -= argcount;
1622-
type = internal_func_ret_type(func_idx, argcount, argtypes, &decl_type);
1622+
type = internal_func_ret_type(func_idx, argcount, argtypes, &decl_type,
1623+
cctx->ctx_type_list);
16231624
if (push_type_stack2(cctx, type, decl_type) == FAIL)
16241625
return FAIL;
16251626

src/vim9type.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
539539
type_T *decl_type; // unused
540540

541541
internal_func_get_argcount(idx, &argcount, &min_argcount);
542-
member_type = internal_func_ret_type(idx, 0, NULL, &decl_type);
542+
member_type = internal_func_ret_type(idx, 0, NULL, &decl_type,
543+
type_gap);
543544
}
544545
else
545546
ufunc = find_func(name, FALSE);

0 commit comments

Comments
 (0)