summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2023-10-26 23:05:07 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-26 23:05:07 +0200
commitc229a6ac0775e07dff456ca8832c516e57a74e74 (patch)
tree59214f47ac823decad11c0eef5beca4bb2e94b1c
parent10407df7a95d0311c7d2eb920d3b72020db5b301 (diff)
patch 9.0.2072: Vim9: no nr2str conversion in list-unpackv9.0.2072
Problem: Vim9: no nr2str conversion in list-unpack Solution: Generate 2STRING instruction to convert dict index to string Generate instruction to convert dict index to a string fixes: #13417 closes: #13424 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
-rw-r--r--src/testdir/test_vim9_assign.vim17
-rw-r--r--src/testdir/test_vim9_class.vim129
-rw-r--r--src/testdir/test_vim9_disassemble.vim1
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c15
5 files changed, 161 insertions, 3 deletions
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 6d2858f6c0..91d302c4c5 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -2986,4 +2986,21 @@ def Test_heredoc_expr()
v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"')
enddef
+" Test for assigning to a multi-dimensional list item.
+def Test_list_item_assign()
+ var lines =<< trim END
+ vim9script
+
+ def Foo()
+ var l: list<list<string>> = [['x', 'x', 'x'], ['y', 'y', 'y']]
+ var z: number = 1
+
+ [l[1][2], z] = ['a', 20]
+ assert_equal([['x', 'x', 'x'], ['y', 'y', 'a']], l)
+ enddef
+ Foo()
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 02e99c84c3..1c309e4f0c 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -8442,4 +8442,133 @@ def Test_class_variable_as_operands()
v9.CheckSourceSuccess(lines)
enddef
+" Test for checking the type of the key used to access an object dict member.
+def Test_dict_member_key_type_check()
+ var lines =<< trim END
+ vim9script
+
+ abstract class State
+ this.numbers: dict<string> = {0: 'nil', 1: 'unity'}
+ endclass
+
+ class Test extends State
+ def ObjMethodTests()
+ var cursor: number = 0
+ var z: number = 0
+ [this.numbers[cursor]] = ['zero.1']
+ assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers)
+ [this.numbers[string(cursor)], z] = ['zero.2', 1]
+ assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers)
+ [z, this.numbers[string(cursor)]] = [1, 'zero.3']
+ assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers)
+ [this.numbers[cursor], z] = ['zero.4', 1]
+ assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers)
+ [z, this.numbers[cursor]] = [1, 'zero.5']
+ assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers)
+ enddef
+
+ static def ClassMethodTests(that: State)
+ var cursor: number = 0
+ var z: number = 0
+ [that.numbers[cursor]] = ['zero.1']
+ assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers)
+ [that.numbers[string(cursor)], z] = ['zero.2', 1]
+ assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers)
+ [z, that.numbers[string(cursor)]] = [1, 'zero.3']
+ assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers)
+ [that.numbers[cursor], z] = ['zero.4', 1]
+ assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers)
+ [z, that.numbers[cursor]] = [1, 'zero.5']
+ assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers)
+ enddef
+
+ def new()
+ enddef
+
+ def newMethodTests()
+ var cursor: number = 0
+ var z: number
+ [this.numbers[cursor]] = ['zero.1']
+ assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers)
+ [this.numbers[string(cursor)], z] = ['zero.2', 1]
+ assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers)
+ [z, this.numbers[string(cursor)]] = [1, 'zero.3']
+ assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers)
+ [this.numbers[cursor], z] = ['zero.4', 1]
+ assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers)
+ [z, this.numbers[cursor]] = [1, 'zero.5']
+ assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers)
+ enddef
+ endclass
+
+ def DefFuncTests(that: Test)
+ var cursor: number = 0
+ var z: number
+ [that.numbers[cursor]] = ['zero.1']
+ assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers)
+ [that.numbers[string(cursor)], z] = ['zero.2', 1]
+ assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers)
+ [z, that.numbers[string(cursor)]] = [1, 'zero.3']
+ assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers)
+ [that.numbers[cursor], z] = ['zero.4', 1]
+ assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers)
+ [z, that.numbers[cursor]] = [1, 'zero.5']
+ assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers)
+ enddef
+
+ Test.newMethodTests()
+ Test.new().ObjMethodTests()
+ Test.ClassMethodTests(Test.new())
+ DefFuncTests(Test.new())
+
+ const test: Test = Test.new()
+ var cursor: number = 0
+ [test.numbers[cursor], cursor] = ['zero', 1]
+ [cursor, test.numbers[cursor]] = [1, 'one']
+ assert_equal({0: 'zero', 1: 'one'}, test.numbers)
+ END
+ v9.CheckSourceSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+
+ class A
+ this.numbers: dict<string> = {a: '1', b: '2'}
+
+ def new()
+ enddef
+
+ def Foo()
+ var z: number
+ [this.numbers.a, z] = [{}, 10]
+ enddef
+ endclass
+
+ var a = A.new()
+ a.Foo()
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected string but got dict<unknown>', 2)
+
+ lines =<< trim END
+ vim9script
+
+ class A
+ this.numbers: dict<number> = {a: 1, b: 2}
+
+ def new()
+ enddef
+
+ def Foo()
+ var x: string = 'a'
+ var y: number
+ [this.numbers[x], y] = [{}, 10]
+ enddef
+ endclass
+
+ var a = A.new()
+ a.Foo()
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 521f75fb17..9d78ad0aae 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -560,6 +560,7 @@ def Test_disassemble_store_index()
'\d LOAD $0\_s*' ..
'\d MEMBER dd\_s*' ..
'\d\+ USEDICT\_s*' ..
+ '\d\+ 2STRING stack\[-2\]\_s*' ..
'\d\+ STOREINDEX any\_s*' ..
'\d\+ RETURN void',
res)
diff --git a/src/version.c b/src/version.c
index dc630b8dc7..85db1c66df 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2072,
+/**/
2071,
/**/
2070,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 03e79f5655..4aa83606b9 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2040,9 +2040,7 @@ compile_lhs(
lhs->lhs_member_type = m->ocm_type;
}
else
- {
lhs->lhs_member_type = lhs->lhs_type->tt_member;
- }
}
return OK;
}
@@ -2220,16 +2218,27 @@ compile_load_lhs(
return FAIL;
}
+ if (lhs->lhs_type->tt_type == VAR_DICT && var_start[varlen] == '[')
+ {
+ // If the lhs is a Dict variable and an item is accessed by "[",
+ // then need to convert the key into a string. The top item in the
+ // type stack is the Dict and the second last item is the key.
+ if (may_generate_2STRING(-2, FALSE, cctx) == FAIL)
+ return FAIL;
+ }
+
// Now we can properly check the type. The variable is indexed, thus
// we need the member type. For a class or object we don't know the
// type yet, it depends on what member is used.
+ // The top item in the stack is the Dict, followed by the key and then
+ // the type of the value.
vartype_T vartype = lhs->lhs_type->tt_type;
type_T *member_type = lhs->lhs_type->tt_member;
if (rhs_type != NULL && member_type != NULL
&& vartype != VAR_OBJECT && vartype != VAR_CLASS
&& rhs_type != &t_void
&& need_type(rhs_type, member_type, FALSE,
- -2, 0, cctx, FALSE, FALSE) == FAIL)
+ -3, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
else