]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2072: Vim9: no nr2str conversion in list-unpack v9.0.2072
authorYegappan Lakshmanan <yegappan@yahoo.com>
Thu, 26 Oct 2023 21:05:07 +0000 (23:05 +0200)
committerChristian Brabandt <cb@256bit.org>
Thu, 26 Oct 2023 21:05:07 +0000 (23:05 +0200)
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>
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_class.vim
src/testdir/test_vim9_disassemble.vim
src/version.c
src/vim9compile.c

index 6d2858f6c0372489c6f43ad0766c7495445e6cc9..91d302c4c5941486a0e490ec94d5f2d45c0347cd 100644 (file)
@@ -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
index 02e99c84c32401581c61fff696e2b466bc247c11..1c309e4f0c3ff0b5d5cd5ab54bff6855045ca8fc 100644 (file)
@@ -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
index 521f75fb171f7f991f67feae55ee09051d866d89..9d78ad0aae915bb35d54f4d6a893980f7ca49369 100644 (file)
@@ -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)
index dc630b8dc7cc3a666e5e8269f703964a5d47c925..85db1c66df79d6ed7d47c0722276e27cb6a63210 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2072,
 /**/
     2071,
 /**/
index 03e79f5655df65346c4e057b7169f90014f192e4..4aa83606b9fbe7cc1e24e8e13c6710d0b7f7e9f3 100644 (file)
@@ -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