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

Commit: 
https://github.com/vim/vim/commit/c229a6ac0775e07dff456ca8832c516e57a74e74
Author: Yegappan Lakshmanan <[email protected]>
Date:   Thu Oct 26 23:05:07 2023 +0200

    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 <[email protected]>
    Co-authored-by: Yegappan Lakshmanan <[email protected]>

diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 6d2858f6c..91d302c4c 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 02e99c84c..1c309e4f0 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 521f75fb1..9d78ad0aa 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 dc630b8dc..85db1c66d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2072,
 /**/
     2071,
 /**/
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 03e79f565..4aa83606b 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

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qw7h4-006rMk-44%40256bit.org.

Raspunde prin e-mail lui