patch 9.0.2072: Vim9: no nr2str conversion in list-unpack

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>
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 6d2858f..91d302c 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -2986,4 +2986,21 @@
   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 02e99c8..1c309e4 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -8442,4 +8442,133 @@
   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 521f75f..9d78ad0 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -560,6 +560,7 @@
         '\d LOAD $0\_s*' ..
         '\d MEMBER dd\_s*' ..
         '\d\+ USEDICT\_s*' ..
+        '\d\+ 2STRING stack\[-2\]\_s*' ..
         '\d\+ STOREINDEX any\_s*' ..
         '\d\+ RETURN void',
         res)