patch 9.2.1236: Vim9: some tuple functionality is not tested

Problem:  Vim9: Some tuple functionality is not tested
Solution: Add more tuple tests (Yegappan Lakshmanan)

Add tests for comparing tuples with items of different types, tuples as
List items, functions that don't support a tuple, printf() with a tuple,
removing a tuple item and using a compound operator on it, a tuple as a
Dict key, exists() with a tuple item, :break and :continue in a :for
loop over a tuple, a tuple as a default argument and in a closure,
shared references and locking with deepcopy(), tuple type aliases, typed
unpacking, interfaces and enums, lambdas and varargs, 'ignorecase',
:const and :final, errors in a tuple item, String indexes,
import/export, Lists of tuples, operators that cannot be used with a
tuple, a tuple as a condition, a Funcref tuple item, nested tuple type
mismatches, repeatedly concatenating and slicing a tuple and tuples from
an autoload script

closes: #21578

Assisted-by: Claude
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan authored and Christian Brabandt committed 2026-10-25 10:04:22 +00:00
1 parent 12d91ed7bb
commit 5a577f6f50
2 files changed
+860 -1

No files matched your search

+858 -1
View File
@@ -1721,8 +1721,27 @@ func Test_tuple_deepcopy()
VAR tuple = (l,)
call add(l, tuple)
call assert_equal('([(...)], )', string(deepcopy(tuple)))
#" items referring to the same List refer to the same copy
VAR l2 = [1]
VAR t4 = (l2, l2)
VAR t5 = deepcopy(t4)
call assert_true(t5[0] is t5[1])
call assert_false(t5[0] is l2)
END
call v9.CheckSourceLegacyAndVim9Success(lines)
" a copy of a locked tuple is not locked
let g:t = (1, [2])
lockvar 2 g:t
let g:t2 = deepcopy(g:t)
call assert_equal(1, islocked('g:t'))
call assert_equal(0, islocked('g:t2'))
call assert_equal(0, islocked('g:t2[1]'))
call add(g:t2[1], 3)
call assert_equal((1, [2, 3]), g:t2)
unlockvar 2 g:t
unlet g:t g:t2
endfunc
" Test for empty()
@@ -1752,12 +1771,20 @@ func Test_tuple_extend()
let lines =<< trim END
VAR t = (1, 2, 3)
call extend(t, (4, 5))
call extendnew(t, (4, 5))
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E896: Argument of extend() must be a List, Dictionary or Blob',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number, number>',
\ 'E896: Argument of extend() must be a List, Dictionary or Blob'])
let lines =<< trim END
VAR t = (1, 2, 3)
call extendnew(t, (4, 5))
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E896: Argument of extendnew() must be a List, Dictionary or Blob',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number, number>',
\ 'E896: Argument of extendnew() must be a List, Dictionary or Blob'])
endfunc
" Test for filter() with a tuple
@@ -1922,6 +1949,14 @@ func Test_tuple_insert()
let lines =<< trim END
VAR t = (1, 2, 3)
call insert(t, 4)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E899: Argument of insert() must be a List or Blob',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number, number>',
\ 'E1226: List or Blob required for argument 1'])
let lines =<< trim END
VAR t = (1, 2, 3)
call insert(t, 4, 2)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
@@ -2359,6 +2394,621 @@ func Test_tuple_viminfo()
call delete('Xviminfo')
endfunc
" Test for using a type alias for a tuple type
def Test_tuple_type_alias()
var lines =<< trim END
vim9script
type Pair = tuple<number, string>
type Nums = tuple<...list<number>>
def Next(x: Pair): Pair
return (x[0] + 1, x[1])
enddef
var p: Pair = (1, 'a')
assert_equal((2, 'a'), Next(p))
assert_equal('tuple<number, string>', typename(p))
var n: Nums = (1, 2, 3)
assert_equal('tuple<...list<number>>', typename(n))
var t: tuple<Pair, Pair> = ((1, 'a'), (2, 'b'))
assert_equal('b', t[1][1])
assert_equal('tuple<tuple<number, string>, tuple<number, string>>',
typename(t))
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
type Pair = tuple<number, string>
var p: Pair = (1, 2)
END
v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<number, string> but got tuple<number, number>', 3)
lines =<< trim END
vim9script
type Pair = tuple<number, string>
def Fn()
var p: Pair = (1, 2)
enddef
defcompile
END
v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<number, string> but got tuple<number, number>', 1)
enddef
" Test for unpacking a tuple into variables with a declared type and into "_"
def Test_tuple_typed_unpack()
var lines =<< trim END
var [a: number, b: string] = (1, 'x')
assert_equal([1, 'x'], [a, b])
var [_, c] = (2, 3)
var [d; _] = (4, 5, 6)
assert_equal([3, 4], [c, d])
var r = []
for [n: number, s: string] in [(1, 'a'), (2, 'b')]
r->add(s .. n)
endfor
assert_equal(['a1', 'b2'], r)
END
v9.CheckSourceDefAndScriptSuccess(lines)
lines =<< trim END
var [a: string, b] = (1, 2)
END
v9.CheckSourceDefExecAndScriptFailure(lines, [
\ 'E1163: Variable 1: type mismatch, expected string but got number',
\ 'E1012: Type mismatch; expected string but got number'], 1)
lines =<< trim END
for [n: string, s: string] in [(1, 'a')]
endfor
END
v9.CheckSourceDefExecAndScriptFailure(lines, [
\ 'E1163: Variable 1: type mismatch, expected string but got number',
\ 'E1012: Type mismatch; expected string but got number'], 1)
enddef
" Test for using a tuple type in an interface and in an enum
def Test_tuple_interface_and_enum()
var lines =<< trim END
vim9script
interface I
var t: tuple<number>
def Get(): tuple<number, string>
endinterface
class A implements I
var t: tuple<number> = (5,)
def Get(): tuple<number, string>
return (1, 'a')
enddef
endclass
var i: I = A.new()
assert_equal((5,), i.t)
assert_equal((1, 'a'), i.Get())
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
interface I
def Get(): tuple<number, string>
endinterface
class A implements I
def Get(): tuple<string, number>
return ('a', 1)
enddef
endclass
END
v9.CheckSourceFailure(lines, 'E1383: Method "Get": type mismatch, expected func(): tuple<number, string> but got func(): tuple<string, number>', 9)
lines =<< trim END
vim9script
enum Color
Red((255, 0, 0)),
Green((0, 255, 0))
final rgb: tuple<number, number, number>
def new(this.rgb)
enddef
endenum
assert_equal((255, 0, 0), Color.Red.rgb)
assert_equal(255, Color.Green.rgb[1])
END
v9.CheckSourceSuccess(lines)
enddef
" Test for a tuple argument of a lambda and a variable number of tuple
" arguments
def Test_tuple_lambda_and_varargs()
var lines =<< trim END
var Fn = (t: tuple<number, string>): string => t[1] .. t[0]
assert_equal('x1', Fn((1, 'x')))
END
v9.CheckSourceDefAndScriptSuccess(lines)
lines =<< trim END
var Fn = (t: tuple<number, string>): string => t[1]
Fn((1, 2))
END
v9.CheckSourceDefAndScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected tuple<number, string> but got tuple<number, number>', 2)
lines =<< trim END
vim9script
def Sum(...args: list<tuple<number>>): number
return args->reduce((acc, t) => acc + t[0], 0)
enddef
assert_equal(0, Sum())
assert_equal(6, Sum((1,), (2,), (3,)))
END
v9.CheckSourceSuccess(lines)
lines =<< trim END
vim9script
def Sum(...args: list<tuple<number>>)
enddef
Sum((1,), ('a',))
END
v9.CheckSourceFailure(lines, 'E1013: Argument 2: type mismatch, expected tuple<number> but got tuple<string>', 4)
enddef
" Test for ignoring case when comparing tuples and with count() and index()
func Test_tuple_ignorecase()
" 'ignorecase' is used for "==" in legacy script, not in Vim9 script
set ignorecase
call assert_true(('a', 1) == ('A', 1))
call assert_false(('a', 1) ==# ('A', 1))
call v9.CheckSourceDefAndScriptSuccess([
\ "assert_false(('a', 1) == ('A', 1))",
\ "assert_true(('a', 1) ==? ('A', 1))"])
set ignorecase&
let lines =<< trim END
VAR t = ('a', 'A', 'b')
call assert_equal(1, count(t, 'a'))
call assert_equal(2, count(t, 'a', TRUE))
call assert_equal(1, index(t, 'A'))
call assert_equal(0, index(t, 'A', 0, TRUE))
END
call v9.CheckSourceLegacyAndVim9Success(lines)
endfunc
" Test for a tuple declared with :const and :final
func Test_tuple_const_and_final()
" :const locks the List, Dict and Tuple items of a tuple literal
let lines =<< trim END
const t = ([1], {a: [2]}, ([3],))
t[0]->add(9)
END
call v9.CheckSourceDefExecAndScriptFailure(lines, 'E741: Value is locked: add() argument', 2)
let lines =<< trim END
const t = ([1], {a: [2]}, ([3],))
t[1].b = [3]
END
call v9.CheckSourceDefExecAndScriptFailure(lines, [
\ 'E1120: Cannot change dict',
\ 'E741: Value is locked:'], 2)
let lines =<< trim END
const t = ([1], {a: [2]}, ([3],))
t[2][0]->add(4)
END
call v9.CheckSourceDefExecAndScriptFailure(lines, 'E741: Value is locked: add() argument', 2)
" :const does not lock a List that is also referenced elsewhere
let lines =<< trim END
var l = [1]
const t = (l,)
l->add(2)
assert_equal(([1, 2],), t)
END
call v9.CheckSourceDefAndScriptSuccess(lines)
" :final does not lock the items, but the variable cannot be changed
let lines =<< trim END
final t = (1, [2])
t[1]->add(3)
assert_equal((1, [2, 3]), t)
END
call v9.CheckSourceDefAndScriptSuccess(lines)
let lines =<< trim END
final t = (1, [2])
t = (3,)
END
call v9.CheckSourceDefAndScriptFailure(lines, [
\ 'E1018: Cannot assign to a constant: t',
\ 'E46: Cannot change read-only variable "t"'], 2)
endfunc
" Test for an error when evaluating a tuple item
func Test_tuple_item_eval_error()
let lines =<< trim END
var l: list<number> = []
var t = (1, l[0])
END
call v9.CheckSourceDefExecAndScriptFailure(lines, 'E684: List index out of range: 0', 2)
" the variable is not changed when evaluating an item throws an exception
let lines =<< trim END
vim9script
def Thrower(): number
throw 'oops'
enddef
def Fn(): tuple<number, ...list<number>>
var t: tuple<number, ...list<number>> = (0,)
try
t = (1, Thrower())
catch /oops/
endtry
return t
enddef
assert_equal((0,), Fn())
var t = (0,)
try
t = (1, Thrower())
catch /oops/
endtry
assert_equal((0,), t)
END
call v9.CheckSourceSuccess(lines)
endfunc
" Test for using a String as a tuple index
func Test_tuple_string_index()
" in legacy script the String is converted to a Number
let t = ('a', 'b')
call assert_equal('b', t['1'])
call assert_equal('a', t['x'])
let lines =<< trim END
var t = ('a', 'b')
echo t['1']
END
call v9.CheckSourceDefAndScriptFailure(lines, [
\ 'E1012: Type mismatch; expected number but got string',
\ 'E1030: Using a String as a Number: "1"'], 2)
endfunc
" Test for exporting and importing a tuple variable, constant and type alias
func Test_tuple_import_export()
let export_lines =<< trim END
vim9script
export const CT = (1, 'a')
export var vt: tuple<number, ...list<number>> = (1, 2)
export type Pair = tuple<number, string>
export def Make(): Pair
return (7, 'x')
enddef
END
call writefile(export_lines, 'Xtupleexport.vim', 'D')
let lines =<< trim END
vim9script
import './Xtupleexport.vim' as E
var p: E.Pair = E.Make()
assert_equal([(1, 'a'), 'a', (1, 2), (7, 'x')], [E.CT, E.CT[1], E.vt, p])
assert_equal('tuple<number, string>', typename(p))
def Fn(): list<any>
var q: E.Pair = E.Make()
return [E.CT[0], E.vt[-1], q[1]]
enddef
assert_equal([1, 2, 'x'], Fn())
E.vt = (5, 6, 7)
assert_equal((5, 6, 7), E.vt)
END
call v9.CheckSourceSuccess(lines)
let lines =<< trim END
vim9script
import './Xtupleexport.vim' as E
E.CT = (2,)
END
call v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "CT"', 3)
let lines =<< trim END
vim9script
import './Xtupleexport.vim' as E
E.vt = ('a',)
END
call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<number, ...list<number>> but got tuple<string>', 3)
let lines =<< trim END
vim9script
import './Xtupleexport.vim' as E
def Fn()
E.vt = ('a',)
enddef
defcompile
END
call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<number, ...list<number>> but got tuple<string>', 1)
let lines =<< trim END
vim9script
import './Xtupleexport.vim' as E
var p: E.Pair = (1, 2)
END
call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<number, string> but got tuple<number, number>', 3)
endfunc
" Test for the tuple<any> type, which is a tuple with one item of any type
def Test_tuple_any_type()
var lines =<< trim END
var t: tuple<any> = ('x',)
var u: tuple<...list<any>> = (1, 'a', [])
assert_equal([('x',), (1, 'a', [])], [t, u])
END
v9.CheckSourceDefAndScriptSuccess(lines)
lines =<< trim END
var t: tuple<any> = (1, 2)
END
v9.CheckSourceDefAndScriptFailure(lines, 'E1012: Type mismatch; expected tuple<any> but got tuple<number, number>', 1)
enddef
" Test for passing a tuple to a function and returning it: it is the same
" tuple
def Test_tuple_func_return_identity()
var lines =<< trim END
vim9script
def Id(x: tuple<any, ...list<any>>): tuple<any, ...list<any>>
return x
enddef
var t1 = (1, [2])
var t2 = Id(t1)
assert_true(t2 is t1)
t2[1]->add(3)
assert_equal((1, [2, 3]), t1)
assert_false(copy(t1) is t1)
END
v9.CheckSourceSuccess(lines)
enddef
" Test for using builtin functions with a List of tuples and for slice() with
" negative indexes
def Test_tuple_list_of_tuples_funcs()
var lines =<< trim END
var l = [(1, 2), (3, 4)]
map(l, (_, v) => (v[1], v[0]))
assert_equal([(2, 1), (4, 3)], l)
assert_equal('list<tuple<number, number>>', typename(l))
var m = mapnew(l, (_, v) => (v[0], 'x'))
assert_equal([(2, 'x'), (4, 'x')], m)
assert_equal('list<tuple<number, string>>', typename(m))
var s = [(3, 'c'), (1, 'a'), (2, 'b')]
sort(s, (a, b) => a[0] - b[0])
assert_equal([(1, 'a'), (2, 'b'), (3, 'c')], s)
# flattennew() does not flatten a tuple
assert_equal([1, (2, [3]), (4,)], flattennew([1, (2, [3]), [(4,)]]))
var d = {x: (1, 'a'), y: (2, 'b')}
assert_equal([(1, 'a'), (2, 'b')], sort(values(d)))
var pairs = [(1, 2), (3, 4)]
assert_equal(14, pairs->reduce((acc, v) => acc + v[0] * v[1], 0))
assert_equal((2, 3), slice((1, 2, 3, 4), 1, -1))
assert_equal((3, 4), slice((1, 2, 3, 4), -2))
END
v9.CheckSourceDefAndScriptSuccess(lines)
# map() cannot change the item type of a List of tuples
lines =<< trim END
var l = [(1, 2), (3, 4)]
map(l, (_, v) => (v[0], 'x'))
END
v9.CheckSourceDefAndScriptFailure(lines, [
\ 'E1013: Argument 2: type mismatch, expected func(?number, ?tuple<number, number>): tuple<number, number> but got func(any, any): tuple<any, string>',
\ 'E1012: Type mismatch; expected tuple<number, number> but got tuple<number, string> in map()'], 2)
enddef
" Test for the operators that cannot be used with a tuple
func Test_tuple_invalid_operators()
" only "==", "!=", "is" and "isnot" can be used to compare tuples
for op in ['<', '<=', '>', '>=']
let lines =<< trim eval END
echo (1,) {op} (2,)
END
call v9.CheckSourceLegacyAndVim9Failure(lines,
\ 'E1518: Invalid operation for Tuple')
endfor
" "+" can only be used with two tuples
let lines =<< trim END
echo (1,) + [2]
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ 'E1051: Wrong argument type for +',
\ 'E1520: Using a Tuple as a Number'])
let lines =<< trim END
echo (1,) + 1
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ 'E1051: Wrong argument type for +',
\ 'E1520: Using a Tuple as a Number'])
for op in ['-', '*']
let lines =<< trim eval END
echo (1,) {op} (2,)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ $'E1036: {op} requires number or float arguments',
\ 'E1520: Using a Tuple as a Number'])
endfor
let lines =<< trim END
VAR t = (1,)
echo -t
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ 'E1012: Type mismatch; expected number but got tuple<number>',
\ 'E1520: Using a Tuple as a Number'])
" a tuple cannot be used as a String
let lines =<< trim END
echo 'a' .. (1,)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1522: Using a Tuple as a String',
\ 'E1105: Cannot convert tuple to string',
\ 'E1522: Using a Tuple as a String'])
let lines =<< trim END
throw (1, 2)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1522: Using a Tuple as a String',
\ 'E1105: Cannot convert tuple to string',
\ 'E1522: Using a Tuple as a String'])
endfunc
" Test for using a tuple as a condition
func Test_tuple_bool_context()
" In Vim9 script "!" works on a tuple, it is falsy when empty
let lines =<< trim END
assert_equal([false, true], [!(1,), !()])
END
call v9.CheckSourceDefAndScriptSuccess(lines)
call assert_fails('echo !(1,)', 'E1520: Using a Tuple as a Number')
" a tuple cannot be used as a bool
let lines =<< trim END
VAR t = (1,)
if t
endif
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ 'E1012: Type mismatch; expected bool but got tuple<number>',
\ 'E1520: Using a Tuple as a Number'])
let lines =<< trim END
VAR t = (1,)
echo t || 0
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1520: Using a Tuple as a Number',
\ 'E1012: Type mismatch; expected bool but got tuple<number>',
\ 'E1520: Using a Tuple as a Number'])
let lines =<< trim END
VAR t = (1,)
echo t ? 1 : 2
END
call v9.CheckSourceLegacyAndVim9Failure(lines,
\ 'E1520: Using a Tuple as a Number')
endfunc
" Test for calling a Funcref that is a tuple item
func Test_tuple_funcref_item()
let lines =<< trim END
VAR t = (function('max'), function('min'))
call assert_equal([3, 1], [t[0]([1, 3]), t[1]([1, 3])])
call assert_equal(3, call(t[0], [[1, 3]]))
END
call v9.CheckSourceLegacyAndVim9Success(lines)
endfunc
" Test for a type mismatch in a nested tuple type
def Test_tuple_nested_type_mismatch()
var lines =<< trim END
var t: tuple<tuple<number>> = (('a',),)
END
v9.CheckSourceDefAndScriptFailure(lines, 'E1012: Type mismatch; expected tuple<tuple<number>> but got tuple<tuple<string>>', 1)
lines =<< trim END
var t: tuple<number, tuple<string, number>> = (1, ('a', 'b'))
END
v9.CheckSourceDefAndScriptFailure(lines, 'E1012: Type mismatch; expected tuple<number, tuple<string, number>> but got tuple<number, tuple<string, string>>', 1)
lines =<< trim END
def Fn(t: tuple<tuple<number>>)
enddef
Fn((('a',),))
END
v9.CheckSourceDefAndScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected tuple<tuple<number>> but got tuple<tuple<string>>', 3)
enddef
" Test for repeatedly building and shrinking a tuple that contains a List.
" The List reference count must be correct every time.
def Test_tuple_repeated_concat_and_slice()
var lines =<< trim END
var l = [1]
assert_equal(1, test_refcount(l))
var t: tuple<...list<list<number>>> = ()
for i in range(10)
t = (l,) + t
endfor
assert_equal(10, len(t))
assert_true(t[0] is l && t[-1] is l)
assert_equal(11, test_refcount(l))
t = t[5 :]
assert_equal(5, len(t))
assert_equal(6, test_refcount(l))
var n = 0
while !empty(t)
t = t[1 :]
n += 1
endwhile
assert_equal(5, n)
assert_equal(1, test_refcount(l))
END
v9.CheckSourceDefAndScriptSuccess(lines)
# a tuple with a variadic type can only be followed by the same type
lines =<< trim END
var t: tuple<...list<number>> = ()
var u: tuple<number> = (1,)
t = t + u
END
v9.CheckSourceDefExecAndScriptFailure(lines, 'E1540: Cannot use a variadic tuple in concatenation', 3)
enddef
" Test for using a tuple from an autoload script
func Test_tuple_autoload()
let dir = 'Xtupleautoload'
call mkdir(dir .. '/autoload', 'pR')
let lines =<< trim END
vim9script
export const Origin = (0, 0)
export def Pair(a: number, b: string): tuple<number, string>
return (a, b)
enddef
END
call writefile(lines, dir .. '/autoload/tupleal.vim')
let save_rtp = &rtp
exe 'set rtp^=' .. dir
let lines =<< trim END
vim9script
import autoload 'tupleal.vim'
assert_equal((0, 0), tupleal.Origin)
assert_equal('tuple<number, string>', typename(tupleal.Pair(1, 'a')))
def Fn(): tuple<number, string>
var p: tuple<number, string> = tupleal.Pair(2, 'b')
return p
enddef
assert_equal((2, 'b'), Fn())
END
call v9.CheckSourceSuccess(lines)
" the type is checked when the autoload function is called
let lines =<< trim END
vim9script
import autoload 'tupleal.vim'
def Fn()
var p: tuple<string, string> = tupleal.Pair(2, 'b')
enddef
Fn()
END
call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<string, string> but got tuple<number, string>', 1)
let &rtp = save_rtp
endfunc
" Test for list2tuple()
func Test_list2tuple()
let lines =<< trim END
@@ -2574,4 +3224,211 @@ func Test_tuple_type_many_items()
call v9.CheckSourceDefAndScriptFailure(lines, 'E1012:', 1)
endfunc
" Test for comparing tuples with items of different types
func Test_tuple_compare_items()
let lines =<< trim END
#" ignoring case for String items
call assert_true(('abc', 1) ==? ('ABC', 1))
call assert_false(('abc', 1) ==# ('ABC', 1))
call assert_true(('abc', 1) !=# ('ABC', 1))
call assert_false(('abc', 1) !=? ('ABC', 1))
#" List, Dict and Tuple items are compared by value
call assert_true(([1, 2], {'a': 3}, (4,)) == ([1, 2], {'a': 3}, (4,)))
call assert_false(([1, 2], {'a': 3}, (4,)) == ([1, 2], {'a': 3}, (5,)))
call assert_true(([1, 2],) != ([1, 3],))
#" a Number item is not equal to a Float item
call assert_false((1,) == (1.0,))
call assert_true((1.5,) == (1.5,))
#" a tuple item is not equal to a list item
call assert_false(((1,),) == ([1],))
#" nested tuples are compared by value, including their length
call assert_true(((1, (2, 3)),) == ((1, (2, 3)),))
call assert_false(((1, 2),) == ((1,),))
call assert_false(((1,),) == ((1, 2),))
#" Funcref and Blob items
call assert_true((function('min'),) == (function('min'),))
call assert_false((function('min'),) == (function('max'),))
call assert_true((0z0102,) == (0z0102,))
call assert_false((0z01,) == (0z02,))
END
call v9.CheckSourceLegacyAndVim9Success(lines)
endfunc
" Test for using tuples as items in a List
func Test_tuple_as_list_item()
let lines =<< trim END
VAR l = [(3, 'c'), (1, 'a'), (2, 'b'), (1, 'a')]
call assert_equal(1, index(l, (1, 'a')))
call assert_equal(-1, index(l, (1, 'b')))
call assert_equal(2, count(l, (1, 'a')))
call assert_equal([(1, 'a'), (1, 'a'), (2, 'b'), (3, 'c')], sort(copy(l)))
call assert_equal([(1, 'a'), (2, 'b'), (3, 'c')], uniq(sort(copy(l))))
END
call v9.CheckSourceLegacyAndVim9Success(lines)
endfunc
" Test for functions that don't support a tuple argument
func Test_tuple_unsupported_funcs()
let lines =<< trim END
VAR t = (1, 2)
call mapnew(t, 'v:val')
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1524: Cannot use a tuple with function mapnew()',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number>',
\ 'E1524: Cannot use a tuple with function mapnew()'])
let lines =<< trim END
VAR t = (1, 2)
call uniq(t)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E686: Argument of uniq() must be a List',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number>',
\ 'E1211: List required for argument 1'])
let lines =<< trim END
VAR t = (2, 1)
call sort(t)
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E686: Argument of sort() must be a List',
\ 'E1013: Argument 1: type mismatch, expected list<any> but got tuple<number, number>',
\ 'E1211: List required for argument 1'])
" a tuple cannot be used for the arguments of call() and function()
let lines =<< trim END
call call('max', (1, 2))
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1211: List required for argument 2',
\ 'E1013: Argument 2: type mismatch, expected list<any> but got tuple<number, number>',
\ 'E1211: List required for argument 2'])
let lines =<< trim END
VAR Fn = function('max', ((1, 2),))
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E923: Second argument of function() must be a list or a dict',
\ 'E1013: Argument 2: type mismatch, expected list<any> but got tuple<tuple<number, number>>',
\ 'E1211: List required for argument 2'])
endfunc
" Test for using a tuple with printf()
func Test_tuple_printf()
let lines =<< trim END
call assert_equal("(1, 'a')", printf('%s', (1, 'a')))
call assert_equal('()', printf('%s', ()))
call assert_equal('()', printf('%s', test_null_tuple()))
END
call v9.CheckSourceLegacyAndVim9Success(lines)
let lines =<< trim END
call printf('%d', (1,))
END
call v9.CheckSourceLegacyAndVim9Failure(lines, 'E1520: Using a Tuple as a Number')
endfunc
" Test for removing a tuple item and using a compound operator on a tuple item
func Test_tuple_modify_item_error()
let lines =<< trim END
VAR t = (1, 2)
unlet t[0]
END
call v9.CheckSourceLegacyAndVim9Failure(lines, 'E1532: Cannot modify a tuple')
let lines =<< trim END
VAR t = (1, 2)
LET t[0] += 1
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1532: Cannot modify a tuple',
\ 'E734: Wrong variable type for +=',
\ 'E1532: Cannot modify a tuple'])
endfunc
" Test for using a tuple as a Dict key
func Test_tuple_dict_key()
let lines =<< trim END
VAR d = {}
LET d[(1,)] = 2
END
call v9.CheckSourceLegacyAndVim9Failure(lines, [
\ 'E1522: Using a Tuple as a String',
\ 'E1105: Cannot convert tuple to string',
\ 'E1522: Using a Tuple as a String'])
endfunc
" Test for exists() with a tuple item
func Test_tuple_exists()
let g:t = (1, 'a')
call assert_true(exists('g:t'))
call assert_true(exists('g:t[0]'))
call assert_true(exists('g:t[-1]'))
call assert_false(exists('g:t[2]'))
call assert_false(exists('g:t[-3]'))
unlet g:t
endfunc
" Test for :break and :continue in a :for loop over a tuple
func Test_tuple_for_break_continue()
let lines =<< trim END
VAR r = []
for v in (1, 2, 3, 4, 5)
if v == 2
continue
endif
if v == 4
break
endif
call add(r, v)
endfor
call assert_equal([1, 3], r)
#" nested loops over the same tuple
VAR t = (1, 2)
LET r = []
for a in t
for b in t
call add(r, [a, b])
endfor
endfor
call assert_equal([[1, 1], [1, 2], [2, 1], [2, 2]], r)
END
call v9.CheckSourceLegacyAndVim9Success(lines)
endfunc
" Test for using a tuple as a default argument value and in a closure
def Test_tuple_default_arg_and_closure()
var lines =<< trim END
vim9script
def Fn(t: tuple<number, string> = (1, 'a')): tuple<number, string>
return t
enddef
assert_equal((1, 'a'), Fn())
assert_equal((2, 'b'), Fn((2, 'b')))
def GetClosure(): func(): tuple<number, ...list<number>>
var t = (1, 2, 3)
return () => t
enddef
var Closure = GetClosure()
assert_equal((1, 2, 3), Closure())
END
v9.CheckSourceScriptSuccess(lines)
lines =<< trim END
vim9script
def Fn(t: tuple<number> = ('a',))
enddef
defcompile
END
v9.CheckSourceScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected tuple<number> but got tuple<string>')
enddef
" vim: shiftwidth=2 sts=2 expandtab
+2
View File
@@ -743,6 +743,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1236,
/**/
1235,
/**/