To: vim_dev@googlegroups.com Subject: Patch 8.2.2455 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.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) Files: runtime/doc/vim9.txt, src/dict.c, src/eval.c, src/vim9compile.c, src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_builtin.vim, src/testdir/test_vim9_script.vim *** ../vim-8.2.2454/runtime/doc/vim9.txt 2021-01-31 17:02:06.278490083 +0100 --- runtime/doc/vim9.txt 2021-02-03 17:39:53.048542236 +0100 *************** *** 548,553 **** --- 548,559 ---- 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 ~ *** ../vim-8.2.2454/src/dict.c 2021-01-22 22:06:51.636529831 +0100 --- src/dict.c 2021-02-03 17:12:40.582241104 +0100 *************** *** 953,963 **** } if (evaluate) { ! if (vim9script && check_for_string(&tvkey) == FAIL) { ! clear_tv(&tvkey); ! goto failret; } key = tv_get_string_buf_chk(&tvkey, buf); if (key == NULL) { --- 953,965 ---- } if (evaluate) { ! #ifdef FEAT_FLOAT ! if (tvkey.v_type == VAR_FLOAT) { ! 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) { *** ../vim-8.2.2454/src/eval.c 2021-01-23 14:22:10.228667110 +0100 --- src/eval.c 2021-02-03 17:23:30.511919709 +0100 *************** *** 3849,3859 **** clear_tv(&var1); return FAIL; } ! else if (evaluate && tv_get_string_chk(&var1) == NULL) { ! // not a number or string ! clear_tv(&var1); ! return FAIL; } /* --- 3849,3871 ---- clear_tv(&var1); return FAIL; } ! else if (evaluate) { ! #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; ! } } /* *** ../vim-8.2.2454/src/vim9compile.c 2021-02-01 20:14:44.566705066 +0100 --- src/vim9compile.c 2021-02-03 16:45:39.511757869 +0100 *************** *** 3145,3151 **** 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; --- 3145,3150 ---- *************** *** 3180,3195 **** 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 { ! 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; } *arg = skipwhite(*arg); if (**arg != ']') { --- 3179,3197 ---- if (compile_expr0(arg, cctx) == FAIL) return FAIL; isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; ! if (isn->isn_type == ISN_PUSHNR) { ! 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 != ']') { *** ../vim-8.2.2454/src/testdir/test_vim9_expr.vim 2021-01-31 21:47:39.036783041 +0100 --- src/testdir/test_vim9_expr.vim 2021-02-03 17:26:13.023355333 +0100 *************** *** 1354,1366 **** 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:') enddef " test multiply, divide, modulo --- 1354,1364 ---- endfor # concatenating two lists with different member types results in "any" ! var dany = {} ! for i in ['a'] + [12] ! dany[i] = i ! endfor ! assert_equal({a: 'a', 12: 12}, dany) enddef " test multiply, divide, modulo *************** *** 2116,2121 **** --- 2114,2138 ---- 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,2157 **** CheckDefExecFailure(['var x: dict = {a: 234, b: "1"}'], 'E1012:', 1) CheckDefExecFailure(['var x: dict = {a: "x", b: 134}'], 'E1012:', 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() --- 2159,2169 ---- CheckDefExecFailure(['var x: dict = {a: 234, b: "1"}'], 'E1012:', 1) CheckDefExecFailure(['var x: dict = {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) enddef def Test_expr7_dict_vim9script() *** ../vim-8.2.2454/src/testdir/test_vim9_builtin.vim 2021-02-01 20:14:44.566705066 +0100 --- src/testdir/test_vim9_builtin.vim 2021-02-03 17:32:01.046156845 +0100 *************** *** 350,359 **** endif enddef - def Wrong_dict_key_type(items: list): list - return filter(items, (_, val) => get({[val]: 1}, 'x')) - enddef - def Test_filereadable() assert_false(filereadable("")) assert_false(filereadable(test_null_string())) --- 350,355 ---- *************** *** 410,417 **** CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E928:') enddef def Test_filter_wrong_dict_key_type() ! assert_fails('Wrong_dict_key_type([1, 2, 3])', 'E1012:') enddef def Test_filter_return_type() --- 406,417 ---- CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E928:') enddef + def Wrong_dict_key_type(items: list): list + return filter(items, (_, val) => get({[val]: 1}, 'x')) + enddef + def Test_filter_wrong_dict_key_type() ! assert_fails('Wrong_dict_key_type([1, v:null, 3])', 'E1013:') enddef def Test_filter_return_type() *** ../vim-8.2.2454/src/testdir/test_vim9_script.vim 2021-01-31 14:04:04.082702516 +0100 --- src/testdir/test_vim9_script.vim 2021-02-03 17:34:55.621558824 +0100 *************** *** 450,457 **** var nd: dict try ! nd = {[g:anumber]: 1} ! catch /E1012:/ n = 266 endtry assert_equal(266, n) --- 450,457 ---- var nd: dict try ! nd = {[g:alist]: 1} ! catch /E1105:/ n = 266 endtry assert_equal(266, n) *** ../vim-8.2.2454/src/version.c 2021-02-03 15:58:09.088690884 +0100 --- src/version.c 2021-02-03 16:34:41.582027061 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2455, /**/ -- E M A C S s e l o h c t t n i a a t f p r t e o l /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///