]> granicus.if.org Git - vim/commitdiff
patch 8.2.0619: null dict is not handled like an empty dict v8.2.0619
authorBram Moolenaar <Bram@vim.org>
Thu, 23 Apr 2020 11:38:02 +0000 (13:38 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 23 Apr 2020 11:38:02 +0000 (13:38 +0200)
Problem:    Null dict is not handled like an empty dict.
Solution:   Fix the code and add tests. (Yegappan Lakshmanan, closes #5968)

12 files changed:
src/dict.c
src/eval.c
src/testdir/test_blob.vim
src/testdir/test_expr.vim
src/testdir/test_filter_map.vim
src/testdir/test_let.vim
src/testdir/test_listdict.vim
src/testdir/test_search.vim
src/testdir/test_unlet.vim
src/testdir/test_usercommands.vim
src/testdir/test_vimscript.vim
src/version.c

index 1a928a35f2094b0b8f447c36a694fc98a6f0b8ed..88bd0e21c6b3d9e2fe57f16792a52500e08ca3cf 100644 (file)
@@ -977,14 +977,15 @@ dict_equal(
     dictitem_T *item2;
     int                todo;
 
-    if (d1 == NULL && d2 == NULL)
-       return TRUE;
-    if (d1 == NULL || d2 == NULL)
-       return FALSE;
     if (d1 == d2)
        return TRUE;
     if (dict_len(d1) != dict_len(d2))
        return FALSE;
+    if (dict_len(d1) == 0)
+       // empty and NULL dicts are considered equal
+       return TRUE;
+    if (d1 == NULL || d2 == NULL)
+       return FALSE;
 
     todo = (int)d1->dv_hashtab.ht_used;
     for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
index 7130620c94bc9799af2fe824e6b0d8b548c4f603..c3f0de8e32be19a35f00b2cbe72be109dee9b8db 100644 (file)
@@ -871,7 +871,10 @@ get_lval(
                if (len != -1)
                    key[len] = prevval;
                if (wrong)
+               {
+                   clear_tv(&var1);
                    return NULL;
+               }
            }
 
            if (lp->ll_di == NULL)
@@ -4553,8 +4556,9 @@ echo_string_core(
        case VAR_DICT:
            if (tv->vval.v_dict == NULL)
            {
+               // NULL dict is equivalent to empty dict.
                *tofree = NULL;
-               r = NULL;
+               r = (char_u *)"{}";
            }
            else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID
                    && tv->vval.v_dict->dv_hashtab.ht_used != 0)
@@ -4565,6 +4569,7 @@ echo_string_core(
            else
            {
                int old_copyID = tv->vval.v_dict->dv_copyID;
+
                tv->vval.v_dict->dv_copyID = copyID;
                *tofree = dict2string(tv, copyID, restore_copyID);
                if (restore_copyID)
index a29e2e61d977a61118c11877258d9b5164bdad4b..4b6774fc9d37cc426f44c06b1d8db093838b8adc 100644 (file)
@@ -207,6 +207,7 @@ func Test_blob_add()
   call assert_equal(0z001122, b)
   call add(b, '51')
   call assert_equal(0z00112233, b)
+  call assert_equal(1, add(test_null_blob(), 0x22))
 
   call assert_fails('call add(b, [9])', 'E745:')
   call assert_fails('call add("", 0x01)', 'E897:')
index 11cd7aa524371e2db57dac5fedddd5481df6bab2..ce167938102c17f489f43685aa206bfaa46bddb1 100644 (file)
@@ -96,13 +96,6 @@ func Test_loop_over_null_list()
   endfor
 endfunc
 
-func Test_compare_null_dict()
-  call assert_fails('let x = test_null_dict()[10]')
-  call assert_equal({}, {})
-  call assert_equal(test_null_dict(), test_null_dict())
-  call assert_notequal({}, test_null_dict())
-endfunc
-
 func Test_set_reg_null_list()
   call setreg('x', test_null_list())
 endfunc
index 63102cd9d4127b16edad440dea5e7765c36047c1..fc9c741bb34d7015b7620b4caaf78f08bd950f6b 100644 (file)
@@ -96,6 +96,7 @@ func Test_map_filter_fails()
   call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:')
   call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:')
   call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:')
+  call assert_fails("let l = filter([1, 2], {})", 'E731:')
   call assert_equal(0, map(test_null_list(), '"> " .. v:val'))
   call assert_equal(0, map(test_null_dict(), '"> " .. v:val'))
 endfunc
index cfe095cfefde3ba34276e3190c9cea9a0e4ad1ce..e0d543c6ce396f16be2ecc80c38c817acfd82654 100644 (file)
@@ -274,6 +274,7 @@ func Test_let_errors()
   call assert_fails('let &buftype[1] = "nofile"', 'E18:')
   let s = "var"
   let var = 1
+  call assert_fails('let var += [1,2]', 'E734:')
   call assert_fails('let {s}.1 = 2', 'E18:')
   call assert_fails('let a[1] = 5', 'E121:')
   let l = [[1,2]]
@@ -286,6 +287,8 @@ func Test_let_errors()
   call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:')
   call assert_fails('let l[-2:-3] = [3, 4]', 'E684:')
   call assert_fails('let l[0:4] = [5, 6]', 'E711:')
+  call assert_fails('let g:["a;b"] = 10', 'E461:')
+  call assert_fails('let g:.min = function("max")', 'E704:')
 
   " This test works only when the language is English
   if v:lang == "C" || v:lang =~ '^[Ee]n'
index c6d6885ec4e398287cfc52b510540b7cf5b32d36..2087f77ec9eb49711c62ae35e06676b1fd26faaf 100644 (file)
@@ -32,7 +32,11 @@ func Test_list_slice()
   call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
   call assert_equal([], l[8:-1])
   call assert_equal([], l[0:-10])
-  call assert_equal([], test_null_list()[:2])
+  " perform an operation on a list slice
+  let l = [1, 2, 3]
+  let l[:1] += [1, 2]
+  let l[2:] -= [1]
+  call assert_equal([2, 4, 2], l)
 endfunc
 
 " List identity
@@ -147,6 +151,20 @@ func Test_list_func_remove()
   call assert_fails("call remove(l, l)", 'E745:')
 endfunc
 
+" List add() function
+func Test_list_add()
+  let l = []
+  call add(l, 1)
+  call add(l, [2, 3])
+  call add(l, [])
+  call add(l, test_null_list())
+  call add(l, {'k' : 3})
+  call add(l, {})
+  call add(l, test_null_dict())
+  call assert_equal([1, [2, 3], [], [], {'k' : 3}, {}, {}], l)
+  call assert_equal(1, add(test_null_list(), 4))
+endfunc
+
 " Tests for Dictionary type
 
 func Test_dict()
@@ -529,6 +547,15 @@ func Test_dict_lock_extend()
   call assert_equal({'a': 99, 'b': 100}, d)
 endfunc
 
+" Cannot use += with a locked dick
+func Test_dict_lock_operator()
+  unlet! d
+  let d = {}
+  lockvar d
+  call assert_fails("let d += {'k' : 10}", 'E741:')
+  unlockvar d
+endfunc
+
 " No remove() of write-protected scope-level variable
 func Tfunc1(this_is_a_long_parameter_name)
   call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
@@ -651,8 +678,6 @@ func Test_reverse_sort_uniq()
   call assert_fails("call sort([1, 2], function('min'), 1)", "E715:")
   call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
   call assert_fails("call sort([1, 2], function('min'))", "E702:")
-  call assert_equal(0, sort(test_null_list()))
-  call assert_equal(0, uniq(test_null_list()))
 endfunc
 
 " splitting a string to a List using split()
@@ -896,23 +921,44 @@ func Test_listdict_index()
   call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:')
   call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:')
   call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:')
+  let l = [1, 2, 3]
+  call assert_fails("let l[i] = 3", 'E121:')
+  call assert_fails("let l[1.1] = 4", 'E806:')
+  call assert_fails("let l[:i] = [4, 5]", 'E121:')
+  call assert_fails("let l[:3.2] = [4, 5]", 'E806:')
 endfunc
 
 " Test for a null list
 func Test_null_list()
-  call assert_equal(0, join(test_null_list()))
+  let l = test_null_list()
+  call assert_equal(0, join(l))
+  call assert_equal(0, len(l))
+  call assert_equal(1, empty(l))
   call assert_fails('let s = join([1, 2], [])', 'E730:')
   call assert_equal([], split(test_null_string()))
+  call assert_equal([], l[:2])
+  call assert_true([] == l)
+  call assert_equal('[]', string(l))
+  call assert_equal(0, sort(l))
+  call assert_equal(0, uniq(l))
+  call assert_fails("let k = [] + l", 'E15:')
+  call assert_fails("let k = l + []", 'E15:')
 endfunc
 
 " Test for a null dict
 func Test_null_dict()
-  call assert_equal(0, items(test_null_dict()))
-  call assert_equal(0, keys(test_null_dict()))
-  call assert_equal(0, values(test_null_dict()))
-  call assert_false(has_key(test_null_dict(), 'k'))
-  call assert_fails("let l = [] + test_null_list()", 'E15:')
-  call assert_fails("let l = test_null_list() + []", 'E15:')
+  call assert_equal(test_null_dict(), test_null_dict())
+  let d = test_null_dict()
+  call assert_equal({}, d)
+  call assert_equal(0, len(d))
+  call assert_equal(1, empty(d))
+  call assert_equal(0, items(d))
+  call assert_equal(0, keys(d))
+  call assert_equal(0, values(d))
+  call assert_false(has_key(d, 'k'))
+  call assert_equal('{}', string(d))
+  call assert_fails('let x = test_null_dict()[10]')
+  call assert_equal({}, {})
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
index b7e751fa04cbc4eb9bd79d7cdee136bc7ff3c447..aaa42352ced65b09f5ec2a3013be79b8fa8a70aa 100644 (file)
@@ -1617,4 +1617,35 @@ func Test_search_in_visual_area()
   close!
 endfunc
 
+" Test for searching with 'smartcase' and 'ignorecase'
+func Test_search_smartcase()
+  new
+  call setline(1, ['', 'Hello'])
+  set noignorecase nosmartcase
+  call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
+
+  set ignorecase nosmartcase
+  exe "normal /\\a\\_.\\(.*\\)O\<CR>"
+  call assert_equal([2, 1], [line('.'), col('.')])
+
+  call cursor(1, 1)
+  set ignorecase smartcase
+  call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
+
+  exe "normal /\\a\\_.\\(.*\\)o\<CR>"
+  call assert_equal([2, 1], [line('.'), col('.')])
+
+  set ignorecase& smartcase&
+  close!
+endfunc
+
+" Test searching past the end of a file
+func Test_search_past_eof()
+  new
+  call setline(1, ['Line'])
+  exe "normal /\\n\\zs\<CR>"
+  call assert_equal([1, 4], [line('.'), col('.')])
+  close!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index dad0953a667a7b8096e0783086e1948f42ea3433..6be963370a03fa01f42afc200c8c161bcb73ca23 100644 (file)
@@ -27,6 +27,7 @@ func Test_unlet_fails()
   call assert_fails("unlet l['k'", 'E111:')
   let d = {'k' : 1}
   call assert_fails("unlet d.k2", 'E716:')
+  call assert_fails("unlet {a};", 'E488:')
 endfunc
 
 func Test_unlet_env()
index 0f0049569bdb68ac4d4b171145eabb487bb3280b..7f87e27aeed2f839f65bb0d28130bd16e35c6a4b 100644 (file)
@@ -587,17 +587,17 @@ func Test_usercmd_custom()
     return "a\nb\n"
   endfunc
   command -nargs=* -complete=customlist,T1 TCmd1
-  call feedkeys(":T1 \<C-A>\<C-B>\"\<CR>", 'xt')
-  call assert_equal('"T1 ', @:)
+  call feedkeys(":TCmd1 \<C-A>\<C-B>\"\<CR>", 'xt')
+  call assert_equal('"TCmd1 ', @:)
   delcommand TCmd1
   delfunc T1
 
   func T2(a, c, p)
-    return ['a', 'b', 'c']
+    return {}
   endfunc
   command -nargs=* -complete=customlist,T2 TCmd2
-  call feedkeys(":T2 \<C-A>\<C-B>\"\<CR>", 'xt')
-  call assert_equal('"T2 ', @:)
+  call feedkeys(":TCmd2 \<C-A>\<C-B>\"\<CR>", 'xt')
+  call assert_equal('"TCmd2 ', @:)
   delcommand TCmd2
   delfunc T2
 endfunc
index 7c8683661985f0b08e8e133023a53ece60baa30f..439114d19b3b3182d1aeed659d27fff3fc970ab6 100644 (file)
@@ -1671,6 +1671,20 @@ func Test_compound_assignment_operators()
       call assert_fails('let x .= "f"', 'E734')
       let x = !3.14
       call assert_equal(0.0, x)
+
+      " integer and float operations
+      let x = 1
+      let x *= 2.1
+      call assert_equal(2.1, x)
+      let x = 1
+      let x /= 0.25
+      call assert_equal(4.0, x)
+      let x = 1
+      call assert_fails('let x %= 0.25', 'E734:')
+      let x = 1
+      call assert_fails('let x .= 0.25', 'E734:')
+      let x = 1.0
+      call assert_fails('let x += [1.1]', 'E734:')
     endif
 
     " Test for environment variable
@@ -1871,6 +1885,9 @@ func Test_missing_end()
 
   " Missing 'in' in a :for statement
   call assert_fails('for i range(1) | endfor', 'E690:')
+
+  " Incorrect number of variables in for
+  call assert_fails('for [i,] in range(3) | endfor', 'E475:')
 endfunc
 
 " Test for deep nesting of if/for/while/try statements              {{{1
index c08008434ca90aea7ea40bd2920bc577bd378b18..ad34a91c0f720e71efe30da6d0f2f5a4c1abcd7e 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    619,
 /**/
     618,
 /**/