Mercurial > vim
diff src/testdir/test_vim9_assign.vim @ 32670:695b50472e85
Fix line endings issue
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 26 Jun 2023 13:13:12 +0200 |
parents | 448aef880252 |
children | 3de472480e91 |
line wrap: on
line diff
--- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1,2894 +1,2894 @@ -" Test Vim9 assignments - -source check.vim -import './vim9.vim' as v9 -source term_util.vim - -let s:appendToMe = 'xxx' -let s:addToMe = 111 -let s:newVar = '' -let g:existing = 'yes' -let g:inc_counter = 1 -let $SOME_ENV_VAR = 'some' -let g:alist = [7] -let g:adict = #{a: 1} -let g:astring = 'text' - -def Test_assignment_bool() - var bool1: bool = true - assert_equal(v:true, bool1) - var bool2: bool = false - assert_equal(v:false, bool2) - - var bool3: bool = 0 - assert_equal(false, bool3) - var bool4: bool = 1 - assert_equal(true, bool4) - - var bool5: bool = 1 && true - assert_equal(true, bool5) - var bool6: bool = 0 && 1 - assert_equal(false, bool6) - var bool7: bool = 0 || 1 && true - assert_equal(true, bool7) - - var lines =<< trim END - vim9script - def GetFlag(): bool - var flag: bool = 1 - return flag - enddef - var flag: bool = GetFlag() - assert_equal(true, flag) - flag = 0 - assert_equal(false, flag) - flag = 1 - assert_equal(true, flag) - flag = 1 || true - assert_equal(true, flag) - flag = 1 && false - assert_equal(false, flag) - - var cp: bool = &cp - var fen: bool = &l:fen - END - v9.CheckScriptSuccess(lines) - v9.CheckDefAndScriptFailure(['var x: bool = 2'], 'E1012:') - v9.CheckDefAndScriptFailure(['var x: bool = -1'], 'E1012:') - v9.CheckDefAndScriptFailure(['var x: bool = [1]'], 'E1012:') - v9.CheckDefAndScriptFailure(['var x: bool = {}'], 'E1012:') - v9.CheckDefAndScriptFailure(['var x: bool = "x"'], 'E1012:') - - v9.CheckDefAndScriptFailure(['var x: bool = "x"', '', 'eval 0'], 'E1012:', 1) -enddef - -def Test_syntax() - var name = 234 - var other: list<string> = ['asdf'] -enddef - -def Test_assignment() - v9.CheckDefFailure(['var x:string'], 'E1069:') - v9.CheckDefFailure(['var x:string = "x"'], 'E1069:') - v9.CheckDefFailure(['var a:string = "x"'], 'E1069:') - v9.CheckDefFailure(['var lambda = () => "lambda"'], 'E704:') - v9.CheckScriptFailure(['var x = "x"'], 'E1124:') - - # lower case name is OK for a list - var lambdaLines =<< trim END - var lambdaList: list<func> = [g:Test_syntax] - lambdaList[0] = () => "lambda" - END - v9.CheckDefAndScriptSuccess(lambdaLines) - - var nr: number = 1234 - v9.CheckDefFailure(['var nr: number = "asdf"'], 'E1012:') - - var a: number = 6 #comment - assert_equal(6, a) - - if has('channel') - var chan1: channel - assert_equal('fail', ch_status(chan1)) - - var job1: job - assert_equal('fail', job_status(job1)) - - # calling job_start() is in test_vim9_fails.vim, it causes leak reports - endif - var float1: float = 3.4 - var Funky1: func - var Funky2: func = function('len') - var Party2: func = funcref('g:Test_syntax') - - g:newvar = 'new' #comment - assert_equal('new', g:newvar) - - assert_equal('yes', g:existing) - g:existing = 'no' - assert_equal('no', g:existing) - - v:char = 'abc' - assert_equal('abc', v:char) - - $ENVVAR = 'foobar' - assert_equal('foobar', $ENVVAR) - $ENVVAR = '' - - var lines =<< trim END - vim9script - $ENVVAR = 'barfoo' - assert_equal('barfoo', $ENVVAR) - $ENVVAR = '' - END - v9.CheckScriptSuccess(lines) - - appendToMe ..= 'yyy' - assert_equal('xxxyyy', appendToMe) - addToMe += 222 - assert_equal(333, addToMe) - newVar = 'new' - assert_equal('new', newVar) - - set ts=7 - var ts: number = &ts - assert_equal(7, ts) - &ts += 1 - assert_equal(8, &ts) - &ts -= 3 - assert_equal(5, &ts) - &ts *= 2 - assert_equal(10, &ts) - &ts /= 3 - assert_equal(3, &ts) - set ts=10 - &ts %= 4 - assert_equal(2, &ts) - - assert_fails('&ts /= 0', ['E1154:', 'E1154:']) - assert_fails('&ts %= 0', ['E1154:', 'E1154:']) - assert_fails('&ts /= []', ['E745:', 'E745:']) - assert_fails('&ts %= []', ['E745:', 'E745:']) - assert_equal(2, &ts) - - var f100: float = 100.0 - f100 /= 5 - assert_equal(20.0, f100) - - var f200: float = 200.0 - f200 /= 5.0 - assert_equal(40.0, f200) - - v9.CheckDefFailure(['var nr: number = 200', 'nr /= 5.0'], 'E1012:') - - lines =<< trim END - &ts = 6 - &ts += 3 - assert_equal(9, &ts) - - &l:ts = 6 - assert_equal(6, &ts) - &l:ts += 2 - assert_equal(8, &ts) - - &g:ts = 6 - assert_equal(6, &g:ts) - &g:ts += 2 - assert_equal(8, &g:ts) - - &number = true - assert_equal(true, &number) - &number = 0 - assert_equal(false, &number) - &number = 1 - assert_equal(true, &number) - &number = false - assert_equal(false, &number) - END - v9.CheckDefAndScriptSuccess(lines) - - v9.CheckDefFailure(['¬ex += 3'], 'E113:') - v9.CheckDefFailure(['&ts ..= "xxx"'], 'E1019:') - v9.CheckDefFailure(['&ts = [7]'], 'E1012:') - v9.CheckDefExecFailure(['&ts = g:alist'], 'E1012: Type mismatch; expected number but got list<number>') - v9.CheckDefFailure(['&ts = "xx"'], 'E1012:') - v9.CheckDefExecFailure(['&ts = g:astring'], 'E1012: Type mismatch; expected number but got string') - v9.CheckDefFailure(['&path += 3'], 'E1012:') - v9.CheckDefExecFailure(['&bs = "asdf"'], 'E474:') - # test freeing ISN_STOREOPT - v9.CheckDefFailure(['&ts = 3', 'var asdf'], 'E1022:') - &ts = 8 - - lines =<< trim END - var save_TI = &t_TI - &t_TI = '' - assert_equal('', &t_TI) - &t_TI = 'xxx' - assert_equal('xxx', &t_TI) - &t_TI = save_TI - END - v9.CheckDefAndScriptSuccess(lines) - - v9.CheckDefFailure(['&t_TI = 123'], 'E1012:') - v9.CheckScriptFailure(['vim9script', '&t_TI = 123'], 'E928:') - - v9.CheckDefFailure(['var s:var = 123'], 'E1101:') - v9.CheckDefFailure(['var s:var: number'], 'E1101:') - - v9.CheckDefAndScriptFailure(['var $VAR: number'], ['E1016:', 'E475:']) - - lines =<< trim END - vim9script - def SomeFunc() - s:var = 123 - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1268:') - - g:inc_counter += 1 - assert_equal(2, g:inc_counter) - - var f: float - f += 1 - assert_equal(1.0, f) - - $SOME_ENV_VAR ..= 'more' - assert_equal('somemore', $SOME_ENV_VAR) - v9.CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:') - v9.CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1012:') - - v:errmsg = 'none' - v:errmsg ..= 'again' - assert_equal('noneagain', v:errmsg) - v9.CheckDefFailure(['v:errmsg += "more"'], 'E1051:') - v9.CheckDefFailure(['v:errmsg += 123'], 'E1012:') - - var text =<< trim END - some text - END -enddef - -def Test_float_and_number() - var lines =<< trim END - var f: float - f += 2 - f -= 1 - assert_equal(1.0, f) - ++f - --f - assert_equal(1.0, f) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -let g:someNumber = 43 - -def Test_assign_concat() - var lines =<< trim END - var s = '-' - s ..= 99 - s ..= true - s ..= '-' - s ..= v:null - s ..= g:someNumber - assert_equal('-99true-null43', s) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var s = '-' - s ..= [1, 2] - END - v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert list to string', 'E734: Wrong variable type for .='], 2) - lines =<< trim END - var s = '-' - s ..= {a: 2} - END - v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2) - - lines =<< trim END - var ls: list<string> = [] - ls[-1] ..= 'foo' - END - v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: -1', 2) -enddef - -def Test_assign_register() - var lines =<< trim END - @c = 'areg' - @c ..= 'add' - assert_equal('aregadd', @c) - - @@ = 'some text' - assert_equal('some text', getreg('"')) - END - v9.CheckDefAndScriptSuccess(lines) - - v9.CheckDefFailure(['@a += "more"'], 'E1051:') - v9.CheckDefFailure(['@a += 123'], 'E1012:') -enddef - -def Test_reserved_name() - var more_names = ['null_job', 'null_channel'] - if !has('job') - more_names = [] - endif - - for name in ['true', - 'false', - 'this', - 'super', - 'null', - 'null_blob', - 'null_dict', - 'null_function', - 'null_list', - 'null_partial', - 'null_string', - ] + more_names - v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' = 0'], 'E1034:') - v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:') - endfor - - var lines =<< trim END - vim9script - def Foo(super: bool) - echo 'something' - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1034:') -enddef - -def Test_null_values() - var lines =<< trim END - var b: blob = null_blob - var dn: dict<number> = null_dict - var ds: dict<string> = null_dict - var ln: list<number> = null_list - var ls: list<string> = null_list - var Ff: func(string): string = null_function - var Fp: func(number): number = null_partial - var s: string = null_string - if has('job') - var j: job = null_job - var c: channel = null_channel - endif - - var d: dict<func> = {a: function('tr'), b: null_function} - - var bl: list<blob> = [0z12, null_blob] - var dnl: list<dict<number>> = [{a: 1}, null_dict] - var dsl: list<dict<string>> = [{a: 'x'}, null_dict] - var lnl: list<list<number>> = [[1], null_list] - var lsl: list<list<string>> = [['x'], null_list] - def Len(v: string): number - return len(v) - enddef - var Ffl: list<func(string): number> = [Len, null_function] - var Fpl: list<func(string): number> = [Len, null_partial] - var sl: list<string> = ['x', null_string] - if has('job') - var jl: list<job> = [null_job] - var cl: list<channel> = [null_channel] - endif - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_type_with_extra_white() - var lines =<< trim END - const x : number = 3 - END - v9.CheckDefExecAndScriptFailure(lines, 'E1059') -enddef - -def Test_keep_type_after_assigning_null() - var lines =<< trim END - var b: blob - b = null_blob - b = 'text' - END - v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected blob but got string') - - lines =<< trim END - var l: list<number> - l = null_list - l = ['text'] - END - v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') - - lines =<< trim END - var d: dict<string> - d = null_dict - d = {a: 1, b: 2} - END - v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<string> but got dict<number>') -enddef - -def Test_skipped_assignment() - var lines =<< trim END - for x in [] - var i: number = 1 - while false - i += 1 - endwhile - endfor - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_assign_keep_type() - var lines =<< trim END - vim9script - var l: list<number> = [123] - l = [123] - l->add('string') - END - v9.CheckScriptFailure(lines, 'E1012:', 4) -enddef - -def Test_assign_unpack() - var lines =<< trim END - var v1: number - var v2: number - [v1, v2] = [1, 2] - assert_equal(1, v1) - assert_equal(2, v2) - - [v1, _, v2, _] = [1, 99, 2, 77] - assert_equal(1, v1) - assert_equal(2, v2) - - [v1, v2; _] = [1, 2, 3, 4, 5] - assert_equal(1, v1) - assert_equal(2, v2) - - var _x: number - [_x, v2] = [6, 7] - assert_equal(6, _x) - assert_equal(7, v2) - - var reslist = [] - for text in ['aaa {bbb} ccc', 'ddd {eee} fff'] - var before: string - var middle: string - var after: string - [_, before, middle, after; _] = text->matchlist('\(.\{-\}\){\(.\{-\}\)}\(.*\)') - reslist->add(before)->add(middle)->add(after) - endfor - assert_equal(['aaa ', 'bbb', ' ccc', 'ddd ', 'eee', ' fff'], reslist) - - var a = 1 - var b = 3 - [a, b] += [2, 4] - assert_equal(3, a) - assert_equal(7, b) - - [a, b] -= [1, 2] - assert_equal(2, a) - assert_equal(5, b) - - [a, b] *= [3, 2] - assert_equal(6, a) - assert_equal(10, b) - - [a, b] /= [2, 4] - assert_equal(3, a) - assert_equal(2, b) - - [a, b] = [17, 15] - [a, b] %= [5, 3] - assert_equal(2, a) - assert_equal(0, b) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = [1, 2, 3] - END - v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 3', 3) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = [1] - END - v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2; _] = [1] - END - v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = - END - v9.CheckDefFailure(lines, 'E1097:', 5) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = xxx - END - v9.CheckDefFailure(lines, 'E1001:', 3) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = popup_clear() - END - v9.CheckDefFailure(lines, 'E1031:', 3) - - lines =<< trim END - [v1, v2] = [1, 2] - END - v9.CheckDefFailure(lines, 'E1089', 1) - v9.CheckScriptFailure(['vim9script'] + lines, 'E1089', 2) - - lines =<< trim END - var v1: number - var v2: number - [v1, v2] = '' - END - v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<any> but got string', 3) - - lines =<< trim END - g:values = [false, 0] - var x: bool - var y: string - [x, y] = g:values - END - v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 2: type mismatch, expected string but got number') - - lines =<< trim END - var x: number - var y: number - var z: string - [x, y, z] = [1, 2, 3] - END - v9.CheckDefAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') - - lines =<< trim END - var x: number - var y: string - var z: string - [x, y, z] = [1, '2', 3] - END - v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') -enddef - -def Test_assign_linebreak() - var nr: number - nr = - 123 - assert_equal(123, nr) - - var n2: number - [nr, n2] = - [12, 34] - assert_equal(12, nr) - assert_equal(34, n2) - - v9.CheckDefFailure(["var x = #"], 'E1097:', 3) - - var lines =<< trim END - var x: list<string> = ['a'] - var y: list<number> = x - ->copy() - ->copy() - END - v9.CheckDefExecFailure(lines, 'E1012:', 4) - - lines =<< trim END - var x: any - x.key = 1 - + 2 - + 3 - + 4 - + 5 - END - v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203:'], 2) -enddef - -def Test_assign_index() - # list of list - var l1: list<number> - l1[0] = 123 - assert_equal([123], l1) - - var l2: list<list<number>> - l2[0] = [] - l2[0][0] = 123 - assert_equal([[123]], l2) - - var l3: list<list<list<number>>> - l3[0] = [] - l3[0][0] = [] - l3[0][0][0] = 123 - assert_equal([[[123]]], l3) - - var lines =<< trim END - var l3: list<list<number>> - l3[0] = [] - l3[0][0] = [] - END - v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3) - - # dict of dict - var d1: dict<number> - d1.one = 1 - assert_equal({one: 1}, d1) - - var d2: dict<dict<number>> - d2.one = {} - d2.one.two = 123 - assert_equal({one: {two: 123}}, d2) - - var d3: dict<dict<dict<number>>> - d3.one = {} - d3.one.two = {} - d3.one.two.three = 123 - assert_equal({one: {two: {three: 123}}}, d3) - - # blob - var bl: blob = 0z11223344 - bl[0] = 0x77 - assert_equal(0z77223344, bl) - bl[-2] = 0x66 - assert_equal(0z77226644, bl) - - lines =<< trim END - g:val = '22' - var bl = 0z11 - bl[1] = g:val - END - v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"') - - # should not read the next line when generating "a.b" - var a = {} - a.b = {} - a.b.c = {} - ->copy() - - lines =<< trim END - var d3: dict<dict<number>> - d3.one = {} - d3.one.two = {} - END - v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3) - - lines =<< trim END - var lines: list<string> - lines['a'] = 'asdf' - END - v9.CheckDefFailure(lines, 'E1012:', 2) - - lines =<< trim END - var lines: string - lines[9] = 'asdf' - END - v9.CheckDefFailure(lines, 'E1141:', 2) - - # list of dict - var ld: list<dict<number>> - ld[0] = {} - ld[0].one = 123 - assert_equal([{one: 123}], ld) - - lines =<< trim END - var ld: list<dict<number>> - ld[0] = [] - END - v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2) - - # dict of list - var dl: dict<list<number>> - dl.one = [] - dl.one[0] = 123 - assert_equal({one: [123]}, dl) - - lines =<< trim END - var dl: dict<list<number>> - dl.one = {} - END - v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2) - - lines =<< trim END - g:l = [1, 2] - g:l['x'] = 3 - END - v9.CheckDefExecAndScriptFailure(lines, ['E39:', 'E1030:'], 2) - - lines =<< trim END - var bl: blob = test_null_blob() - bl[1] = 8 - END - v9.CheckDefExecAndScriptFailure(lines, ['E1184:', 'E979:'], 2) - - lines =<< trim END - g:bl = 'not a blob' - g:bl[1 : 2] = 8 - END - v9.CheckDefExecAndScriptFailure(lines, ['E897:', 'E689:'], 2) -enddef - -def Test_init_in_for_loop() - var lines =<< trim END - var l: list<number> = [] - for i in [3, 4] - var n: number - add(l, n) - n = 123 - endfor - assert_equal([0, 0], l) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var l: list<number> = [] - for i in [3, 4] - var n: number = 0 - add(l, n) - n = 123 - endfor - assert_equal([0, 0], l) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var l: list<number> = [] - for i in [3, 4] - var n: number = 3 - add(l, n) - n = 123 - endfor - assert_equal([3, 3], l) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_redir_is_not_assign() - if false - redir => res - echo var_job - redir END - endif -enddef - -def Test_extend_list() - # using uninitialized list assigns empty list - var lines =<< trim END - var l1: list<number> - var l2 = l1 - assert_true(l1 is l2) - l1 += [123] - assert_equal([123], l1) - assert_true(l1 is l2) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var list: list<string> - extend(list, ['x']) - assert_equal(['x'], list) - END - v9.CheckDefAndScriptSuccess(lines) - - # appending to uninitialized list from a function works - lines =<< trim END - vim9script - var list: list<string> - def Func() - list += ['a', 'b'] - enddef - Func() - assert_equal(['a', 'b'], list) - END - v9.CheckScriptSuccess(lines) - lines =<< trim END - vim9script - var list: list<string> - def Func() - extend(list, ['x', 'b']) - enddef - Func() - assert_equal(['x', 'b'], list) - END - v9.CheckScriptSuccess(lines) - - # initialized to null, with type, does not default to empty list - lines =<< trim END - vim9script - var l: list<string> = test_null_list() - extend(l, ['x']) - END - v9.CheckScriptFailure(lines, 'E1134:', 3) - - # initialized to null, without type, does not default to empty list - lines =<< trim END - vim9script - var l = null_list - extend(l, ['x']) - END - v9.CheckScriptFailure(lines, 'E1134:', 3) - - # assigned null, does not default to empty list - lines =<< trim END - vim9script - var l: list<string> - l = null_list - extend(l, ['x']) - END - v9.CheckScriptFailure(lines, 'E1134:', 4) - - lines =<< trim END - vim9script - extend(test_null_list(), ['x']) - END - v9.CheckScriptFailure(lines, 'E1134:', 2) - - # using global var has no declared type - g:myList = [] - g:myList->extend([1]) - g:myList->extend(['x']) - assert_equal([1, 'x'], g:myList) - unlet g:myList - - # using declared list gives an error - lines =<< trim END - var l: list<number> - g:myList = l - g:myList->extend([1]) - g:myList->extend(['x']) - END - v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4) - unlet g:myList - - lines =<< trim END - vim9script - var lds = [1, 2, 3] - def Func() - echo lds->extend(['x']) - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1013:') -enddef - -def Test_extend_dict() - var lines =<< trim END - vim9script - var d: dict<number> - extend(d, {a: 1}) - assert_equal({a: 1}, d) - - var d2: dict<number> - d2['one'] = 1 - assert_equal({one: 1}, d2) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var d: dict<string> = test_null_dict() - extend(d, {a: 'x'}) - END - v9.CheckScriptFailure(lines, 'E1133:', 3) - - lines =<< trim END - vim9script - extend(test_null_dict(), {a: 'x'}) - END - v9.CheckScriptFailure(lines, 'E1133:', 2) -enddef - -def Test_single_letter_vars() - # single letter variables - var a: number = 123 - a = 123 - assert_equal(123, a) - var b: number - b = 123 - assert_equal(123, b) - var g: number - g = 123 - assert_equal(123, g) - var s: number - s = 123 - assert_equal(123, s) - var t: number - t = 123 - assert_equal(123, t) - var v: number - v = 123 - assert_equal(123, v) - var w: number - w = 123 - assert_equal(123, w) -enddef - -def Test_vim9_single_char_vars() - var lines =<< trim END - vim9script - - # single character variable declarations work - var a: string - var b: number - var l: list<any> - var s: string - var t: number - var v: number - var w: number - - # script-local variables can be used without s: prefix - a = 'script-a' - b = 111 - l = [1, 2, 3] - s = 'script-s' - t = 222 - v = 333 - w = 444 - - assert_equal('script-a', a) - assert_equal(111, b) - assert_equal([1, 2, 3], l) - assert_equal('script-s', s) - assert_equal(222, t) - assert_equal(333, v) - assert_equal(444, w) - END - writefile(lines, 'Xsinglechar', 'D') - source Xsinglechar -enddef - -def Test_assignment_list() - var list1: list<bool> = [false, true, false] - var list2: list<number> = [1, 2, 3] - var list3: list<string> = ['sdf', 'asdf'] - var list4: list<any> = ['yes', true, 1234] - var list5: list<blob> = [0z01, 0z02] - - var listS: list<string> = [] - var listN: list<number> = [] - - assert_equal([1, 2, 3], list2) - list2[-1] = 99 - assert_equal([1, 2, 99], list2) - list2[-2] = 88 - assert_equal([1, 88, 99], list2) - list2[-3] = 77 - assert_equal([77, 88, 99], list2) - list2 += [100] - assert_equal([77, 88, 99, 100], list2) - - list3 += ['end'] - assert_equal(['sdf', 'asdf', 'end'], list3) - - v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') - v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[8 : 9]'], 'E684:') - v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[1 : -9]'], 'E684:') - v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[2 : 1]'], 'E684:') - - # type becomes list<any> - var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] - - # type is list<any> even though initializer is list<number> - var anyList: list<any> = [0] - assert_equal([0, 'x'], extend(anyList, ['x'])) - - var lines =<< trim END - var d = {dd: test_null_list()} - d.dd[0] = 0 - END - v9.CheckDefExecFailure(lines, 'E1147:', 2) - - lines =<< trim END - def OneArg(x: bool) - enddef - def TwoArgs(x: bool, y: bool) - enddef - var fl: list<func(bool, bool, bool)> = [OneArg, TwoArgs] - END - v9.CheckDefExecAndScriptFailure(lines, 'E1012:', 5) -enddef - -def Test_list_declaration() - var [v1, v2] = [1, 2] - v1 += 3 - assert_equal(4, v1) - v2 *= 3 - assert_equal(6, v2) - - var lines =<< trim END - var [v1, v2] = [1] - END - v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) - lines =<< trim END - var testlist = [1] - var [v1, v2] = testlist - END - v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) - lines =<< trim END - var [v1, v2] = [1, 2, 3] - END - v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) - lines =<< trim END - var testlist = [1, 2, 3] - var [v1, v2] = testlist - END - v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) - - var [vnr, vstr] = [123, 'text'] - vnr += 3 - assert_equal(126, vnr) - vstr ..= 'end' - assert_equal('textend', vstr) - - var [vnr2: number, vstr2: string] = [123, 'text'] - vnr2 += 3 - assert_equal(126, vnr2) - vstr2 ..= 'end' - assert_equal('textend', vstr2) - - var [vnr3: number; vlist: list<string>] = [123, 'foo', 'bar'] - vnr3 += 5 - assert_equal(128, vnr3) - assert_equal(['foo', 'bar'], vlist) - - lines =<< trim END - var [vnr2: number, vstr2: number] = [123, 'text'] - END - v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) - lines =<< trim END - var testlist = [234, 'text'] - var [vnr2: number, vstr2: number] = testlist - END - v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) -enddef - -def PartFuncBool(b: bool): string - return 'done' -enddef - -def Test_assignment_partial() - var lines =<< trim END - var Partial: func(): string = function(g:PartFuncBool, [true]) - assert_equal('done', Partial()) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - vim9script - def Func(b: bool) - enddef - var Ref: func = function(Func, [true]) - assert_equal('func()', typename(Ref)) - Ref() - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - - var nres: any - var sres: any - def Func(nr: number, s = '') - nres = nr - sres = s - enddef - - var n: number - var Ref = function(Func, [n]) - Ref('x') - assert_equal(0, nres) - assert_equal('x', sres) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - - def Func(nr: number, s = '') - enddef - - var n: number - var Ref = function(Func, [n]) - Ref(0) - END - v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number') -enddef - -def Test_assignment_list_any_index() - var l: list<number> = [1, 2] - for [x, y, _] - in [[0, 1, ''], [1, 3, '']] - l[x] = l[x] + y - endfor - assert_equal([2, 5], l) -enddef - -def Test_assignment_list_vim9script() - var lines =<< trim END - vim9script - var v1: number - var v2: number - var v3: number - [v1, v2, v3] = [1, 2, 3] - assert_equal([1, 2, 3], [v1, v2, v3]) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_assignment_dict() - var dict1: dict<bool> = {one: false, two: true} - var dict2: dict<number> = {one: 1, two: 2} - var dict3: dict<string> = {key: 'value'} - var dict4: dict<any> = {one: 1, two: '2'} - var dict5: dict<blob> = {one: 0z01, two: 0z02} - - # check the type is OK - var events: dict<string> = v:event - - # overwrite - dict3['key'] = 'another' - assert_equal(dict3, {key: 'another'}) - dict3.key = 'yet another' - assert_equal(dict3, {key: 'yet another'}) - - # member "any" can also be a dict and assigned to - var anydict: dict<any> = {nest: {}, nr: 0} - anydict.nest['this'] = 123 - anydict.nest.that = 456 - assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict) - - var lines =<< trim END - var dd = {} - dd.two = 2 - assert_equal({two: 2}, dd) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var d = {dd: {}} - d.dd[0] = 2 - d.dd['x'] = 3 - d.dd.y = 4 - assert_equal({dd: {0: 2, x: 3, y: 4}}, d) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var key = 'foo' - g:[key] = 'value' - assert_equal('value', g:foo) - unlet g:foo - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var dd = {one: 1} - dd.one) = 2 - END - v9.CheckDefFailure(lines, 'E488:', 2) - - lines =<< trim END - var dd = {one: 1} - var dd.one = 2 - END - v9.CheckDefAndScriptFailure(lines, 'E1017:', 2) - - # empty key can be used - var dd = {} - dd[""] = 6 - assert_equal({['']: 6}, dd) - - # type becomes dict<any> - var somedict = rand() > 0 ? {a: 1, b: 2} : {a: 'a', b: 'b'} - - # type is dict<any> even though initializer is dict<number> - var anyDict: dict<any> = {a: 0} - assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'})) - - # using global var, which has no declared type - g:myDict = {} - g:myDict->extend({a: 1}) - g:myDict->extend({b: 'x'}) - assert_equal({a: 1, b: 'x'}, g:myDict) - unlet g:myDict - - # using list with declared type gives an error - lines =<< trim END - var d: dict<number> - g:myDict = d - g:myDict->extend({a: 1}) - g:myDict->extend({b: 'x'}) - END - v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4) - unlet g:myDict - - # assignment to script-local dict - lines =<< trim END - vim9script - var test: dict<any> = {} - def FillDict(): dict<any> - test['a'] = 43 - return test - enddef - assert_equal({a: 43}, FillDict()) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var test: dict<any> - def FillDict(): dict<any> - test['a'] = 43 - return test - enddef - FillDict() - assert_equal({a: 43}, test) - END - v9.CheckScriptSuccess(lines) - - # assignment to global dict - lines =<< trim END - vim9script - g:test = {} - def FillDict(): dict<any> - g:test['a'] = 43 - return g:test - enddef - assert_equal({a: 43}, FillDict()) - END - v9.CheckScriptSuccess(lines) - - # assignment to buffer dict - lines =<< trim END - vim9script - b:test = {} - def FillDict(): dict<any> - b:test['a'] = 43 - return b:test - enddef - assert_equal({a: 43}, FillDict()) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - var d = {dd: test_null_dict()} - d.dd[0] = 0 - END - v9.CheckDefExecFailure(lines, 'E1103:', 2) - - lines =<< trim END - var d = {dd: 'string'} - d.dd[0] = 0 - END - v9.CheckDefExecFailure(lines, 'E1148:', 2) - - lines =<< trim END - var n: any - n.key = 5 - END - v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203: Dot can only be used on a dictionary: n.key = 5'], 2) -enddef - -def Test_assignment_local() - # Test in a separated file in order not to the current buffer/window/tab is - # changed. - var script_lines: list<string> =<< trim END - let b:existing = 'yes' - let w:existing = 'yes' - let t:existing = 'yes' - - def Test_assignment_local_internal() - b:newvar = 'new' - assert_equal('new', b:newvar) - assert_equal('yes', b:existing) - b:existing = 'no' - assert_equal('no', b:existing) - b:existing ..= 'NO' - assert_equal('noNO', b:existing) - - w:newvar = 'new' - assert_equal('new', w:newvar) - assert_equal('yes', w:existing) - w:existing = 'no' - assert_equal('no', w:existing) - w:existing ..= 'NO' - assert_equal('noNO', w:existing) - - t:newvar = 'new' - assert_equal('new', t:newvar) - assert_equal('yes', t:existing) - t:existing = 'no' - assert_equal('no', t:existing) - t:existing ..= 'NO' - assert_equal('noNO', t:existing) - enddef - call Test_assignment_local_internal() - END - v9.CheckScriptSuccess(script_lines) -enddef - -def Test_assignment_default() - # Test default values. - var thebool: bool - assert_equal(v:false, thebool) - - var thenumber: number - assert_equal(0, thenumber) - - var thefloat: float - assert_equal(0.0, thefloat) - - var thestring: string - assert_equal('', thestring) - - var theblob: blob - assert_equal(0z, theblob) - - var Thefunc: func - assert_equal(test_null_function(), Thefunc) - - var thelist: list<any> - assert_equal([], thelist) - - var thedict: dict<any> - assert_equal({}, thedict) - - if has('channel') - var thejob: job - assert_equal(test_null_job(), thejob) - - var thechannel: channel - assert_equal(test_null_channel(), thechannel) - - if has('unix') && executable('cat') - # check with non-null job and channel, types must match - thejob = job_start("cat ", {}) - thechannel = job_getchannel(thejob) - job_stop(thejob, 'kill') - endif - endif - - var nr = 1234 | nr = 5678 - assert_equal(5678, nr) -enddef - -def Test_script_var_default() - var lines =<< trim END - vim9script - var l: list<number> - var li = [1, 2] - var bl: blob - var bli = 0z12 - var d: dict<number> - var di = {'a': 1, 'b': 2} - def Echo() - assert_equal([], l) - assert_equal([1, 2], li) - assert_equal(0z, bl) - assert_equal(0z12, bli) - assert_equal({}, d) - assert_equal({'a': 1, 'b': 2}, di) - enddef - Echo() - END - v9.CheckScriptSuccess(lines) -enddef - -let s:scriptvar = 'init' - -def Test_assignment_var_list() - var lines =<< trim END - var v1: string - var v2: string - var vrem: list<string> - [v1] = ['aaa'] - assert_equal('aaa', v1) - - [v1, v2] = ['one', 'two'] - assert_equal('one', v1) - assert_equal('two', v2) - - [v1, v2; vrem] = ['one', 'two'] - assert_equal('one', v1) - assert_equal('two', v2) - assert_equal([], vrem) - - [v1, v2; vrem] = ['one', 'two', 'three'] - assert_equal('one', v1) - assert_equal('two', v2) - assert_equal(['three'], vrem) - - [&ts, &sw] = [3, 4] - assert_equal(3, &ts) - assert_equal(4, &sw) - set ts=8 sw=4 - - [@a, @z] = ['aa', 'zz'] - assert_equal('aa', @a) - assert_equal('zz', @z) - - [$SOME_VAR, $OTHER_VAR] = ['some', 'other'] - assert_equal('some', $SOME_VAR) - assert_equal('other', $OTHER_VAR) - - [g:globalvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = - ['global', 'buf', 'win', 'tab', 'error'] - assert_equal('global', g:globalvar) - assert_equal('buf', b:bufvar) - assert_equal('win', w:winvar) - assert_equal('tab', t:tabvar) - assert_equal('error', v:errmsg) - unlet g:globalvar - END - v9.CheckDefAndScriptSuccess(lines) - - [g:globalvar, scriptvar, b:bufvar] = ['global', 'script', 'buf'] - assert_equal('global', g:globalvar) - assert_equal('script', scriptvar) - assert_equal('buf', b:bufvar) - - lines =<< trim END - vim9script - var scriptvar = 'init' - [g:globalvar, scriptvar, w:winvar] = ['global', 'script', 'win'] - assert_equal('global', g:globalvar) - assert_equal('script', scriptvar) - assert_equal('win', w:winvar) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_assignment_empty_list() - var lines =<< trim END - var l2: list<any> = [] - var l: list<string> - l = l2 - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_assignment_vim9script() - var lines =<< trim END - vim9script - def Func(): list<number> - return [1, 2] - enddef - var name1: number - var name2: number - [name1, name2] = - Func() - assert_equal(1, name1) - assert_equal(2, name2) - var ll = - Func() - assert_equal([1, 2], ll) - - @/ = 'text' - assert_equal('text', @/) - @0 = 'zero' - assert_equal('zero', @0) - @1 = 'one' - assert_equal('one', @1) - @9 = 'nine' - assert_equal('nine', @9) - @- = 'minus' - assert_equal('minus', @-) - if has('clipboard_working') - @* = 'star' - assert_equal('star', @*) - @+ = 'plus' - assert_equal('plus', @+) - endif - - var a: number = 123 - assert_equal(123, a) - var s: string = 'yes' - assert_equal('yes', s) - var b: number = 42 - assert_equal(42, b) - var w: number = 43 - assert_equal(43, w) - var t: number = 44 - assert_equal(44, t) - - var to_var = 0 - to_var = 3 - assert_equal(3, to_var) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var n: number - def Func() - n = 'string' - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string') -enddef - -def Mess(): string - v:foldstart = 123 - return 'xxx' -enddef - -def Test_assignment_failure() - v9.CheckDefFailure(['var name=234'], 'E1004:') - v9.CheckDefFailure(['var name =234'], 'E1004:') - v9.CheckDefFailure(['var name= 234'], 'E1004:') - - v9.CheckScriptFailure(['vim9script', 'var name=234'], 'E1004:') - v9.CheckScriptFailure(['vim9script', 'var name=234'], "before and after '='") - v9.CheckScriptFailure(['vim9script', 'var name =234'], 'E1004:') - v9.CheckScriptFailure(['vim9script', 'var name= 234'], 'E1004:') - v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], 'E1004:') - v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], "before and after '+='") - v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], 'E1004:') - v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], "before and after '..='") - - v9.CheckDefFailure(['var true = 1'], 'E1034:') - v9.CheckDefFailure(['var false = 1'], 'E1034:') - v9.CheckDefFailure(['var null = 1'], 'E1034:') - v9.CheckDefFailure(['var this = 1'], 'E1034:') - v9.CheckDefFailure(['var super = 1'], 'E1034:') - - v9.CheckDefFailure(['[a; b; c] = g:list'], 'E1001:') - v9.CheckDefFailure(['var [a; b; c] = g:list'], 'E1080:') - v9.CheckDefExecFailure(['var a: number', - '[a] = test_null_list()'], 'E1093:') - v9.CheckDefExecFailure(['var a: number', - '[a] = []'], 'E1093:') - v9.CheckDefExecFailure(['var x: number', - 'var y: number', - '[x, y] = [1]'], 'E1093:') - v9.CheckDefExecFailure(['var x: string', - 'var y: string', - '[x, y] = ["x"]'], 'E1093:') - v9.CheckDefExecFailure(['var x: number', - 'var y: number', - 'var z: list<number>', - '[x, y; z] = [1]'], 'E1093:') - - v9.CheckDefFailure(['var somevar'], "E1022:") - v9.CheckDefFailure(['var &tabstop = 4'], 'E1052:') - v9.CheckDefFailure(['&g:option = 5'], 'E113:') - v9.CheckScriptFailure(['vim9script', 'var &tabstop = 4'], 'E1052:') - - v9.CheckDefFailure(['var $VAR = 5'], 'E1016: Cannot declare an environment variable:') - v9.CheckScriptFailure(['vim9script', 'var $ENV = "xxx"'], 'E1016:') - - if has('dnd') - v9.CheckDefFailure(['var @~ = 5'], 'E1066:') - else - v9.CheckDefFailure(['var @~ = 5'], 'E354:') - v9.CheckDefFailure(['@~ = 5'], 'E354:') - endif - v9.CheckDefFailure(['var @a = 5'], 'E1066:') - v9.CheckDefFailure(['var @/ = "x"'], 'E1066:') - v9.CheckScriptFailure(['vim9script', 'var @a = "abc"'], 'E1066:') - - v9.CheckDefFailure(['var g:var = 5'], 'E1016: Cannot declare a global variable:') - v9.CheckDefFailure(['var w:var = 5'], 'E1016: Cannot declare a window variable:') - v9.CheckDefFailure(['var b:var = 5'], 'E1016: Cannot declare a buffer variable:') - v9.CheckDefFailure(['var t:var = 5'], 'E1016: Cannot declare a tab variable:') - - v9.CheckDefFailure(['var anr = 4', 'anr ..= "text"'], 'E1019:') - v9.CheckDefFailure(['var xnr += 4'], 'E1020:', 1) - v9.CheckScriptFailure(['vim9script', 'var xnr += 4'], 'E1020:') - v9.CheckDefFailure(["var xnr = xnr + 1"], 'E1001:', 1) - v9.CheckScriptFailure(['vim9script', 'var xnr = xnr + 4'], 'E121:') - - v9.CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = notfound', 'enddef', 'defcompile'], 'E1001:') - - v9.CheckDefFailure(['var name: list<string> = [123]'], 'expected list<string> but got list<number>') - v9.CheckDefFailure(['var name: list<number> = ["xx"]'], 'expected list<number> but got list<string>') - - v9.CheckDefFailure(['var name: dict<string> = {key: 123}'], 'expected dict<string> but got dict<number>') - v9.CheckDefFailure(['var name: dict<number> = {key: "xx"}'], 'expected dict<number> but got dict<string>') - - v9.CheckDefFailure(['var name = feedkeys("0")'], 'E1031:') - v9.CheckDefFailure(['var name: number = feedkeys("0")'], 'expected number but got void') - - v9.CheckDefFailure(['var name: dict <number>'], 'E1068:') - v9.CheckDefFailure(['var name: dict<number'], 'E1009: Missing > after type: <number') - - assert_fails('s/^/\=g:Mess()/n', 'E794:') - v9.CheckDefFailure(['var name: dict<number'], 'E1009:') - - v9.CheckDefFailure(['w:foo: number = 10'], - 'E1016: Cannot declare a window variable: w:foo') - v9.CheckDefFailure(['t:foo: bool = true'], - 'E1016: Cannot declare a tab variable: t:foo') - v9.CheckDefFailure(['b:foo: string = "x"'], - 'E1016: Cannot declare a buffer variable: b:foo') - v9.CheckDefFailure(['g:foo: number = 123'], - 'E1016: Cannot declare a global variable: g:foo') - - v9.CheckScriptFailure(['vim9script', 'w:foo: number = 123'], - 'E1304: Cannot use type with this variable: w:foo:') - v9.CheckScriptFailure(['vim9script', 't:foo: number = 123'], - 'E1304: Cannot use type with this variable: t:foo:') - v9.CheckScriptFailure(['vim9script', 'b:foo: number = 123'], - 'E1304: Cannot use type with this variable: b:foo:') - v9.CheckScriptFailure(['vim9script', 'g:foo: number = 123'], - 'E1304: Cannot use type with this variable: g:foo:') - - v9.CheckScriptFailure(['vim9script', 'const w:FOO: number = 123'], - 'E1304: Cannot use type with this variable: w:FOO:') - v9.CheckScriptFailure(['vim9script', 'const t:FOO: number = 123'], - 'E1304: Cannot use type with this variable: t:FOO:') - v9.CheckScriptFailure(['vim9script', 'const b:FOO: number = 123'], - 'E1304: Cannot use type with this variable: b:FOO:') - v9.CheckScriptFailure(['vim9script', 'const g:FOO: number = 123'], - 'E1304: Cannot use type with this variable: g:FOO:') -enddef - -def Test_assign_list() - var lines =<< trim END - var l: list<string> = [] - l[0] = 'value' - assert_equal('value', l[0]) - - l[1] = 'asdf' - assert_equal('value', l[0]) - assert_equal('asdf', l[1]) - assert_equal('asdf', l[-1]) - assert_equal('value', l[-2]) - - var nrl: list<number> = [] - for i in range(5) - nrl[i] = i - endfor - assert_equal([0, 1, 2, 3, 4], nrl) - - var ul: list<any> - ul[0] = 1 - ul[1] = 2 - ul[2] = 3 - assert_equal([1, 2, 3], ul) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var l = [1, 2] - g:idx = 'x' - l[g:idx : 1] = [0] - echo l - END - v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "x"']) - - lines =<< trim END - var l = [1, 2] - g:idx = 3 - l[g:idx : 1] = [0] - echo l - END - v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: 3') - - lines =<< trim END - var l = [1, 2] - g:idx = 'y' - l[1 : g:idx] = [0] - echo l - END - v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "y"']) - - v9.CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1) - v9.CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1) -enddef - -def Test_assign_dict() - var lines =<< trim END - var d: dict<string> = {} - d['key'] = 'value' - assert_equal('value', d['key']) - - d[123] = 'qwerty' - assert_equal('qwerty', d[123]) - assert_equal('qwerty', d['123']) - - var nrd: dict<number> = {} - for i in range(3) - nrd[i] = i - endfor - assert_equal({0: 0, 1: 1, 2: 2}, nrd) - - d.somekey = 'someval' - assert_equal({key: 'value', '123': 'qwerty', somekey: 'someval'}, d) - unlet d.somekey - assert_equal({key: 'value', '123': 'qwerty'}, d) - END - v9.CheckDefAndScriptSuccess(lines) - - v9.CheckDefFailure(["var d: dict<number> = {a: '', b: true}"], 'E1012: Type mismatch; expected dict<number> but got dict<any>', 1) - v9.CheckDefFailure(["var d: dict<dict<number>> = {x: {a: '', b: true}}"], 'E1012: Type mismatch; expected dict<dict<number>> but got dict<dict<any>>', 1) - v9.CheckDefFailure(["var d = {x: 1}", "d[1 : 2] = {y: 2}"], 'E1165: Cannot use a range with an assignment: d[1 : 2] =', 2) -enddef - -def Test_assign_dict_unknown_type() - var lines =<< trim END - vim9script - var mylist = [] - mylist += [{one: 'one'}] - def Func() - var dd = mylist[0] - assert_equal('one', dd.one) - enddef - Func() - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var mylist = [[]] - mylist[0] += [{one: 'one'}] - def Func() - var dd = mylist[0][0] - assert_equal('one', dd.one) - enddef - Func() - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_assign_dict_with_op() - var lines =<< trim END - var ds: dict<string> = {a: 'x'} - ds['a'] ..= 'y' - ds.a ..= 'z' - assert_equal('xyz', ds.a) - - var dn: dict<number> = {a: 9} - dn['a'] += 2 - assert_equal(11, dn.a) - dn.a += 2 - assert_equal(13, dn.a) - - dn['a'] -= 3 - assert_equal(10, dn.a) - dn.a -= 2 - assert_equal(8, dn.a) - - dn['a'] *= 2 - assert_equal(16, dn.a) - dn.a *= 2 - assert_equal(32, dn.a) - - dn['a'] /= 3 - assert_equal(10, dn.a) - dn.a /= 2 - assert_equal(5, dn.a) - - dn['a'] %= 3 - assert_equal(2, dn.a) - dn.a %= 6 - assert_equal(2, dn.a) - - var dd: dict<dict<list<any>>> - dd.a = {} - dd.a.b = [0] - dd.a.b += [1] - assert_equal({a: {b: [0, 1]}}, dd) - - var dab = {a: ['b']} - dab.a[0] ..= 'c' - assert_equal({a: ['bc']}, dab) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_assign_list_with_op() - var lines =<< trim END - var ls: list<string> = ['x'] - ls[0] ..= 'y' - assert_equal('xy', ls[0]) - - var ln: list<number> = [9] - ln[0] += 2 - assert_equal(11, ln[0]) - - ln[0] -= 3 - assert_equal(8, ln[0]) - - ln[0] *= 2 - assert_equal(16, ln[0]) - - ln[0] /= 3 - assert_equal(5, ln[0]) - - ln[0] %= 3 - assert_equal(2, ln[0]) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_assign_with_op_fails() - var lines =<< trim END - var s = 'abc' - s[1] += 'x' - END - v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) - - lines =<< trim END - var s = 'abc' - s[1] ..= 'x' - END - v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) - - lines =<< trim END - var dd: dict<dict<list<any>>> - dd.a = {} - dd.a.b += [1] - END - v9.CheckDefExecAndScriptFailure(lines, 'E716:', 3) -enddef - -def Test_assign_lambda() - # check if assign a lambda to a variable which type is func or any. - var lines =<< trim END - vim9script - var FuncRef = () => 123 - assert_equal(123, FuncRef()) - var FuncRef_Func: func = () => 123 - assert_equal(123, FuncRef_Func()) - var FuncRef_Any: any = () => 123 - assert_equal(123, FuncRef_Any()) - var FuncRef_Number: func(): number = () => 321 - assert_equal(321, FuncRef_Number()) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - var Ref: func(number) - Ref = (j) => !j - END - v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') - - lines =<< trim END - echo filter([1, 2, 3], (_, v: string) => v + 1) - END - v9.CheckDefAndScriptFailure(lines, 'E1051:') -enddef - -def Test_heredoc() - # simple heredoc - var lines =<< trim END - var text =<< trim TEXT # comment - abc - TEXT - assert_equal(['abc'], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # empty heredoc - lines =<< trim END - var text =<< trim TEXT - TEXT - assert_equal([], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # heredoc with a single empty line - lines =<< trim END - var text =<< trim TEXT - - TEXT - assert_equal([''], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # assign heredoc to variable with type - lines =<< trim END - var text: list<string> =<< trim TEXT - var foo =<< trim FOO - TEXT - assert_equal(['var foo =<< trim FOO'], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # extra whitespace before type is allowed - lines =<< trim END - var text: list<string> =<< trim TEXT - var foo =<< trim FOO - TEXT - assert_equal(['var foo =<< trim FOO'], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # missing whitespace before type is an error - lines =<< trim END - var text:list<string> =<< trim TEXT - var foo =<< trim FOO - TEXT - assert_equal(['var foo =<< trim FOO'], text) - END - v9.CheckDefAndScriptFailure(lines, 'E1069:') - - # assign heredoc to list slice - lines =<< trim END - var text = [''] - text[ : ] =<< trim TEXT - var foo =<< trim FOO - TEXT - assert_equal(['var foo =<< trim FOO'], text) - END - v9.CheckDefAndScriptSuccess(lines) - - # assign heredoc to curly braces name in legacy function in Vim9 script - lines =<< trim END - vim9script - func Func() - let foo_3_bar = [''] - let foo_{1 + 2}_bar[ : ] =<< trim TEXT - var foo =<< trim FOO - TEXT - call assert_equal(['var foo =<< trim FOO'], foo_3_bar) - endfunc - Func() - END - v9.CheckScriptSuccess(lines) - - v9.CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:') - v9.CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:') - - lines =<< trim [END] - def Func() - var&lines =<< trim END - x - x - enddef - defcompile - [END] - v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') - delfunc! g:Func - - lines =<< trim [END] - def Func() - var lines =<< trim END - x - x - x - x - x - x - x - x - enddef - call Func() - [END] - v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') - delfunc! g:Func - - lines =<< trim END - var lines: number =<< trim STOP - aaa - bbb - STOP - END - v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<string>', 1) - - lines =<< trim END - var lines=<< STOP - xxx - STOP - END - v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<< STOP"', 1) - lines =<< trim END - var lines =<<STOP - xxx - STOP - END - v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) - lines =<< trim END - var lines=<<STOP - xxx - STOP - END - v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) -enddef - -def Test_var_func_call() - var lines =<< trim END - vim9script - func GetValue() - if exists('g:count') - let g:count += 1 - else - let g:count = 1 - endif - return 'this' - endfunc - var val: string = GetValue() - # env var is always a string - var env = $TERM - END - writefile(lines, 'Xfinished', 'D') - source Xfinished - # GetValue() is not called during discovery phase - assert_equal(1, g:count) - - unlet g:count -enddef - -def Test_var_missing_type() - var lines =<< trim END - vim9script - var name = g:unknown - END - v9.CheckScriptFailure(lines, 'E121:') - - lines =<< trim END - vim9script - var nr: number = 123 - var name = nr - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_var_declaration() - var lines =<< trim END - vim9script - var name: string - g:var_uninit = name - name = 'text' - g:var_test = name - # prefixing s: is not allowed - name = 'prefixed' - g:var_prefixed = name - - const FOO: number = 123 - assert_equal(123, FOO) - const FOOS = 'foos' - assert_equal('foos', FOOS) - final FLIST = [1] - assert_equal([1], FLIST) - FLIST[0] = 11 - assert_equal([11], FLIST) - - const g:FOOS = 'gfoos' - assert_equal('gfoos', g:FOOS) - final g:FLIST = [2] - assert_equal([2], g:FLIST) - g:FLIST[0] = 22 - assert_equal([22], g:FLIST) - - def SetGlobalConst() - const g:globConst = 123 - enddef - SetGlobalConst() - assert_equal(123, g:globConst) - assert_true(islocked('g:globConst')) - - const w:FOOS = 'wfoos' - assert_equal('wfoos', w:FOOS) - final w:FLIST = [3] - assert_equal([3], w:FLIST) - w:FLIST[0] = 33 - assert_equal([33], w:FLIST) - - var s:other: number - other = 1234 - g:other_var = other - - var xyz: string # comment - - # type is inferred - var dict = {['a']: 222} - def GetDictVal(key: any) - g:dict_val = dict[key] - enddef - GetDictVal('a') - - final adict: dict<string> = {} - def ChangeAdict() - adict.foo = 'foo' - enddef - ChangeAdict() - END - v9.CheckScriptSuccess(lines) - assert_equal('', g:var_uninit) - assert_equal('text', g:var_test) - assert_equal('prefixed', g:var_prefixed) - assert_equal(1234, g:other_var) - assert_equal(222, g:dict_val) - - unlet g:var_uninit - unlet g:var_test - unlet g:var_prefixed - unlet g:other_var - unlet g:globConst - unlet g:FOOS - unlet g:FLIST - unlet w:FOOS - unlet w:FLIST -enddef - -def Test_create_list_after_const() - const a = 1 - g:ll = [] - assert_equal(0, islocked('g:ll')) - unlet g:ll -enddef - -def Test_var_declaration_fails() - var lines =<< trim END - vim9script - final var: string - END - v9.CheckScriptFailure(lines, 'E1125:') - - lines =<< trim END - vim9script - const g:constvar = 'string' - g:constvar = 'xx' - END - v9.CheckScriptFailure(lines, 'E741:') - unlet g:constvar - - lines =<< trim END - vim9script - var name = 'one' - lockvar name - def SetLocked() - name = 'two' - enddef - SetLocked() - END - v9.CheckScriptFailure(lines, 'E741: Value is locked: name', 1) - - lines =<< trim END - let s:legacy = 'one' - lockvar s:legacy - def SetLocked() - s:legacy = 'two' - enddef - call SetLocked() - END - v9.CheckScriptFailure(lines, 'E741: Value is locked: s:legacy', 1) - - lines =<< trim END - vim9script - def SetGlobalConst() - const g:globConst = 123 - enddef - SetGlobalConst() - g:globConst = 234 - END - v9.CheckScriptFailure(lines, 'E741: Value is locked: g:globConst', 6) - unlet g:globConst - - lines =<< trim END - vim9script - const cdict: dict<string> = {} - def Change() - cdict.foo = 'foo' - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E46:') - - lines =<< trim END - vim9script - final w:finalvar = [9] - w:finalvar = [8] - END - v9.CheckScriptFailure(lines, 'E1122:') - unlet w:finalvar - - lines =<< trim END - vim9script - const var: string - END - v9.CheckScriptFailure(lines, 'E1021:') - - lines =<< trim END - vim9script - var 9var: string - END - v9.CheckScriptFailure(lines, 'E488:') - - v9.CheckDefFailure(['var foo.bar = 2'], 'E1087:') - v9.CheckDefFailure(['var foo[3] = 2'], 'E1087:') - v9.CheckDefFailure(['const foo: number'], 'E1021:') - - lines =<< trim END - va foo = 123 - END - v9.CheckDefAndScriptFailure(lines, 'E1065:', 1) - - lines =<< trim END - var foo: func(number - END - v9.CheckDefAndScriptFailure(lines, 'E110:', 1) - - lines =<< trim END - var foo: func(number): func( - END - v9.CheckDefAndScriptFailure(lines, 'E110:', 1) - - for type in ['num_ber', - 'anys', 'ani', - 'bools', 'boel', - 'blobs', 'blub', - 'channels', 'channol', - 'dicts', 'duct', - 'floats', 'floot', - 'funcs', 'funk', - 'jobs', 'jop', - 'lists', 'last', - 'numbers', 'numbar', - 'strings', 'strung', - 'voids', 'viod'] - v9.CheckDefAndScriptFailure([$'var foo: {type}'], 'E1010:', 1) - endfor -enddef - -def Test_var_declaration_inferred() - # check that type is set on the list so that extend() fails - var lines =<< trim END - vim9script - def GetList(): list<number> - var l = [1, 2, 3] - return l - enddef - echo GetList()->extend(['x']) - END - v9.CheckScriptFailure(lines, 'E1013:', 6) - - lines =<< trim END - vim9script - def GetNr(): number - return 5 - enddef - def TestOne() - var some = [function('len'), GetNr] - g:res = typename(some) - enddef - TestOne() - assert_equal('list<func(): number>', g:res) - - def TestTwo() - var some = [function('len'), GetNr] - g:res = typename(some) - enddef - TestTwo() - assert_equal('list<func(): number>', g:res) - unlet g:res - - # FIXME: why is the type different? - var first = [function('len'), GetNr] - assert_equal('list<func(...): number>', typename(first)) - var second = [GetNr, function('len')] - assert_equal('list<func(...): number>', typename(second)) - END - v9.CheckScriptSuccess(lines) -enddef - -def Test_script_local_in_legacy() - # OK to define script-local later but before compiling - var lines =<< trim END - def SetLater() - legvar = 'two' - enddef - let s:legvar = 'one' - defcompile - call SetLater() - call assert_equal('two', s:legvar) - END - v9.CheckScriptSuccess(lines) - - # OK to leave out s: prefix when script-local already defined - lines =<< trim END - let s:legvar = 'one' - def SetNoPrefix() - legvar = 'two' - enddef - call SetNoPrefix() - call assert_equal('two', s:legvar) - END - v9.CheckScriptSuccess(lines) - - # Not OK to leave out s: prefix when script-local defined after compiling - lines =<< trim END - def SetLaterNoPrefix() - legvar = 'two' - enddef - defcompile - let s:legvar = 'one' - END - v9.CheckScriptFailure(lines, 'E476:', 1) - - edit! Xslfile - lines =<< trim END - var edit: bool - legacy edit - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_var_type_check() - var lines =<< trim END - vim9script - var name: string - name = 1234 - END - v9.CheckScriptFailure(lines, 'E1012:') - - lines =<< trim END - vim9script - var name:string - END - v9.CheckScriptFailure(lines, 'E1069:') - - v9.CheckDefAndScriptFailure(['var n:number = 42'], 'E1069:') - - lines =<< trim END - vim9script - var name: asdf - END - v9.CheckScriptFailure(lines, 'E1010:') - - lines =<< trim END - vim9script - var l: list<number> - l = [] - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var d: dict<number> - d = {} - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var d = {a: 1, b: [2]} - def Func(b: bool) - var l: list<number> = b ? d.b : [3] - enddef - defcompile - END - v9.CheckScriptSuccess(lines) -enddef - -let g:dict_number = #{one: 1, two: 2} - -def Test_var_list_dict_type() - var ll: list<number> - ll = [1, 2, 2, 3, 3, 3]->uniq() - ll->assert_equal([1, 2, 3]) - - var dd: dict<number> - dd = g:dict_number - dd->assert_equal(g:dict_number) - - var lines =<< trim END - var ll: list<number> - ll = [1, 2, 3]->map('"one"') - END - v9.CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') -enddef - -def Test_cannot_use_let() - v9.CheckDefAndScriptFailure(['let a = 34'], 'E1126:', 1) -enddef - -def Test_unlet() - g:somevar = 'yes' - assert_true(exists('g:somevar')) - unlet g:somevar - assert_false(exists('g:somevar')) - unlet! g:somevar - - # also works for script-local variable in legacy Vim script - s:somevar = 'legacy' - assert_true(exists('s:somevar')) - unlet s:somevar - assert_false(exists('s:somevar')) - unlet! s:somevar - - if 0 - unlet g:does_not_exist - endif - - v9.CheckDefExecFailure(['unlet v:notfound.key'], 'E1001:') - - v9.CheckDefExecFailure([ - 'var dd = 111', - 'unlet dd', - ], 'E1081:', 2) - - # dict unlet - var dd = {a: 1, b: 2, c: 3, 4: 4} - unlet dd['a'] - unlet dd.c - unlet dd[4] - assert_equal({b: 2}, dd) - - # null key works like empty string - dd = {'': 1, x: 9} - unlet dd[null_string] - assert_equal({x: 9}, dd) - - # list unlet - var ll = [1, 2, 3, 4] - unlet ll[1] - unlet ll[-1] - assert_equal([1, 3], ll) - - ll = [1, 2, 3, 4] - unlet ll[0 : 1] - assert_equal([3, 4], ll) - - ll = [1, 2, 3, 4] - unlet ll[2 : 8] - assert_equal([1, 2], ll) - - ll = [1, 2, 3, 4] - unlet ll[-2 : -1] - assert_equal([1, 2], ll) - - g:nrdict = {1: 1, 2: 2} - g:idx = 1 - unlet g:nrdict[g:idx] - assert_equal({2: 2}, g:nrdict) - unlet g:nrdict - unlet g:idx - - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'll[1 : 2] = 7', - ], 'E1012: Type mismatch; expected list<number> but got number', 2) - v9.CheckDefFailure([ - 'var dd = {a: 1}', - 'unlet dd["a" : "a"]', - ], 'E1166:', 2) - v9.CheckDefExecFailure([ - 'unlet g:adict[0 : 1]', - ], 'E1148:', 1) - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'unlet ll[0:1]', - ], 'E1004:', 2) - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'unlet ll[0 :1]', - ], 'E1004:', 2) - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'unlet ll[0: 1]', - ], 'E1004:', 2) - - v9.CheckDefExecFailure([ - 'g:ll = [1, 2]', - 'g:idx = "x"', - 'unlet g:ll[g:idx]', - ], 'E1029: Expected number but got string', 3) - - v9.CheckDefExecFailure([ - 'g:ll = [1, 2, 3]', - 'g:idx = "x"', - 'unlet g:ll[g:idx : 2]', - ], 'E1029: Expected number but got string', 3) - - v9.CheckDefExecFailure([ - 'g:ll = [1, 2, 3]', - 'g:idx = "x"', - 'unlet g:ll[0 : g:idx]', - ], 'E1029: Expected number but got string', 3) - - # command recognized as assignment when skipping, should not give an error - v9.CheckScriptSuccess([ - 'vim9script', - 'for i in []', - " put =''", - 'endfor']) - - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'unlet ll["x" : 1]', - ], 'E1012:', 2) - v9.CheckDefFailure([ - 'var ll = [1, 2]', - 'unlet ll[0 : "x"]', - ], 'E1012:', 2) - - # list of dict unlet - var dl = [{a: 1, b: 2}, {c: 3}] - unlet dl[0]['b'] - assert_equal([{a: 1}, {c: 3}], dl) - - v9.CheckDefExecFailure([ - 'var ll = test_null_list()', - 'unlet ll[0]', - ], 'E684:', 2) - v9.CheckDefExecFailure([ - 'var ll = [1]', - 'unlet ll[2]', - ], 'E684:', 2) - v9.CheckDefExecFailure([ - 'var ll = [1]', - 'unlet ll[g:astring]', - ], 'E1012:', 2) - v9.CheckDefExecFailure([ - 'var dd = test_null_dict()', - 'unlet dd["a"]', - ], 'E716:', 2) - v9.CheckDefExecFailure([ - 'var dd = {a: 1}', - 'unlet dd["b"]', - ], 'E716:', 2) - v9.CheckDefExecFailure([ - 'var dd = {a: 1}', - 'unlet dd[g:alist]', - ], 'E1105:', 2) - - v9.CheckDefExecFailure([ - 'g:dd = {"a": 1, 2: 2}', - 'unlet g:dd[0z11]', - ], 'E1029:', 2) - v9.CheckDefExecFailure([ - 'g:str = "a string"', - 'unlet g:str[0]', - ], 'E1148: Cannot index a string', 2) - - # can compile unlet before variable exists - g:someDict = {key: 'val'} - var k = 'key' - unlet g:someDict[k] - assert_equal({}, g:someDict) - unlet g:someDict - assert_false(exists('g:someDict')) - - v9.CheckScriptFailure([ - 'vim9script', - 'var svar = 123', - 'unlet svar', - ], 'E1081:') - v9.CheckScriptFailure([ - 'vim9script', - 'var svar = 123', - 'unlet s:svar', - ], 'E1268:') - v9.CheckScriptFailure([ - 'vim9script', - 'var svar = 123', - 'def Func()', - ' unlet svar', - 'enddef', - 'defcompile', - ], 'E1081:') - v9.CheckScriptFailure([ - 'vim9script', - 'var svar = 123', - 'func Func()', - ' unlet s:svar', - 'endfunc', - 'Func()', - ], 'E1081:') - v9.CheckScriptFailure([ - 'vim9script', - 'var svar = 123', - 'def Func()', - ' unlet s:svar', - 'enddef', - 'defcompile', - ], 'E1081:') - - v9.CheckScriptFailure([ - 'vim9script', - 'def Delcount(dict: dict<any>)', - ' unlet dict.count', - 'enddef', - 'Delcount(v:)', - ], 'E742:') - - v9.CheckScriptFailure([ - 'vim9script', - 'def DelChangedtick(dict: dict<any>)', - ' unlet dict.changedtick', - 'enddef', - 'DelChangedtick(b:)', - ], 'E795:') - - writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim', 'D') - var lines =<< trim END - vim9script - import './XunletExport.vim' as exp - def UnletSvar() - unlet exp.svar - enddef - defcompile - END - v9.CheckScriptFailure(lines, 'E1260:', 1) - - $ENVVAR = 'foobar' - assert_equal('foobar', $ENVVAR) - unlet $ENVVAR - assert_equal('', $ENVVAR) -enddef - -def Test_expr_error_no_assign() - var lines =<< trim END - vim9script - var x = invalid - echo x - END - v9.CheckScriptFailureList(lines, ['E121:', 'E121:']) - - lines =<< trim END - vim9script - var x = 1 / 0 - echo x - END - v9.CheckScriptFailure(lines, 'E1154:') - - lines =<< trim END - vim9script - var x = 1 % 0 - echo x - END - v9.CheckScriptFailure(lines, 'E1154:') - - lines =<< trim END - var x: string 'string' - END - v9.CheckDefAndScriptFailure(lines, 'E488:') -enddef - - -def Test_assign_command_modifier() - var lines =<< trim END - var verbose = 0 - verbose = 1 - assert_equal(1, verbose) - silent verbose = 2 - assert_equal(2, verbose) - silent verbose += 2 - assert_equal(4, verbose) - silent verbose -= 1 - assert_equal(3, verbose) - - var topleft = {one: 1} - sandbox topleft.one = 3 - assert_equal({one: 3}, topleft) - leftabove topleft[' '] = 4 - assert_equal({one: 3, ' ': 4}, topleft) - - var x: number - var y: number - silent [x, y] = [1, 2] - assert_equal(1, x) - assert_equal(2, y) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_assign_alt_buf_register() - var lines =<< trim END - edit 'file_b1' - var b1 = bufnr() - edit 'file_b2' - var b2 = bufnr() - assert_equal(b1, bufnr('#')) - @# = b2 - assert_equal(b2, bufnr('#')) - END - v9.CheckDefAndScriptSuccess(lines) -enddef - -def Test_script_funcref_case() - var lines =<< trim END - var Len = (s: string): number => len(s) + 1 - assert_equal(5, Len('asdf')) - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var len = (s: string): number => len(s) + 1 - END - v9.CheckDefAndScriptFailure(lines, 'E704:') - - lines =<< trim END - vim9script - var Len = (s: string): number => len(s) + 2 - assert_equal(6, Len('asdf')) - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var len = (s: string): number => len(s) + 1 - END - v9.CheckScriptFailure(lines, 'E704:') -enddef - -def Test_script_funcref_runtime_type_check() - var lines =<< trim END - vim9script - def FuncWithNumberArg(n: number) - enddef - def Test() - var Ref: func(string) = function(FuncWithNumberArg) - enddef - defcompile - END - # OK at compile time - v9.CheckScriptSuccess(lines) - - # Type check fails at runtime - v9.CheckScriptFailure(lines + ['Test()'], 'E1012: Type mismatch; expected func(string) but got func(number)') -enddef - -def Test_inc_dec() - var lines =<< trim END - var nr = 7 - ++nr - assert_equal(8, nr) - --nr - assert_equal(7, nr) - ++nr | ++nr - assert_equal(9, nr) - ++nr # comment - assert_equal(10, nr) - - var ll = [1, 2] - --ll[0] - ++ll[1] - assert_equal([0, 3], ll) - - g:count = 1 - ++g:count - --g:count - assert_equal(1, g:count) - unlet g:count - END - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim END - var nr = 7 - ++ nr - END - v9.CheckDefAndScriptFailure(lines, "E1202: No white space allowed after '++': ++ nr") -enddef - -def Test_abort_after_error() - # should abort after strpart() fails, not give another type error - var lines =<< trim END - vim9script - var x: string - x = strpart(1, 2) - END - writefile(lines, 'Xtestscript', 'D') - var expected = 'E1174: String required for argument 1' - assert_fails('so Xtestscript', [expected, expected], 3) -enddef - -def Test_using_s_var_in_function() - var lines =<< trim END - vim9script - var scriptlevel = 123 - def SomeFunc() - echo s:scriptlevel - enddef - SomeFunc() - END - v9.CheckScriptFailure(lines, 'E1268:') - - # OK in legacy script - lines =<< trim END - let s:scriptlevel = 123 - def s:SomeFunc() - echo s:scriptlevel - enddef - call s:SomeFunc() - END - v9.CheckScriptSuccess(lines) - - lines =<< trim END - vim9script - var scriptlevel = 123 - def SomeFunc() - s:scriptlevel = 456 - enddef - SomeFunc() - END - v9.CheckScriptFailure(lines, 'E1268:') - - # OK in legacy script - lines =<< trim END - let s:scriptlevel = 123 - def s:SomeFunc() - s:scriptlevel = 456 - enddef - call s:SomeFunc() - call assert_equal(456, s:scriptlevel) - END - v9.CheckScriptSuccess(lines) -enddef - -let g:someVar = 'X' - -" Test for heredoc with Vim expressions. -" This messes up highlighting, keep it near the end. -def Test_heredoc_expr() - var lines =<< trim CODE - var s = "local" - var a1 = "1" - var a2 = "2" - var a3 = "3" - var a4 = "" - var code =<< trim eval END - var a = {5 + 10} - var b = {min([10, 6])} + {max([4, 6])} - var c = "{s}" - var d = x{a1}x{a2}x{a3}x{a4} - END - assert_equal(['var a = 15', 'var b = 6 + 6', 'var c = "local"', 'var d = x1x2x3x'], code) - CODE - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim CODE - var code =<< eval trim END - var s = "{$SOME_ENV_VAR}" - END - assert_equal(['var s = "somemore"'], code) - CODE - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim CODE - var code =<< eval END - var s = "{$SOME_ENV_VAR}" - END - assert_equal([' var s = "somemore"'], code) - CODE - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim CODE - var code =<< eval trim END - let a = {{abc}} - let b = {g:someVar} - let c = {{ - END - assert_equal(['let a = {abc}', 'let b = X', 'let c = {'], code) - CODE - v9.CheckDefAndScriptSuccess(lines) - - lines =<< trim LINES - var text =<< eval trim END - let b = { - END - LINES - v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") - - lines =<< trim LINES - var text =<< eval trim END - let b = {abc - END - LINES - v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") - - lines =<< trim LINES - var text =<< eval trim END - let b = {} - END - LINES - v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"') -enddef - -" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker +" Test Vim9 assignments + +source check.vim +import './vim9.vim' as v9 +source term_util.vim + +let s:appendToMe = 'xxx' +let s:addToMe = 111 +let s:newVar = '' +let g:existing = 'yes' +let g:inc_counter = 1 +let $SOME_ENV_VAR = 'some' +let g:alist = [7] +let g:adict = #{a: 1} +let g:astring = 'text' + +def Test_assignment_bool() + var bool1: bool = true + assert_equal(v:true, bool1) + var bool2: bool = false + assert_equal(v:false, bool2) + + var bool3: bool = 0 + assert_equal(false, bool3) + var bool4: bool = 1 + assert_equal(true, bool4) + + var bool5: bool = 1 && true + assert_equal(true, bool5) + var bool6: bool = 0 && 1 + assert_equal(false, bool6) + var bool7: bool = 0 || 1 && true + assert_equal(true, bool7) + + var lines =<< trim END + vim9script + def GetFlag(): bool + var flag: bool = 1 + return flag + enddef + var flag: bool = GetFlag() + assert_equal(true, flag) + flag = 0 + assert_equal(false, flag) + flag = 1 + assert_equal(true, flag) + flag = 1 || true + assert_equal(true, flag) + flag = 1 && false + assert_equal(false, flag) + + var cp: bool = &cp + var fen: bool = &l:fen + END + v9.CheckScriptSuccess(lines) + v9.CheckDefAndScriptFailure(['var x: bool = 2'], 'E1012:') + v9.CheckDefAndScriptFailure(['var x: bool = -1'], 'E1012:') + v9.CheckDefAndScriptFailure(['var x: bool = [1]'], 'E1012:') + v9.CheckDefAndScriptFailure(['var x: bool = {}'], 'E1012:') + v9.CheckDefAndScriptFailure(['var x: bool = "x"'], 'E1012:') + + v9.CheckDefAndScriptFailure(['var x: bool = "x"', '', 'eval 0'], 'E1012:', 1) +enddef + +def Test_syntax() + var name = 234 + var other: list<string> = ['asdf'] +enddef + +def Test_assignment() + v9.CheckDefFailure(['var x:string'], 'E1069:') + v9.CheckDefFailure(['var x:string = "x"'], 'E1069:') + v9.CheckDefFailure(['var a:string = "x"'], 'E1069:') + v9.CheckDefFailure(['var lambda = () => "lambda"'], 'E704:') + v9.CheckScriptFailure(['var x = "x"'], 'E1124:') + + # lower case name is OK for a list + var lambdaLines =<< trim END + var lambdaList: list<func> = [g:Test_syntax] + lambdaList[0] = () => "lambda" + END + v9.CheckDefAndScriptSuccess(lambdaLines) + + var nr: number = 1234 + v9.CheckDefFailure(['var nr: number = "asdf"'], 'E1012:') + + var a: number = 6 #comment + assert_equal(6, a) + + if has('channel') + var chan1: channel + assert_equal('fail', ch_status(chan1)) + + var job1: job + assert_equal('fail', job_status(job1)) + + # calling job_start() is in test_vim9_fails.vim, it causes leak reports + endif + var float1: float = 3.4 + var Funky1: func + var Funky2: func = function('len') + var Party2: func = funcref('g:Test_syntax') + + g:newvar = 'new' #comment + assert_equal('new', g:newvar) + + assert_equal('yes', g:existing) + g:existing = 'no' + assert_equal('no', g:existing) + + v:char = 'abc' + assert_equal('abc', v:char) + + $ENVVAR = 'foobar' + assert_equal('foobar', $ENVVAR) + $ENVVAR = '' + + var lines =<< trim END + vim9script + $ENVVAR = 'barfoo' + assert_equal('barfoo', $ENVVAR) + $ENVVAR = '' + END + v9.CheckScriptSuccess(lines) + + appendToMe ..= 'yyy' + assert_equal('xxxyyy', appendToMe) + addToMe += 222 + assert_equal(333, addToMe) + newVar = 'new' + assert_equal('new', newVar) + + set ts=7 + var ts: number = &ts + assert_equal(7, ts) + &ts += 1 + assert_equal(8, &ts) + &ts -= 3 + assert_equal(5, &ts) + &ts *= 2 + assert_equal(10, &ts) + &ts /= 3 + assert_equal(3, &ts) + set ts=10 + &ts %= 4 + assert_equal(2, &ts) + + assert_fails('&ts /= 0', ['E1154:', 'E1154:']) + assert_fails('&ts %= 0', ['E1154:', 'E1154:']) + assert_fails('&ts /= []', ['E745:', 'E745:']) + assert_fails('&ts %= []', ['E745:', 'E745:']) + assert_equal(2, &ts) + + var f100: float = 100.0 + f100 /= 5 + assert_equal(20.0, f100) + + var f200: float = 200.0 + f200 /= 5.0 + assert_equal(40.0, f200) + + v9.CheckDefFailure(['var nr: number = 200', 'nr /= 5.0'], 'E1012:') + + lines =<< trim END + &ts = 6 + &ts += 3 + assert_equal(9, &ts) + + &l:ts = 6 + assert_equal(6, &ts) + &l:ts += 2 + assert_equal(8, &ts) + + &g:ts = 6 + assert_equal(6, &g:ts) + &g:ts += 2 + assert_equal(8, &g:ts) + + &number = true + assert_equal(true, &number) + &number = 0 + assert_equal(false, &number) + &number = 1 + assert_equal(true, &number) + &number = false + assert_equal(false, &number) + END + v9.CheckDefAndScriptSuccess(lines) + + v9.CheckDefFailure(['¬ex += 3'], 'E113:') + v9.CheckDefFailure(['&ts ..= "xxx"'], 'E1019:') + v9.CheckDefFailure(['&ts = [7]'], 'E1012:') + v9.CheckDefExecFailure(['&ts = g:alist'], 'E1012: Type mismatch; expected number but got list<number>') + v9.CheckDefFailure(['&ts = "xx"'], 'E1012:') + v9.CheckDefExecFailure(['&ts = g:astring'], 'E1012: Type mismatch; expected number but got string') + v9.CheckDefFailure(['&path += 3'], 'E1012:') + v9.CheckDefExecFailure(['&bs = "asdf"'], 'E474:') + # test freeing ISN_STOREOPT + v9.CheckDefFailure(['&ts = 3', 'var asdf'], 'E1022:') + &ts = 8 + + lines =<< trim END + var save_TI = &t_TI + &t_TI = '' + assert_equal('', &t_TI) + &t_TI = 'xxx' + assert_equal('xxx', &t_TI) + &t_TI = save_TI + END + v9.CheckDefAndScriptSuccess(lines) + + v9.CheckDefFailure(['&t_TI = 123'], 'E1012:') + v9.CheckScriptFailure(['vim9script', '&t_TI = 123'], 'E928:') + + v9.CheckDefFailure(['var s:var = 123'], 'E1101:') + v9.CheckDefFailure(['var s:var: number'], 'E1101:') + + v9.CheckDefAndScriptFailure(['var $VAR: number'], ['E1016:', 'E475:']) + + lines =<< trim END + vim9script + def SomeFunc() + s:var = 123 + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1268:') + + g:inc_counter += 1 + assert_equal(2, g:inc_counter) + + var f: float + f += 1 + assert_equal(1.0, f) + + $SOME_ENV_VAR ..= 'more' + assert_equal('somemore', $SOME_ENV_VAR) + v9.CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:') + v9.CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1012:') + + v:errmsg = 'none' + v:errmsg ..= 'again' + assert_equal('noneagain', v:errmsg) + v9.CheckDefFailure(['v:errmsg += "more"'], 'E1051:') + v9.CheckDefFailure(['v:errmsg += 123'], 'E1012:') + + var text =<< trim END + some text + END +enddef + +def Test_float_and_number() + var lines =<< trim END + var f: float + f += 2 + f -= 1 + assert_equal(1.0, f) + ++f + --f + assert_equal(1.0, f) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +let g:someNumber = 43 + +def Test_assign_concat() + var lines =<< trim END + var s = '-' + s ..= 99 + s ..= true + s ..= '-' + s ..= v:null + s ..= g:someNumber + assert_equal('-99true-null43', s) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var s = '-' + s ..= [1, 2] + END + v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert list to string', 'E734: Wrong variable type for .='], 2) + lines =<< trim END + var s = '-' + s ..= {a: 2} + END + v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2) + + lines =<< trim END + var ls: list<string> = [] + ls[-1] ..= 'foo' + END + v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: -1', 2) +enddef + +def Test_assign_register() + var lines =<< trim END + @c = 'areg' + @c ..= 'add' + assert_equal('aregadd', @c) + + @@ = 'some text' + assert_equal('some text', getreg('"')) + END + v9.CheckDefAndScriptSuccess(lines) + + v9.CheckDefFailure(['@a += "more"'], 'E1051:') + v9.CheckDefFailure(['@a += 123'], 'E1012:') +enddef + +def Test_reserved_name() + var more_names = ['null_job', 'null_channel'] + if !has('job') + more_names = [] + endif + + for name in ['true', + 'false', + 'this', + 'super', + 'null', + 'null_blob', + 'null_dict', + 'null_function', + 'null_list', + 'null_partial', + 'null_string', + ] + more_names + v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' = 0'], 'E1034:') + v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:') + endfor + + var lines =<< trim END + vim9script + def Foo(super: bool) + echo 'something' + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1034:') +enddef + +def Test_null_values() + var lines =<< trim END + var b: blob = null_blob + var dn: dict<number> = null_dict + var ds: dict<string> = null_dict + var ln: list<number> = null_list + var ls: list<string> = null_list + var Ff: func(string): string = null_function + var Fp: func(number): number = null_partial + var s: string = null_string + if has('job') + var j: job = null_job + var c: channel = null_channel + endif + + var d: dict<func> = {a: function('tr'), b: null_function} + + var bl: list<blob> = [0z12, null_blob] + var dnl: list<dict<number>> = [{a: 1}, null_dict] + var dsl: list<dict<string>> = [{a: 'x'}, null_dict] + var lnl: list<list<number>> = [[1], null_list] + var lsl: list<list<string>> = [['x'], null_list] + def Len(v: string): number + return len(v) + enddef + var Ffl: list<func(string): number> = [Len, null_function] + var Fpl: list<func(string): number> = [Len, null_partial] + var sl: list<string> = ['x', null_string] + if has('job') + var jl: list<job> = [null_job] + var cl: list<channel> = [null_channel] + endif + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_type_with_extra_white() + var lines =<< trim END + const x : number = 3 + END + v9.CheckDefExecAndScriptFailure(lines, 'E1059') +enddef + +def Test_keep_type_after_assigning_null() + var lines =<< trim END + var b: blob + b = null_blob + b = 'text' + END + v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected blob but got string') + + lines =<< trim END + var l: list<number> + l = null_list + l = ['text'] + END + v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') + + lines =<< trim END + var d: dict<string> + d = null_dict + d = {a: 1, b: 2} + END + v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<string> but got dict<number>') +enddef + +def Test_skipped_assignment() + var lines =<< trim END + for x in [] + var i: number = 1 + while false + i += 1 + endwhile + endfor + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_assign_keep_type() + var lines =<< trim END + vim9script + var l: list<number> = [123] + l = [123] + l->add('string') + END + v9.CheckScriptFailure(lines, 'E1012:', 4) +enddef + +def Test_assign_unpack() + var lines =<< trim END + var v1: number + var v2: number + [v1, v2] = [1, 2] + assert_equal(1, v1) + assert_equal(2, v2) + + [v1, _, v2, _] = [1, 99, 2, 77] + assert_equal(1, v1) + assert_equal(2, v2) + + [v1, v2; _] = [1, 2, 3, 4, 5] + assert_equal(1, v1) + assert_equal(2, v2) + + var _x: number + [_x, v2] = [6, 7] + assert_equal(6, _x) + assert_equal(7, v2) + + var reslist = [] + for text in ['aaa {bbb} ccc', 'ddd {eee} fff'] + var before: string + var middle: string + var after: string + [_, before, middle, after; _] = text->matchlist('\(.\{-\}\){\(.\{-\}\)}\(.*\)') + reslist->add(before)->add(middle)->add(after) + endfor + assert_equal(['aaa ', 'bbb', ' ccc', 'ddd ', 'eee', ' fff'], reslist) + + var a = 1 + var b = 3 + [a, b] += [2, 4] + assert_equal(3, a) + assert_equal(7, b) + + [a, b] -= [1, 2] + assert_equal(2, a) + assert_equal(5, b) + + [a, b] *= [3, 2] + assert_equal(6, a) + assert_equal(10, b) + + [a, b] /= [2, 4] + assert_equal(3, a) + assert_equal(2, b) + + [a, b] = [17, 15] + [a, b] %= [5, 3] + assert_equal(2, a) + assert_equal(0, b) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = [1, 2, 3] + END + v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 3', 3) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = [1] + END + v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2; _] = [1] + END + v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = + END + v9.CheckDefFailure(lines, 'E1097:', 5) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = xxx + END + v9.CheckDefFailure(lines, 'E1001:', 3) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = popup_clear() + END + v9.CheckDefFailure(lines, 'E1031:', 3) + + lines =<< trim END + [v1, v2] = [1, 2] + END + v9.CheckDefFailure(lines, 'E1089', 1) + v9.CheckScriptFailure(['vim9script'] + lines, 'E1089', 2) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = '' + END + v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<any> but got string', 3) + + lines =<< trim END + g:values = [false, 0] + var x: bool + var y: string + [x, y] = g:values + END + v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 2: type mismatch, expected string but got number') + + lines =<< trim END + var x: number + var y: number + var z: string + [x, y, z] = [1, 2, 3] + END + v9.CheckDefAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') + + lines =<< trim END + var x: number + var y: string + var z: string + [x, y, z] = [1, '2', 3] + END + v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') +enddef + +def Test_assign_linebreak() + var nr: number + nr = + 123 + assert_equal(123, nr) + + var n2: number + [nr, n2] = + [12, 34] + assert_equal(12, nr) + assert_equal(34, n2) + + v9.CheckDefFailure(["var x = #"], 'E1097:', 3) + + var lines =<< trim END + var x: list<string> = ['a'] + var y: list<number> = x + ->copy() + ->copy() + END + v9.CheckDefExecFailure(lines, 'E1012:', 4) + + lines =<< trim END + var x: any + x.key = 1 + + 2 + + 3 + + 4 + + 5 + END + v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203:'], 2) +enddef + +def Test_assign_index() + # list of list + var l1: list<number> + l1[0] = 123 + assert_equal([123], l1) + + var l2: list<list<number>> + l2[0] = [] + l2[0][0] = 123 + assert_equal([[123]], l2) + + var l3: list<list<list<number>>> + l3[0] = [] + l3[0][0] = [] + l3[0][0][0] = 123 + assert_equal([[[123]]], l3) + + var lines =<< trim END + var l3: list<list<number>> + l3[0] = [] + l3[0][0] = [] + END + v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3) + + # dict of dict + var d1: dict<number> + d1.one = 1 + assert_equal({one: 1}, d1) + + var d2: dict<dict<number>> + d2.one = {} + d2.one.two = 123 + assert_equal({one: {two: 123}}, d2) + + var d3: dict<dict<dict<number>>> + d3.one = {} + d3.one.two = {} + d3.one.two.three = 123 + assert_equal({one: {two: {three: 123}}}, d3) + + # blob + var bl: blob = 0z11223344 + bl[0] = 0x77 + assert_equal(0z77223344, bl) + bl[-2] = 0x66 + assert_equal(0z77226644, bl) + + lines =<< trim END + g:val = '22' + var bl = 0z11 + bl[1] = g:val + END + v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"') + + # should not read the next line when generating "a.b" + var a = {} + a.b = {} + a.b.c = {} + ->copy() + + lines =<< trim END + var d3: dict<dict<number>> + d3.one = {} + d3.one.two = {} + END + v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3) + + lines =<< trim END + var lines: list<string> + lines['a'] = 'asdf' + END + v9.CheckDefFailure(lines, 'E1012:', 2) + + lines =<< trim END + var lines: string + lines[9] = 'asdf' + END + v9.CheckDefFailure(lines, 'E1141:', 2) + + # list of dict + var ld: list<dict<number>> + ld[0] = {} + ld[0].one = 123 + assert_equal([{one: 123}], ld) + + lines =<< trim END + var ld: list<dict<number>> + ld[0] = [] + END + v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2) + + # dict of list + var dl: dict<list<number>> + dl.one = [] + dl.one[0] = 123 + assert_equal({one: [123]}, dl) + + lines =<< trim END + var dl: dict<list<number>> + dl.one = {} + END + v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2) + + lines =<< trim END + g:l = [1, 2] + g:l['x'] = 3 + END + v9.CheckDefExecAndScriptFailure(lines, ['E39:', 'E1030:'], 2) + + lines =<< trim END + var bl: blob = test_null_blob() + bl[1] = 8 + END + v9.CheckDefExecAndScriptFailure(lines, ['E1184:', 'E979:'], 2) + + lines =<< trim END + g:bl = 'not a blob' + g:bl[1 : 2] = 8 + END + v9.CheckDefExecAndScriptFailure(lines, ['E897:', 'E689:'], 2) +enddef + +def Test_init_in_for_loop() + var lines =<< trim END + var l: list<number> = [] + for i in [3, 4] + var n: number + add(l, n) + n = 123 + endfor + assert_equal([0, 0], l) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var l: list<number> = [] + for i in [3, 4] + var n: number = 0 + add(l, n) + n = 123 + endfor + assert_equal([0, 0], l) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var l: list<number> = [] + for i in [3, 4] + var n: number = 3 + add(l, n) + n = 123 + endfor + assert_equal([3, 3], l) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_redir_is_not_assign() + if false + redir => res + echo var_job + redir END + endif +enddef + +def Test_extend_list() + # using uninitialized list assigns empty list + var lines =<< trim END + var l1: list<number> + var l2 = l1 + assert_true(l1 is l2) + l1 += [123] + assert_equal([123], l1) + assert_true(l1 is l2) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var list: list<string> + extend(list, ['x']) + assert_equal(['x'], list) + END + v9.CheckDefAndScriptSuccess(lines) + + # appending to uninitialized list from a function works + lines =<< trim END + vim9script + var list: list<string> + def Func() + list += ['a', 'b'] + enddef + Func() + assert_equal(['a', 'b'], list) + END + v9.CheckScriptSuccess(lines) + lines =<< trim END + vim9script + var list: list<string> + def Func() + extend(list, ['x', 'b']) + enddef + Func() + assert_equal(['x', 'b'], list) + END + v9.CheckScriptSuccess(lines) + + # initialized to null, with type, does not default to empty list + lines =<< trim END + vim9script + var l: list<string> = test_null_list() + extend(l, ['x']) + END + v9.CheckScriptFailure(lines, 'E1134:', 3) + + # initialized to null, without type, does not default to empty list + lines =<< trim END + vim9script + var l = null_list + extend(l, ['x']) + END + v9.CheckScriptFailure(lines, 'E1134:', 3) + + # assigned null, does not default to empty list + lines =<< trim END + vim9script + var l: list<string> + l = null_list + extend(l, ['x']) + END + v9.CheckScriptFailure(lines, 'E1134:', 4) + + lines =<< trim END + vim9script + extend(test_null_list(), ['x']) + END + v9.CheckScriptFailure(lines, 'E1134:', 2) + + # using global var has no declared type + g:myList = [] + g:myList->extend([1]) + g:myList->extend(['x']) + assert_equal([1, 'x'], g:myList) + unlet g:myList + + # using declared list gives an error + lines =<< trim END + var l: list<number> + g:myList = l + g:myList->extend([1]) + g:myList->extend(['x']) + END + v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4) + unlet g:myList + + lines =<< trim END + vim9script + var lds = [1, 2, 3] + def Func() + echo lds->extend(['x']) + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1013:') +enddef + +def Test_extend_dict() + var lines =<< trim END + vim9script + var d: dict<number> + extend(d, {a: 1}) + assert_equal({a: 1}, d) + + var d2: dict<number> + d2['one'] = 1 + assert_equal({one: 1}, d2) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d: dict<string> = test_null_dict() + extend(d, {a: 'x'}) + END + v9.CheckScriptFailure(lines, 'E1133:', 3) + + lines =<< trim END + vim9script + extend(test_null_dict(), {a: 'x'}) + END + v9.CheckScriptFailure(lines, 'E1133:', 2) +enddef + +def Test_single_letter_vars() + # single letter variables + var a: number = 123 + a = 123 + assert_equal(123, a) + var b: number + b = 123 + assert_equal(123, b) + var g: number + g = 123 + assert_equal(123, g) + var s: number + s = 123 + assert_equal(123, s) + var t: number + t = 123 + assert_equal(123, t) + var v: number + v = 123 + assert_equal(123, v) + var w: number + w = 123 + assert_equal(123, w) +enddef + +def Test_vim9_single_char_vars() + var lines =<< trim END + vim9script + + # single character variable declarations work + var a: string + var b: number + var l: list<any> + var s: string + var t: number + var v: number + var w: number + + # script-local variables can be used without s: prefix + a = 'script-a' + b = 111 + l = [1, 2, 3] + s = 'script-s' + t = 222 + v = 333 + w = 444 + + assert_equal('script-a', a) + assert_equal(111, b) + assert_equal([1, 2, 3], l) + assert_equal('script-s', s) + assert_equal(222, t) + assert_equal(333, v) + assert_equal(444, w) + END + writefile(lines, 'Xsinglechar', 'D') + source Xsinglechar +enddef + +def Test_assignment_list() + var list1: list<bool> = [false, true, false] + var list2: list<number> = [1, 2, 3] + var list3: list<string> = ['sdf', 'asdf'] + var list4: list<any> = ['yes', true, 1234] + var list5: list<blob> = [0z01, 0z02] + + var listS: list<string> = [] + var listN: list<number> = [] + + assert_equal([1, 2, 3], list2) + list2[-1] = 99 + assert_equal([1, 2, 99], list2) + list2[-2] = 88 + assert_equal([1, 88, 99], list2) + list2[-3] = 77 + assert_equal([77, 88, 99], list2) + list2 += [100] + assert_equal([77, 88, 99, 100], list2) + + list3 += ['end'] + assert_equal(['sdf', 'asdf', 'end'], list3) + + v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') + v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[8 : 9]'], 'E684:') + v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[1 : -9]'], 'E684:') + v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[2 : 1]'], 'E684:') + + # type becomes list<any> + var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] + + # type is list<any> even though initializer is list<number> + var anyList: list<any> = [0] + assert_equal([0, 'x'], extend(anyList, ['x'])) + + var lines =<< trim END + var d = {dd: test_null_list()} + d.dd[0] = 0 + END + v9.CheckDefExecFailure(lines, 'E1147:', 2) + + lines =<< trim END + def OneArg(x: bool) + enddef + def TwoArgs(x: bool, y: bool) + enddef + var fl: list<func(bool, bool, bool)> = [OneArg, TwoArgs] + END + v9.CheckDefExecAndScriptFailure(lines, 'E1012:', 5) +enddef + +def Test_list_declaration() + var [v1, v2] = [1, 2] + v1 += 3 + assert_equal(4, v1) + v2 *= 3 + assert_equal(6, v2) + + var lines =<< trim END + var [v1, v2] = [1] + END + v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) + lines =<< trim END + var testlist = [1] + var [v1, v2] = testlist + END + v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) + lines =<< trim END + var [v1, v2] = [1, 2, 3] + END + v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) + lines =<< trim END + var testlist = [1, 2, 3] + var [v1, v2] = testlist + END + v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) + + var [vnr, vstr] = [123, 'text'] + vnr += 3 + assert_equal(126, vnr) + vstr ..= 'end' + assert_equal('textend', vstr) + + var [vnr2: number, vstr2: string] = [123, 'text'] + vnr2 += 3 + assert_equal(126, vnr2) + vstr2 ..= 'end' + assert_equal('textend', vstr2) + + var [vnr3: number; vlist: list<string>] = [123, 'foo', 'bar'] + vnr3 += 5 + assert_equal(128, vnr3) + assert_equal(['foo', 'bar'], vlist) + + lines =<< trim END + var [vnr2: number, vstr2: number] = [123, 'text'] + END + v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) + lines =<< trim END + var testlist = [234, 'text'] + var [vnr2: number, vstr2: number] = testlist + END + v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) +enddef + +def PartFuncBool(b: bool): string + return 'done' +enddef + +def Test_assignment_partial() + var lines =<< trim END + var Partial: func(): string = function(g:PartFuncBool, [true]) + assert_equal('done', Partial()) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + vim9script + def Func(b: bool) + enddef + var Ref: func = function(Func, [true]) + assert_equal('func()', typename(Ref)) + Ref() + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + var nres: any + var sres: any + def Func(nr: number, s = '') + nres = nr + sres = s + enddef + + var n: number + var Ref = function(Func, [n]) + Ref('x') + assert_equal(0, nres) + assert_equal('x', sres) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + def Func(nr: number, s = '') + enddef + + var n: number + var Ref = function(Func, [n]) + Ref(0) + END + v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number') +enddef + +def Test_assignment_list_any_index() + var l: list<number> = [1, 2] + for [x, y, _] + in [[0, 1, ''], [1, 3, '']] + l[x] = l[x] + y + endfor + assert_equal([2, 5], l) +enddef + +def Test_assignment_list_vim9script() + var lines =<< trim END + vim9script + var v1: number + var v2: number + var v3: number + [v1, v2, v3] = [1, 2, 3] + assert_equal([1, 2, 3], [v1, v2, v3]) + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_assignment_dict() + var dict1: dict<bool> = {one: false, two: true} + var dict2: dict<number> = {one: 1, two: 2} + var dict3: dict<string> = {key: 'value'} + var dict4: dict<any> = {one: 1, two: '2'} + var dict5: dict<blob> = {one: 0z01, two: 0z02} + + # check the type is OK + var events: dict<string> = v:event + + # overwrite + dict3['key'] = 'another' + assert_equal(dict3, {key: 'another'}) + dict3.key = 'yet another' + assert_equal(dict3, {key: 'yet another'}) + + # member "any" can also be a dict and assigned to + var anydict: dict<any> = {nest: {}, nr: 0} + anydict.nest['this'] = 123 + anydict.nest.that = 456 + assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict) + + var lines =<< trim END + var dd = {} + dd.two = 2 + assert_equal({two: 2}, dd) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var d = {dd: {}} + d.dd[0] = 2 + d.dd['x'] = 3 + d.dd.y = 4 + assert_equal({dd: {0: 2, x: 3, y: 4}}, d) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var key = 'foo' + g:[key] = 'value' + assert_equal('value', g:foo) + unlet g:foo + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var dd = {one: 1} + dd.one) = 2 + END + v9.CheckDefFailure(lines, 'E488:', 2) + + lines =<< trim END + var dd = {one: 1} + var dd.one = 2 + END + v9.CheckDefAndScriptFailure(lines, 'E1017:', 2) + + # empty key can be used + var dd = {} + dd[""] = 6 + assert_equal({['']: 6}, dd) + + # type becomes dict<any> + var somedict = rand() > 0 ? {a: 1, b: 2} : {a: 'a', b: 'b'} + + # type is dict<any> even though initializer is dict<number> + var anyDict: dict<any> = {a: 0} + assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'})) + + # using global var, which has no declared type + g:myDict = {} + g:myDict->extend({a: 1}) + g:myDict->extend({b: 'x'}) + assert_equal({a: 1, b: 'x'}, g:myDict) + unlet g:myDict + + # using list with declared type gives an error + lines =<< trim END + var d: dict<number> + g:myDict = d + g:myDict->extend({a: 1}) + g:myDict->extend({b: 'x'}) + END + v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4) + unlet g:myDict + + # assignment to script-local dict + lines =<< trim END + vim9script + var test: dict<any> = {} + def FillDict(): dict<any> + test['a'] = 43 + return test + enddef + assert_equal({a: 43}, FillDict()) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var test: dict<any> + def FillDict(): dict<any> + test['a'] = 43 + return test + enddef + FillDict() + assert_equal({a: 43}, test) + END + v9.CheckScriptSuccess(lines) + + # assignment to global dict + lines =<< trim END + vim9script + g:test = {} + def FillDict(): dict<any> + g:test['a'] = 43 + return g:test + enddef + assert_equal({a: 43}, FillDict()) + END + v9.CheckScriptSuccess(lines) + + # assignment to buffer dict + lines =<< trim END + vim9script + b:test = {} + def FillDict(): dict<any> + b:test['a'] = 43 + return b:test + enddef + assert_equal({a: 43}, FillDict()) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + var d = {dd: test_null_dict()} + d.dd[0] = 0 + END + v9.CheckDefExecFailure(lines, 'E1103:', 2) + + lines =<< trim END + var d = {dd: 'string'} + d.dd[0] = 0 + END + v9.CheckDefExecFailure(lines, 'E1148:', 2) + + lines =<< trim END + var n: any + n.key = 5 + END + v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203: Dot can only be used on a dictionary: n.key = 5'], 2) +enddef + +def Test_assignment_local() + # Test in a separated file in order not to the current buffer/window/tab is + # changed. + var script_lines: list<string> =<< trim END + let b:existing = 'yes' + let w:existing = 'yes' + let t:existing = 'yes' + + def Test_assignment_local_internal() + b:newvar = 'new' + assert_equal('new', b:newvar) + assert_equal('yes', b:existing) + b:existing = 'no' + assert_equal('no', b:existing) + b:existing ..= 'NO' + assert_equal('noNO', b:existing) + + w:newvar = 'new' + assert_equal('new', w:newvar) + assert_equal('yes', w:existing) + w:existing = 'no' + assert_equal('no', w:existing) + w:existing ..= 'NO' + assert_equal('noNO', w:existing) + + t:newvar = 'new' + assert_equal('new', t:newvar) + assert_equal('yes', t:existing) + t:existing = 'no' + assert_equal('no', t:existing) + t:existing ..= 'NO' + assert_equal('noNO', t:existing) + enddef + call Test_assignment_local_internal() + END + v9.CheckScriptSuccess(script_lines) +enddef + +def Test_assignment_default() + # Test default values. + var thebool: bool + assert_equal(v:false, thebool) + + var thenumber: number + assert_equal(0, thenumber) + + var thefloat: float + assert_equal(0.0, thefloat) + + var thestring: string + assert_equal('', thestring) + + var theblob: blob + assert_equal(0z, theblob) + + var Thefunc: func + assert_equal(test_null_function(), Thefunc) + + var thelist: list<any> + assert_equal([], thelist) + + var thedict: dict<any> + assert_equal({}, thedict) + + if has('channel') + var thejob: job + assert_equal(test_null_job(), thejob) + + var thechannel: channel + assert_equal(test_null_channel(), thechannel) + + if has('unix') && executable('cat') + # check with non-null job and channel, types must match + thejob = job_start("cat ", {}) + thechannel = job_getchannel(thejob) + job_stop(thejob, 'kill') + endif + endif + + var nr = 1234 | nr = 5678 + assert_equal(5678, nr) +enddef + +def Test_script_var_default() + var lines =<< trim END + vim9script + var l: list<number> + var li = [1, 2] + var bl: blob + var bli = 0z12 + var d: dict<number> + var di = {'a': 1, 'b': 2} + def Echo() + assert_equal([], l) + assert_equal([1, 2], li) + assert_equal(0z, bl) + assert_equal(0z12, bli) + assert_equal({}, d) + assert_equal({'a': 1, 'b': 2}, di) + enddef + Echo() + END + v9.CheckScriptSuccess(lines) +enddef + +let s:scriptvar = 'init' + +def Test_assignment_var_list() + var lines =<< trim END + var v1: string + var v2: string + var vrem: list<string> + [v1] = ['aaa'] + assert_equal('aaa', v1) + + [v1, v2] = ['one', 'two'] + assert_equal('one', v1) + assert_equal('two', v2) + + [v1, v2; vrem] = ['one', 'two'] + assert_equal('one', v1) + assert_equal('two', v2) + assert_equal([], vrem) + + [v1, v2; vrem] = ['one', 'two', 'three'] + assert_equal('one', v1) + assert_equal('two', v2) + assert_equal(['three'], vrem) + + [&ts, &sw] = [3, 4] + assert_equal(3, &ts) + assert_equal(4, &sw) + set ts=8 sw=4 + + [@a, @z] = ['aa', 'zz'] + assert_equal('aa', @a) + assert_equal('zz', @z) + + [$SOME_VAR, $OTHER_VAR] = ['some', 'other'] + assert_equal('some', $SOME_VAR) + assert_equal('other', $OTHER_VAR) + + [g:globalvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = + ['global', 'buf', 'win', 'tab', 'error'] + assert_equal('global', g:globalvar) + assert_equal('buf', b:bufvar) + assert_equal('win', w:winvar) + assert_equal('tab', t:tabvar) + assert_equal('error', v:errmsg) + unlet g:globalvar + END + v9.CheckDefAndScriptSuccess(lines) + + [g:globalvar, scriptvar, b:bufvar] = ['global', 'script', 'buf'] + assert_equal('global', g:globalvar) + assert_equal('script', scriptvar) + assert_equal('buf', b:bufvar) + + lines =<< trim END + vim9script + var scriptvar = 'init' + [g:globalvar, scriptvar, w:winvar] = ['global', 'script', 'win'] + assert_equal('global', g:globalvar) + assert_equal('script', scriptvar) + assert_equal('win', w:winvar) + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_assignment_empty_list() + var lines =<< trim END + var l2: list<any> = [] + var l: list<string> + l = l2 + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_assignment_vim9script() + var lines =<< trim END + vim9script + def Func(): list<number> + return [1, 2] + enddef + var name1: number + var name2: number + [name1, name2] = + Func() + assert_equal(1, name1) + assert_equal(2, name2) + var ll = + Func() + assert_equal([1, 2], ll) + + @/ = 'text' + assert_equal('text', @/) + @0 = 'zero' + assert_equal('zero', @0) + @1 = 'one' + assert_equal('one', @1) + @9 = 'nine' + assert_equal('nine', @9) + @- = 'minus' + assert_equal('minus', @-) + if has('clipboard_working') + @* = 'star' + assert_equal('star', @*) + @+ = 'plus' + assert_equal('plus', @+) + endif + + var a: number = 123 + assert_equal(123, a) + var s: string = 'yes' + assert_equal('yes', s) + var b: number = 42 + assert_equal(42, b) + var w: number = 43 + assert_equal(43, w) + var t: number = 44 + assert_equal(44, t) + + var to_var = 0 + to_var = 3 + assert_equal(3, to_var) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var n: number + def Func() + n = 'string' + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string') +enddef + +def Mess(): string + v:foldstart = 123 + return 'xxx' +enddef + +def Test_assignment_failure() + v9.CheckDefFailure(['var name=234'], 'E1004:') + v9.CheckDefFailure(['var name =234'], 'E1004:') + v9.CheckDefFailure(['var name= 234'], 'E1004:') + + v9.CheckScriptFailure(['vim9script', 'var name=234'], 'E1004:') + v9.CheckScriptFailure(['vim9script', 'var name=234'], "before and after '='") + v9.CheckScriptFailure(['vim9script', 'var name =234'], 'E1004:') + v9.CheckScriptFailure(['vim9script', 'var name= 234'], 'E1004:') + v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], 'E1004:') + v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], "before and after '+='") + v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], 'E1004:') + v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], "before and after '..='") + + v9.CheckDefFailure(['var true = 1'], 'E1034:') + v9.CheckDefFailure(['var false = 1'], 'E1034:') + v9.CheckDefFailure(['var null = 1'], 'E1034:') + v9.CheckDefFailure(['var this = 1'], 'E1034:') + v9.CheckDefFailure(['var super = 1'], 'E1034:') + + v9.CheckDefFailure(['[a; b; c] = g:list'], 'E1001:') + v9.CheckDefFailure(['var [a; b; c] = g:list'], 'E1080:') + v9.CheckDefExecFailure(['var a: number', + '[a] = test_null_list()'], 'E1093:') + v9.CheckDefExecFailure(['var a: number', + '[a] = []'], 'E1093:') + v9.CheckDefExecFailure(['var x: number', + 'var y: number', + '[x, y] = [1]'], 'E1093:') + v9.CheckDefExecFailure(['var x: string', + 'var y: string', + '[x, y] = ["x"]'], 'E1093:') + v9.CheckDefExecFailure(['var x: number', + 'var y: number', + 'var z: list<number>', + '[x, y; z] = [1]'], 'E1093:') + + v9.CheckDefFailure(['var somevar'], "E1022:") + v9.CheckDefFailure(['var &tabstop = 4'], 'E1052:') + v9.CheckDefFailure(['&g:option = 5'], 'E113:') + v9.CheckScriptFailure(['vim9script', 'var &tabstop = 4'], 'E1052:') + + v9.CheckDefFailure(['var $VAR = 5'], 'E1016: Cannot declare an environment variable:') + v9.CheckScriptFailure(['vim9script', 'var $ENV = "xxx"'], 'E1016:') + + if has('dnd') + v9.CheckDefFailure(['var @~ = 5'], 'E1066:') + else + v9.CheckDefFailure(['var @~ = 5'], 'E354:') + v9.CheckDefFailure(['@~ = 5'], 'E354:') + endif + v9.CheckDefFailure(['var @a = 5'], 'E1066:') + v9.CheckDefFailure(['var @/ = "x"'], 'E1066:') + v9.CheckScriptFailure(['vim9script', 'var @a = "abc"'], 'E1066:') + + v9.CheckDefFailure(['var g:var = 5'], 'E1016: Cannot declare a global variable:') + v9.CheckDefFailure(['var w:var = 5'], 'E1016: Cannot declare a window variable:') + v9.CheckDefFailure(['var b:var = 5'], 'E1016: Cannot declare a buffer variable:') + v9.CheckDefFailure(['var t:var = 5'], 'E1016: Cannot declare a tab variable:') + + v9.CheckDefFailure(['var anr = 4', 'anr ..= "text"'], 'E1019:') + v9.CheckDefFailure(['var xnr += 4'], 'E1020:', 1) + v9.CheckScriptFailure(['vim9script', 'var xnr += 4'], 'E1020:') + v9.CheckDefFailure(["var xnr = xnr + 1"], 'E1001:', 1) + v9.CheckScriptFailure(['vim9script', 'var xnr = xnr + 4'], 'E121:') + + v9.CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = notfound', 'enddef', 'defcompile'], 'E1001:') + + v9.CheckDefFailure(['var name: list<string> = [123]'], 'expected list<string> but got list<number>') + v9.CheckDefFailure(['var name: list<number> = ["xx"]'], 'expected list<number> but got list<string>') + + v9.CheckDefFailure(['var name: dict<string> = {key: 123}'], 'expected dict<string> but got dict<number>') + v9.CheckDefFailure(['var name: dict<number> = {key: "xx"}'], 'expected dict<number> but got dict<string>') + + v9.CheckDefFailure(['var name = feedkeys("0")'], 'E1031:') + v9.CheckDefFailure(['var name: number = feedkeys("0")'], 'expected number but got void') + + v9.CheckDefFailure(['var name: dict <number>'], 'E1068:') + v9.CheckDefFailure(['var name: dict<number'], 'E1009: Missing > after type: <number') + + assert_fails('s/^/\=g:Mess()/n', 'E794:') + v9.CheckDefFailure(['var name: dict<number'], 'E1009:') + + v9.CheckDefFailure(['w:foo: number = 10'], + 'E1016: Cannot declare a window variable: w:foo') + v9.CheckDefFailure(['t:foo: bool = true'], + 'E1016: Cannot declare a tab variable: t:foo') + v9.CheckDefFailure(['b:foo: string = "x"'], + 'E1016: Cannot declare a buffer variable: b:foo') + v9.CheckDefFailure(['g:foo: number = 123'], + 'E1016: Cannot declare a global variable: g:foo') + + v9.CheckScriptFailure(['vim9script', 'w:foo: number = 123'], + 'E1304: Cannot use type with this variable: w:foo:') + v9.CheckScriptFailure(['vim9script', 't:foo: number = 123'], + 'E1304: Cannot use type with this variable: t:foo:') + v9.CheckScriptFailure(['vim9script', 'b:foo: number = 123'], + 'E1304: Cannot use type with this variable: b:foo:') + v9.CheckScriptFailure(['vim9script', 'g:foo: number = 123'], + 'E1304: Cannot use type with this variable: g:foo:') + + v9.CheckScriptFailure(['vim9script', 'const w:FOO: number = 123'], + 'E1304: Cannot use type with this variable: w:FOO:') + v9.CheckScriptFailure(['vim9script', 'const t:FOO: number = 123'], + 'E1304: Cannot use type with this variable: t:FOO:') + v9.CheckScriptFailure(['vim9script', 'const b:FOO: number = 123'], + 'E1304: Cannot use type with this variable: b:FOO:') + v9.CheckScriptFailure(['vim9script', 'const g:FOO: number = 123'], + 'E1304: Cannot use type with this variable: g:FOO:') +enddef + +def Test_assign_list() + var lines =<< trim END + var l: list<string> = [] + l[0] = 'value' + assert_equal('value', l[0]) + + l[1] = 'asdf' + assert_equal('value', l[0]) + assert_equal('asdf', l[1]) + assert_equal('asdf', l[-1]) + assert_equal('value', l[-2]) + + var nrl: list<number> = [] + for i in range(5) + nrl[i] = i + endfor + assert_equal([0, 1, 2, 3, 4], nrl) + + var ul: list<any> + ul[0] = 1 + ul[1] = 2 + ul[2] = 3 + assert_equal([1, 2, 3], ul) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var l = [1, 2] + g:idx = 'x' + l[g:idx : 1] = [0] + echo l + END + v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "x"']) + + lines =<< trim END + var l = [1, 2] + g:idx = 3 + l[g:idx : 1] = [0] + echo l + END + v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: 3') + + lines =<< trim END + var l = [1, 2] + g:idx = 'y' + l[1 : g:idx] = [0] + echo l + END + v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "y"']) + + v9.CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1) + v9.CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1) +enddef + +def Test_assign_dict() + var lines =<< trim END + var d: dict<string> = {} + d['key'] = 'value' + assert_equal('value', d['key']) + + d[123] = 'qwerty' + assert_equal('qwerty', d[123]) + assert_equal('qwerty', d['123']) + + var nrd: dict<number> = {} + for i in range(3) + nrd[i] = i + endfor + assert_equal({0: 0, 1: 1, 2: 2}, nrd) + + d.somekey = 'someval' + assert_equal({key: 'value', '123': 'qwerty', somekey: 'someval'}, d) + unlet d.somekey + assert_equal({key: 'value', '123': 'qwerty'}, d) + END + v9.CheckDefAndScriptSuccess(lines) + + v9.CheckDefFailure(["var d: dict<number> = {a: '', b: true}"], 'E1012: Type mismatch; expected dict<number> but got dict<any>', 1) + v9.CheckDefFailure(["var d: dict<dict<number>> = {x: {a: '', b: true}}"], 'E1012: Type mismatch; expected dict<dict<number>> but got dict<dict<any>>', 1) + v9.CheckDefFailure(["var d = {x: 1}", "d[1 : 2] = {y: 2}"], 'E1165: Cannot use a range with an assignment: d[1 : 2] =', 2) +enddef + +def Test_assign_dict_unknown_type() + var lines =<< trim END + vim9script + var mylist = [] + mylist += [{one: 'one'}] + def Func() + var dd = mylist[0] + assert_equal('one', dd.one) + enddef + Func() + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var mylist = [[]] + mylist[0] += [{one: 'one'}] + def Func() + var dd = mylist[0][0] + assert_equal('one', dd.one) + enddef + Func() + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_assign_dict_with_op() + var lines =<< trim END + var ds: dict<string> = {a: 'x'} + ds['a'] ..= 'y' + ds.a ..= 'z' + assert_equal('xyz', ds.a) + + var dn: dict<number> = {a: 9} + dn['a'] += 2 + assert_equal(11, dn.a) + dn.a += 2 + assert_equal(13, dn.a) + + dn['a'] -= 3 + assert_equal(10, dn.a) + dn.a -= 2 + assert_equal(8, dn.a) + + dn['a'] *= 2 + assert_equal(16, dn.a) + dn.a *= 2 + assert_equal(32, dn.a) + + dn['a'] /= 3 + assert_equal(10, dn.a) + dn.a /= 2 + assert_equal(5, dn.a) + + dn['a'] %= 3 + assert_equal(2, dn.a) + dn.a %= 6 + assert_equal(2, dn.a) + + var dd: dict<dict<list<any>>> + dd.a = {} + dd.a.b = [0] + dd.a.b += [1] + assert_equal({a: {b: [0, 1]}}, dd) + + var dab = {a: ['b']} + dab.a[0] ..= 'c' + assert_equal({a: ['bc']}, dab) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_assign_list_with_op() + var lines =<< trim END + var ls: list<string> = ['x'] + ls[0] ..= 'y' + assert_equal('xy', ls[0]) + + var ln: list<number> = [9] + ln[0] += 2 + assert_equal(11, ln[0]) + + ln[0] -= 3 + assert_equal(8, ln[0]) + + ln[0] *= 2 + assert_equal(16, ln[0]) + + ln[0] /= 3 + assert_equal(5, ln[0]) + + ln[0] %= 3 + assert_equal(2, ln[0]) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_assign_with_op_fails() + var lines =<< trim END + var s = 'abc' + s[1] += 'x' + END + v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) + + lines =<< trim END + var s = 'abc' + s[1] ..= 'x' + END + v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) + + lines =<< trim END + var dd: dict<dict<list<any>>> + dd.a = {} + dd.a.b += [1] + END + v9.CheckDefExecAndScriptFailure(lines, 'E716:', 3) +enddef + +def Test_assign_lambda() + # check if assign a lambda to a variable which type is func or any. + var lines =<< trim END + vim9script + var FuncRef = () => 123 + assert_equal(123, FuncRef()) + var FuncRef_Func: func = () => 123 + assert_equal(123, FuncRef_Func()) + var FuncRef_Any: any = () => 123 + assert_equal(123, FuncRef_Any()) + var FuncRef_Number: func(): number = () => 321 + assert_equal(321, FuncRef_Number()) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + var Ref: func(number) + Ref = (j) => !j + END + v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') + + lines =<< trim END + echo filter([1, 2, 3], (_, v: string) => v + 1) + END + v9.CheckDefAndScriptFailure(lines, 'E1051:') +enddef + +def Test_heredoc() + # simple heredoc + var lines =<< trim END + var text =<< trim TEXT # comment + abc + TEXT + assert_equal(['abc'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # empty heredoc + lines =<< trim END + var text =<< trim TEXT + TEXT + assert_equal([], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # heredoc with a single empty line + lines =<< trim END + var text =<< trim TEXT + + TEXT + assert_equal([''], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # assign heredoc to variable with type + lines =<< trim END + var text: list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # extra whitespace before type is allowed + lines =<< trim END + var text: list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # missing whitespace before type is an error + lines =<< trim END + var text:list<string> =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptFailure(lines, 'E1069:') + + # assign heredoc to list slice + lines =<< trim END + var text = [''] + text[ : ] =<< trim TEXT + var foo =<< trim FOO + TEXT + assert_equal(['var foo =<< trim FOO'], text) + END + v9.CheckDefAndScriptSuccess(lines) + + # assign heredoc to curly braces name in legacy function in Vim9 script + lines =<< trim END + vim9script + func Func() + let foo_3_bar = [''] + let foo_{1 + 2}_bar[ : ] =<< trim TEXT + var foo =<< trim FOO + TEXT + call assert_equal(['var foo =<< trim FOO'], foo_3_bar) + endfunc + Func() + END + v9.CheckScriptSuccess(lines) + + v9.CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:') + v9.CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:') + + lines =<< trim [END] + def Func() + var&lines =<< trim END + x + x + enddef + defcompile + [END] + v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') + delfunc! g:Func + + lines =<< trim [END] + def Func() + var lines =<< trim END + x + x + x + x + x + x + x + x + enddef + call Func() + [END] + v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') + delfunc! g:Func + + lines =<< trim END + var lines: number =<< trim STOP + aaa + bbb + STOP + END + v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<string>', 1) + + lines =<< trim END + var lines=<< STOP + xxx + STOP + END + v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<< STOP"', 1) + lines =<< trim END + var lines =<<STOP + xxx + STOP + END + v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) + lines =<< trim END + var lines=<<STOP + xxx + STOP + END + v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) +enddef + +def Test_var_func_call() + var lines =<< trim END + vim9script + func GetValue() + if exists('g:count') + let g:count += 1 + else + let g:count = 1 + endif + return 'this' + endfunc + var val: string = GetValue() + # env var is always a string + var env = $TERM + END + writefile(lines, 'Xfinished', 'D') + source Xfinished + # GetValue() is not called during discovery phase + assert_equal(1, g:count) + + unlet g:count +enddef + +def Test_var_missing_type() + var lines =<< trim END + vim9script + var name = g:unknown + END + v9.CheckScriptFailure(lines, 'E121:') + + lines =<< trim END + vim9script + var nr: number = 123 + var name = nr + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_var_declaration() + var lines =<< trim END + vim9script + var name: string + g:var_uninit = name + name = 'text' + g:var_test = name + # prefixing s: is not allowed + name = 'prefixed' + g:var_prefixed = name + + const FOO: number = 123 + assert_equal(123, FOO) + const FOOS = 'foos' + assert_equal('foos', FOOS) + final FLIST = [1] + assert_equal([1], FLIST) + FLIST[0] = 11 + assert_equal([11], FLIST) + + const g:FOOS = 'gfoos' + assert_equal('gfoos', g:FOOS) + final g:FLIST = [2] + assert_equal([2], g:FLIST) + g:FLIST[0] = 22 + assert_equal([22], g:FLIST) + + def SetGlobalConst() + const g:globConst = 123 + enddef + SetGlobalConst() + assert_equal(123, g:globConst) + assert_true(islocked('g:globConst')) + + const w:FOOS = 'wfoos' + assert_equal('wfoos', w:FOOS) + final w:FLIST = [3] + assert_equal([3], w:FLIST) + w:FLIST[0] = 33 + assert_equal([33], w:FLIST) + + var s:other: number + other = 1234 + g:other_var = other + + var xyz: string # comment + + # type is inferred + var dict = {['a']: 222} + def GetDictVal(key: any) + g:dict_val = dict[key] + enddef + GetDictVal('a') + + final adict: dict<string> = {} + def ChangeAdict() + adict.foo = 'foo' + enddef + ChangeAdict() + END + v9.CheckScriptSuccess(lines) + assert_equal('', g:var_uninit) + assert_equal('text', g:var_test) + assert_equal('prefixed', g:var_prefixed) + assert_equal(1234, g:other_var) + assert_equal(222, g:dict_val) + + unlet g:var_uninit + unlet g:var_test + unlet g:var_prefixed + unlet g:other_var + unlet g:globConst + unlet g:FOOS + unlet g:FLIST + unlet w:FOOS + unlet w:FLIST +enddef + +def Test_create_list_after_const() + const a = 1 + g:ll = [] + assert_equal(0, islocked('g:ll')) + unlet g:ll +enddef + +def Test_var_declaration_fails() + var lines =<< trim END + vim9script + final var: string + END + v9.CheckScriptFailure(lines, 'E1125:') + + lines =<< trim END + vim9script + const g:constvar = 'string' + g:constvar = 'xx' + END + v9.CheckScriptFailure(lines, 'E741:') + unlet g:constvar + + lines =<< trim END + vim9script + var name = 'one' + lockvar name + def SetLocked() + name = 'two' + enddef + SetLocked() + END + v9.CheckScriptFailure(lines, 'E741: Value is locked: name', 1) + + lines =<< trim END + let s:legacy = 'one' + lockvar s:legacy + def SetLocked() + s:legacy = 'two' + enddef + call SetLocked() + END + v9.CheckScriptFailure(lines, 'E741: Value is locked: s:legacy', 1) + + lines =<< trim END + vim9script + def SetGlobalConst() + const g:globConst = 123 + enddef + SetGlobalConst() + g:globConst = 234 + END + v9.CheckScriptFailure(lines, 'E741: Value is locked: g:globConst', 6) + unlet g:globConst + + lines =<< trim END + vim9script + const cdict: dict<string> = {} + def Change() + cdict.foo = 'foo' + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E46:') + + lines =<< trim END + vim9script + final w:finalvar = [9] + w:finalvar = [8] + END + v9.CheckScriptFailure(lines, 'E1122:') + unlet w:finalvar + + lines =<< trim END + vim9script + const var: string + END + v9.CheckScriptFailure(lines, 'E1021:') + + lines =<< trim END + vim9script + var 9var: string + END + v9.CheckScriptFailure(lines, 'E488:') + + v9.CheckDefFailure(['var foo.bar = 2'], 'E1087:') + v9.CheckDefFailure(['var foo[3] = 2'], 'E1087:') + v9.CheckDefFailure(['const foo: number'], 'E1021:') + + lines =<< trim END + va foo = 123 + END + v9.CheckDefAndScriptFailure(lines, 'E1065:', 1) + + lines =<< trim END + var foo: func(number + END + v9.CheckDefAndScriptFailure(lines, 'E110:', 1) + + lines =<< trim END + var foo: func(number): func( + END + v9.CheckDefAndScriptFailure(lines, 'E110:', 1) + + for type in ['num_ber', + 'anys', 'ani', + 'bools', 'boel', + 'blobs', 'blub', + 'channels', 'channol', + 'dicts', 'duct', + 'floats', 'floot', + 'funcs', 'funk', + 'jobs', 'jop', + 'lists', 'last', + 'numbers', 'numbar', + 'strings', 'strung', + 'voids', 'viod'] + v9.CheckDefAndScriptFailure([$'var foo: {type}'], 'E1010:', 1) + endfor +enddef + +def Test_var_declaration_inferred() + # check that type is set on the list so that extend() fails + var lines =<< trim END + vim9script + def GetList(): list<number> + var l = [1, 2, 3] + return l + enddef + echo GetList()->extend(['x']) + END + v9.CheckScriptFailure(lines, 'E1013:', 6) + + lines =<< trim END + vim9script + def GetNr(): number + return 5 + enddef + def TestOne() + var some = [function('len'), GetNr] + g:res = typename(some) + enddef + TestOne() + assert_equal('list<func(): number>', g:res) + + def TestTwo() + var some = [function('len'), GetNr] + g:res = typename(some) + enddef + TestTwo() + assert_equal('list<func(): number>', g:res) + unlet g:res + + # FIXME: why is the type different? + var first = [function('len'), GetNr] + assert_equal('list<func(...): number>', typename(first)) + var second = [GetNr, function('len')] + assert_equal('list<func(...): number>', typename(second)) + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_script_local_in_legacy() + # OK to define script-local later but before compiling + var lines =<< trim END + def SetLater() + legvar = 'two' + enddef + let s:legvar = 'one' + defcompile + call SetLater() + call assert_equal('two', s:legvar) + END + v9.CheckScriptSuccess(lines) + + # OK to leave out s: prefix when script-local already defined + lines =<< trim END + let s:legvar = 'one' + def SetNoPrefix() + legvar = 'two' + enddef + call SetNoPrefix() + call assert_equal('two', s:legvar) + END + v9.CheckScriptSuccess(lines) + + # Not OK to leave out s: prefix when script-local defined after compiling + lines =<< trim END + def SetLaterNoPrefix() + legvar = 'two' + enddef + defcompile + let s:legvar = 'one' + END + v9.CheckScriptFailure(lines, 'E476:', 1) + + edit! Xslfile + lines =<< trim END + var edit: bool + legacy edit + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_var_type_check() + var lines =<< trim END + vim9script + var name: string + name = 1234 + END + v9.CheckScriptFailure(lines, 'E1012:') + + lines =<< trim END + vim9script + var name:string + END + v9.CheckScriptFailure(lines, 'E1069:') + + v9.CheckDefAndScriptFailure(['var n:number = 42'], 'E1069:') + + lines =<< trim END + vim9script + var name: asdf + END + v9.CheckScriptFailure(lines, 'E1010:') + + lines =<< trim END + vim9script + var l: list<number> + l = [] + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d: dict<number> + d = {} + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d = {a: 1, b: [2]} + def Func(b: bool) + var l: list<number> = b ? d.b : [3] + enddef + defcompile + END + v9.CheckScriptSuccess(lines) +enddef + +let g:dict_number = #{one: 1, two: 2} + +def Test_var_list_dict_type() + var ll: list<number> + ll = [1, 2, 2, 3, 3, 3]->uniq() + ll->assert_equal([1, 2, 3]) + + var dd: dict<number> + dd = g:dict_number + dd->assert_equal(g:dict_number) + + var lines =<< trim END + var ll: list<number> + ll = [1, 2, 3]->map('"one"') + END + v9.CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') +enddef + +def Test_cannot_use_let() + v9.CheckDefAndScriptFailure(['let a = 34'], 'E1126:', 1) +enddef + +def Test_unlet() + g:somevar = 'yes' + assert_true(exists('g:somevar')) + unlet g:somevar + assert_false(exists('g:somevar')) + unlet! g:somevar + + # also works for script-local variable in legacy Vim script + s:somevar = 'legacy' + assert_true(exists('s:somevar')) + unlet s:somevar + assert_false(exists('s:somevar')) + unlet! s:somevar + + if 0 + unlet g:does_not_exist + endif + + v9.CheckDefExecFailure(['unlet v:notfound.key'], 'E1001:') + + v9.CheckDefExecFailure([ + 'var dd = 111', + 'unlet dd', + ], 'E1081:', 2) + + # dict unlet + var dd = {a: 1, b: 2, c: 3, 4: 4} + unlet dd['a'] + unlet dd.c + unlet dd[4] + assert_equal({b: 2}, dd) + + # null key works like empty string + dd = {'': 1, x: 9} + unlet dd[null_string] + assert_equal({x: 9}, dd) + + # list unlet + var ll = [1, 2, 3, 4] + unlet ll[1] + unlet ll[-1] + assert_equal([1, 3], ll) + + ll = [1, 2, 3, 4] + unlet ll[0 : 1] + assert_equal([3, 4], ll) + + ll = [1, 2, 3, 4] + unlet ll[2 : 8] + assert_equal([1, 2], ll) + + ll = [1, 2, 3, 4] + unlet ll[-2 : -1] + assert_equal([1, 2], ll) + + g:nrdict = {1: 1, 2: 2} + g:idx = 1 + unlet g:nrdict[g:idx] + assert_equal({2: 2}, g:nrdict) + unlet g:nrdict + unlet g:idx + + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'll[1 : 2] = 7', + ], 'E1012: Type mismatch; expected list<number> but got number', 2) + v9.CheckDefFailure([ + 'var dd = {a: 1}', + 'unlet dd["a" : "a"]', + ], 'E1166:', 2) + v9.CheckDefExecFailure([ + 'unlet g:adict[0 : 1]', + ], 'E1148:', 1) + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'unlet ll[0:1]', + ], 'E1004:', 2) + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'unlet ll[0 :1]', + ], 'E1004:', 2) + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'unlet ll[0: 1]', + ], 'E1004:', 2) + + v9.CheckDefExecFailure([ + 'g:ll = [1, 2]', + 'g:idx = "x"', + 'unlet g:ll[g:idx]', + ], 'E1029: Expected number but got string', 3) + + v9.CheckDefExecFailure([ + 'g:ll = [1, 2, 3]', + 'g:idx = "x"', + 'unlet g:ll[g:idx : 2]', + ], 'E1029: Expected number but got string', 3) + + v9.CheckDefExecFailure([ + 'g:ll = [1, 2, 3]', + 'g:idx = "x"', + 'unlet g:ll[0 : g:idx]', + ], 'E1029: Expected number but got string', 3) + + # command recognized as assignment when skipping, should not give an error + v9.CheckScriptSuccess([ + 'vim9script', + 'for i in []', + " put =''", + 'endfor']) + + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'unlet ll["x" : 1]', + ], 'E1012:', 2) + v9.CheckDefFailure([ + 'var ll = [1, 2]', + 'unlet ll[0 : "x"]', + ], 'E1012:', 2) + + # list of dict unlet + var dl = [{a: 1, b: 2}, {c: 3}] + unlet dl[0]['b'] + assert_equal([{a: 1}, {c: 3}], dl) + + v9.CheckDefExecFailure([ + 'var ll = test_null_list()', + 'unlet ll[0]', + ], 'E684:', 2) + v9.CheckDefExecFailure([ + 'var ll = [1]', + 'unlet ll[2]', + ], 'E684:', 2) + v9.CheckDefExecFailure([ + 'var ll = [1]', + 'unlet ll[g:astring]', + ], 'E1012:', 2) + v9.CheckDefExecFailure([ + 'var dd = test_null_dict()', + 'unlet dd["a"]', + ], 'E716:', 2) + v9.CheckDefExecFailure([ + 'var dd = {a: 1}', + 'unlet dd["b"]', + ], 'E716:', 2) + v9.CheckDefExecFailure([ + 'var dd = {a: 1}', + 'unlet dd[g:alist]', + ], 'E1105:', 2) + + v9.CheckDefExecFailure([ + 'g:dd = {"a": 1, 2: 2}', + 'unlet g:dd[0z11]', + ], 'E1029:', 2) + v9.CheckDefExecFailure([ + 'g:str = "a string"', + 'unlet g:str[0]', + ], 'E1148: Cannot index a string', 2) + + # can compile unlet before variable exists + g:someDict = {key: 'val'} + var k = 'key' + unlet g:someDict[k] + assert_equal({}, g:someDict) + unlet g:someDict + assert_false(exists('g:someDict')) + + v9.CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'unlet svar', + ], 'E1081:') + v9.CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'unlet s:svar', + ], 'E1268:') + v9.CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'def Func()', + ' unlet svar', + 'enddef', + 'defcompile', + ], 'E1081:') + v9.CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'func Func()', + ' unlet s:svar', + 'endfunc', + 'Func()', + ], 'E1081:') + v9.CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'def Func()', + ' unlet s:svar', + 'enddef', + 'defcompile', + ], 'E1081:') + + v9.CheckScriptFailure([ + 'vim9script', + 'def Delcount(dict: dict<any>)', + ' unlet dict.count', + 'enddef', + 'Delcount(v:)', + ], 'E742:') + + v9.CheckScriptFailure([ + 'vim9script', + 'def DelChangedtick(dict: dict<any>)', + ' unlet dict.changedtick', + 'enddef', + 'DelChangedtick(b:)', + ], 'E795:') + + writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim', 'D') + var lines =<< trim END + vim9script + import './XunletExport.vim' as exp + def UnletSvar() + unlet exp.svar + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1260:', 1) + + $ENVVAR = 'foobar' + assert_equal('foobar', $ENVVAR) + unlet $ENVVAR + assert_equal('', $ENVVAR) +enddef + +def Test_expr_error_no_assign() + var lines =<< trim END + vim9script + var x = invalid + echo x + END + v9.CheckScriptFailureList(lines, ['E121:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 / 0 + echo x + END + v9.CheckScriptFailure(lines, 'E1154:') + + lines =<< trim END + vim9script + var x = 1 % 0 + echo x + END + v9.CheckScriptFailure(lines, 'E1154:') + + lines =<< trim END + var x: string 'string' + END + v9.CheckDefAndScriptFailure(lines, 'E488:') +enddef + + +def Test_assign_command_modifier() + var lines =<< trim END + var verbose = 0 + verbose = 1 + assert_equal(1, verbose) + silent verbose = 2 + assert_equal(2, verbose) + silent verbose += 2 + assert_equal(4, verbose) + silent verbose -= 1 + assert_equal(3, verbose) + + var topleft = {one: 1} + sandbox topleft.one = 3 + assert_equal({one: 3}, topleft) + leftabove topleft[' '] = 4 + assert_equal({one: 3, ' ': 4}, topleft) + + var x: number + var y: number + silent [x, y] = [1, 2] + assert_equal(1, x) + assert_equal(2, y) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_assign_alt_buf_register() + var lines =<< trim END + edit 'file_b1' + var b1 = bufnr() + edit 'file_b2' + var b2 = bufnr() + assert_equal(b1, bufnr('#')) + @# = b2 + assert_equal(b2, bufnr('#')) + END + v9.CheckDefAndScriptSuccess(lines) +enddef + +def Test_script_funcref_case() + var lines =<< trim END + var Len = (s: string): number => len(s) + 1 + assert_equal(5, Len('asdf')) + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var len = (s: string): number => len(s) + 1 + END + v9.CheckDefAndScriptFailure(lines, 'E704:') + + lines =<< trim END + vim9script + var Len = (s: string): number => len(s) + 2 + assert_equal(6, Len('asdf')) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var len = (s: string): number => len(s) + 1 + END + v9.CheckScriptFailure(lines, 'E704:') +enddef + +def Test_script_funcref_runtime_type_check() + var lines =<< trim END + vim9script + def FuncWithNumberArg(n: number) + enddef + def Test() + var Ref: func(string) = function(FuncWithNumberArg) + enddef + defcompile + END + # OK at compile time + v9.CheckScriptSuccess(lines) + + # Type check fails at runtime + v9.CheckScriptFailure(lines + ['Test()'], 'E1012: Type mismatch; expected func(string) but got func(number)') +enddef + +def Test_inc_dec() + var lines =<< trim END + var nr = 7 + ++nr + assert_equal(8, nr) + --nr + assert_equal(7, nr) + ++nr | ++nr + assert_equal(9, nr) + ++nr # comment + assert_equal(10, nr) + + var ll = [1, 2] + --ll[0] + ++ll[1] + assert_equal([0, 3], ll) + + g:count = 1 + ++g:count + --g:count + assert_equal(1, g:count) + unlet g:count + END + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var nr = 7 + ++ nr + END + v9.CheckDefAndScriptFailure(lines, "E1202: No white space allowed after '++': ++ nr") +enddef + +def Test_abort_after_error() + # should abort after strpart() fails, not give another type error + var lines =<< trim END + vim9script + var x: string + x = strpart(1, 2) + END + writefile(lines, 'Xtestscript', 'D') + var expected = 'E1174: String required for argument 1' + assert_fails('so Xtestscript', [expected, expected], 3) +enddef + +def Test_using_s_var_in_function() + var lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + echo s:scriptlevel + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + echo s:scriptlevel + enddef + call s:SomeFunc() + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + s:scriptlevel = 456 + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + s:scriptlevel = 456 + enddef + call s:SomeFunc() + call assert_equal(456, s:scriptlevel) + END + v9.CheckScriptSuccess(lines) +enddef + +let g:someVar = 'X' + +" Test for heredoc with Vim expressions. +" This messes up highlighting, keep it near the end. +def Test_heredoc_expr() + var lines =<< trim CODE + var s = "local" + var a1 = "1" + var a2 = "2" + var a3 = "3" + var a4 = "" + var code =<< trim eval END + var a = {5 + 10} + var b = {min([10, 6])} + {max([4, 6])} + var c = "{s}" + var d = x{a1}x{a2}x{a3}x{a4} + END + assert_equal(['var a = 15', 'var b = 6 + 6', 'var c = "local"', 'var d = x1x2x3x'], code) + CODE + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim CODE + var code =<< eval trim END + var s = "{$SOME_ENV_VAR}" + END + assert_equal(['var s = "somemore"'], code) + CODE + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim CODE + var code =<< eval END + var s = "{$SOME_ENV_VAR}" + END + assert_equal([' var s = "somemore"'], code) + CODE + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim CODE + var code =<< eval trim END + let a = {{abc}} + let b = {g:someVar} + let c = {{ + END + assert_equal(['let a = {abc}', 'let b = X', 'let c = {'], code) + CODE + v9.CheckDefAndScriptSuccess(lines) + + lines =<< trim LINES + var text =<< eval trim END + let b = { + END + LINES + v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") + + lines =<< trim LINES + var text =<< eval trim END + let b = {abc + END + LINES + v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") + + lines =<< trim LINES + var text =<< eval trim END + let b = {} + END + LINES + v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"') +enddef + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker