]> granicus.if.org Git - vim/commitdiff
patch 8.2.2455: Vim9: key type for literal dict and indexing is inconsistent v8.2.2455
authorBram Moolenaar <Bram@vim.org>
Wed, 3 Feb 2021 16:41:24 +0000 (17:41 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 3 Feb 2021 16:41:24 +0000 (17:41 +0100)
Problem:    Vim9: key type that can be used for literal dict and indexing is
            inconsistent.
Solution:   Allow using number and bool as key for a literal dict. (#7771)

runtime/doc/vim9.txt
src/dict.c
src/eval.c
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_script.vim
src/version.c
src/vim9compile.c

index 7246ff87a6966d32d032eaebafecb221ba48eb12..220a19ba844a4ce433506720816dc8a2fbec902f 100644 (file)
@@ -548,6 +548,12 @@ In case the key needs to be an expression, square brackets can be used, just
 like in JavaScript: >
        var dict = {["key" .. nr]: value}
 
+The key type can be string, number, bool or float.  Other types result in an
+error.  A number can be given with and without the []: >
+       var dict = {123: 'without', [456]: 'with'}
+       echo dict
+       {'456': 'with', '123': 'without'}
+
 
 No :xit, :t, :append, :change or :insert ~
 
index b267e240db130afccc5d2bd91313dbbcf21a090b..260f229850f042e3ec4addffcaba27fccb6c00e2 100644 (file)
@@ -953,11 +953,13 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
        }
        if (evaluate)
        {
-           if (vim9script && check_for_string(&tvkey) == FAIL)
+#ifdef FEAT_FLOAT
+           if (tvkey.v_type == VAR_FLOAT)
            {
-               clear_tv(&tvkey);
-               goto failret;
+               tvkey.vval.v_string = typval_tostring(&tvkey, TRUE);
+               tvkey.v_type = VAR_STRING;
            }
+#endif
            key = tv_get_string_buf_chk(&tvkey, buf);
            if (key == NULL)
            {
index ebd25077c3ede3b3701a608f7c7dba2351640b5c..239ddb6009398d09a504c90b74b51291abc1daaf 100644 (file)
@@ -3849,11 +3849,23 @@ eval_index(
            clear_tv(&var1);
            return FAIL;
        }
-       else if (evaluate && tv_get_string_chk(&var1) == NULL)
+       else if (evaluate)
        {
-           // not a number or string
-           clear_tv(&var1);
-           return FAIL;
+#ifdef FEAT_FLOAT
+           // allow for indexing with float
+           if (vim9 && rettv->v_type == VAR_DICT
+                                                  && var1.v_type == VAR_FLOAT)
+           {
+               var1.vval.v_string = typval_tostring(&var1, TRUE);
+               var1.v_type = VAR_STRING;
+           }
+#endif
+           if (tv_get_string_chk(&var1) == NULL)
+           {
+               // not a number or string
+               clear_tv(&var1);
+               return FAIL;
+           }
        }
 
        /*
index 5e678fa6d36a1cd39a7da6a18aee12bc8fb0abeb..06839c0c5145d86bc917aa02d2f37f8cc72c99b9 100644 (file)
@@ -350,10 +350,6 @@ def Test_job_info_return_type()
   endif
 enddef
 
-def Wrong_dict_key_type(items: list<number>): list<number>
-  return filter(items, (_, val) => get({[val]: 1}, 'x'))
-enddef
-
 def Test_filereadable()
   assert_false(filereadable(""))
   assert_false(filereadable(test_null_string()))
@@ -410,8 +406,12 @@ def Test_fnamemodify()
   CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E928:')
 enddef
 
+def Wrong_dict_key_type(items: list<number>): list<number>
+  return filter(items, (_, val) => get({[val]: 1}, 'x'))
+enddef
+
 def Test_filter_wrong_dict_key_type()
-  assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:')
+  assert_fails('Wrong_dict_key_type([1, v:null, 3])', 'E1013:')
 enddef
 
 def Test_filter_return_type()
index aead431f5aef89d5cb6962e4f6da10bc38d794c7..348fb934df06a8af5f3f4bb63cd82d2b9d7bb6f3 100644 (file)
@@ -1354,13 +1354,11 @@ def Test_expr5_list_add()
   endfor
 
   # concatenating two lists with different member types results in "any"
-  var lines =<< trim END
-      var d = {}
-      for i in ['a'] + [0]
-        d = {[i]: 0}
-      endfor
-  END
-  CheckDefExecFailure(lines, 'E1012:')
+  var dany = {}
+  for i in ['a'] + [12]
+    dany[i] = i
+  endfor
+  assert_equal({a: 'a', 12: 12}, dany)
 enddef
 
 " test multiply, divide, modulo
@@ -2116,6 +2114,25 @@ def Test_expr7_dict()
       var cd = { # comment
                 key: 'val' # comment
                }
+
+      # different types used for the key
+      var dkeys = {['key']: 'string',
+                   [12]: 'numberexpr',
+                   34: 'number',
+                   [true]: 'bool'} 
+      assert_equal('string', dkeys['key'])
+      assert_equal('numberexpr', dkeys[12])
+      assert_equal('number', dkeys[34])
+      assert_equal('bool', dkeys[true])
+      if has('float')
+        dkeys = {[1.2]: 'floatexpr', [3.4]: 'float'}
+        assert_equal('floatexpr', dkeys[1.2])
+        assert_equal('float', dkeys[3.4])
+      endif
+
+      # automatic conversion from number to string
+      var n = 123
+      var dictnr = {[n]: 1}
   END
   CheckDefAndScriptSuccess(lines)
  
@@ -2142,16 +2159,11 @@ def Test_expr7_dict()
   CheckDefExecFailure(['var x: dict<string> = {a: 234, b: "1"}'], 'E1012:', 1)
   CheckDefExecFailure(['var x: dict<string> = {a: "x", b: 134}'], 'E1012:', 1)
 
+  # invalid types for the key
+  CheckDefFailure(["var x = {[[1, 2]]: 0}"], 'E1105:', 1)
+
   CheckDefFailure(['var x = ({'], 'E723:', 2)
   CheckDefExecFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
-
-  # no automatic conversion from number to string
-  lines =<< trim END
-      var n = 123
-      var d = {[n]: 1}
-  END
-  CheckDefFailure(lines, 'E1012:', 2)
-  CheckScriptFailure(['vim9script'] + lines, 'E928:', 3)
 enddef
 
 def Test_expr7_dict_vim9script()
index 94be7c14e18ff5acdd488d06ca932f9a0a260fc5..d25bb47aaa4188e634560c2fb1023a1f1e4e8232 100644 (file)
@@ -450,8 +450,8 @@ def Test_try_catch_throw()
 
   var nd: dict<any>
   try
-    nd = {[g:anumber]: 1}
-  catch /E1012:/
+    nd = {[g:alist]: 1}
+  catch /E1105:/
     n = 266
   endtry
   assert_equal(266, n)
index 9eb0f5d5b48cf289b310e54e2a51fb39b1663c99..19a2f8296a29d3b15213595f3be62086ab705fe1 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2455,
 /**/
     2454,
 /**/
index 5718efdf8f327b4f195f70c80113d1090836a021..55e33eb12df7e9e78c7a4171804cb09389096b46 100644 (file)
@@ -3145,7 +3145,6 @@ compile_lambda(char_u **arg, cctx_T *cctx)
 compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
 {
     garray_T   *instr = &cctx->ctx_instr;
-    garray_T   *stack = &cctx->ctx_type_stack;
     int                count = 0;
     dict_T     *d = dict_alloc();
     dictitem_T *item;
@@ -3180,16 +3179,19 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
            if (compile_expr0(arg, cctx) == FAIL)
                return FAIL;
            isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
-           if (isn->isn_type == ISN_PUSHS)
-               key = isn->isn_arg.string;
-           else
+           if (isn->isn_type == ISN_PUSHNR)
            {
-               type_T *keytype = ((type_T **)stack->ga_data)
-                                                      [stack->ga_len - 1];
-               if (need_type(keytype, &t_string, -1, 0, cctx,
-                                                    FALSE, FALSE) == FAIL)
-                   return FAIL;
+               char buf[NUMBUFLEN];
+
+               // Convert to string at compile time.
+               vim_snprintf(buf, NUMBUFLEN, "%lld", isn->isn_arg.number);
+               isn->isn_type = ISN_PUSHS;
+               isn->isn_arg.string = vim_strsave((char_u *)buf);
            }
+           if (isn->isn_type == ISN_PUSHS)
+               key = isn->isn_arg.string;
+           else if (may_generate_2STRING(-1, cctx) == FAIL)
+               return FAIL;
            *arg = skipwhite(*arg);
            if (**arg != ']')
            {