Skip to content

Commit 127542b

Browse files
committed
patch 8.2.1407: Vim9: type of list and dict only depends on first item
Problem: Vim9: type of list and dict only depends on first item. Solution: Use all items to decide about the type.
1 parent a1b9b0c commit 127542b

6 files changed

Lines changed: 91 additions & 17 deletions

File tree

runtime/doc/vim9.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,8 @@ called in the same way the declaration is the same.
619619

620620
Custom types can be defined with `:type`: >
621621
:type MyList list<string>
622+
Custom types must start with a capital letter, to avoid name clashes with
623+
builtin types added later, similarly to user functions.
622624
{not implemented yet}
623625

624626
And classes and interfaces can be used as types: >
@@ -645,6 +647,12 @@ declaring a variable and giving it a value: >
645647
let var = 0 " infers number type
646648
let var = 'hello' " infers string type
647649
650+
The type of a list and dictionary comes from the common type of the values.
651+
If the values all have the same type, that type is used for the list or
652+
dictionary. If there is a mix of types, the "any" type is used. >
653+
[1, 2, 3] list<number>
654+
['a', 'b', 'c'] list<string>
655+
[1, 'x', 3] list<any>
648656
649657
==============================================================================
650658

src/proto/vim9type.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ int check_type(type_T *expected, type_T *actual, int give_msg);
1414
char_u *skip_type(char_u *start, int optional);
1515
type_T *parse_type(char_u **arg, garray_T *type_gap);
1616
void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap);
17+
type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap);
1718
char *vartype_name(vartype_T type);
1819
char *type_name(type_T *type, char **tofree);
1920
/* vim: set ft=c : */

src/testdir/test_vim9_expr.vim

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,17 @@ def Test_expr7_list()
13341334
# list
13351335
assert_equal(g:list_empty, [])
13361336
assert_equal(g:list_empty, [ ])
1337-
assert_equal(g:list_mixed, [1, 'b', false,])
1337+
1338+
let numbers: list<number> = [1, 2, 3]
1339+
numbers = [1]
1340+
numbers = []
1341+
1342+
let strings: list<string> = ['a', 'b', 'c']
1343+
strings = ['x']
1344+
strings = []
1345+
1346+
let mixed: list<any> = [1, 'b', false,]
1347+
assert_equal(g:list_mixed, mixed)
13381348
assert_equal('b', g:list_mixed[1])
13391349

