Skip to content

Commit dc234ca

Browse files
committed
patch 8.2.2063: Vim9: only one level of indexing supported
Problem: Vim9: only one level of indexing supported. Solution: Handle more than one index in an assignment.
1 parent 4a44120 commit dc234ca

4 files changed

Lines changed: 168 additions & 15 deletions

File tree

src/errors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,5 @@ EXTERN char e_missing_matching_bracket_after_dict_key[]
311311
INIT(= N_("E1139: Missing matching bracket after dict key"));
312312
EXTERN char e_for_argument_must_be_sequence_of_lists[]
313313
INIT(= N_("E1140: For argument must be a sequence of lists"));
314+
EXTERN char e_indexable_type_required[]
315+
INIT(= N_("E1141: Indexable type required"));

src/testdir/test_vim9_assign.vim

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,78 @@ def Test_assignment()
225225
END
226226
enddef
227227

228+
def Test_assign_index()
229+
# list of list
230+
var l1: list<number>
231+
l1[0] = 123
232+
assert_equal([123], l1)
233+
234+
var l2: list<list<number>>
235+
l2[0] = []
236+
l2[0][0] = 123
237+
assert_equal([[123]], l2)
238+
239+
var l3: list<list<list<number>>>
240+
l3[0] = []
241+
l3[0][0] = []
242+
l3[0][0][0] = 123
243+
assert_equal([[[123]]], l3)
244+
245+
var lines =<< trim END
246+
var l3: list<list<number>>
247+
l3[0] = []
248+
l3[0][0] = []
249+
END
250+
CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3)
251+
252+
# dict of dict
253+
var d1: dict<number>
254+
d1.one = 1
255+
assert_equal({one: 1}, d1)
256+
257+
var d2: dict<dict<number>>
258+
d2.one = {}
259+
d2.one.two = 123
260+
assert_equal({one: {two: 123}}, d2)
261+
262+
var d3: dict<dict<dict<number>>>
263+
d3.one = {}
264+
d3.one.two = {}
265+
d3.one.two.three = 123
266+
assert_equal({one: {two: {three: 123}}}, d3)
267+
268+
lines =<< trim END
269+
var d3: dict<dict<number>>
270+
d3.one = {}
271+
d3.one.two = {}
272+
END
273+
CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3)
274+
275+
# list of dict
276+
var ld: list<dict<number>>
277+
ld[0] = {}
278+
ld[0].one = 123
279+
assert_equal([{one: 123}], ld)
280+
281+
lines =<< trim END
282+
var ld: list<dict<number>>
283+
ld[0] = []
284+
END
285+
CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
286+
287+
# dict of list
288+
var dl: dict<list<number>>
289+
dl.one = []
290+
dl.one[0] = 123
291+
assert_equal({one: [123]}, dl)
292+
293+
lines =<< trim END
294+
var dl: dict<list<number>>
295+
dl.one = {}
296+
END
297+
CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2)
298+
enddef
299+
228300
def Test_extend_list()
229301
var lines =<< trim END
230302
vim9script

src/version.c

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

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2063,
753755
/**/
754756
2062,
755757
/**/

src/vim9compile.c

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4961,6 +4961,7 @@ typedef enum {
49614961
dest_vimvar,
49624962
dest_script,
49634963
dest_reg,
4964+
dest_expr,
49644965
} assign_dest_T;
49654966

49664967
/*
@@ -5013,9 +5014,34 @@ generate_loadvar(
50135014
else
50145015
generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
50155016
break;
5017+
case dest_expr:
5018+
// list or dict value should already be on the stack.
5019+
break;
50165020
}
50175021
}
50185022

5023+
/*
5024+
* Skip over "[expr]" or ".member".
5025+
* Does not check for any errors.
5026+
*/
5027+
static char_u *
5028+
skip_index(char_u *start)
5029+
{
5030+
char_u *p = start;
5031+
5032+
if (*p == '[')
5033+
{
5034+
p = skipwhite(p + 1);
5035+
(void)skip_expr(&p, NULL);
5036+
p = skipwhite(p);
5037+
if (*p == ']')
5038+
return p + 1;
5039+
return p;
5040+
}
5041+
// if (*p == '.')
5042+
return to_name_end(p + 1, TRUE);
5043+
}
5044+
50195045
void
50205046
vim9_declare_error(char_u *name)
50215047
{
@@ -5069,6 +5095,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
50695095
int heredoc = FALSE;
50705096
type_T *type = &t_any;
50715097
type_T *member_type = &t_any;
5098+
type_T *rhs_type = &t_any;
50725099
char_u *name = NULL;
50735100
char_u *sp;
50745101
int is_decl = cmdidx == CMD_let || cmdidx == CMD_var
@@ -5157,6 +5184,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
51575184
// TODO: check the length of a constant list here
51585185
generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count,
51595186
semicolon);
5187+
if (stacktype->tt_member != NULL)
5188+
rhs_type = stacktype->tt_member;
51605189
}
51615190
}
51625191

