diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-02-03 17:41:24 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-02-03 17:41:24 +0100 |
commit | 2e5910bfbb05957c10c9c69756dfa342557e9a8b (patch) | |
tree | c70cb2b5240cb3f8465cb14773a11c25622e9a41 | |
parent | 91478ae49a1b2dc1de63821db731a343e855dcc0 (diff) | |
download | vim-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.txt | 6 | ||||
-rw-r--r-- | src/dict.c | 8 | ||||
-rw-r--r-- | src/eval.c | 20 | ||||
-rw-r--r-- | src/testdir/test_vim9_builtin.vim | 10 | ||||
-rw-r--r-- | src/testdir/test_vim9_expr.vim | 42 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 4 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 20 |
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 != ']') { |