summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-02-03 17:41:24 +0100
committerBram Moolenaar <Bram@vim.org>2021-02-03 17:41:24 +0100
commit2e5910bfbb05957c10c9c69756dfa342557e9a8b (patch)
treec70cb2b5240cb3f8465cb14773a11c25622e9a41
parent91478ae49a1b2dc1de63821db731a343e855dcc0 (diff)
downloadvim-git-2e5910bfbb05957c10c9c69756dfa342557e9a8b.tar.gz
patch 8.2.2455: Vim9: key type for literal dict and indexing is inconsistentv8.2.2455
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)
-rw-r--r--runtime/doc/vim9.txt6
-rw-r--r--src/dict.c8
-rw-r--r--src/eval.c20
-rw-r--r--src/testdir/test_vim9_builtin.vim10
-rw-r--r--src/testdir/test_vim9_expr.vim42
-rw-r--r--src/testdir/test_vim9_script.vim4
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c20
8 files changed, 74 insertions, 38 deletions
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt
index 7246ff87a..220a19ba8 100644
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -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 ~
diff --git a/src/dict.c b/src/dict.c
index b267e240d..260f22985 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -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)
{
diff --git a/src/eval.c b/src/eval.c
index ebd25077c..239ddb600 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
+ }
}
/*
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 5e678fa6d..06839c0c5 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -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()
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index aead431f5..348fb934d 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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()
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 94be7c14e..d25bb47aa 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -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)
diff --git a/src/version.c b/src/version.c
index 9eb0f5d5b..19a2f8296 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2455,
+/**/
2454,
/**/
2453,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 5718efdf8..55e33eb12 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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 != ']')
{