Patch 8.2.2063

6 views
Skip to first unread message

Bram Moolenaar

unread,
Nov 28, 2020, 12:53:10 PM11/28/20
to vim...@googlegroups.com

Patch 8.2.2063
Problem: Vim9: only one level of indexing supported.
Solution: Handle more than one index in an assignment.
Files: src/vim9compile.c, src/errors.h, src/testdir/test_vim9_assign.vim


*** ../vim-8.2.2062/src/vim9compile.c 2020-11-23 08:31:14.097789125 +0100
--- src/vim9compile.c 2020-11-28 18:11:22.207332958 +0100
***************
*** 4961,4966 ****
--- 4961,4967 ----
dest_vimvar,
dest_script,
dest_reg,
+ dest_expr,
} assign_dest_T;

/*
***************
*** 5013,5019 ****
--- 5014,5045 ----
else
generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
break;
+ case dest_expr:
+ // list or dict value should already be on the stack.
+ break;
+ }
+ }
+
+ /*
+ * Skip over "[expr]" or ".member".
+ * Does not check for any errors.
+ */
+ static char_u *
+ skip_index(char_u *start)
+ {
+ char_u *p = start;
+
+ if (*p == '[')
+ {
+ p = skipwhite(p + 1);
+ (void)skip_expr(&p, NULL);
+ p = skipwhite(p);
+ if (*p == ']')
+ return p + 1;
+ return p;
}
+ // if (*p == '.')
+ return to_name_end(p + 1, TRUE);
}

void
***************
*** 5069,5074 ****
--- 5095,5101 ----
int heredoc = FALSE;
type_T *type = &t_any;
type_T *member_type = &t_any;
+ type_T *rhs_type = &t_any;
char_u *name = NULL;
char_u *sp;
int is_decl = cmdidx == CMD_let || cmdidx == CMD_var
***************
*** 5157,5162 ****
--- 5184,5191 ----
// TODO: check the length of a constant list here
generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count,
semicolon);
+ if (stacktype->tt_member != NULL)
+ rhs_type = stacktype->tt_member;
}
}

***************
*** 5467,5472 ****
--- 5496,5502 ----
if (var_end > var_start + varlen)
{
// Something follows after the variable: "var[idx]" or "var.key".
+ // TODO: should we also handle "->func()" here?
if (is_decl)
{
emsg(_(e_cannot_use_index_when_declaring_variable));
***************
*** 5475,5480 ****
--- 5505,5531 ----

if (var_start[varlen] == '[' || var_start[varlen] == '.')
{
+ char_u *after = var_start + varlen;
+
+ // Only the last index is used below, if there are others
+ // before it generate code for the expression. Thus for
+ // "ll[1][2]" the expression is "ll[1]" and "[2]" is the index.
+ for (;;)
+ {
+ p = skip_index(after);
+ if (*p != '[' && *p != '.')
+ break;
+ after = p;
+ }
+ if (after > var_start + varlen)
+ {
+ varlen = after - var_start;
+ dest = dest_expr;
+ // We don't know the type before evaluating the expression,
+ // use "any" until then.
+ type = &t_any;
+ }
+
has_index = TRUE;
if (type->tt_member == NULL)
member_type = &t_any;
***************
*** 5511,5517 ****
}
else if (oplen > 0)
{
- type_T *stacktype;
int is_const = FALSE;

// For "var = expr" evaluate the expression.
--- 5562,5567 ----
***************
*** 5558,5575 ****
return FAIL;
}

! stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
{
! if ((stacktype->tt_type == VAR_FUNC
! || stacktype->tt_type == VAR_PARTIAL)
&& var_wrong_func_name(name, TRUE))
goto theend;

if (new_local && !has_type)
{
! if (stacktype->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void_value));
goto theend;
--- 5608,5625 ----
return FAIL;
}

! rhs_type = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
{
! if ((rhs_type->tt_type == VAR_FUNC
! || rhs_type->tt_type == VAR_PARTIAL)
&& var_wrong_func_name(name, TRUE))
goto theend;

if (new_local && !has_type)
{
! if (rhs_type->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void_value));
goto theend;
***************
*** 5578,5591 ****
{
// An empty list or dict has a &t_unknown member,
// for a variable that implies &t_any.
! if (stacktype == &t_list_empty)
lvar->lv_type = &t_list_any;
! else if (stacktype == &t_dict_empty)
lvar->lv_type = &t_dict_any;
! else if (stacktype == &t_unknown)
lvar->lv_type = &t_any;
else
! lvar->lv_type = stacktype;
}
}
else if (*op == '=')
--- 5628,5641 ----
{
// An empty list or dict has a &t_unknown member,
// for a variable that implies &t_any.
! if (rhs_type == &t_list_empty)
lvar->lv_type = &t_list_any;
! else if (rhs_type == &t_dict_empty)
lvar->lv_type = &t_dict_any;
! else if (rhs_type == &t_unknown)
lvar->lv_type = &t_any;
else
! lvar->lv_type = rhs_type;
}
}
else if (*op == '=')
***************
*** 5595,5611 ****
// without operator check type here, otherwise below
if (has_index)
{
! use_type = use_type->tt_member;
! if (use_type == NULL)
// could be indexing "any"
use_type = &t_any;
}
! if (need_type(stacktype, use_type, -1, cctx,
FALSE, is_const) == FAIL)
goto theend;
}
}
! else if (*p != '=' && need_type(stacktype, member_type, -1,
cctx, FALSE, FALSE) == FAIL)
goto theend;
}
--- 5645,5661 ----
// without operator check type here, otherwise below
if (has_index)
{
! use_type = member_type;
! if (member_type == NULL)
// could be indexing "any"
use_type = &t_any;
}
! if (need_type(rhs_type, use_type, -1, cctx,
FALSE, is_const) == FAIL)
goto theend;
}
}
! else if (*p != '=' && need_type(rhs_type, member_type, -1,
cctx, FALSE, FALSE) == FAIL)
goto theend;
}
***************
*** 5771,5777 ****
// - value
// - index
// - variable
! generate_loadvar(cctx, dest, name, lvar, type);

