" Tests for the Tuple types import './vim9.vim' as v9 func TearDown() " Run garbage collection after every test call test_garbagecollect_now() endfunc " Tuple declaration func Test_tuple_declaration() let lines =<< trim END var Fn = function('min') var t = (1, 'a', true, 3.1, 0z10, ['x'], {'a': []}, Fn) assert_equal((1, 'a', true, 3.1, 0z10, ['x'], {'a': []}, Fn), t) END call v9.CheckSourceDefAndScriptSuccess(lines) " Multiline tuple declaration let lines =<< trim END var t = ( 'a', 'b', ) assert_equal(('a', 'b'), t) END call v9.CheckSourceDefAndScriptSuccess(lines) " Tuple declaration with comments let lines =<< trim END var t = ( # xxx # xxx 'a', # xxx # xxx 'b', # xxx ) # xxx assert_equal(('a', 'b'), t) END call v9.CheckSourceDefAndScriptSuccess(lines) " Tuple declaration separated by '|' let lines =<< trim END VAR t1 = ('a', 'b') | VAR t2 = ('c', 'd') call assert_equal(('a', 'b'), t1) call assert_equal(('c', 'd'), t2) END call v9.CheckSourceLegacyAndVim9Success(lines) " Space after and before parens let lines =<< trim END var t = ( 1, 2 ) assert_equal((1, 2), t) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Tuple declaration error func Test_tuple_declaration_error() let lines =<< trim END var t: tuple<> = ('a', 'b') END call v9.CheckSourceDefAndScriptFailure(lines, "E1008: Missing after > = ('a', 'b')") let lines =<< trim END var t: tuple = ('a', 'b') END call v9.CheckSourceDefAndScriptFailure(lines, "E1008: Missing after tuple") let lines =<< trim END var t: tuple = ('a','b') END call v9.CheckSourceDefAndScriptFailure(lines, "E1069: White space required after ',': ,'b')") let lines =<< trim END var t: tuple = ('a', 'b','c') END call v9.CheckSourceDefAndScriptFailure(lines, "E1069: White space required after ',': ,'c')") let lines =<< trim END var t: tuple = () END call v9.CheckSourceDefAndScriptFailure(lines, "E1068: No white space allowed before '<'") let lines =<< trim END var t: tuple END call v9.CheckSourceDefAndScriptFailure(lines, "E1069: White space required after ','") let lines =<< trim END var t: tuple END call v9.CheckSourceDefFailure(lines, "E1068: No white space allowed before ','") let lines =<< trim END var t = ('a', 'b' , 'c') END call v9.CheckSourceDefAndScriptFailure(lines, [ \ "E1068: No white space allowed before ','", \ "E1068: No white space allowed before ','"]) let lines =<< trim END VAR t = ('a', 'b' 'c') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ "E1527: Missing comma in Tuple: 'c')", \ "E1527: Missing comma in Tuple: 'c')", \ "E1527: Missing comma in Tuple: 'c')"]) let lines =<< trim END VAR t = ('a', 'b', END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ "E1526: Missing end of Tuple ')'", \ "E1526: Missing end of Tuple ')'", \ "E1526: Missing end of Tuple ')'"]) let lines =<< trim END var t: tuple = (1, 2, 3) END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1010: Type not recognized: ', \ 'E1010: Type not recognized: ']) let lines =<< trim END var t: tuple = (1, 2, 3) END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1539: Variadic tuple must end with a list type: number', \ 'E1539: Variadic tuple must end with a list type: number']) " Invalid expression in the tuple let lines =<< trim END def Foo() var t = (1, 1*2, 2) enddef defcompile END call v9.CheckSourceDefFailure(lines, 'E1004: White space required before and after ''*'' at "*2, 2)"') let lines =<< trim END VAR t = ('a', , 'b',) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E15: Invalid expression: ", ''b'',)"', \ "E1068: No white space allowed before ',': , 'b',)", \ 'E15: Invalid expression: ", ''b'',)"']) let lines =<< trim END VAR t = ('a', 'b', ,) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E15: Invalid expression: ",)"', \ "E1068: No white space allowed before ',': ,)", \ 'E15: Invalid expression: ",)"']) let lines =<< trim END VAR t = (, 'a', 'b') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E15: Invalid expression: ", ''a'', ''b'')"', \ "E1015: Name expected: , 'a', 'b')", \ 'E15: Invalid expression: ", ''a'', ''b'')"']) let lines =<< trim END var t: tupel = (1,) END call v9.CheckSourceDefAndScriptFailure(lines, 'E1010: Type not recognized: tupel') let lines =<< trim END var t: tuple = [1, 2] END call v9.CheckSourceDefAndScriptFailure(lines, 'E1012: Type mismatch; expected tuple but got list') endfunc " Test for indexing a tuple func Test_tuple_indexing() let lines =<< trim END VAR t = ('a', 'b', 'c') call assert_equal(['a', 'b', 'c'], [t[0], t[1], t[2]]) call assert_equal(['c', 'b', 'a'], [t[-1], t[-2], t[-3]]) END call v9.CheckSourceLegacyAndVim9Success(lines) " Indexing a tuple passed as a function argument let lines =<< trim END vim9script def Fn(t: any) call assert_equal(['a', 'b', 'c'], [t[0], t[1], t[2]]) call assert_equal(['c', 'b', 'a'], [t[-1], t[-2], t[-3]]) enddef Fn(('a', 'b', 'c')) END call v9.CheckSourceSuccess(lines) let lines =<< trim END var t: tuple<...list> = (10, 20) var x: number = t[0] assert_equal(10, x) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END var t: tuple<...list>> = ([1, 2], [3, 4]) t[0][1] = 5 assert_equal(([1, 5], [3, 4]), t) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END var t: tuple> = ([2, 4],) t[0][1] = 6 assert_equal(([2, 6],), t) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Indexing a tuple in a Dict func Test_tuple_in_a_dict_index() let lines =<< trim END vim9script def Fn() var d = {a: (1, 2)} var x = d.a[0] assert_equal('number', typename(x)) enddef Fn() END call v9.CheckSourceSuccess(lines) endfunc func Test_tuple_index_error() let lines =<< trim END echo ('a', 'b', 'c')[3] END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: 3', \ 'E1519: Tuple index out of range: 3', \ 'E1519: Tuple index out of range: 3']) let lines =<< trim END echo ('a', 'b', 'c')[-4] END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: -4', \ 'E1519: Tuple index out of range: -4', \ 'E1519: Tuple index out of range: -4']) let lines =<< trim END vim9script def Fn(t: any) echo t[3] enddef Fn(('a', 'b', 'c')) END call v9.CheckSourceFailure(lines, 'E1519: Tuple index out of range: 3') let lines =<< trim END vim9script def Fn(t: any) echo t[-4] enddef Fn(('a', 'b', 'c')) END call v9.CheckSourceFailure(lines, 'E1519: Tuple index out of range: -4') let lines =<< trim END vim9script def Fn(t: any) var x = t[0] enddef Fn(()) END call v9.CheckSourceFailure(lines, 'E1519: Tuple index out of range: 0') " Index a null tuple let lines =<< trim END VAR t = test_null_tuple() LET t[0][0] = 10 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: 0', \ 'E1519: Tuple index out of range: 0', \ 'E1519: Tuple index out of range: 0']) let lines =<< trim END var x = null_tuple x[0][0] = 10 END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1519: Tuple index out of range: 0', \ 'E1519: Tuple index out of range: 0']) " Use a float as the index let lines =<< trim END VAR t = (1, 2) VAR x = t[0.1] END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E805: Using a Float as a Number', \ 'E1012: Type mismatch; expected number but got float', \ 'E805: Using a Float as a Number']) endfunc " Test for slicing a tuple func Test_tuple_slice() let lines =<< trim END VAR t = (1, 3, 5, 7, 9) call assert_equal((3, 5), t[1 : 2]) call assert_equal((9,), t[4 : 4]) call assert_equal((7, 9), t[3 : 6]) call assert_equal((1, 3, 5), t[: 2]) call assert_equal((5, 7, 9), t[2 :]) call assert_equal((1, 3, 5, 7, 9), t[:]) call assert_equal((), test_null_tuple()[:]) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END call assert_equal(('b', 'c'), ('a', 'b', 'c')[1 : 5]) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for concatenating tuples func Test_tuple_concatenate() let lines =<< trim END VAR t1 = ('a', 'b') + ('c', 'd') call assert_equal(('a', 'b', 'c', 'd'), t1) VAR t2 = ('a',) + ('b',) call assert_equal(('a', 'b'), t2) VAR t3 = ('a',) + () call assert_equal(('a',), t3) VAR t4 = () + ('b',) call assert_equal(('b',), t4) VAR t5 = ('a', 'b') + test_null_tuple() call assert_equal(('a', 'b'), t5) call assert_equal('tuple', typename(t5)) VAR t6 = test_null_tuple() + ('c', 'd') call assert_equal(('c', 'd'), t6) call assert_equal('tuple', typename(t6)) VAR t7 = ('a', 'b') + (8, 9) call assert_equal(('a', 'b', 8, 9), t7) call assert_equal('tuple', typename(t7)) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END var t1: tuple<...list>> = () var t2: tuple<...list>> = () var t: tuple<...list>> = t1 + t2 assert_equal((), t) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END var t: tuple<...list> = (1, 2) + ('a', 'b') END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1012: Type mismatch; expected tuple<...list> but got tuple', \ 'E1012: Type mismatch; expected tuple<...list> but got tuple']) let lines =<< trim END var a: tuple<...list> = (1, 2) var b: tuple<...list> = ('a', 'b') var t = a + b END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) let lines =<< trim END var a: tuple<...list> = (1, 2) var b: tuple = ('a', 'b') var t = a + b END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) let lines =<< trim END var a: tuple> = (1, 'a', 'b') var b: tuple> = (2, 'c', 'd') var t = a + b END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) let lines =<< trim END var a: tuple> = (1, 'a', 'b') var b: tuple<...list> = ('c', 'd') var t = a + b END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) let lines =<< trim END var a: tuple<...list> = ('a', 'b') var b: tuple> = (2, 'c', 'd') var t = a + b END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) let lines =<< trim END var t1: tuple<...list>> = () var t2: tuple<...list>> = () var t = t1 + t2 END call v9.CheckSourceDefExecAndScriptFailure(lines, [ \ 'E1540: Cannot use a variadic tuple in concatenation', \ 'E1540: Cannot use a variadic tuple in concatenation']) " Make sure the correct line number is used in the error message let lines =<< trim END vim9script var t1: tuple<...list>> = () var t2: tuple<...list>> = () var t = t1 + t2 END call v9.CheckSourceFailure(lines, 'E1540: Cannot use a variadic tuple in concatenation', 4) let lines =<< trim END vim9script def Fn() var t1: tuple<...list>> = () var t2: tuple<...list>> = () var t = t1 + t2 enddef Fn() END call v9.CheckSourceFailure(lines, 'E1540: Cannot use a variadic tuple in concatenation', 3) " One or both the operands are variadic tuples let lines =<< trim END var a1: tuple = (1, 2) var b1: tuple<...list> = ('a', 'b') var t1 = a1 + b1 assert_equal((1, 2, 'a', 'b'), t1) var a2: tuple = ('a', 'b') var b2: tuple> = (1, 'c', 'd') var t2 = a2 + b2 assert_equal(('a', 'b', 1, 'c', 'd'), t2) var a3: tuple<...list> = ('a', 'b') var b3: tuple<...list> = ('c', 'd') var t3 = a3 + b3 assert_equal(('a', 'b', 'c', 'd'), t3) var a4: tuple<...list> = (1, 2) var t4 = a4 + () assert_equal((1, 2), t4) var b5: tuple<...list> = (1, 2) var t5 = () + b5 assert_equal((1, 2), t5) var a6: tuple<...list> = (1, 2) var t6 = a6 + null_tuple assert_equal((1, 2), t6) var b7: tuple<...list> = ('a', 'b') var t7 = null_tuple + b7 assert_equal(('a', 'b'), t7) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END VAR t = test_null_tuple() + test_null_tuple() call assert_equal(test_null_tuple(), t) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END vim9script def Fn(x: any, y: any): any return x + y enddef assert_equal((1, 2), Fn((1,), (2,))) assert_equal((1, 'a'), Fn((1,), ('a',))) assert_equal((1,), Fn((1,), null_tuple)) assert_equal(('a',), Fn(null_tuple, ('a',))) assert_equal((), Fn(null_tuple, null_tuple)) END call v9.CheckSourceScriptSuccess(lines) " Test for concatenating to lists containing tuples let lines =<< trim END var x = [test_null_tuple()] + [test_null_tuple()] assert_equal([(), ()], x) var y = [()] + [()] assert_equal([(), ()], y) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Test for comparing tuples func Test_tuple_compare() let lines =<< trim END call assert_false((1, 2) == (1, 3)) call assert_true((1, 2) == (1, 2)) call assert_true((1,) == (1,)) call assert_true(() == ()) call assert_false((1, 2) == (1, 2, 3)) call assert_false((1, 2) == test_null_tuple()) VAR t1 = (1, 2) VAR t2 = t1 call assert_true(t1 == t2) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END echo (1.0, ) == 1.0 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1517: Can only compare Tuple with Tuple', \ 'E1072: Cannot compare tuple with float', \ 'E1072: Cannot compare tuple with float']) let lines =<< trim END echo 1.0 == (1.0,) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1517: Can only compare Tuple with Tuple', \ 'E1072: Cannot compare float with tuple', \ 'E1072: Cannot compare float with tuple']) let lines =<< trim END echo (1, 2) =~ [] END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E691: Can only compare List with List', \ 'E1072: Cannot compare tuple with list', \ 'E1072: Cannot compare tuple with list']) let lines =<< trim END echo (1, 2) =~ (1, 2) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1518: Invalid operation for Tuple', \ 'E1518: Invalid operation for Tuple', \ 'E1518: Invalid operation for Tuple']) endfunc " Test for assigning multiple items from a tuple func Test_multi_assign_from_tuple() let lines =<< trim END VAR [v1, v2] = ('a', 'b') call assert_equal(['a', 'b'], [v1, v2]) VAR [v3] = ('c',) call assert_equal('c', v3) VAR [v4; v5] = ('a', 'b', 'c') call assert_equal('a', v4) call assert_equal(('b', 'c'), v5) VAR [v6; v7] = ('a',) call assert_equal('a', v6) call assert_equal((), v7) VAR sum = 0 for [v8, v9] in ((2, 2), (2, 3)) LET sum += v8 * v9 endfor call assert_equal(10, sum) #" for: rest of the items in a List LET sum = 0 for [v10; v11] in ((2, 1, 2, 5), (2, 1, 2, 10)) LET sum += v10 * max(v11) endfor call assert_equal(30, sum) #" for: one item in the list LET sum = 0 for [v12; v13] in ((2, 6), (2, 7)) LET sum += v12 * max(v13) endfor call assert_equal(26, sum) #" for: zero items in the list LET sum = 0 for [v14; v15] in ((4,), (5,)) LET sum += v14 + max(v15) endfor call assert_equal(9, sum) #" A null tuple should be treated like an empty tuple for [v16, v17] in test_null_tuple() endfor END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END var t: tuple<...list> = (4, 8) var [x: number, y: number] = t assert_equal([4, 8], [x, y]) END call v9.CheckSourceDefAndScriptSuccess(lines) " Test a mix lists and tuples with "any" type let lines =<< trim END vim9script def Fn(x: any): string var str = '' for [a, b] in x str ..= a .. b endfor return str enddef # List of lists assert_equal('abcd', Fn([['a', 'b'], ['c', 'd']])) # List of tuples assert_equal('abcd', Fn([('a', 'b'), ('c', 'd')])) # Tuple of lists assert_equal('abcd', Fn((['a', 'b'], ['c', 'd']))) # Tuple of tuples assert_equal('abcd', Fn((('a', 'b'), ('c', 'd')))) END call v9.CheckSourceSuccess(lines) let lines =<< trim END VAR [v1, v2] = ('a', 'b', 'c') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1537: Less targets than Tuple items', \ 'E1093: Expected 2 items but got 3', \ 'E1537: Less targets than Tuple items']) let lines =<< trim END VAR [v1, v2, v3] = ('a', 'b') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1538: More targets than Tuple items', \ 'E1093: Expected 3 items but got 2', \ 'E1538: More targets than Tuple items']) let lines =<< trim END VAR [v1; v2] = test_null_tuple() END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1536: Tuple required', \ 'E1093: Expected 1 items but got 0', \ 'E1536: Tuple required']) let lines =<< trim END for [v1, v2] in (('a', 'b', 'c'),) endfor END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1537: Less targets than Tuple items', \ 'E1537: Less targets than Tuple items', \ 'E1537: Less targets than Tuple items']) let lines =<< trim END for [v1, v2] in (('a',),) endfor END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1538: More targets than Tuple items', \ 'E1538: More targets than Tuple items', \ 'E1538: More targets than Tuple items']) let lines =<< trim END for [v1, v2] in (test_null_tuple(),) endfor END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1536: Tuple required', \ 'E1538: More targets than Tuple items', \ 'E1536: Tuple required']) let lines =<< trim END for [v1; v2] in (test_null_tuple(),) endfor END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1536: Tuple required', \ 'E1538: More targets than Tuple items', \ 'E1536: Tuple required']) " List assignment errors using a function tuple argument let lines =<< trim END vim9script def Fn(x: tuple<...list>) var [a, b] = x enddef Fn((1, 2, 3)) END call v9.CheckSourceFailure(lines, 'E1093: Expected 2 items but got 3') let lines =<< trim END vim9script def Fn(x: tuple) var [a, b] = x enddef Fn((1,)) END call v9.CheckSourceFailure(lines, 'E1093: Expected 2 items but got 1') let lines =<< trim END vim9script def Fn(x: tuple) var [a, b] = x enddef Fn(null_tuple) END call v9.CheckSourceFailure(lines, 'E1093: Expected 2 items but got 0') endfunc " Test for performing an arithmetic operation on multiple variables using " items from a tuple func Test_multi_arithmetic_op_from_tuple() let lines =<< trim END VAR x = 10 VAR y = 10 LET [x, y] += (2, 4) call assert_equal([12, 14], [x, y]) LET [x, y] -= (4, 2) call assert_equal([8, 12], [x, y]) LET [x, y] *= (2, 3) call assert_equal([16, 36], [x, y]) LET [x, y] /= (4, 2) call assert_equal([4, 18], [x, y]) LET [x, y] %= (3, 5) call assert_equal([1, 3], [x, y]) END call v9.CheckSourceLegacyAndVim9Success(lines) " The "." operator is supported only in Vim script let lines =<< trim END let x = 'a' let y = 'b' let [x, y] .= ('a', 'b') call assert_equal(['aa', 'bb'], [x, y]) END call v9.CheckSourceSuccess(lines) let lines =<< trim END VAR x = 'a' VAR y = 'b' LET [x, y] ..= ('a', 'b') call assert_equal(('aa', 'bb'), (x, y)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for using a tuple in a for statement func Test_tuple_for() let lines =<< trim END VAR sum = 0 for v1 in (1, 3, 5) LET sum += v1 endfor call assert_equal(9, sum) LET sum = 0 for v2 in () LET sum += v2 endfor call assert_equal(0, sum) LET sum = 0 for v2 in test_null_tuple() LET sum += v2 endfor call assert_equal(0, sum) END call v9.CheckSourceLegacyAndVim9Success(lines) " ignoring the for loop assignment using '_' let lines =<< trim END vim9script var count = 0 for _ in (1, 2, 3) count += 1 endfor assert_equal(3, count) END call v9.CheckSourceSuccess(lines) let lines =<< trim END var sum = 0 for v in null_tuple sum += v endfor assert_equal(0, sum) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END vim9script def Foo() for x in ((1, 2), (3, 4)) endfor enddef Foo() END call v9.CheckSourceSuccess(lines) " Test for assigning multiple items from a tuple in a for loop let lines =<< trim END vim9script def Fn() for [x, y] in ([1, 2],) assert_equal([1, 2], [x, y]) endfor enddef defcompile Fn() END call v9.CheckSourceSuccess(lines) " iterate over tuple<...list let lines =<< trim END vim9script def Fn() var t: tuple<...list> = (1, 2) var sum = 0 for i: number in t sum += i endfor assert_equal(3, sum) enddef Fn() END call v9.CheckSourceSuccess(lines) " iterate over tuple<...list>> let lines =<< trim END vim9script def Fn() var t: tuple<...list>> = ([1, 2], [3, 4]) var sum = 0 for [x: number, y: number] in t sum += x + y endfor assert_equal(10, sum) enddef Fn() END call v9.CheckSourceSuccess(lines) " iterate over tuple<...list>>> let lines =<< trim END vim9script def Fn() var t: tuple<...list>>> = ((1, 2), (3, 4)) var sum = 0 for [x: number, y: number] in t sum += x + y endfor assert_equal(10, sum) enddef Fn() END call v9.CheckSourceSuccess(lines) " iterate over tuple<...list>> let lines =<< trim END vim9script def Fn() var t: tuple<...list>> = ([1, 2], [3, 4]) var sum = 0 for [x: number, y: number] in t sum += x + y endfor assert_equal(10, sum) enddef Fn() END call v9.CheckSourceSuccess(lines) " iterate over a tuple<...list> let lines =<< trim END vim9script def Fn() var t: tuple<...list> = (1, 'x', true, [], {}, ()) var str = '' for v in t str ..= string(v) endfor assert_equal("1'x'true[]{}()", str) enddef Fn() END call v9.CheckSourceSuccess(lines) " use multiple variable assignment syntax with a tuple<...list> let lines =<< trim END vim9script def Fn() var t: tuple<...list> = (1, 2, 3) for [i] in t endfor enddef Fn() END call v9.CheckSourceFailure(lines, 'E1140: :for argument must be a sequence of lists or tuples', 2) endfunc " Test for checking the tuple type in assignment and return value func Test_tuple_type_check() let lines =<< trim END var t: tuple<...list> = ('a', 'b') END call v9.CheckSourceDefFailure(lines, 'E1012: Type mismatch; expected tuple<...list> but got tuple', 1) let lines =<< trim END var t1: tuple<...list> = ('a', 'b') assert_equal(('a', 'b'), t1) var t2 = (1, 2) assert_equal((1, 2), t2) var t = null_tuple assert_equal(null_tuple, t) t = test_null_tuple() assert_equal(test_null_tuple(), t) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END var t = ('a', 'b') t = (1, 2) END call v9.CheckSourceDefFailure(lines, 'E1012: Type mismatch; expected tuple but got tuple', 2) let lines =<< trim END var t: tuple = [] END call v9.CheckSourceDefFailure(lines, 'E1012: Type mismatch; expected tuple but got list', 1) let lines =<< trim END var t: tuple = {} END call v9.CheckSourceDefFailure(lines, 'E1012: Type mismatch; expected tuple but got dict', 1) let lines =<< trim END var l: list = (1, 2) END call v9.CheckSourceDefFailure(lines, 'E1012: Type mismatch; expected list but got tuple', 1) let lines =<< trim END vim9script def Fn(): tuple<...list>>> return ((1, 2), (3, 4)) enddef defcompile END call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple<...list>>> but got tuple, tuple>', 1) let lines =<< trim END var t: tuple = () END call v9.CheckSourceDefSuccess(lines) let lines =<< trim END vim9script def Fn(): tuple> return () enddef defcompile END call v9.CheckSourceSuccess(lines) let lines =<< trim END vim9script def Fn(t: tuple<...list>) enddef Fn(('a', 'b')) END call v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected tuple<...list> but got tuple') let lines =<< trim END var t: any = (1, 2) t = ('a', 'b') END call v9.CheckSourceDefSuccess(lines) let lines =<< trim END var t: tuple<...list> = (1, 2) t = ('a', 'b') END call v9.CheckSourceDefSuccess(lines) let lines =<< trim END var nll: tuple> = ([1, 2],) nll->copy()[0]->extend(['x']) END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1013: Argument 2: type mismatch, expected list but got list', \ 'E1013: Argument 2: type mismatch, expected list but got list in extend()']) let lines =<< trim END vim9script def Fn(y: tuple>) var x: tuple> x = y enddef var t: tuple> = (1, true, false) Fn(t) END call v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected tuple> but got tuple>') endfunc " Test for setting the type of a script variable to tuple func Test_tuple_scriptvar_type() " Uninitialized script variable should retain the type let lines =<< trim END vim9script var foobar: tuple> def Foo() var x = foobar assert_equal('tuple>', typename(x)) enddef Foo() END call v9.CheckSourceScriptSuccess(lines) " Initialized script variable should retain the type let lines =<< trim END vim9script var foobar: tuple<...list> = ('a', 'b') def Foo() var x = foobar assert_equal('tuple<...list>', typename(x)) enddef Foo() END call v9.CheckSourceScriptSuccess(lines) endfunc " Test for modifying a tuple func Test_tuple_modify() let lines =<< trim END var t = (1, 2) t[0] = 3 END call v9.CheckSourceDefAndScriptFailure(lines, ['E1532: Cannot modify a tuple', 'E1532: Cannot modify a tuple']) endfunc def Test_using_null_tuple() var lines =<< trim END var x = null_tuple assert_true(x is null_tuple) var y = copy(x) assert_true(y is null_tuple) call assert_true((1, 2) != null_tuple) call assert_true(null_tuple != (1, 2)) assert_equal(0, count(null_tuple, 'xx')) var z = deepcopy(x) assert_true(z is null_tuple) assert_equal(1, empty(x)) assert_equal('xx', get(x, 0, 'xx')) assert_equal(-1, index(null_tuple, 10)) assert_equal(-1, indexof(null_tuple, 'v:val == 2')) assert_equal('', join(null_tuple)) assert_equal(0, len(x)) assert_equal(0, min(null_tuple)) assert_equal(0, max(null_tuple)) assert_equal((), repeat(null_tuple, 3)) assert_equal((), reverse(null_tuple)) assert_equal((), slice(null_tuple, 0, 0)) assert_equal('()', string(x)) assert_equal('tuple', typename(x)) assert_equal(17, type(x)) END v9.CheckSourceDefAndScriptSuccess(lines) lines =<< trim END # An uninitialized tuple is not equal to null var t1: tuple assert_true(t1 != null) # An empty tuple is equal to null_tuple but not equal to null var t2: tuple = () assert_true(t2 == null_tuple) assert_true(t2 != null) # null_tuple is equal to null assert_true(null_tuple == null) END v9.CheckSourceDefAndScriptSuccess(lines) lines =<< trim END var x = null_tupel END v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1001: Variable not found: null_tupel', \ 'E121: Undefined variable: null_tupel']) enddef " Test for modifying a mutable item in a tuple func Test_tuple_modify_mutable_item() let lines =<< trim END VAR t = ('a', ['b', 'c'], {'a': 10, 'b': 20}) LET t[1][1] = 'x' LET t[2].a = 30 call assert_equal(('a', ['b', 'x'], {'a': 30, 'b': 20}), t) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END VAR t = ('a', (['b'], 'c')) LET t[1][0][0] = 'x' call assert_equal(('a', (['x'], 'c')), t) END call v9.CheckSourceLegacyAndVim9Success(lines) " Use a negative index let lines =<< trim END VAR t = ([1, 2], [3]) LET t[-2][-2] = 5 call assert_equal(([5, 2], [3]), t) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END VAR t = ('a', ('b', 'c')) LET t[1][0] = 'x' END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple']) let lines =<< trim END VAR t = ['a', ('b', 'c')] LET t[1][0] = 'x' END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple']) let lines =<< trim END VAR t = {'a': ('b', 'c')} LET t['a'][0] = 'x' END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple']) let lines =<< trim END VAR t = {'a': ['b', ('c',)]} LET t['a'][1][0] = 'x' END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple', \ 'E1532: Cannot modify a tuple']) let lines =<< trim END let t = ('a', 'b', 'c', 'd') let t[1 : 2] = ('x', 'y') END call v9.CheckSourceFailure(lines, 'E1533: Cannot slice a tuple') let lines =<< trim END var t: tuple<...list> = ('a', 'b', 'c', 'd') t[1 : 2] = ('x', 'y') END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1533: Cannot slice a tuple', \ 'E1533: Cannot slice a tuple']) let lines =<< trim END var t: tuple<...list> = ('a', 'b', 'c', 'd') t[ : 2] = ('x', 'y') END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1533: Cannot slice a tuple', \ 'E1533: Cannot slice a tuple']) let lines =<< trim END let t = ('a', 'b', 'c', 'd') let t[ : ] = ('x', 'y') END call v9.CheckSourceFailure(lines, 'E1533: Cannot slice a tuple') let lines =<< trim END var t: tuple<...list> = ('a', 'b', 'c', 'd') t[ : ] = ('x', 'y') END call v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1533: Cannot slice a tuple', \ 'E1533: Cannot slice a tuple']) let lines =<< trim END VAR t = ('abc',) LET t[0][1] = 'x' END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ "E689: Index not allowed after a string: t[0][1] = 'x'", \ 'E1148: Cannot index a string', \ "E689: Index not allowed after a string: t[0][1] = 'x'"]) " Out of range indexing let lines =<< trim END VAR t = ([1, 2], [3]) LET t[2][0] = 5 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: 2', \ 'E1519: Tuple index out of range: 2', \ 'E1519: Tuple index out of range: 2']) let lines =<< trim END VAR t = ([1, 2], [3]) LET t[-3][0] = 5 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: -3', \ 'E1519: Tuple index out of range: -3', \ 'E1519: Tuple index out of range: -3']) " Use a null tuple let lines =<< trim END VAR t = test_null_tuple() LET t[0][0] = 5 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1519: Tuple index out of range: 0', \ 'E1519: Tuple index out of range: 0', \ 'E1519: Tuple index out of range: 0']) endfunc " Test for locking and unlocking a tuple variable func Test_tuple_lock() " lockvar 0 let g:t = ([0, 1],) let lines =<< trim END lockvar 0 g:t LET g:t = () END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1122: Variable is locked: g:t', \ 'E1122: Variable is locked: t', \ 'E1122: Variable is locked: g:t']) unlet g:t " Tuple is immutable. So "lockvar 1" is not applicable to a tuple. " lockvar 2 let g:t = ([0, 1],) let lines =<< trim END lockvar 2 g:t call add(g:t[0], 2) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E741: Value is locked: add() argument', \ 'E741: Value is locked: add() argument', \ 'E741: Value is locked: add() argument']) unlet g:t " lockvar 3 let g:t = ([0, 1],) let lines =<< trim END lockvar 3 g:t LET g:t[0][0] = 10 END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E741: Value is locked: g:t[0][0] = 10', \ 'E1119: Cannot change locked list item', \ 'E741: Value is locked: g:t[0][0] = 10']) unlet g:t let lines =<< trim END VAR t = ([0, 1],) lockvar 2 t call add(t[0], 2) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E741: Value is locked: add() argument', \ 'E1178: Cannot lock or unlock a local variable', \ 'E741: Value is locked: add() argument']) let lines =<< trim END LET g:t = ([0, 1],) lockvar 2 g:t unlockvar 2 g:t call add(g:t[0], 3) call assert_equal(([0, 1, 3], ), g:t) unlet g:t END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END VAR t1 = (1, 2) const t2 = t1 LET t2 = () END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E741: Value is locked: t2', \ 'E1018: Cannot assign to a constant: t2', \ 'E46: Cannot change read-only variable "t2"']) endfunc " Test for using a class as a tuple item func Test_tuple_use_class_item() let lines =<< trim END vim9script class A endclass var t = (A,) END call v9.CheckSourceScriptFailure(lines, 'E1405: Class "A" cannot be used as a value', 4) let lines =<< trim END vim9script class A endclass var t = ('a', A) END call v9.CheckSourceScriptFailure(lines, 'E1405: Class "A" cannot be used as a value', 4) let lines =<< trim END vim9script class A endclass def Fn() var t = (A,) enddef defcompile END call v9.CheckSourceScriptFailure(lines, 'E1405: Class "A" cannot be used as a value', 1) let lines =<< trim END vim9script class A endclass def Fn() var t = ('a', A) enddef defcompile END call v9.CheckSourceScriptFailure(lines, 'E1405: Class "A" cannot be used as a value', 1) endfunc " Test for using a user-defined type as a tuple item func Test_tuple_user_defined_type_as_item() let lines =<< trim END vim9script type N = number var t = (N,) END call v9.CheckSourceScriptFailure(lines, 'E1403: Type alias "N" cannot be used as a value', 3) let lines =<< trim END vim9script type N = number var t = ('a', N) END call v9.CheckSourceScriptFailure(lines, 'E1403: Type alias "N" cannot be used as a value', 3) let lines =<< trim END vim9script type N = number def Fn() var t = (N,) enddef defcompile END call v9.CheckSourceScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1) let lines =<< trim END vim9script type N = number def Fn() var t = ('a', N) enddef defcompile END call v9.CheckSourceScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1) endfunc " Test for using a tuple as a function argument func Test_tuple_func_arg() let lines =<< trim END vim9script def Fn(t: tuple<...list>): tuple<...list> return t[:] enddef var r1 = Fn(('a', 'b')) assert_equal(('a', 'b'), r1) var r2 = Fn(('a',)) assert_equal(('a',), r2) var r3 = Fn(()) assert_equal((), r3) var r4 = Fn(null_tuple) assert_equal((), r4) END call v9.CheckSourceScriptSuccess(lines) func TupleArgFunc(t) return a:t[:] endfunc let r = TupleArgFunc(('a', 'b')) call assert_equal(('a', 'b'), r) let r = TupleArgFunc(('a',)) call assert_equal(('a',), r) let r = TupleArgFunc(()) call assert_equal((), r) let r = TupleArgFunc(test_null_tuple()) call assert_equal((), r) delfunc TupleArgFunc endfunc " Test for tuple identity func Test_tuple_identity() let lines =<< trim END call assert_false((1, 2) is (1, 2)) call assert_true((1, 2) isnot (1, 2)) call assert_true((1, 2) isnot test_null_tuple()) VAR t1 = ('abc', 'def') VAR t2 = t1 call assert_true(t2 is t1) VAR t3 = (1, 2) call assert_false(t3 is t1) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for using a compound op with a tuple func Test_tuple_compound_op() let lines =<< trim END VAR t = (1, 2) LET t += (3,) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E734: Wrong variable type for +=', \ 'E734: Wrong variable type for +=', \ 'E734: Wrong variable type for +=']) for op in ['-', '*', '/', '%'] let lines =<< trim eval END VAR t = (1, 2) LET t {op}= (3,) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ $'E734: Wrong variable type for {op}=', \ $'E734: Wrong variable type for {op}=', \ $'E734: Wrong variable type for {op}=']) endfor let lines =<< trim END VAR t = (1, 2) LET t ..= (3,) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E734: Wrong variable type for .=', \ 'E1019: Can only concatenate to string', \ 'E734: Wrong variable type for .=']) endfunc " Test for using the falsy operator with tuple func Test_tuple_falsy_op() let lines =<< trim END VAR t = test_null_tuple() call assert_equal('null tuple', t ?? 'null tuple') END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for tuple typecasting def Test_tuple_typecast() var lines =<< trim END var x = >('a', 'b') END v9.CheckSourceDefAndScriptFailure(lines, [ \ 'E1012: Type mismatch; expected tuple but got tuple', \ 'E1012: Type mismatch; expected tuple but got tuple']) enddef " Test for using a tuple in string interpolation def Test_tuple_string_interop() var lines =<< trim END VAR emptytuple = () call assert_equal("a()b", $'a{emptytuple}b') VAR nulltuple = test_null_tuple() call assert_equal("a()b", $'a{nulltuple}b') #" Tuple interpolation VAR t = ('a', 'b', 'c') call assert_equal("x('a', 'b', 'c')x", $'x{t}x') END v9.CheckSourceLegacyAndVim9Success(lines) lines =<< trim END call assert_equal("a()b", $'a{null_tuple}b') END v9.CheckSourceDefAndScriptSuccess(lines) #" Tuple evaluation in heredoc lines =<< trim END VAR t1 = ('a', 'b', 'c') VAR data =<< eval trim DATA let x = {t1} DATA call assert_equal(["let x = ('a', 'b', 'c')"], data) END v9.CheckSourceLegacyAndVim9Success(lines) #" Empty tuple evaluation in heredoc lines =<< trim END VAR t1 = () VAR data =<< eval trim DATA let x = {t1} DATA call assert_equal(["let x = ()"], data) END v9.CheckSourceLegacyAndVim9Success(lines) #" Null tuple evaluation in heredoc lines =<< trim END VAR t1 = test_null_tuple() VAR data =<< eval trim DATA let x = {t1} DATA call assert_equal(["let x = ()"], data) END v9.CheckSourceLegacyAndVim9Success(lines) lines =<< trim END var t1 = null_tuple var data =<< eval trim DATA let x = {t1} DATA call assert_equal(["let x = ()"], data) END v9.CheckSourceDefAndScriptSuccess(lines) enddef " Test for a return in "finally" block overriding the tuple return value in a " try block. func Test_try_finally_with_tuple_return() let lines =<< trim END func s:Fn() try return (1, 2) finally return (3, 4) endtry endfunc call assert_equal((3, 4), s:Fn()) delfunc s:Fn END call v9.CheckSourceSuccess(lines) let lines =<< trim END vim9script def Fn(): tuple<...list> try return (1, 2) finally return (3, 4) endtry enddef assert_equal((3, 4), Fn()) END call v9.CheckSourceSuccess(lines) endfunc " Test for evaluating a recursive tuple that results in an error func Test_recursive_tuple_eval_fails() let lines =<< trim END call assert_fails(((((((((((((((('tag xyz', func2(pat, flags, infn) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E121: Undefined variable: pat', \ 'E1001: Variable not found: pat', \ 'E121: Undefined variable: pat']) endfunc " The following used to crash Vim func Test_import_invalid_tuple() let lines =<< trim END imp(",G0}11*f[+\x","#| END new call setline(1, lines) call assert_fails('source', 'E114: Missing double quote: "#|') bw! endfunc " Test for add() with a tuple func Test_tuple_add() let lines =<< trim END VAR t = (1, 2) call add(t, 3) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E897: List or Blob required', \ 'E1013: Argument 1: type mismatch, expected list but got tuple', \ 'E1226: List or Blob required for argument 1']) endfunc " Test for copy() func Test_tuple_copy() let lines =<< trim END VAR t1 = (['a', 'b'], ['c', 'd'], ['e', 'f']) VAR t2 = copy(t1) VAR t3 = t1 call assert_false(t2 is t1) call assert_true(t3 is t1) call assert_true(t2[1] is t1[1]) call assert_equal((), copy(())) call assert_equal((), copy(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for count() func Test_tuple_count() let lines =<< trim END VAR t = ('ab', 'cd', 'ab') call assert_equal(2, count(t, 'ab')) call assert_equal(0, count(t, 'xx')) call assert_equal(0, count((), 'xx')) call assert_equal(0, count(test_null_tuple(), 'xx')) call assert_fails("call count((1, 2), 1, v:true, 2)", 'E1519: Tuple index out of range: 2') END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for deepcopy() func Test_tuple_deepcopy() let lines =<< trim END VAR t1 = (['a', 'b'], ['c', 'd'], ['e', 'f']) VAR t2 = deepcopy(t1) VAR t3 = t1 call assert_false(t2 is t1) call assert_true(t3 is t1) call assert_false(t2[1] is t1[1]) call assert_equal((), deepcopy(())) call assert_equal((), deepcopy(test_null_tuple())) #" copy a recursive tuple VAR l = [] VAR tuple = (l,) call add(l, tuple) call assert_equal('([(...)], )', string(deepcopy(tuple))) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for empty() func Test_tuple_empty() let lines =<< trim END call assert_true(empty(())) call assert_true(empty(test_null_tuple())) call assert_false(empty((1, 2))) VAR t = ('abc', 'def') call assert_false(empty(t)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for eval() func Test_tuple_eval() let lines =<< trim END call assert_equal((), eval('()')) call assert_equal(([],), eval('([],)')) call assert_equal((1, 2, 3), eval('(1, 2, 3)')) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for extend() with a tuple 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, [ \ 'E712: Argument of extend() must be a List or Dictionary', \ 'E1013: Argument 1: type mismatch, expected list but got tuple', \ 'E712: Argument of extend() must be a List or Dictionary']) endfunc " Test for filter() with a tuple func Test_tuple_filter() let lines =<< trim END VAR t = (1, 2, 3) call filter(t, 'v:val == 2') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1524: Cannot use a tuple with function filter()', \ 'E1013: Argument 1: type mismatch, expected list but got tuple', \ 'E1524: Cannot use a tuple with function filter()']) endfunc " Test for flatten() with a tuple func Test_tuple_flatten() let t = ([1, 2], [3, 4], [5, 6]) call assert_fails("call flatten(t, 2)", 'E686: Argument of flatten() must be a List') endfunc " Test for flattennew() with a tuple func Test_tuple_flattennew() let lines =<< trim END var t = ([1, 2], [3, 4], [5, 6]) flattennew(t, 2) END call v9.CheckSourceDefFailure(lines, 'E1013: Argument 1: type mismatch, expected list but got tuple, list, list>') endfunc " Test for foreach() with a tuple func Test_tuple_foreach() let t = ('a', 'b', 'c') let str = '' call foreach(t, 'let str ..= v:val') call assert_equal('abc', str) let sum = 0 call foreach(test_null_tuple(), 'let sum += v:val') call assert_equal(0, sum) let lines =<< trim END def Concatenate(k: number, v: string) g:str ..= v enddef var t = ('a', 'b', 'c') var str = 0 g:str = '' call foreach(t, Concatenate) call assert_equal('abc', g:str) g:str = '' call foreach(test_null_tuple(), Concatenate) call assert_equal('', g:str) END call v9.CheckSourceDefAndScriptSuccess(lines) let lines =<< trim END LET g:sum = 0 call foreach((1, 2, 3), 'LET g:sum += x') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E121: Undefined variable: x', \ 'E121: Undefined variable: x', \ 'E121: Undefined variable: x']) endfunc " Test for get() func Test_tuple_get() let lines =<< trim END VAR t = (10, 20, 30) for [i, v] in [[0, 10], [1, 20], [2, 30], [3, 0]] call assert_equal(v, get(t, i)) endfor for [i, v] in [[-1, 30], [-2, 20], [-3, 10], [-4, 0]] call assert_equal(v, get(t, i)) endfor call assert_equal(0, get((), 5)) call assert_equal('c', get(('a', 'b'), 2, 'c')) call assert_equal('x', get(test_null_tuple(), 0, 'x')) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for id() func Test_tuple_id() let lines =<< trim END VAR t1 = (['a'], ['b'], ['c']) VAR t2 = (['a'], ['b'], ['c']) VAR t3 = t1 call assert_true(id(t1) != id(t2)) call assert_true(id(t1) == id(t3)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for index() function func Test_tuple_index_func() let lines =<< trim END VAR t = (88, 33, 99, 77) call assert_equal(3, index(t, 77)) call assert_equal(2, index(t, 99, 1)) call assert_equal(2, index(t, 99, -4)) call assert_equal(2, index(t, 99, -5)) call assert_equal(-1, index(t, 66)) call assert_equal(-1, index(t, 77, 4)) call assert_equal(-1, index((), 8)) call assert_equal(-1, index(test_null_tuple(), 9)) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END VAR t = (88, 33, 99, 77) call assert_equal(-1, index(t, 77, [])) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E745: Using a List as a Number', \ 'E1013: Argument 3: type mismatch, expected number but got list', \ 'E1210: Number required for argument 3']) let lines =<< trim END VAR t = (88,) call assert_equal(-1, index(t, 77, 1, ())) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1520: Using a Tuple as a Number', \ 'E1013: Argument 4: type mismatch, expected bool but got tuple', \ 'E1212: Bool required for argument 4']) endfunc " Test for indexof() func Test_tuple_indexof() let lines =<< trim END VAR t = ('a', 'b', 'c', 'd') call assert_equal(2, indexof(t, 'v:val =~ "c"')) call assert_equal(2, indexof(t, 'v:val =~ "c"', {'startidx': 2})) call assert_equal(-1, indexof(t, 'v:val =~ "c"', {'startidx': 3})) call assert_equal(2, indexof(t, 'v:val =~ "c"', {'startidx': -3})) call assert_equal(2, indexof(t, 'v:val =~ "c"', {'startidx': -6})) call assert_equal(-1, indexof(t, 'v:val =~ "e"')) call assert_equal(-1, indexof((), 'v:val == 1')) call assert_equal(-1, indexof(test_null_tuple(), 'v:val == 2')) END call v9.CheckSourceLegacyAndVim9Success(lines) func g:MyIndexOf(k, v) echoerr 'MyIndexOf failed' endfunc let lines =<< trim END VAR t = (1, 2, 3) echo indexof(t, function('g:MyIndexOf')) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'MyIndexOf failed', \ 'MyIndexOf failed', \ 'MyIndexOf failed']) delfunc g:MyIndexOf endfunc " Test for insert() func Test_tuple_insert() let lines =<< trim END VAR t = (1, 2, 3) call insert(t, 4) call insert(t, 4, 2) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E899: Argument of insert() must be a List or Blob', \ 'E1013: Argument 1: type mismatch, expected list but got tuple', \ 'E1226: List or Blob required for argument 1']) endfunc " Test for islocked() func Test_tuple_islocked() let lines =<< trim END let t = (1, [2], 3) call assert_equal(0, islocked('t')) call assert_equal(0, islocked('t[1]')) lockvar 1 t call assert_equal(1, islocked('t')) call assert_equal(0, islocked('t[1]')) unlockvar t call assert_equal(0, islocked('t')) lockvar 2 t call assert_equal(1, islocked('t[1]')) unlockvar t call assert_equal(0, islocked('t[1]')) END call v9.CheckSourceSuccess(lines) endfunc " Test for items() func Test_tuple_items() let lines =<< trim END VAR t = ([], {}, ()) call assert_equal([[0, []], [1, {}], [2, ()]], items(t)) call assert_equal([[0, 1]], items((1, ))) call assert_equal([], items(())) call assert_equal([], items(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for join() func Test_tuple_join() let lines =<< trim END VAR t = ('a', 'b', 'c') call assert_equal('a b c', join(t)) call assert_equal('f o o', ('f', 'o', 'o')->join()) call assert_equal('a-b-c', join(t, '-')) call assert_equal('', join(())) call assert_equal('', join(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for js_encode() func Test_tuple_js_encode() let lines =<< trim END call assert_equal('["a","b","c"]', js_encode(('a', 'b', 'c'))) call assert_equal('["a","b"]', js_encode(('a', 'b'))) call assert_equal('["a"]', js_encode(('a',))) call assert_equal("[]", js_encode(())) call assert_equal("[]", js_encode(test_null_tuple())) call assert_equal('["a",,]', js_encode(('a', v:none))) #" encode a recursive tuple VAR l = [] VAR tuple = (l,) call add(l, tuple) call assert_equal("[[[]]]", js_encode(tuple)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for json_encode() func Test_tuple_json_encode() let lines =<< trim END call assert_equal('["a","b","c"]', json_encode(('a', 'b', 'c'))) call assert_equal('["a","b"]', json_encode(('a', 'b'))) call assert_equal('["a"]', json_encode(('a',))) call assert_equal("[]", json_encode(())) call assert_equal("[]", json_encode(test_null_tuple())) #" encode a recursive tuple VAR l = [] VAR tuple = (l,) call add(l, tuple) call assert_equal("[[[]]]", json_encode(tuple)) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END VAR t = (function('min'), function('max')) VAR s = json_encode(t) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1161: Cannot json encode a func', \ 'E1161: Cannot json encode a func', \ 'E1161: Cannot json encode a func']) endfunc " Test for len() func Test_tuple_len() let lines =<< trim END call assert_equal(0, len(())) call assert_equal(0, len(test_null_tuple())) call assert_equal(1, len(("abc",))) call assert_equal(3, len(("abc", "def", "ghi"))) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for map() with a tuple func Test_tuple_map() let t = (1, 3, 5) call assert_fails("call map(t, 'v:val + 1')", 'E1524: Cannot use a tuple with function map()') endfunc " Test for max() func Test_tuple_max() let lines =<< trim END VAR t1 = (1, 3, 5) call assert_equal(5, max(t1)) VAR t2 = (6,) call assert_equal(6, max(t2)) call assert_equal(0, max(())) call assert_equal(0, max(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END vim9script var x = max(('a', 2)) END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') let lines =<< trim END vim9script var x = max((1, 'b')) END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "b"') let lines =<< trim END vim9script def Fn() var x = max(('a', 'b')) enddef Fn() END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') let lines =<< trim END echo max([('a', 'b'), 20]) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1520: Using a Tuple as a Number', \ 'E1520: Using a Tuple as a Number', \ 'E1520: Using a Tuple as a Number']) endfunc " Test for min() func Test_tuple_min() let lines =<< trim END VAR t1 = (5, 3, 1) call assert_equal(1, min(t1)) VAR t2 = (6,) call assert_equal(6, min(t2)) call assert_equal(0, min(())) call assert_equal(0, min(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END vim9script var x = min(('a', 2)) END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') let lines =<< trim END vim9script var x = min((1, 'b')) END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "b"') let lines =<< trim END vim9script def Fn() var x = min(('a', 'b')) enddef Fn() END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') endfunc " Test for reduce() func Test_tuple_reduce() let lines =<< trim END call assert_equal(1, reduce((), LSTART acc, val LMIDDLE acc + val LEND, 1)) call assert_equal(10, reduce((1, 3, 5), LSTART acc, val LMIDDLE acc + val LEND, 1)) call assert_equal(2 * (2 * ((2 * 1) + 2) + 3) + 4, reduce((2, 3, 4), LSTART acc, val LMIDDLE 2 * acc + val LEND, 1)) call assert_equal('a x y z', ('x', 'y', 'z')->reduce(LSTART acc, val LMIDDLE acc .. ' ' .. val LEND, 'a')) VAR t = ('x', 'y', 'z') call assert_equal(42, reduce(t, function('get'), {'x': {'y': {'z': 42 } } })) call assert_equal(('x', 'y', 'z'), t) call assert_equal(1, reduce((1,), LSTART acc, val LMIDDLE acc + val LEND)) call assert_equal('x y z', reduce(('x', 'y', 'z'), LSTART acc, val LMIDDLE acc .. ' ' .. val LEND)) call assert_equal(5, reduce(test_null_tuple(), LSTART acc, val LMIDDLE acc + val LEND, 5)) END call v9.CheckSourceLegacyAndVim9Success(lines) call assert_equal({'x': 1, 'y': 1, 'z': 1 }, ('x', 'y', 'z')->reduce({ acc, val -> extend(acc, { val: 1 }) }, {})) call assert_fails("call reduce((), { acc, val -> acc + val })", 'E998: Reduce of an empty Tuple with no initial value') call assert_fails("call reduce(test_null_tuple(), { acc, val -> acc + val })", 'E998: Reduce of an empty Tuple with no initial value') let lines =<< trim END echo reduce((1, 2, 3), LSTART acc, val LMIDDLE acc + foo LEND) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E121: Undefined variable: foo', \ 'E1001: Variable not found: foo', \ 'E1001: Variable not found: foo']) endfunc " Test for remove() func Test_tuple_remove() let lines =<< trim END VAR t = (1, 3, 5) call remove(t, 1) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E896: Argument of remove() must be a List, Dictionary or Blob', \ 'E1013: Argument 1: type mismatch, expected list but got tuple', \ 'E1228: List, Dictionary or Blob required for argument 1']) endfunc " Test for test_refcount() func Test_tuple_refcount() let lines =<< trim END VAR t = (1, 2, 3) call assert_equal(1, test_refcount(t)) VAR x = t call assert_equal(2, test_refcount(t)) LET x = (4, 5, 6) call assert_equal(1, test_refcount(t)) for n in t call assert_equal(2, test_refcount(t)) endfor call assert_equal(1, test_refcount(t)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for repeat() func Test_tuple_repeat() let lines =<< trim END VAR t = ('a', 'b') call assert_equal(('a', 'b', 'a', 'b', 'a', 'b'), repeat(('a', 'b'), 3)) call assert_equal(('x', 'x', 'x'), repeat(('x',), 3)) call assert_equal((), repeat((), 3)) call assert_equal((), repeat((), 0)) call assert_equal((), repeat((), -1)) call assert_equal((), repeat(test_null_tuple(), 3)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for reverse() func Test_tuple_reverse() let lines =<< trim END VAR t = (['a'], ['b'], ['c']) call assert_equal((['c'], ['b'], ['a']), reverse(t)) call assert_equal(('a',), reverse(('a',))) call assert_equal((), reverse(())) call assert_equal((), reverse(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for slicing a tuple func Test_tuple_slice_func() let lines =<< trim END VAR t = (1, 3, 5, 7, 9) call assert_equal((9,), slice(t, 4)) call assert_equal((5, 7, 9), slice(t, 2)) call assert_equal((), slice(t, 5)) call assert_equal((), slice((), 1, 2)) call assert_equal((), slice(test_null_tuple(), 1, 2)) END call v9.CheckSourceLegacyAndVim9Success(lines) " return value of slice() should be the correct tuple type let lines =<< trim END var t: tuple<...list> = (1, 3, 5) var x: tuple<...list> = slice(t, 1, 2) assert_equal((3,), x) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Test for sort() func Test_tuple_sort() let lines =<< trim END call sort([1.1, (1.2,)], 'f') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1521: Using a Tuple as a Float', \ 'E1521: Using a Tuple as a Float', \ 'E1521: Using a Tuple as a Float']) endfunc " Test for stridx() func Test_tuple_stridx() let lines =<< trim END call stridx(('abc', ), 'a') END call v9.CheckSourceLegacyAndVim9Failure(lines, [ \ 'E1522: Using a Tuple as a String', \ 'E1013: Argument 1: type mismatch, expected string but got tuple', \ 'E1174: String required for argument 1']) endfunc " Test for string() func Test_tuple_string() let lines =<< trim END VAR t1 = (1, 'as''d', [1, 2, function("strlen")], {'a': 1}, ) call assert_equal("(1, 'as''d', [1, 2, function('strlen')], {'a': 1})", string(t1)) #" empty tuple VAR t2 = () call assert_equal("()", string(t2)) #" one item tuple VAR t3 = ("a", ) call assert_equal("('a', )", string(t3)) call assert_equal("()", string(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) " recursive tuple let lines =<< trim END VAR l = [] VAR t = (l,) call add(l, t) call assert_equal('([(...)], )', string(t)) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for type() func Test_tuple_type() let lines =<< trim END VAR t = (1, 2) call assert_equal(17, type(t)) call assert_equal(v:t_tuple, type(t)) call assert_equal(v:t_tuple, type(())) call assert_equal(v:t_tuple, type(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) endfunc " Test for typename() func Test_tuple_typename() let lines =<< trim END call assert_equal('tuple', typename((1, 2))) call assert_equal('tuple', typename(('a', 'b'))) call assert_equal('tuple', typename((v:true, v:true))) call assert_equal('tuple', typename((1, 'b'))) call assert_equal('tuple', typename(())) call assert_equal('tuple>', typename(({}, ))) call assert_equal('tuple>', typename(([], ))) call assert_equal('tuple>', typename(([1, 2], ))) call assert_equal('tuple>', typename((['a', 'b'], ))) call assert_equal('tuple>>', typename(([[1], [2]], ))) call assert_equal('tuple>', typename(((1, 2), ))) VAR t1 = (([1, 2],), (['a', 'b'],)) call assert_equal('tuple>, tuple>>', typename(t1)) call assert_equal('list>', typename([(1,)])) call assert_equal('list>', typename([()])) call assert_equal('tuple', typename(test_null_tuple())) END call v9.CheckSourceLegacyAndVim9Success(lines) let lines =<< trim END var d: dict = {a: 0} var t2 = (d,) t2[0].e = {b: t2} call assert_equal('tuple>', typename(t2)) END call v9.CheckSourceDefAndScriptSuccess(lines) " check the type of a circular reference tuple let lines =<< trim END # circular reference tuple var l: list> = [] var t = (l,) add(l, t) assert_equal('tuple>>', typename(t)) assert_equal('list>', typename(l)) END call v9.CheckSourceDefAndScriptSuccess(lines) " When a tuple item is used in a "for" loop, the type is tuple let lines =<< trim END vim9script var l = [(1, 2)] for t in l assert_equal('tuple', typename(t)) endfor END call v9.CheckSourceScriptSuccess(lines) " type of a tuple copy should be the same let lines =<< trim END var t: tuple<...list> = (1, 2) var x: tuple<...list> = t assert_equal('tuple<...list>', typename(x)) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Test for saving and restoring tuples from a viminfo file func Test_tuple_viminfo() let viminfo_save = &viminfo set viminfo^=! let g:MYTUPLE = ([1, 2], [3, 4], 'a', 'b', 1, 2) " create a tuple with circular reference " This should not be saved in the viminfo file let l = [] let g:CIRCTUPLE = (l,) call add(l, g:CIRCTUPLE) wviminfo! Xviminfo unlet g:MYTUPLE unlet g:CIRCTUPLE rviminfo! Xviminfo call assert_equal(([1, 2], [3, 4], 'a', 'b', 1, 2), g:MYTUPLE) call assert_false(exists('g:CIRCTUPLE')) let &viminfo = viminfo_save call delete('Xviminfo') endfunc " Test for list2tuple() func Test_list2tuple() let lines =<< trim END call assert_equal((), list2tuple([])) call assert_equal((), list2tuple(test_null_list())) call assert_equal(('a', ['b'], {'n': 20}), list2tuple(['a', ['b'], {'n': 20}])) VAR l = ['a', 'b'] VAR t = list2tuple(l) LET l[0] = 'x' call assert_equal(('a', 'b'), t) call assert_equal((0, 1, 2), list2tuple(range(3))) call assert_equal(((),), [()]->list2tuple()) END call v9.CheckSourceLegacyAndVim9Success(lines) call assert_fails('call list2tuple(())', 'E1211: List required for argument 1') " Check the returned type let lines =<< trim END var l1 = [1, 2] var t1: tuple<...list> = list2tuple(l1) assert_equal('tuple<...list>', typename(t1)) var l2 = ['a', 'b'] var t2: tuple<...list> = list2tuple(l2) assert_equal('tuple<...list>', typename(t2)) var l3 = [] var t3 = list2tuple(l3) assert_equal('tuple', typename(t3)) var l4 = [([{}])] var t4: tuple>> = list2tuple(l4) assert_equal('tuple>>', typename(t4)) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " Test for tuple2list() func Test_tuple2list() let lines =<< trim END call assert_equal([], tuple2list(())) call assert_equal([], tuple2list(test_null_tuple())) VAR t1 = ('a', ['b'], {'n': 20}, ('a',)) call assert_equal(['a', ['b'], {'n': 20}, ('a',)], tuple2list(t1)) VAR t = ('a', 'b') VAR l = tuple2list(t) LET l[0] = 'x' call assert_equal(('a', 'b'), t) call assert_equal([[]], ([],)->tuple2list()) END call v9.CheckSourceLegacyAndVim9Success(lines) call assert_fails('call tuple2list([])', 'E1534: Tuple required for argument 1') " Check the returned type let lines =<< trim END var t1 = (1, 2) var l1 = tuple2list(t1) assert_equal('list', typename(l1)) var t2 = ('a', 'b') var l2 = tuple2list(t2) assert_equal('list', typename(l2)) var t3 = () var l3 = tuple2list(t3) assert_equal('list', typename(l3)) var t4 = ([({},)],) var l4 = tuple2list(t4) assert_equal('list>>>', typename(l4)) END call v9.CheckSourceDefAndScriptSuccess(lines) endfunc " vim: shiftwidth=2 sts=2 expandtab