13401350
echo [1,
@@ -1348,6 +1358,10 @@ def Test_expr7_list()
13481358
call CheckDefFailure(["let x = g:list_mixed["], 'E1097:')
13491359
call CheckDefFailure(["let x = g:list_mixed[0"], 'E1097:')
13501360
call CheckDefExecFailure(["let x = g:list_empty[3]"], 'E684:')
1361+
call CheckDefFailure(["let l: list<number> = [234, 'x']"], 'E1013:')
1362+
call CheckDefFailure(["let l: list<number> = ['x', 234]"], 'E1013:')
1363+
call CheckDefFailure(["let l: list<string> = [234, 'x']"], 'E1013:')
1364+
call CheckDefFailure(["let l: list<string> = ['x', 123]"], 'E1013:')
13511365
enddef
13521366

13531367
def Test_expr7_list_vim9script()
@@ -1437,6 +1451,19 @@ def Test_expr7_dict()
14371451
let val = 1
14381452
assert_equal(g:dict_one, {key: val})
14391453

1454+
let numbers: dict<number> = #{a: 1, b: 2, c: 3}
1455+
numbers = #{a: 1}
1456+
numbers = #{}
1457+
1458+
let strings: dict<string> = #{a: 'a', b: 'b', c: 'c'}
1459+
strings = #{a: 'x'}
1460+
strings = #{}
1461+
1462+
let mixed: dict<any> = #{a: 'a', b: 42}
1463+
mixed = #{a: 'x'}
1464+
mixed = #{a: 234}
1465+
mixed = #{}
1466+
14401467
call CheckDefFailure(["let x = #{8: 8}"], 'E1014:')
14411468
call CheckDefFailure(["let x = #{xxx}"], 'E720:')
14421469
call CheckDefFailure(["let x = #{xxx: 1", "let y = 2"], 'E722:')
@@ -1449,6 +1476,11 @@ def Test_expr7_dict()
14491476
call CheckDefFailure(["let x = x + 1"], 'E1001:')
14501477
call CheckDefExecFailure(["let x = g:anint.member"], 'E715:')
14511478
call CheckDefExecFailure(["let x = g:dict_empty.member"], 'E716:')
1479+
1480+
call CheckDefFailure(['let x: dict<number> = #{a: 234, b: "1"}'], 'E1013:')
1481+
call CheckDefFailure(['let x: dict<number> = #{a: "x", b: 134}'], 'E1013:')
1482+
call CheckDefFailure(['let x: dict<string> = #{a: 234, b: "1"}'], 'E1013:')
1483+
call CheckDefFailure(['let x: dict<string> = #{a: "x", b: 134}'], 'E1013:')
14521484
enddef
14531485

14541486
def Test_expr7_dict_vim9script()

src/version.c

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

755755
static int included_patches[] =
756756
{ /* Add new patch number below this line */
757+
/**/
758+
1407,
757759
/**/
758760
1406,
759761
/**/

src/vim9compile.c

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,17 +1110,15 @@ generate_NEWLIST(cctx_T *cctx, int count)
11101110
return FAIL;
11111111
isn->isn_arg.number = count;
11121112

1113+
// get the member type from all the items on the stack.
1114+
member = get_member_type_from_stack(
1115+
((type_T **)stack->ga_data) + stack->ga_len, count, 1,
1116+
cctx->ctx_type_list);
1117+
type = get_list_type(member, cctx->ctx_type_list);
1118+
11131119
// drop the value types
11141120
stack->ga_len -= count;
11151121

1116-
// Use the first value type for the list member type. Use "any" for an
1117-
// empty list.
1118-
if (count > 0)
1119-
member = ((type_T **)stack->ga_data)[stack->ga_len];
1120-
else
1121-
member = &t_void;
1122-
type = get_list_type(member, cctx->ctx_type_list);
1123-
11241122
// add the list type to the type stack
11251123
if (ga_grow(stack, 1) == FAIL)
11261124
return FAIL;
@@ -1146,17 +1144,14 @@ generate_NEWDICT(cctx_T *cctx, int count)
11461144
return FAIL;
11471145
isn->isn_arg.number = count;
11481146

1147+
member = get_member_type_from_stack(
1148+
((type_T **)stack->ga_data) + stack->ga_len, count, 2,
1149+
cctx->ctx_type_list);
1150+
type = get_dict_type(member, cctx->ctx_type_list);
1151+
11491152
// drop the key and value types
11501153
stack->ga_len -= 2 * count;
11511154

1152-
// Use the first value type for the list member type. Use "void" for an
1153-
// empty dict.
1154-
if (count > 0)
1155-
member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
1156-
else
1157-
member = &t_void;
1158-
type = get_dict_type(member, cctx->ctx_type_list);
1159-
11601155
// add the dict type to the type stack
11611156
if (ga_grow(stack, 1) == FAIL)
11621157
return FAIL;

src/vim9type.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,42 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
789789
*dest = &t_any;
790790
}
791791

792+
/*
793+
* Get the member type of a dict or list from the items on the stack.
794+
* "stack_top" points just after the last type on the type stack.
795+
* For a list "skip" is 1, for a dict "skip" is 2, keys are skipped.
796+
* Returns &t_void for an empty list or dict.
797+
* Otherwise finds the common type of all items.
798+
*/
799+
type_T *
800+
get_member_type_from_stack(
801+
type_T **stack_top,
802+
int count,
803+
int skip,
804+
garray_T *type_gap)
805+
{
806+
int i;
807+
type_T *result;
808+
type_T *type;
809+
810+
// Use "any" for an empty list or dict.
811+
if (count == 0)
812+
return &t_void;
813+
814+
// Use the first value type for the list member type, then find the common
815+
// type from following items.
816+
result = *(stack_top -(count * skip) + skip - 1);
817+
for (i = 1; i < count; ++i)
818+
{
819+
if (result == &t_any)
820+
break; // won't get more common
821+
type = *(stack_top -((count - i) * skip) + skip - 1);
822+
common_type(type, result, &result, type_gap);
823+
}
824+
825+
return result;
826+
}
827+
792828
char *
793829
vartype_name(vartype_T type)
794830
{

0 commit comments

Comments
 (0)