if (type->tt_type == VAR_LIST)
{
--- 5821,5851 ----
// - value
// - index
// - variable
! if (dest == dest_expr)
! {
! int c = var_start[varlen];
!
! // Evaluate "ll[expr]" of "ll[expr][idx]"
! p = var_start;
! var_start[varlen] = NUL;
! if (compile_expr0(&p, cctx) == OK && p != var_start + varlen)
! {
! // this should not happen
! emsg(_(e_missbrac));
! goto theend;
! }
! var_start[varlen] = c;
!
! type = stack->ga_len == 0 ? &t_void
! : ((type_T **)stack->ga_data)[stack->ga_len - 1];
! // now we can properly check the type
! if (type->tt_member != NULL
! && need_type(rhs_type, type->tt_member, -2, cctx,
! FALSE, FALSE) == FAIL)
! goto theend;
! }
! else
! generate_loadvar(cctx, dest, name, lvar, type);

if (type->tt_type == VAR_LIST)
{
***************
*** 5785,5791 ****
}
else
{
! emsg(_(e_listreq));
goto theend;
}
}
--- 5859,5865 ----
}
else
{
! emsg(_(e_indexable_type_required));
goto theend;
}
}
***************
*** 5882,5887 ****
--- 5956,5964 ----
generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
}
break;
+ case dest_expr:
+ // cannot happen
+ break;
}
}

*** ../vim-8.2.2062/src/errors.h 2020-11-23 08:31:14.101789113 +0100
--- src/errors.h 2020-11-28 18:00:34.709736698 +0100
***************
*** 311,313 ****
--- 311,315 ----
INIT(= N_("E1139: Missing matching bracket after dict key"));
EXTERN char e_for_argument_must_be_sequence_of_lists[]
INIT(= N_("E1140: For argument must be a sequence of lists"));
+ EXTERN char e_indexable_type_required[]
+ INIT(= N_("E1141: Indexable type required"));
*** ../vim-8.2.2062/src/testdir/test_vim9_assign.vim 2020-11-16 22:11:39.625599176 +0100
--- src/testdir/test_vim9_assign.vim 2020-11-28 18:50:41.476298895 +0100
***************
*** 225,230 ****
--- 225,302 ----
END
enddef

+ def Test_assign_index()
+ # list of list
+ var l1: list<number>
+ l1[0] = 123
+ assert_equal([123], l1)
+
+ var l2: list<list<number>>
+ l2[0] = []
+ l2[0][0] = 123
+ assert_equal([[123]], l2)
+
+ var l3: list<list<list<number>>>
+ l3[0] = []
+ l3[0][0] = []
+ l3[0][0][0] = 123
+ assert_equal([[[123]]], l3)
+
+ var lines =<< trim END
+ var l3: list<list<number>>
+ l3[0] = []
+ l3[0][0] = []
+ END
+ CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3)
+
+ # dict of dict
+ var d1: dict<number>
+ d1.one = 1
+ assert_equal({one: 1}, d1)
+
+ var d2: dict<dict<number>>
+ d2.one = {}
+ d2.one.two = 123
+ assert_equal({one: {two: 123}}, d2)
+
+ var d3: dict<dict<dict<number>>>
+ d3.one = {}
+ d3.one.two = {}
+ d3.one.two.three = 123
+ assert_equal({one: {two: {three: 123}}}, d3)
+
+ lines =<< trim END
+ var d3: dict<dict<number>>
+ d3.one = {}
+ d3.one.two = {}
+ END
+ CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3)
+
+ # list of dict
+ var ld: list<dict<number>>
+ ld[0] = {}
+ ld[0].one = 123
+ assert_equal([{one: 123}], ld)
+
+ lines =<< trim END
+ var ld: list<dict<number>>
+ ld[0] = []
+ END
+ CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
+
+ # dict of list
+ var dl: dict<list<number>>
+ dl.one = []
+ dl.one[0] = 123
+ assert_equal({one: [123]}, dl)
+
+ lines =<< trim END
+ var dl: dict<list<number>>
+ dl.one = {}
+ END
+ CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2)
+ enddef
+
def Test_extend_list()
var lines =<< trim END
vim9script
*** ../vim-8.2.2062/src/version.c 2020-11-28 14:43:23.950237798 +0100
--- src/version.c 2020-11-28 18:01:31.801550593 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2063,
/**/

--
The question is: What do you do with your life?
The wrong answer is: Become the richest guy in the graveyard.
(billionaire and Oracle founder Larry Ellison)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages