1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar 2020-08-09 17:22:04 +02:00
parent a1b9b0cc01
commit 127542bceb
6 changed files with 91 additions and 17 deletions

View File

@ -619,6 +619,8 @@ called in the same way the declaration is the same.
Custom types can be defined with `:type`: >
:type MyList list<string>
Custom types must start with a capital letter, to avoid name clashes with
builtin types added later, similarly to user functions.
{not implemented yet}
And classes and interfaces can be used as types: >
@ -645,6 +647,12 @@ declaring a variable and giving it a value: >
let var = 0 " infers number type
let var = 'hello' " infers string type
The type of a list and dictionary comes from the common type of the values.
If the values all have the same type, that type is used for the list or
dictionary. If there is a mix of types, the "any" type is used. >
[1, 2, 3] list<number>
['a', 'b', 'c'] list<string>
[1, 'x', 3] list<any>
==============================================================================

View File

@ -14,6 +14,7 @@ int check_type(type_T *expected, type_T *actual, int give_msg);
char_u *skip_type(char_u *start, int optional);
type_T *parse_type(char_u **arg, garray_T *type_gap);
void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap);
type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap);
char *vartype_name(vartype_T type);
char *type_name(type_T *type, char **tofree);
/* vim: set ft=c : */

View File

@ -1334,7 +1334,17 @@ def Test_expr7_list()
# list
assert_equal(g:list_empty, [])
assert_equal(g:list_empty, [ ])
assert_equal(g:list_mixed, [1, 'b', false,])
let numbers: list<number> = [1, 2, 3]
numbers = [1]
numbers = []
let strings: list<string> = ['a', 'b', 'c']
strings = ['x']
strings = []
let mixed: list<any> = [1, 'b', false,]
assert_equal(g:list_mixed, mixed)
assert_equal('b', g:list_mixed[1])
echo [1,
@ -1348,6 +1358,10 @@ def Test_expr7_list()
call CheckDefFailure(["let x = g:list_mixed["], 'E1097:')
call CheckDefFailure(["let x = g:list_mixed[0"], 'E1097:')
call CheckDefExecFailure(["let x = g:list_empty[3]"], 'E684:')
call CheckDefFailure(["let l: list<number> = [234, 'x']"], 'E1013:')
call CheckDefFailure(["let l: list<number> = ['x', 234]"], 'E1013:')
call CheckDefFailure(["let l: list<string> = [234, 'x']"], 'E1013:')
call CheckDefFailure(["let l: list<string> = ['x', 123]"], 'E1013:')
enddef
def Test_expr7_list_vim9script()
@ -1437,6 +1451,19 @@ def Test_expr7_dict()
let val = 1
assert_equal(g:dict_one, {key: val})
let numbers: dict<number> = #{a: 1, b: 2, c: 3}
numbers = #{a: 1}
numbers = #{}
let strings: dict<string> = #{a: 'a', b: 'b', c: 'c'}
strings = #{a: 'x'}
strings = #{}
let mixed: dict<any> = #{a: 'a', b: 42}
mixed = #{a: 'x'}
mixed = #{a: 234}
mixed = #{}
call CheckDefFailure(["let x = #{8: 8}"], 'E1014:')
call CheckDefFailure(["let x = #{xxx}"], 'E720:')
call CheckDefFailure(["let x = #{xxx: 1", "let y = 2"], 'E722:')
@ -1449,6 +1476,11 @@ def Test_expr7_dict()
call CheckDefFailure(["let x = x + 1"], 'E1001:')
call CheckDefExecFailure(["let x = g:anint.member"], 'E715:')
call CheckDefExecFailure(["let x = g:dict_empty.member"], 'E716:')
call CheckDefFailure(['let x: dict<number> = #{a: 234, b: "1"}'], 'E1013:')
call CheckDefFailure(['let x: dict<number> = #{a: "x", b: 134}'], 'E1013:')
call CheckDefFailure(['let x: dict<string> = #{a: 234, b: "1"}'], 'E1013:')
call CheckDefFailure(['let x: dict<string> = #{a: "x", b: 134}'], 'E1013:')
enddef
def Test_expr7_dict_vim9script()

View File

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

View File

@ -1110,17 +1110,15 @@ generate_NEWLIST(cctx_T *cctx, int count)
return FAIL;
isn->isn_arg.number = count;
// get the member type from all the items on the stack.
member = get_member_type_from_stack(
((type_T **)stack->ga_data) + stack->ga_len, count, 1,
cctx->ctx_type_list);
type = get_list_type(member, cctx->ctx_type_list);
// drop the value types
stack->ga_len -= count;
// Use the first value type for the list member type. Use "any" for an
// empty list.
if (count > 0)
member = ((type_T **)stack->ga_data)[stack->ga_len];
else
member = &t_void;
type = get_list_type(member, cctx->ctx_type_list);
// add the list type to the type stack
if (ga_grow(stack, 1) == FAIL)
return FAIL;
@ -1146,17 +1144,14 @@ generate_NEWDICT(cctx_T *cctx, int count)
return FAIL;
isn->isn_arg.number = count;
member = get_member_type_from_stack(
((type_T **)stack->ga_data) + stack->ga_len, count, 2,
cctx->ctx_type_list);
type = get_dict_type(member, cctx->ctx_type_list);
// drop the key and value types
stack->ga_len -= 2 * count;
// Use the first value type for the list member type. Use "void" for an
// empty dict.
if (count > 0)
member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
else
member = &t_void;
type = get_dict_type(member, cctx->ctx_type_list);
// add the dict type to the type stack
if (ga_grow(stack, 1) == FAIL)
return FAIL;

View File

@ -789,6 +789,42 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
*dest = &t_any;
}
/*
* Get the member type of a dict or list from the items on the stack.
* "stack_top" points just after the last type on the type stack.
* For a list "skip" is 1, for a dict "skip" is 2, keys are skipped.
* Returns &t_void for an empty list or dict.
* Otherwise finds the common type of all items.
*/
type_T *
get_member_type_from_stack(
type_T **stack_top,
int count,
int skip,
garray_T *type_gap)
{
int i;
type_T *result;
type_T *type;
// Use "any" for an empty list or dict.
if (count == 0)
return &t_void;
// Use the first value type for the list member type, then find the common
// type from following items.
result = *(stack_top -(count * skip) + skip - 1);
for (i = 1; i < count; ++i)
{
if (result == &t_any)
break; // won't get more common
type = *(stack_top -((count - i) * skip) + skip - 1);
common_type(type, result, &result, type_gap);
}
return result;
}
char *
vartype_name(vartype_T type)
{