@@ -5467,6 +5496,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
54675496
if (var_end > var_start + varlen)
54685497
{
54695498
// Something follows after the variable: "var[idx]" or "var.key".
5499+
// TODO: should we also handle "->func()" here?
54705500
if (is_decl)
54715501
{
54725502
emsg(_(e_cannot_use_index_when_declaring_variable));
@@ -5475,6 +5505,27 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
54755505

54765506
if (var_start[varlen] == '[' || var_start[varlen] == '.')
54775507
{
5508+
char_u *after = var_start + varlen;
5509+
5510+
// Only the last index is used below, if there are others
5511+
// before it generate code for the expression. Thus for
5512+
// "ll[1][2]" the expression is "ll[1]" and "[2]" is the index.
5513+
for (;;)
5514+
{
5515+
p = skip_index(after);
5516+
if (*p != '[' && *p != '.')
5517+
break;
5518+
after = p;
5519+
}
5520+
if (after > var_start + varlen)
5521+
{
5522+
varlen = after - var_start;
5523+
dest = dest_expr;
5524+
// We don't know the type before evaluating the expression,
5525+
// use "any" until then.
5526+
type = &t_any;
5527+
}
5528+
54785529
has_index = TRUE;
54795530
if (type->tt_member == NULL)
54805531
member_type = &t_any;
@@ -5511,7 +5562,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
55115562
}
55125563
else if (oplen > 0)
55135564
{
5514-
type_T *stacktype;
55155565
int is_const = FALSE;
55165566

55175567
// For "var = expr" evaluate the expression.
@@ -5558,18 +5608,18 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
55585608
return FAIL;
55595609
}
55605610

5561-
stacktype = stack->ga_len == 0 ? &t_void
5611+
rhs_type = stack->ga_len == 0 ? &t_void
55625612
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
55635613
if (lvar != NULL && (is_decl || !has_type))
55645614
{
5565-
if ((stacktype->tt_type == VAR_FUNC
5566-
|| stacktype->tt_type == VAR_PARTIAL)
5615+
if ((rhs_type->tt_type == VAR_FUNC
5616+
|| rhs_type->tt_type == VAR_PARTIAL)
55675617
&& var_wrong_func_name(name, TRUE))
55685618
goto theend;
55695619

55705620
if (new_local && !has_type)
55715621
{
5572-
if (stacktype->tt_type == VAR_VOID)
5622+
if (rhs_type->tt_type == VAR_VOID)
55735623
{
55745624
emsg(_(e_cannot_use_void_value));
55755625
goto theend;
@@ -5578,14 +5628,14 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
55785628
{
55795629
// An empty list or dict has a &t_unknown member,
55805630
// for a variable that implies &t_any.
5581-
if (stacktype == &t_list_empty)
5631+
if (rhs_type == &t_list_empty)
55825632
lvar->lv_type = &t_list_any;
5583-
else if (stacktype == &t_dict_empty)
5633+
else if (rhs_type == &t_dict_empty)
55845634
lvar->lv_type = &t_dict_any;
5585-
else if (stacktype == &t_unknown)
5635+
else if (rhs_type == &t_unknown)
55865636
lvar->lv_type = &t_any;
55875637
else
5588-
lvar->lv_type = stacktype;
5638+
lvar->lv_type = rhs_type;
55895639
}
55905640
}
55915641
else if (*op == '=')
@@ -5595,17 +5645,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
55955645
// without operator check type here, otherwise below
55965646
if (has_index)
55975647
{
5598-
use_type = use_type->tt_member;
5599-
if (use_type == NULL)
5648+
use_type = member_type;
5649+
if (member_type == NULL)
56005650
// could be indexing "any"
56015651
use_type = &t_any;
56025652
}
5603-
if (need_type(stacktype, use_type, -1, cctx,
5653+
if (need_type(rhs_type, use_type, -1, cctx,
56045654
FALSE, is_const) == FAIL)
56055655
goto theend;
56065656
}
56075657
}
5608-
else if (*p != '=' && need_type(stacktype, member_type, -1,
5658+
else if (*p != '=' && need_type(rhs_type, member_type, -1,
56095659
cctx, FALSE, FALSE) == FAIL)
56105660
goto theend;
56115661
}
@@ -5771,7 +5821,31 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
57715821
// - value
57725822
// - index
57735823
// - variable
5774-
generate_loadvar(cctx, dest, name, lvar, type);
5824+
if (dest == dest_expr)
5825+
{
5826+
int c = var_start[varlen];
5827+
5828+
// Evaluate "ll[expr]" of "ll[expr][idx]"
5829+
p = var_start;
5830+
var_start[varlen] = NUL;
5831+
if (compile_expr0(&p, cctx) == OK && p != var_start + varlen)
5832+
{
5833+
// this should not happen
5834+
emsg(_(e_missbrac));
5835+
goto theend;
5836+
}
5837+
var_start[varlen] = c;
5838+
5839+
type = stack->ga_len == 0 ? &t_void
5840+
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
5841+
// now we can properly check the type
5842+
if (type->tt_member != NULL
5843+
&& need_type(rhs_type, type->tt_member, -2, cctx,
5844+
FALSE, FALSE) == FAIL)
5845+
goto theend;
5846+
}
5847+
else
5848+
generate_loadvar(cctx, dest, name, lvar, type);
57755849

57765850
if (type->tt_type == VAR_LIST)
57775851
{
@@ -5785,7 +5859,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
57855859
}
57865860
else
57875861
{
5788-
emsg(_(e_listreq));
5862+
emsg(_(e_indexable_type_required));
57895863
goto theend;
57905864
}
57915865
}
@@ -5882,6 +5956,9 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
58825956
generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
58835957
}
58845958
break;
5959+
case dest_expr:
5960+
// cannot happen
5961+
break;
58855962
}
58865963
}
58875964

0 commit comments

Comments
 (0)