mirror of
https://github.com/vim/vim.git
synced 2025-07-04 23:07:33 -04:00
patch 9.0.2072: Vim9: no nr2str conversion in list-unpack
Problem: Vim9: no nr2str conversion in list-unpack Solution: Generate 2STRING instruction to convert dict index to string Generate instruction to convert dict index to a string fixes: #13417 closes: #13424 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
parent
10407df7a9
commit
c229a6ac07
@ -2986,4 +2986,21 @@ def Test_heredoc_expr()
|
|||||||
v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"')
|
v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for assigning to a multi-dimensional list item.
|
||||||
|
def Test_list_item_assign()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
def Foo()
|
||||||
|
var l: list<list<string>> = [['x', 'x', 'x'], ['y', 'y', 'y']]
|
||||||
|
var z: number = 1
|
||||||
|
|
||||||
|
[l[1][2], z] = ['a', 20]
|
||||||
|
assert_equal([['x', 'x', 'x'], ['y', 'y', 'a']], l)
|
||||||
|
enddef
|
||||||
|
Foo()
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -8442,4 +8442,133 @@ def Test_class_variable_as_operands()
|
|||||||
v9.CheckSourceSuccess(lines)
|
v9.CheckSourceSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for checking the type of the key used to access an object dict member.
|
||||||
|
def Test_dict_member_key_type_check()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
abstract class State
|
||||||
|
this.numbers: dict<string> = {0: 'nil', 1: 'unity'}
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Test extends State
|
||||||
|
def ObjMethodTests()
|
||||||
|
var cursor: number = 0
|
||||||
|
var z: number = 0
|
||||||
|
[this.numbers[cursor]] = ['zero.1']
|
||||||
|
assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers)
|
||||||
|
[this.numbers[string(cursor)], z] = ['zero.2', 1]
|
||||||
|
assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers)
|
||||||
|
[z, this.numbers[string(cursor)]] = [1, 'zero.3']
|
||||||
|
assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers)
|
||||||
|
[this.numbers[cursor], z] = ['zero.4', 1]
|
||||||
|
assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers)
|
||||||
|
[z, this.numbers[cursor]] = [1, 'zero.5']
|
||||||
|
assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
static def ClassMethodTests(that: State)
|
||||||
|
var cursor: number = 0
|
||||||
|
var z: number = 0
|
||||||
|
[that.numbers[cursor]] = ['zero.1']
|
||||||
|
assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers)
|
||||||
|
[that.numbers[string(cursor)], z] = ['zero.2', 1]
|
||||||
|
assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers)
|
||||||
|
[z, that.numbers[string(cursor)]] = [1, 'zero.3']
|
||||||
|
assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers)
|
||||||
|
[that.numbers[cursor], z] = ['zero.4', 1]
|
||||||
|
assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers)
|
||||||
|
[z, that.numbers[cursor]] = [1, 'zero.5']
|
||||||
|
assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def new()
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def newMethodTests()
|
||||||
|
var cursor: number = 0
|
||||||
|
var z: number
|
||||||
|
[this.numbers[cursor]] = ['zero.1']
|
||||||
|
assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers)
|
||||||
|
[this.numbers[string(cursor)], z] = ['zero.2', 1]
|
||||||
|
assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers)
|
||||||
|
[z, this.numbers[string(cursor)]] = [1, 'zero.3']
|
||||||
|
assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers)
|
||||||
|
[this.numbers[cursor], z] = ['zero.4', 1]
|
||||||
|
assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers)
|
||||||
|
[z, this.numbers[cursor]] = [1, 'zero.5']
|
||||||
|
assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers)
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
def DefFuncTests(that: Test)
|
||||||
|
var cursor: number = 0
|
||||||
|
var z: number
|
||||||
|
[that.numbers[cursor]] = ['zero.1']
|
||||||
|
assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers)
|
||||||
|
[that.numbers[string(cursor)], z] = ['zero.2', 1]
|
||||||
|
assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers)
|
||||||
|
[z, that.numbers[string(cursor)]] = [1, 'zero.3']
|
||||||
|
assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers)
|
||||||
|
[that.numbers[cursor], z] = ['zero.4', 1]
|
||||||
|
assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers)
|
||||||
|
[z, that.numbers[cursor]] = [1, 'zero.5']
|
||||||
|
assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
Test.newMethodTests()
|
||||||
|
Test.new().ObjMethodTests()
|
||||||
|
Test.ClassMethodTests(Test.new())
|
||||||
|
DefFuncTests(Test.new())
|
||||||
|
|
||||||
|
const test: Test = Test.new()
|
||||||
|
var cursor: number = 0
|
||||||
|
[test.numbers[cursor], cursor] = ['zero', 1]
|
||||||
|
[cursor, test.numbers[cursor]] = [1, 'one']
|
||||||
|
assert_equal({0: 'zero', 1: 'one'}, test.numbers)
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
this.numbers: dict<string> = {a: '1', b: '2'}
|
||||||
|
|
||||||
|
def new()
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Foo()
|
||||||
|
var z: number
|
||||||
|
[this.numbers.a, z] = [{}, 10]
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var a = A.new()
|
||||||
|
a.Foo()
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected string but got dict<unknown>', 2)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
this.numbers: dict<number> = {a: 1, b: 2}
|
||||||
|
|
||||||
|
def new()
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Foo()
|
||||||
|
var x: string = 'a'
|
||||||
|
var y: number
|
||||||
|
[this.numbers[x], y] = [{}, 10]
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var a = A.new()
|
||||||
|
a.Foo()
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3)
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -560,6 +560,7 @@ def Test_disassemble_store_index()
|
|||||||
'\d LOAD $0\_s*' ..
|
'\d LOAD $0\_s*' ..
|
||||||
'\d MEMBER dd\_s*' ..
|
'\d MEMBER dd\_s*' ..
|
||||||
'\d\+ USEDICT\_s*' ..
|
'\d\+ USEDICT\_s*' ..
|
||||||
|
'\d\+ 2STRING stack\[-2\]\_s*' ..
|
||||||
'\d\+ STOREINDEX any\_s*' ..
|
'\d\+ STOREINDEX any\_s*' ..
|
||||||
'\d\+ RETURN void',
|
'\d\+ RETURN void',
|
||||||
res)
|
res)
|
||||||
|
@ -704,6 +704,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 */
|
||||||
|
/**/
|
||||||
|
2072,
|
||||||
/**/
|
/**/
|
||||||
2071,
|
2071,
|
||||||
/**/
|
/**/
|
||||||
|
@ -2040,9 +2040,7 @@ compile_lhs(
|
|||||||
lhs->lhs_member_type = m->ocm_type;
|
lhs->lhs_member_type = m->ocm_type;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
lhs->lhs_member_type = lhs->lhs_type->tt_member;
|
lhs->lhs_member_type = lhs->lhs_type->tt_member;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -2220,16 +2218,27 @@ compile_load_lhs(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lhs->lhs_type->tt_type == VAR_DICT && var_start[varlen] == '[')
|
||||||
|
{
|
||||||
|
// If the lhs is a Dict variable and an item is accessed by "[",
|
||||||
|
// then need to convert the key into a string. The top item in the
|
||||||
|
// type stack is the Dict and the second last item is the key.
|
||||||
|
if (may_generate_2STRING(-2, FALSE, cctx) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
// Now we can properly check the type. The variable is indexed, thus
|
// Now we can properly check the type. The variable is indexed, thus
|
||||||
// we need the member type. For a class or object we don't know the
|
// we need the member type. For a class or object we don't know the
|
||||||
// type yet, it depends on what member is used.
|
// type yet, it depends on what member is used.
|
||||||
|
// The top item in the stack is the Dict, followed by the key and then
|
||||||
|
// the type of the value.
|
||||||
vartype_T vartype = lhs->lhs_type->tt_type;
|
vartype_T vartype = lhs->lhs_type->tt_type;
|
||||||
type_T *member_type = lhs->lhs_type->tt_member;
|
type_T *member_type = lhs->lhs_type->tt_member;
|
||||||
if (rhs_type != NULL && member_type != NULL
|
if (rhs_type != NULL && member_type != NULL
|
||||||
&& vartype != VAR_OBJECT && vartype != VAR_CLASS
|
&& vartype != VAR_OBJECT && vartype != VAR_CLASS
|
||||||
&& rhs_type != &t_void
|
&& rhs_type != &t_void
|
||||||
&& need_type(rhs_type, member_type, FALSE,
|
&& need_type(rhs_type, member_type, FALSE,
|
||||||
-2, 0, cctx, FALSE, FALSE) == FAIL)
|
-3, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user