Mercurial > vim
view src/testdir/test_vim9_assign.vim @ 27970:212c5894b8b1 v8.2.4510
patch 8.2.4510: Vim9: shortening commands leads to confusing script
Commit: https://github.com/vim/vim/commit/204852ae2adfdde10c656ca7f14e5b4207a69172
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Mar 5 12:56:44 2022 +0000
patch 8.2.4510: Vim9: shortening commands leads to confusing script
Problem: Vim9: shortening commands leads to confusing script.
Solution: In Vim9 script require at least ":cont" for ":continue", "const"
instead of "cons", "break" instead of "brea", "catch" instead of
"cat", "else" instead of "el" "elseif" instead of "elsei" "endfor"
instead of "endfo" "endif" instead of "en" "endtry" instead of
"endt", "finally" instead of "fina", "throw" instead of "th",
"while" instead of "wh".
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 05 Mar 2022 14:00:03 +0100 |
parents | 40c6e5f849dc |
children | 1012048eed26 |
line wrap: on
line source
" 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 if has('float') var float1: float = 3.4 endif 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) if has('float') 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:') endif 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:') 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) if has('float') var f: float f += 1 assert_equal(1.0, f) endif $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() if !has('float') MissingFeature float else 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) endif 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) 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() for name in ['true', 'false', 'null'] v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' = 0'], 'E1034:') v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:') endfor 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_extend_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 NULL list from a function 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) lines =<< trim END vim9script var l: list<string> = test_null_list() extend(l, ['x']) assert_equal(['x'], l) END v9.CheckScriptSuccess(lines) 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'}) assert_equal({a: 'x'}, d) END v9.CheckScriptSuccess(lines) 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') source Xsinglechar delete('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} # 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 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) if has('float') var thefloat: float assert_equal(0.0, thefloat) endif 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(['[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:') assert_fails('s/^/\=g:Mess()/n', 'E794:') v9.CheckDefFailure(['var name: dict<number'], 'E1009:') v9.CheckDefFailure(['w:foo: number = 10'], 'E488: Trailing characters: : number = 1') v9.CheckDefFailure(['t:foo: bool = true'], 'E488: Trailing characters: : bool = true') v9.CheckDefFailure(['b:foo: string = "x"'], 'E488: Trailing characters: : string = "x"') v9.CheckDefFailure(['g:foo: number = 123'], 'E488: Trailing characters: : number = 123') 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, '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() var lines =<< trim END # comment text END assert_equal(['text'], 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) 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') source Xfinished # GetValue() is not called during discovery phase assert_equal(1, g:count) unlet g:count delete('Xfinished') 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:FOO: number = 321 assert_equal(321, g:FOO) 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:FOO: number = 46 assert_equal(46, w:FOO) 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:FOO unlet g:FOOS unlet g:FLIST unlet w:FOO unlet w:FOOS unlet w:FLIST 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) 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) 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! Xfile 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) # 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') var lines =<< trim END vim9script import './XunletExport.vim' as exp def UnletSvar() unlet exp.svar enddef defcompile END v9.CheckScriptFailure(lines, 'E1260:', 1) delete('XunletExport.vim') $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') var expected = 'E1174: String required for argument 1' assert_fails('so Xtestscript', [expected, expected], 3) delete('Xtestscript') 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 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker