mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.2455: Vim9: key type for literal dict and indexing is inconsistent
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)
This commit is contained in:
@@ -548,6 +548,12 @@ In case the key needs to be an expression, square brackets can be used, just
|
|||||||
like in JavaScript: >
|
like in JavaScript: >
|
||||||
var dict = {["key" .. nr]: value}
|
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 ~
|
No :xit, :t, :append, :change or :insert ~
|
||||||
|
|
||||||
|
@@ -953,11 +953,13 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
|
|||||||
}
|
}
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
if (vim9script && check_for_string(&tvkey) == FAIL)
|
#ifdef FEAT_FLOAT
|
||||||
|
if (tvkey.v_type == VAR_FLOAT)
|
||||||
{
|
{
|
||||||
clear_tv(&tvkey);
|
tvkey.vval.v_string = typval_tostring(&tvkey, TRUE);
|
||||||
goto failret;
|
tvkey.v_type = VAR_STRING;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
key = tv_get_string_buf_chk(&tvkey, buf);
|
key = tv_get_string_buf_chk(&tvkey, buf);
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
{
|
{
|
||||||
|
14
src/eval.c
14
src/eval.c
@@ -3849,12 +3849,24 @@ eval_index(
|
|||||||
clear_tv(&var1);
|
clear_tv(&var1);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
else if (evaluate && tv_get_string_chk(&var1) == NULL)
|
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
|
// not a number or string
|
||||||
clear_tv(&var1);
|
clear_tv(&var1);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the second variable from inside the [:].
|
* Get the second variable from inside the [:].
|
||||||
|
@@ -350,10 +350,6 @@ def Test_job_info_return_type()
|
|||||||
endif
|
endif
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Wrong_dict_key_type(items: list<number>): list<number>
|
|
||||||
return filter(items, (_, val) => get({[val]: 1}, 'x'))
|
|
||||||
enddef
|
|
||||||
|
|
||||||
def Test_filereadable()
|
def Test_filereadable()
|
||||||
assert_false(filereadable(""))
|
assert_false(filereadable(""))
|
||||||
assert_false(filereadable(test_null_string()))
|
assert_false(filereadable(test_null_string()))
|
||||||
@@ -410,8 +406,12 @@ def Test_fnamemodify()
|
|||||||
CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E928:')
|
CheckDefExecFailure(['echo fnamemodify("file", true)'], 'E928:')
|
||||||
enddef
|
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()
|
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
|
enddef
|
||||||
|
|
||||||
def Test_filter_return_type()
|
def Test_filter_return_type()
|
||||||
|
@@ -1354,13 +1354,11 @@ def Test_expr5_list_add()
|
|||||||
endfor
|
endfor
|
||||||
|
|
||||||
# concatenating two lists with different member types results in "any"
|
# concatenating two lists with different member types results in "any"
|
||||||
var lines =<< trim END
|
var dany = {}
|
||||||
var d = {}
|
for i in ['a'] + [12]
|
||||||
for i in ['a'] + [0]
|
dany[i] = i
|
||||||
d = {[i]: 0}
|
|
||||||
endfor
|
endfor
|
||||||
END
|
assert_equal({a: 'a', 12: 12}, dany)
|
||||||
CheckDefExecFailure(lines, 'E1012:')
|
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
" test multiply, divide, modulo
|
" test multiply, divide, modulo
|
||||||
@@ -2116,6 +2114,25 @@ def Test_expr7_dict()
|
|||||||
var cd = { # comment
|
var cd = { # comment
|
||||||
key: 'val' # 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
|
END
|
||||||
CheckDefAndScriptSuccess(lines)
|
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: 234, b: "1"}'], 'E1012:', 1)
|
||||||
CheckDefExecFailure(['var x: dict<string> = {a: "x", b: 134}'], '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)
|
CheckDefFailure(['var x = ({'], 'E723:', 2)
|
||||||
CheckDefExecFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
|
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
|
enddef
|
||||||
|
|
||||||
def Test_expr7_dict_vim9script()
|
def Test_expr7_dict_vim9script()
|
||||||
|
@@ -450,8 +450,8 @@ def Test_try_catch_throw()
|
|||||||
|
|
||||||
var nd: dict<any>
|
var nd: dict<any>
|
||||||
try
|
try
|
||||||
nd = {[g:anumber]: 1}
|
nd = {[g:alist]: 1}
|
||||||
catch /E1012:/
|
catch /E1105:/
|
||||||
n = 266
|
n = 266
|
||||||
endtry
|
endtry
|
||||||
assert_equal(266, n)
|
assert_equal(266, n)
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2455,
|
||||||
/**/
|
/**/
|
||||||
2454,
|
2454,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -3145,7 +3145,6 @@ compile_lambda(char_u **arg, cctx_T *cctx)
|
|||||||
compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||||
{
|
{
|
||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
dict_T *d = dict_alloc();
|
dict_T *d = dict_alloc();
|
||||||
dictitem_T *item;
|
dictitem_T *item;
|
||||||
@@ -3180,16 +3179,19 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
if (compile_expr0(arg, cctx) == FAIL)
|
if (compile_expr0(arg, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
|
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)
|
if (isn->isn_type == ISN_PUSHS)
|
||||||
key = isn->isn_arg.string;
|
key = isn->isn_arg.string;
|
||||||
else
|
else if (may_generate_2STRING(-1, cctx) == FAIL)
|
||||||
{
|
|
||||||
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;
|
return FAIL;
|
||||||
}
|
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
if (**arg != ']')
|
if (**arg != ']')
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user