diff src/testdir/test_vim9_script.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 aecd03679315
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -1,4643 +1,4643 @@
-" Test various aspects of the Vim9 script language.
-
-source check.vim
-source term_util.vim
-import './vim9.vim' as v9
-source screendump.vim
-source shared.vim
-
-def Test_vim9script_feature()
-  # example from the help, here the feature is always present
-  var lines =<< trim END
-      " old style comment
-      if !has('vim9script')
-        " legacy commands would go here
-        finish
-      endif
-      vim9script
-      # Vim9 script commands go here
-      g:didit = true
-  END
-  v9.CheckScriptSuccess(lines)
-  assert_equal(true, g:didit)
-  unlet g:didit
-enddef
-
-def Test_range_only()
-  new
-  setline(1, ['blah', 'Blah'])
-  :/Blah/
-  assert_equal(2, getcurpos()[1])
-  bwipe!
-
-  # without range commands use current line
-  new
-  setline(1, ['one', 'two', 'three'])
-  :2
-  print
-  assert_equal('two', g:Screenline(&lines))
-  :3
-  list
-  assert_equal('three$', g:Screenline(&lines))
-
-  # missing command does not print the line
-  var lines =<< trim END
-    vim9script
-    :1|
-    assert_equal('three$', g:Screenline(&lines))
-    :|
-    assert_equal('three$', g:Screenline(&lines))
-  END
-  v9.CheckScriptSuccess(lines)
-
-  bwipe!
-
-  lines =<< trim END
-      set cpo+=-
-      :1,999
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E16:', 2)
-  set cpo&vim
-
-  v9.CheckDefExecAndScriptFailure([":'x"], 'E20:', 1)
-
-  # won't generate anything
-  if false
-    :123
-  endif
-enddef
-
-def Test_invalid_range()
-  var lines =<< trim END
-      :123 eval 1 + 2
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
-
-  lines =<< trim END
-      :123 if true
-      endif
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
-
-  lines =<< trim END
-      :123 echo 'yes'
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
-
-  lines =<< trim END
-      :123 cd there
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
-enddef
-
-let g:alist = [7]
-let g:astring = 'text'
-let g:anumber = 123
-
-def Test_delfunction()
-  # Check function is defined in script namespace
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'func CheckMe()',
-      '  return 123',
-      'endfunc',
-      'func DoTest()',
-      '  call assert_equal(123, s:CheckMe())',
-      'endfunc',
-      'DoTest()',
-      ])
-
-  # Check function in script namespace cannot be deleted
-  v9.CheckScriptFailure([
-      'vim9script',
-      'func DeleteMe1()',
-      'endfunc',
-      'delfunction DeleteMe1',
-      ], 'E1084:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'func DeleteMe2()',
-      'endfunc',
-      'def DoThat()',
-      '  delfunction DeleteMe2',
-      'enddef',
-      'DoThat()',
-      ], 'E1084:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'def DeleteMe3()',
-      'enddef',
-      'delfunction DeleteMe3',
-      ], 'E1084:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'def DeleteMe4()',
-      'enddef',
-      'def DoThat()',
-      '  delfunction DeleteMe4',
-      'enddef',
-      'DoThat()',
-      ], 'E1084:')
-
-  # Check that global :def function can be replaced and deleted
-  var lines =<< trim END
-      vim9script
-      def g:Global(): string
-        return "yes"
-      enddef
-      assert_equal("yes", g:Global())
-      def! g:Global(): string
-        return "no"
-      enddef
-      assert_equal("no", g:Global())
-      delfunc g:Global
-      assert_false(exists('*g:Global'))
-  END
-  v9.CheckScriptSuccess(lines)
-
-  # Check that global function can be replaced by a :def function and deleted
-  lines =<< trim END
-      vim9script
-      func g:Global()
-        return "yes"
-      endfunc
-      assert_equal("yes", g:Global())
-      def! g:Global(): string
-        return "no"
-      enddef
-      assert_equal("no", g:Global())
-      delfunc g:Global
-      assert_false(exists('*g:Global'))
-  END
-  v9.CheckScriptSuccess(lines)
-
-  # Check that global :def function can be replaced by a function and deleted
-  lines =<< trim END
-      vim9script
-      def g:Global(): string
-        return "yes"
-      enddef
-      assert_equal("yes", g:Global())
-      func! g:Global()
-        return "no"
-      endfunc
-      assert_equal("no", g:Global())
-      delfunc g:Global
-      assert_false(exists('*g:Global'))
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_wrong_type()
-  v9.CheckDefFailure(['var name: list<nothing>'], 'E1010:')
-  v9.CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
-  v9.CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
-  v9.CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
-
-  v9.CheckDefFailure(['var name: dict<number'], 'E1009:')
-  v9.CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
-
-  v9.CheckDefFailure(['var name: ally'], 'E1010:')
-  v9.CheckDefFailure(['var name: bram'], 'E1010:')
-  v9.CheckDefFailure(['var name: cathy'], 'E1010:')
-  v9.CheckDefFailure(['var name: dom'], 'E1010:')
-  v9.CheckDefFailure(['var name: freddy'], 'E1010:')
-  v9.CheckDefFailure(['var name: john'], 'E1010:')
-  v9.CheckDefFailure(['var name: larry'], 'E1010:')
-  v9.CheckDefFailure(['var name: ned'], 'E1010:')
-  v9.CheckDefFailure(['var name: pam'], 'E1010:')
-  v9.CheckDefFailure(['var name: sam'], 'E1010:')
-  v9.CheckDefFailure(['var name: vim'], 'E1010:')
-
-  v9.CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
-  v9.CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
-enddef
-
-def Test_script_namespace()
-  # defining a function or variable with s: is not allowed
-  var lines =<< trim END
-      vim9script
-      def s:Function()
-      enddef
-  END
-  v9.CheckScriptFailure(lines, 'E1268:')
-
-  for decl in ['var', 'const', 'final']
-    lines =<< trim END
-        vim9script
-        var s:var = 'var'
-    END
-    v9.CheckScriptFailure([
-        'vim9script',
-        decl .. ' s:var = "var"',
-        ], 'E1268:')
-  endfor
-
-  # Calling a function or using a variable with s: is not allowed at script
-  # level
-  lines =<< trim END
-      vim9script
-      def Function()
-      enddef
-      s:Function()
-  END
-  v9.CheckScriptFailure(lines, 'E1268:')
-  lines =<< trim END
-      vim9script
-      def Function()
-      enddef
-      call s:Function()
-  END
-  v9.CheckScriptFailure(lines, 'E1268:')
-  lines =<< trim END
-      vim9script
-      var var = 'var'
-      echo s:var
-  END
-  v9.CheckScriptFailure(lines, 'E1268:')
-enddef
-
-def Test_script_wrong_type()
-  var lines =<< trim END
-      vim9script
-      var dict: dict<string>
-      dict['a'] = ['x']
-  END
-  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
-enddef
-
-def Test_const()
-  v9.CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
-  v9.CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
-  v9.CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
-  v9.CheckDefFailure(['final two'], 'E1125:')
-  v9.CheckDefFailure(['final &option'], 'E996:')
-
-  var lines =<< trim END
-    final list = [1, 2, 3]
-    list[0] = 4
-    list->assert_equal([4, 2, 3])
-    const other = [5, 6, 7]
-    other->assert_equal([5, 6, 7])
-
-    var varlist = [7, 8]
-    const constlist = [1, varlist, 3]
-    varlist[0] = 77
-    constlist[1][1] = 88
-    var cl = constlist[1]
-    cl[1] = 88
-    constlist->assert_equal([1, [77, 88], 3])
-
-    var vardict = {five: 5, six: 6}
-    const constdict = {one: 1, two: vardict, three: 3}
-    vardict['five'] = 55
-    constdict['two']['six'] = 66
-    var cd = constdict['two']
-    cd['six'] = 66
-    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # "any" type with const flag is recognized as "any"
-  lines =<< trim END
-      const dict: dict<any> = {foo: {bar: 42}}
-      const foo = dict.foo
-      assert_equal(v:t_number, type(foo.bar))
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # also when used as a builtin function argument
-  lines =<< trim END
-      vim9script
-
-      def SorterFunc(lhs: dict<string>, rhs: dict<string>): number
-        return lhs.name <# rhs.name ? -1 : 1
-      enddef
-
-      def Run(): void
-        var list =  [{name: "3"}, {name: "2"}]
-        const Sorter = get({}, "unknown", SorterFunc)
-        sort(list, Sorter)
-        assert_equal([{name: "2"}, {name: "3"}], list)
-      enddef
-
-      Run()
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_const_bang()
-  var lines =<< trim END
-      const var = 234
-      var = 99
-  END
-  v9.CheckDefExecFailure(lines, 'E1018:', 2)
-  v9.CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
-
-  lines =<< trim END
-      const ll = [2, 3, 4]
-      ll[0] = 99
-  END
-  v9.CheckDefExecFailure(lines, 'E1119:', 2)
-  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
-
-  lines =<< trim END
-      const ll = [2, 3, 4]
-      ll[3] = 99
-  END
-  v9.CheckDefExecFailure(lines, 'E1118:', 2)
-  v9.CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
-
-  lines =<< trim END
-      const dd = {one: 1, two: 2}
-      dd["one"] = 99
-  END
-  v9.CheckDefExecFailure(lines, 'E1121:', 2)
-  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
-
-  lines =<< trim END
-      const dd = {one: 1, two: 2}
-      dd["three"] = 99
-  END
-  v9.CheckDefExecFailure(lines, 'E1120:')
-  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
-enddef
-
-def Test_range_no_colon()
-  v9.CheckDefFailure(['%s/a/b/'], 'E1050:')
-  v9.CheckDefFailure(['+ s/a/b/'], 'E1050:')
-  v9.CheckDefFailure(['- s/a/b/'], 'E1050:')
-  v9.CheckDefFailure(['. s/a/b/'], 'E1050:')
-enddef
-
-
-def Test_block()
-  var outer = 1
-  {
-    var inner = 2
-    assert_equal(1, outer)
-    assert_equal(2, inner)
-  }
-  assert_equal(1, outer)
-
-  {|echo 'yes'|}
-enddef
-
-def Test_block_failure()
-  v9.CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
-  v9.CheckDefFailure(['}'], 'E1025:')
-  v9.CheckDefFailure(['{', 'echo 1'], 'E1026:')
-enddef
-
-def Test_block_local_vars()
-  var lines =<< trim END
-      vim9script
-      v:testing = 1
-      if true
-        var text = ['hello']
-        def SayHello(): list<string>
-          return text
-        enddef
-        def SetText(v: string)
-          text = [v]
-        enddef
-      endif
-
-      if true
-        var text = ['again']
-        def SayAgain(): list<string>
-          return text
-        enddef
-      endif
-
-      # test that the "text" variables are not cleaned up
-      test_garbagecollect_now()
-
-      defcompile
-
-      assert_equal(['hello'], SayHello())
-      assert_equal(['again'], SayAgain())
-
-      SetText('foobar')
-      assert_equal(['foobar'], SayHello())
-
-      call writefile(['ok'], 'Xdidit')
-      qall!
-  END
-
-  # need to execute this with a separate Vim instance to avoid the current
-  # context gets garbage collected.
-  writefile(lines, 'Xscript', 'D')
-  g:RunVim([], [], '-S Xscript')
-  assert_equal(['ok'], readfile('Xdidit'))
-
-  delete('Xdidit')
-enddef
-
-def Test_block_local_vars_with_func()
-  var lines =<< trim END
-      vim9script
-      if true
-        var foo = 'foo'
-        if true
-          var bar = 'bar'
-          def Func(): list<string>
-            return [foo, bar]
-          enddef
-        endif
-      endif
-      # function is compiled here, after blocks have finished, can still access
-      # "foo" and "bar"
-      assert_equal(['foo', 'bar'], Func())
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-" legacy func for command that's defined later
-func s:InvokeSomeCommand()
-  SomeCommand
-endfunc
-
-def Test_autocommand_block()
-  com SomeCommand {
-      g:someVar = 'some'
-    }
-  InvokeSomeCommand()
-  assert_equal('some', g:someVar)
-
-  delcommand SomeCommand
-  unlet g:someVar
-enddef
-
-def Test_command_block()
-  au BufNew *.xml {
-      g:otherVar = 'other'
-    }
-  split other.xml
-  assert_equal('other', g:otherVar)
-
-  bwipe!
-  au! BufNew *.xml
-  unlet g:otherVar
-enddef
-
-func g:NoSuchFunc()
-  echo 'none'
-endfunc
-
-def Test_try_catch_throw()
-  var l = []
-  try # comment
-    add(l, '1')
-    throw 'wrong'
-    add(l, '2')  # "unreachable code"
-  catch # comment
-    add(l, v:exception)
-  finally # comment
-    add(l, '3')
-  endtry # comment
-  assert_equal(['1', 'wrong', '3'], l)
-
-  l = []
-  try
-    try
-      add(l, '1')
-      throw 'wrong'
-      add(l, '2')  # "unreachable code"
-    catch /right/
-      add(l, v:exception)
-    endtry
-  catch /wrong/
-    add(l, 'caught')
-  finally
-    add(l, 'finally')
-  endtry
-  assert_equal(['1', 'caught', 'finally'], l)
-
-  var n: number
-  try
-    n = l[3]
-  catch /E684:/
-    n = 99
-  endtry
-  assert_equal(99, n)
-
-  var done = 'no'
-  if 0
-    try | catch | endtry
-  else
-    done = 'yes'
-  endif
-  assert_equal('yes', done)
-
-  done = 'no'
-  if 1
-    done = 'yes'
-  else
-    try | catch | endtry
-    done = 'never'
-  endif
-  assert_equal('yes', done)
-
-  if 1
-  else
-    try | catch /pat/ | endtry
-    try | catch /pat/
-    endtry
-    try
-    catch /pat/ | endtry
-    try
-    catch /pat/
-    endtry
-  endif
-
-  try
-    # string slice returns a string, not a number
-    n = g:astring[3]
-  catch /E1012:/
-    n = 77
-  endtry
-  assert_equal(77, n)
-
-  try
-    n = l[g:astring]
-  catch /E1012:/
-    n = 88
-  endtry
-  assert_equal(88, n)
-
-  try
-    n = s:does_not_exist
-  catch /E121:/
-    n = 111
-  endtry
-  assert_equal(111, n)
-
-  try
-    n = g:does_not_exist
-  catch /E121:/
-    n = 121
-  endtry
-  assert_equal(121, n)
-
-  var d = {one: 1}
-  try
-    n = d[g:astring]
-  catch /E716:/
-    n = 222
-  endtry
-  assert_equal(222, n)
-
-  try
-    n = -g:astring
-  catch /E1012:/
-    n = 233
-  endtry
-  assert_equal(233, n)
-
-  try
-    n = +g:astring
-  catch /E1012:/
-    n = 244
-  endtry
-  assert_equal(244, n)
-
-  try
-    n = +g:alist
-  catch /E1012:/
-    n = 255
-  endtry
-  assert_equal(255, n)
-
-  var nd: dict<any>
-  try
-    nd = {[g:alist]: 1}
-  catch /E1105:/
-    n = 266
-  endtry
-  assert_equal(266, n)
-
-  l = [1, 2, 3]
-  try
-    [n] = l
-  catch /E1093:/
-    n = 277
-  endtry
-  assert_equal(277, n)
-
-  try
-    &ts = g:astring
-  catch /E1012:/
-    n = 288
-  endtry
-  assert_equal(288, n)
-
-  try
-    &backspace = 'asdf'
-  catch /E474:/
-    n = 299
-  endtry
-  assert_equal(299, n)
-
-  l = [1]
-  try
-    l[3] = 3
-  catch /E684:/
-    n = 300
-  endtry
-  assert_equal(300, n)
-
-  try
-    unlet g:does_not_exist
-  catch /E108:/
-    n = 322
-  endtry
-  assert_equal(322, n)
-
-  try
-    d = {text: 1, [g:astring]: 2}
-  catch /E721:/
-    n = 333
-  endtry
-  assert_equal(333, n)
-
-  try
-    l = g:DeletedFunc()
-  catch /E933:/
-    n = 344
-  endtry
-  assert_equal(344, n)
-
-  try
-    echo range(1, 2, 0)
-  catch /E726:/
-    n = 355
-  endtry
-  assert_equal(355, n)
-
-  var P = function('g:NoSuchFunc')
-  delfunc g:NoSuchFunc
-  try
-    echo P()
-  catch /E117:/
-    n = 366
-  endtry
-  assert_equal(366, n)
-
-  try
-    echo g:NoSuchFunc()
-  catch /E117:/
-    n = 377
-  endtry
-  assert_equal(377, n)
-
-  try
-    echo g:alist + 4
-  catch /E745:/
-    n = 388
-  endtry
-  assert_equal(388, n)
-
-  try
-    echo 4 + g:alist
-  catch /E745:/
-    n = 399
-  endtry
-  assert_equal(399, n)
-
-  try
-    echo g:alist.member
-  catch /E715:/
-    n = 400
-  endtry
-  assert_equal(400, n)
-
-  try
-    echo d.member
-  catch /E716:/
-    n = 411
-  endtry
-  assert_equal(411, n)
-
-  var counter = 0
-  for i in range(4)
-    try
-      eval [][0]
-    catch
-    endtry
-    counter += 1
-  endfor
-  assert_equal(4, counter)
-
-  # no requirement for spaces before |
-  try|echo 0|catch|endtry
-
-  # return in try with finally
-  def ReturnInTry(): number
-    var ret = 4
-    try
-      return ret
-    catch /this/
-      return -1
-    catch /that/
-      return -1
-    finally
-      # changing ret has no effect
-      ret = 7
-    endtry
-    return -2
-  enddef
-  assert_equal(4, ReturnInTry())
-
-  # return in catch with finally
-  def ReturnInCatch(): number
-    var ret = 5
-    try
-      throw 'getout'
-      return -1 # "unreachable code"
-    catch /getout/
-      # ret is evaluated here
-      return ret
-    finally
-      # changing ret later has no effect
-      ret = -3
-    endtry
-    return -2
-  enddef
-  assert_equal(5, ReturnInCatch())
-
-  # return in finally after empty catch
-  def ReturnInFinally(): number
-    try
-    finally
-      return 6
-    endtry
-  enddef
-  assert_equal(6, ReturnInFinally())
-
-  var lines =<< trim END
-      vim9script
-      try
-        acos('0.5')
-          ->setline(1)
-      catch
-        g:caught = v:exception
-      endtry
-  END
-  v9.CheckScriptSuccess(lines)
-  assert_match('E1219: Float or Number required for argument 1', g:caught)
-  unlet g:caught
-
-  # missing catch and/or finally
-  lines =<< trim END
-      vim9script
-      try
-        echo 'something'
-      endtry
-  END
-  v9.CheckScriptFailure(lines, 'E1032:')
-
-  # skipping try-finally-endtry when try-finally-endtry is used in another block
-  lines =<< trim END
-      if v:true
-        try
-        finally
-        endtry
-      else
-        try
-        finally
-        endtry
-      endif
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_unreachable_after()
-  var lines =<< trim END
-      try
-        throw 'Error'
-        echo 'not reached'
-      catch /Error/
-      endtry
-  END
-  v9.CheckDefFailure(lines, 'E1095: Unreachable code after :throw')
-
-  lines =<< trim END
-      def SomeFunc(): number
-        try
-          return 3
-          echo 'not reached'
-        catch /Error/
-        endtry
-        return 4
-      enddef
-      defcompile
-  END
-  v9.CheckScriptFailure(lines, 'E1095: Unreachable code after :return')
-enddef
-
-def Test_throw_in_nested_try()
-  var lines =<< trim END
-      vim9script
-
-      def Try(F: func(): void)
-        try
-          F()
-        catch
-        endtry
-      enddef
-
-      class X
-        def F()
-          try
-            throw 'Foobar'
-          catch
-            throw v:exception
-          endtry
-        enddef
-      endclass
-
-      def Test_TryMethod()
-        var x = X.new()
-        Try(() => x.F())
-      enddef
-
-
-      try
-        Test_TryMethod()
-      catch
-      endtry
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_try_var_decl()
-  var lines =<< trim END
-      vim9script
-      try
-        var in_try = 1
-        assert_equal(1, get(s:, 'in_try', -1))
-        throw "getout"
-      catch
-        var in_catch = 2
-        assert_equal(-1, get(s:, 'in_try', -1))
-        assert_equal(2, get(s:, 'in_catch', -1))
-      finally
-        var in_finally = 3
-        assert_equal(-1, get(s:, 'in_try', -1))
-        assert_equal(-1, get(s:, 'in_catch', -1))
-        assert_equal(3, get(s:, 'in_finally', -1))
-      endtry
-      assert_equal(-1, get(s:, 'in_try', -1))
-      assert_equal(-1, get(s:, 'in_catch', -1))
-      assert_equal(-1, get(s:, 'in_finally', -1))
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_try_ends_in_return()
-  var lines =<< trim END
-      vim9script
-      def Foo(): string
-        try
-          return 'foo'
-        catch
-          return 'caught'
-        endtry
-      enddef
-      assert_equal('foo', Foo())
-  END
-  v9.CheckScriptSuccess(lines)
-
-  lines =<< trim END
-      vim9script
-      def Foo(): string
-        try
-          return 'foo'
-        catch
-          return 'caught'
-        endtry
-        echo 'notreached'
-      enddef
-      assert_equal('foo', Foo())
-  END
-  v9.CheckScriptFailure(lines, 'E1095:')
-
-  lines =<< trim END
-      vim9script
-      def Foo(): string
-        try
-          return 'foo'
-        catch /x/
-          return 'caught'
-        endtry
-      enddef
-      assert_equal('foo', Foo())
-  END
-  v9.CheckScriptFailure(lines, 'E1027:')
-
-  lines =<< trim END
-      vim9script
-      def Foo(): string
-        try
-          echo 'foo'
-        catch
-          echo 'caught'
-        finally
-          return 'done'
-        endtry
-      enddef
-      assert_equal('done', Foo())
-  END
-  v9.CheckScriptSuccess(lines)
-
-enddef
-
-def Test_try_in_catch()
-  var lines =<< trim END
-      vim9script
-      var seq = []
-      def DoIt()
-        try
-          seq->add('throw 1')
-          eval [][0]
-          seq->add('notreached')
-        catch
-          seq->add('catch')
-          try
-            seq->add('throw 2')
-            eval [][0]
-            seq->add('notreached')
-          catch /nothing/
-            seq->add('notreached')
-          endtry
-          seq->add('done')
-        endtry
-      enddef
-      DoIt()
-      assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq)
-  END
-enddef
-
-def Test_error_in_catch()
-  var lines =<< trim END
-      try
-        eval [][0]
-      catch /E684:/
-        eval [][0]
-      endtry
-  END
-  v9.CheckDefExecFailure(lines, 'E684:', 4)
-enddef
-
-" :while at the very start of a function that :continue jumps to
-def s:TryContinueFunc()
- while g:Count < 2
-   g:sequence ..= 't'
-    try
-      echoerr 'Test'
-    catch
-      g:Count += 1
-      g:sequence ..= 'c'
-      continue
-    endtry
-    g:sequence ..= 'e'
-    g:Count += 1
-  endwhile
-enddef
-
-def Test_continue_in_try_in_while()
-  g:Count = 0
-  g:sequence = ''
-  TryContinueFunc()
-  assert_equal('tctc', g:sequence)
-  unlet g:Count
-  unlet g:sequence
-enddef
-
-def Test_break_in_try_in_for()
-  var lines =<< trim END
-      vim9script
-      def Ls(): list<string>
-        var ls: list<string>
-        for s in ['abc', 'def']
-          for _ in [123, 456]
-            try
-              eval [][0]
-            catch
-              break
-            endtry
-          endfor
-          ls += [s]
-        endfor
-        return ls
-      enddef
-      assert_equal(['abc', 'def'], Ls())
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_nocatch_return_in_try()
-  # return in try block returns normally
-  def ReturnInTry(): string
-    try
-      return '"some message"'
-    catch
-    endtry
-    return 'not reached'
-  enddef
-  exe 'echoerr ' .. ReturnInTry()
-enddef
-
-def Test_cnext_works_in_catch()
-  var lines =<< trim END
-      vim9script
-      au BufEnter * eval 1 + 2
-      writefile(['text'], 'Xcncfile1')
-      writefile(['text'], 'Xcncfile2')
-      var items = [
-          {lnum: 1, filename: 'Xcncfile1', valid: true},
-          {lnum: 1, filename: 'Xcncfile2', valid: true}
-        ]
-      setqflist([], ' ', {items: items})
-      cwindow
-
-      def CnextOrCfirst()
-        # if cnext fails, cfirst is used
-        try
-          cnext
-        catch
-          cfirst
-        endtry
-      enddef
-
-      CnextOrCfirst()
-      CnextOrCfirst()
-      writefile([getqflist({idx: 0}).idx], 'Xcncresult')
-      qall
-  END
-  writefile(lines, 'XCatchCnext', 'D')
-  g:RunVim([], [], '--clean -S XCatchCnext')
-  assert_equal(['1'], readfile('Xcncresult'))
-
-  delete('Xcncfile1')
-  delete('Xcncfile2')
-  delete('Xcncresult')
-enddef
-
-def Test_throw_skipped()
-  if 0
-    throw dontgethere
-  endif
-enddef
-
-def Test_nocatch_throw_silenced()
-  var lines =<< trim END
-    vim9script
-    def Func()
-      throw 'error'
-    enddef
-    silent! Func()
-  END
-  writefile(lines, 'XthrowSilenced', 'D')
-  source XthrowSilenced
-enddef
-
-" g:DeletedFunc() is found when compiling Test_try_catch_throw() and then
-" deleted, this should give a runtime error.
-def DeletedFunc(): list<any>
-  return ['delete me']
-enddef
-defcompile DeletedFunc
-
-call test_override('unreachable', 1)
-defcompile Test_try_catch_throw
-call test_override('unreachable', 0)
-
-delfunc DeletedFunc
-
-def s:ThrowFromDef()
-  throw "getout" # comment
-enddef
-
-func s:CatchInFunc()
-  try
-    call s:ThrowFromDef()
-  catch
-    let g:thrown_func = v:exception
-  endtry
-endfunc
-
-def s:CatchInDef()
-  try
-    ThrowFromDef()
-  catch
-    g:thrown_def = v:exception
-  endtry
-enddef
-
-def s:ReturnFinally(): string
-  try
-    return 'intry'
-  finally
-    g:in_finally = 'finally'
-  endtry
-  return 'end'
-enddef
-
-def Test_try_catch_nested()
-  CatchInFunc()
-  assert_equal('getout', g:thrown_func)
-
-  CatchInDef()
-  assert_equal('getout', g:thrown_def)
-
-  assert_equal('intry', ReturnFinally())
-  assert_equal('finally', g:in_finally)
-
-  var l = []
-  try
-    l->add('1')
-    throw 'bad'
-    l->add('x')  # "unreachable code"
-  catch /bad/
-    l->add('2')
-    try
-      l->add('3')
-      throw 'one'
-      l->add('x')
-    catch /one/
-      l->add('4')
-      try
-        l->add('5')
-        throw 'more'
-        l->add('x')
-      catch /more/
-        l->add('6')
-      endtry
-    endtry
-  endtry
-  assert_equal(['1', '2', '3', '4', '5', '6'], l)
-
-  l = []
-  try
-    try
-      l->add('1')
-      throw 'foo'
-      l->add('x')
-    catch
-      l->add('2')
-      throw 'bar'
-      l->add('x')
-    finally
-      l->add('3')
-    endtry
-    l->add('x')
-  catch /bar/
-    l->add('4')
-  endtry
-  assert_equal(['1', '2', '3', '4'], l)
-enddef
-
-call test_override('unreachable', 1)
-defcompile Test_try_catch_nested
-call test_override('unreachable', 0)
-
-def s:TryOne(): number
-  try
-    return 0
-  catch
-  endtry
-  return 0
-enddef
-
-def s:TryTwo(n: number): string
-  try
-    var x = {}
-  catch
-  endtry
-  return 'text'
-enddef
-
-def Test_try_catch_twice()
-  assert_equal('text', TryOne()->TryTwo())
-enddef
-
-def Test_try_catch_match()
-  var seq = 'a'
-  try
-    throw 'something'
-  catch /nothing/
-    seq ..= 'x'
-  catch /some/
-    seq ..= 'b'
-  catch /asdf/
-    seq ..= 'x'
-  catch ?a\?sdf?
-    seq ..= 'y'
-  finally
-    seq ..= 'c'
-  endtry
-  assert_equal('abc', seq)
-enddef
-
-def Test_try_catch_fails()
-  v9.CheckDefFailure(['catch'], 'E603:')
-  v9.CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
-  v9.CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
-  v9.CheckDefFailure(['finally'], 'E606:')
-  v9.CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
-  v9.CheckDefFailure(['endtry'], 'E602:')
-  v9.CheckDefFailure(['while 1', 'endtry'], 'E170:')
-  v9.CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
-  v9.CheckDefFailure(['if 1', 'endtry'], 'E171:')
-  v9.CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
-
-  v9.CheckDefFailure(['throw'], 'E1143:')
-  v9.CheckDefFailure(['throw xxx'], 'E1001:')
-enddef
-
-def Try_catch_skipped()
-  var l = []
-  try
-  finally
-  endtry
-
-  if 1
-  else
-    try
-    endtry
-  endif
-enddef
-
-" The skipped try/endtry was updating the wrong instruction.
-def Test_try_catch_skipped()
-  var instr = execute('disassemble Try_catch_skipped')
-  assert_match("NEWLIST size 0\n", instr)
-enddef
-
-def Test_throw_line_number()
-  def Func()
-    eval 1 + 1
-    eval 2 + 2
-    throw 'exception'
-  enddef
-  try
-    Func()
-  catch /exception/
-    assert_match('line 3', v:throwpoint)
-  endtry
-enddef
-
-
-def Test_throw_vimscript()
-  # only checks line continuation
-  var lines =<< trim END
-      vim9script
-      try
-        throw 'one'
-              .. 'two'
-      catch
-        assert_equal('onetwo', v:exception)
-      endtry
-  END
-  v9.CheckScriptSuccess(lines)
-
-  lines =<< trim END
-    vim9script
-    @r = ''
-    def Func()
-      throw @r
-    enddef
-    var result = ''
-    try
-      Func()
-    catch /E1129:/
-      result = 'caught'
-    endtry
-    assert_equal('caught', result)
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_error_in_nested_function()
-  # an error in a nested :function aborts executing in the calling :def function
-  var lines =<< trim END
-      vim9script
-      def Func()
-        Error()
-        g:test_var = 1
-      enddef
-      func Error() abort
-        eval [][0]
-      endfunc
-      Func()
-  END
-  g:test_var = 0
-  v9.CheckScriptFailure(lines, 'E684:')
-  assert_equal(0, g:test_var)
-enddef
-
-def Test_abort_after_error()
-  var lines =<< trim END
-      vim9script
-      while true
-        echo notfound
-      endwhile
-      g:gotthere = true
-  END
-  g:gotthere = false
-  v9.CheckScriptFailure(lines, 'E121:')
-  assert_false(g:gotthere)
-  unlet g:gotthere
-enddef
-
-def Test_cexpr_vimscript()
-  # only checks line continuation
-  set errorformat=File\ %f\ line\ %l
-  var lines =<< trim END
-      vim9script
-      cexpr 'File'
-                .. ' someFile' ..
-                   ' line 19'
-      assert_equal(19, getqflist()[0].lnum)
-  END
-  v9.CheckScriptSuccess(lines)
-
-  lines =<< trim END
-      vim9script
-      def CexprFail()
-        au QuickfixCmdPre * echo g:doesnotexist
-        cexpr 'File otherFile line 99'
-        g:didContinue = 'yes'
-      enddef
-      CexprFail()
-      g:didContinue = 'also'
-  END
-  g:didContinue = 'no'
-  v9.CheckScriptFailure(lines, 'E121: Undefined variable: g:doesnotexist')
-  assert_equal('no', g:didContinue)
-  au! QuickfixCmdPre
-
-  lines =<< trim END
-      vim9script
-      def CexprFail()
-        cexpr g:aNumber
-        g:didContinue = 'yes'
-      enddef
-      CexprFail()
-      g:didContinue = 'also'
-  END
-  g:aNumber = 123
-  g:didContinue = 'no'
-  v9.CheckScriptFailure(lines, 'E777: String or List expected')
-  assert_equal('no', g:didContinue)
-  unlet g:didContinue
-
-  set errorformat&
-enddef
-
-def Test_statusline_syntax()
-  # legacy syntax is used for 'statusline'
-  var lines =<< trim END
-      vim9script
-      func g:Status()
-        return '%{"x" is# "x"}'
-      endfunc
-      set laststatus=2 statusline=%!Status()
-      redrawstatus
-      set laststatus statusline=
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_list_vimscript()
-  # checks line continuation and comments
-  var lines =<< trim END
-      vim9script
-      var mylist = [
-            'one',
-            # comment
-            'two', # empty line follows
-
-            'three',
-            ]
-      assert_equal(['one', 'two', 'three'], mylist)
-  END
-  v9.CheckScriptSuccess(lines)
-
-  # check all lines from heredoc are kept
-  lines =<< trim END
-      # comment 1
-      two
-      # comment 3
-
-      five
-      # comment 6
-  END
-  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
-
-  lines =<< trim END
-    [{
-      a: 0}]->string()->assert_equal("[{'a': 0}]")
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-if has('channel')
-  let someJob = test_null_job()
-
-  def FuncWithError()
-    echomsg g:someJob
-  enddef
-
-  func Test_convert_emsg_to_exception()
-    try
-      call FuncWithError()
-    catch
-      call assert_match('Vim:E908:', v:exception)
-    endtry
-  endfunc
-endif
-
-def Test_vim9script_mix()
-  var lines =<< trim END
-    if has(g:feature)
-      " legacy script
-      let g:legacy = 1
-      finish
-    endif
-    vim9script
-    g:legacy = 0
-  END
-  g:feature = 'eval'
-  g:legacy = -1
-  v9.CheckScriptSuccess(lines)
-  assert_equal(1, g:legacy)
-
-  g:feature = 'noteval'
-  g:legacy = -1
-  v9.CheckScriptSuccess(lines)
-  assert_equal(0, g:legacy)
-enddef
-
-def Test_vim9script_fails()
-  v9.CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
-  v9.CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
-
-  v9.CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
-  v9.CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
-
-  assert_fails('vim9script', 'E1038:')
-  v9.CheckDefFailure(['vim9script'], 'E1038:')
-
-  # no error when skipping
-  if has('nothing')
-    vim9script
-  endif
-enddef
-
-def Test_script_var_shadows_function()
-  var lines =<< trim END
-      vim9script
-      def Func(): number
-        return 123
-      enddef
-      var Func = 1
-  END
-  v9.CheckScriptFailure(lines, 'E1041:', 5)
-enddef
-
-def Test_function_shadows_script_var()
-  var lines =<< trim END
-      vim9script
-      var Func = 1
-      def Func(): number
-        return 123
-      enddef
-  END
-  v9.CheckScriptFailure(lines, 'E1041:', 3)
-enddef
-
-def Test_script_var_shadows_command()
-  var lines =<< trim END
-      var undo = 1
-      undo = 2
-      assert_equal(2, undo)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  lines =<< trim END
-      var undo = 1
-      undo
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1207:', 2)
-enddef
-
-def Test_vim9script_call_wrong_type()
-  var lines =<< trim END
-      vim9script
-      var Time = 'localtime'
-      Time()
-  END
-  v9.CheckScriptFailure(lines, 'E1085:')
-enddef
-
-def Test_vim9script_reload_delfunc()
-  var first_lines =<< trim END
-    vim9script
-    def FuncYes(): string
-      return 'yes'
-    enddef
-  END
-  var withno_lines =<< trim END
-    def FuncNo(): string
-      return 'no'
-    enddef
-    def g:DoCheck(no_exists: bool)
-      assert_equal('yes', FuncYes())
-      assert_equal('no', FuncNo())
-    enddef
-  END
-  var nono_lines =<< trim END
-    def g:DoCheck(no_exists: bool)
-      assert_equal('yes', FuncYes())
-      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
-    enddef
-  END
-
-  # FuncNo() is defined
-  writefile(first_lines + withno_lines, 'Xreloaded.vim', 'D')
-  source Xreloaded.vim
-  g:DoCheck(true)
-
-  # FuncNo() is not redefined
-  writefile(first_lines + nono_lines, 'Xreloaded.vim')
-  source Xreloaded.vim
-  g:DoCheck(false)
-
-  # FuncNo() is back
-  writefile(first_lines + withno_lines, 'Xreloaded.vim')
-  source Xreloaded.vim
-  g:DoCheck(false)
-enddef
-
-def Test_vim9script_reload_delvar()
-  # write the script with a script-local variable
-  var lines =<< trim END
-    vim9script
-    var name = 'string'
-  END
-  writefile(lines, 'XreloadVar.vim', 'D')
-  source XreloadVar.vim
-
-  # now write the script using the same variable locally - works
-  lines =<< trim END
-    vim9script
-    def Func()
-      var name = 'string'
-    enddef
-  END
-  writefile(lines, 'XreloadVar.vim')
-  source XreloadVar.vim
-enddef
-
-def Test_func_redefine_error()
-  var lines = [
-        'vim9script',
-        'def Func()',
-        '  eval [][0]',
-        'enddef',
-        'Func()',
-        ]
-  writefile(lines, 'Xtestscript.vim', 'D')
-
-  for count in range(3)
-    try
-      source Xtestscript.vim
-    catch /E684/
-      # function name should contain <SNR> every time
-      assert_match('E684: List index out of range', v:exception)
-      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
-    endtry
-  endfor
-enddef
-
-def Test_func_redefine_fails()
-  var lines =<< trim END
-    vim9script
-    def Func()
-      echo 'one'
-    enddef
-    def Func()
-      echo 'two'
-    enddef
-  END
-  v9.CheckScriptFailure(lines, 'E1073:')
-
-  lines =<< trim END
-    vim9script
-    def Foo(): string
-      return 'foo'
-    enddef
-    def Func()
-      var  Foo = {-> 'lambda'}
-    enddef
-    defcompile
-  END
-  v9.CheckScriptFailure(lines, 'E1073:')
-enddef
-
-def Test_lambda_split()
-  # this was using freed memory, because of the split expression
-  var lines =<< trim END
-      vim9script
-      try
-      0
-      0->(0
-        ->a.0(
-        ->u
-  END
-  v9.CheckScriptFailure(lines, 'E1050:')
-enddef
-
-def Test_fixed_size_list()
-  # will be allocated as one piece of memory, check that changes work
-  var l = [1, 2, 3, 4]
-  l->remove(0)
-  l->add(5)
-  l->insert(99, 1)
-  assert_equal([2, 99, 3, 4, 5], l)
-enddef
-
-def Test_no_insert_xit()
-  v9.CheckDefExecFailure(['a = 1'], 'E1100:')
-  v9.CheckDefExecFailure(['c = 1'], 'E1100:')
-  v9.CheckDefExecFailure(['i = 1'], 'E1100:')
-  v9.CheckDefExecFailure(['t = 1'], 'E1100:')
-  v9.CheckDefExecFailure(['x = 1'], 'E1100:')
-
-  v9.CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
-  v9.CheckScriptFailure(['vim9script', 'a'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
-  v9.CheckScriptFailure(['vim9script', 'c'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
-  v9.CheckScriptFailure(['vim9script', 'i'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 'o'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 't'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
-  v9.CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
-enddef
-
-def s:IfElse(what: number): string
-  var res = ''
-  if what == 1
-    res = "one"
-  elseif what == 2
-    res = "two"
-  else
-    res = "three"
-  endif
-  return res
-enddef
-
-def Test_if_elseif_else()
-  assert_equal('one', IfElse(1))
-  assert_equal('two', IfElse(2))
-  assert_equal('three', IfElse(3))
-enddef
-
-def Test_if_elseif_else_fails()
-  v9.CheckDefFailure(['elseif true'], 'E582:')
-  v9.CheckDefFailure(['else'], 'E581:')
-  v9.CheckDefFailure(['endif'], 'E580:')
-  v9.CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
-  v9.CheckDefFailure(['if true', 'echo 1'], 'E171:')
-
-  var lines =<< trim END
-      var s = ''
-      if s = ''
-      endif
-  END
-  v9.CheckDefFailure(lines, 'E488:')
-
-  lines =<< trim END
-      var s = ''
-      if s == ''
-      elseif s = ''
-      endif
-  END
-  v9.CheckDefFailure(lines, 'E488:')
-
-  lines =<< trim END
-      var cond = true
-      if cond
-        echo 'true'
-      elseif
-        echo 'false'
-      endif
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E1143:', 'E15:'], 4)
-enddef
-
-def Test_if_else_func_using_var()
-  var lines =<< trim END
-      vim9script
-
-      const debug = true
-      if debug
-        var mode_chars = 'something'
-        def Bits2Ascii()
-          var x = mode_chars
-          g:where = 'in true'
-        enddef
-      else
-        def Bits2Ascii()
-          g:where = 'in false'
-        enddef
-      endif
-
-      Bits2Ascii()
-  END
-  v9.CheckScriptSuccess(lines)
-  assert_equal('in true', g:where)
-  unlet g:where
-
-  lines =<< trim END
-      vim9script
-
-      const debug = false
-      if debug
-        var mode_chars = 'something'
-        def Bits2Ascii()
-          g:where = 'in true'
-        enddef
-      else
-        def Bits2Ascii()
-          var x = mode_chars
-          g:where = 'in false'
-        enddef
-      endif
-
-      Bits2Ascii()
-  END
-  v9.CheckScriptFailure(lines, 'E1001: Variable not found: mode_chars')
-enddef
-
-let g:bool_true = v:true
-let g:bool_false = v:false
-
-def Test_if_const_expr()
-  var res = false
-  if true ? true : false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  g:glob = 2
-  if false
-    execute('g:glob = 3')
-  endif
-  assert_equal(2, g:glob)
-  if true
-    execute('g:glob = 3')
-  endif
-  assert_equal(3, g:glob)
-
-  res = false
-  if g:bool_true ? true : false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if true ? g:bool_true : false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if true ? true : g:bool_false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if true ? false : true
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if false ? false : true
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if false ? true : false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if has('xyz') ? true : false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if true && true
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if true && false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if g:bool_true && false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if true && g:bool_false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if false && false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  res = false
-  if true || false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if g:bool_true || false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if true || g:bool_false
-    res = true
-  endif
-  assert_equal(true, res)
-
-  res = false
-  if false || false
-    res = true
-  endif
-  assert_equal(false, res)
-
-  # with constant "false" expression may be invalid so long as the syntax is OK
-  if false | eval 1 + 2 | endif
-  if false | eval burp + 234 | endif
-  if false | echo burp 234 'asd' | endif
-  if false
-    burp
-  endif
-
-  if 0
-    if 1
-      echo nothing
-    elseif 1
-      echo still nothing
-    endif
-  endif
-
-  # expression with line breaks skipped
-  if false
-      ('aaa'
-      .. 'bbb'
-      .. 'ccc'
-      )->setline(1)
-  endif
-enddef
-
-def Test_if_const_expr_fails()
-  v9.CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
-  v9.CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
-  v9.CheckDefFailure(["if has('aaa'"], 'E110:')
-  v9.CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
-enddef
-
-def s:RunNested(i: number): number
-  var x: number = 0
-  if i % 2
-    if 1
-      # comment
-    else
-      # comment
-    endif
-    x += 1
-  else
-    x += 1000
-  endif
-  return x
-enddef
-
-def Test_nested_if()
-  assert_equal(1, RunNested(1))
-  assert_equal(1000, RunNested(2))
-enddef
-
-def Test_execute_cmd()
-  # missing argument is ignored
-  execute
-  execute # comment
-
-  new
-  setline(1, 'default')
-  execute 'setline(1, "execute-string")'
-  assert_equal('execute-string', getline(1))
-
-  execute "setline(1, 'execute-string')"
-  assert_equal('execute-string', getline(1))
-
-  var cmd1 = 'setline(1,'
-  var cmd2 = '"execute-var")'
-  execute cmd1 cmd2 # comment
-  assert_equal('execute-var', getline(1))
-
-  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
-  assert_equal('execute-var-string', getline(1))
-
-  var cmd_first = 'call '
-  var cmd_last = 'setline(1, "execute-var-var")'
-  execute cmd_first .. cmd_last
-  assert_equal('execute-var-var', getline(1))
-  bwipe!
-
-  var n = true
-  execute 'echomsg' (n ? '"true"' : '"no"')
-  assert_match('^true$', g:Screenline(&lines))
-
-  echomsg [1, 2, 3] {a: 1, b: 2}
-  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', g:Screenline(&lines))
-
-  v9.CheckDefFailure(['execute xxx'], 'E1001:', 1)
-  v9.CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
-  v9.CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
-  if has('channel')
-    v9.CheckDefExecFailure(['execute test_null_channel()'], 'E908:', 1)
-  endif
-enddef
-
-def Test_execute_cmd_vimscript()
-  # only checks line continuation
-  var lines =<< trim END
-      vim9script
-      execute 'g:someVar'
-                .. ' = ' ..
-                   '28'
-      assert_equal(28, g:someVar)
-      unlet g:someVar
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_execute_finish()
-  # the empty lines are relevant here
-  var lines =<< trim END
-      vim9script
-
-      var vname = "g:hello"
-
-      if exists(vname) | finish | endif | execute vname '= "world"'
-
-      assert_equal('world', g:hello)
-
-      if exists(vname) | finish | endif | execute vname '= "world"'
-
-      assert_report('should not be reached')
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_echo_cmd()
-  echo 'some' # comment
-  echon 'thing'
-  assert_match('^something$', g:Screenline(&lines))
-
-  echo "some" # comment
-  echon "thing"
-  assert_match('^something$', g:Screenline(&lines))
-
-  var str1 = 'some'
-  var str2 = 'more'
-  echo str1 str2
-  assert_match('^some more$', g:Screenline(&lines))
-
-  echo "one\ntwo"
-  assert_match('^one$', g:Screenline(&lines - 1))
-  assert_match('^two$', g:Screenline(&lines))
-
-  v9.CheckDefFailure(['echo "xxx"# comment'], 'E488:')
-enddef
-
-def Test_echomsg_cmd()
-  echomsg 'some' 'more' # comment
-  assert_match('^some more$', g:Screenline(&lines))
-  echo 'clear'
-  :1messages
-  assert_match('^some more$', g:Screenline(&lines))
-
-  v9.CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
-enddef
-
-def Test_echomsg_cmd_vimscript()
-  # only checks line continuation
-  var lines =<< trim END
-      vim9script
-      echomsg 'here'
-                .. ' is ' ..
-                   'a message'
-      assert_match('^here is a message$', g:Screenline(&lines))
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_echoerr_cmd()
-  var local = 'local'
-  try
-    echoerr 'something' local 'wrong' # comment
-  catch
-    assert_match('something local wrong', v:exception)
-  endtry
-enddef
-
-def Test_echoerr_cmd_vimscript()
-  # only checks line continuation
-  var lines =<< trim END
-      vim9script
-      try
-        echoerr 'this'
-                .. ' is ' ..
-                   'wrong'
-      catch
-        assert_match('this is wrong', v:exception)
-      endtry
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_echoconsole_cmd()
-  var local = 'local'
-  echoconsole 'something' local # comment
-  # output goes anywhere
-enddef
-
-def Test_echowindow_cmd()
-  var local = 'local'
-  echowindow 'something' local # comment
-
-  # with modifier
-  unsilent echowin 'loud'
-
-  # output goes in message window
-  popup_clear()
-enddef
-
-def Test_for_outside_of_function()
-  var lines =<< trim END
-    vim9script
-    new
-    for var in range(0, 3)
-      append(line('$'), var)
-    endfor
-    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
-    bwipe!
-
-    var result = ''
-    for i in [1, 2, 3]
-      var loop = ' loop ' .. i
-      result ..= loop
-    endfor
-    assert_equal(' loop 1 loop 2 loop 3', result)
-  END
-  writefile(lines, 'Xvim9for.vim', 'D')
-  source Xvim9for.vim
-enddef
-
-def Test_for_skipped_block()
-  # test skipped blocks at outside of function
-  var lines =<< trim END
-    var result = []
-    if true
-      for n in [1, 2]
-        result += [n]
-      endfor
-    else
-      for n in [3, 4]
-        result += [n]
-      endfor
-    endif
-    assert_equal([1, 2], result)
-
-    result = []
-    if false
-      for n in [1, 2]
-        result += [n]
-      endfor
-    else
-      for n in [3, 4]
-        result += [n]
-      endfor
-    endif
-    assert_equal([3, 4], result)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # test skipped blocks at inside of function
-  lines =<< trim END
-    def DefTrue()
-      var result = []
-      if true
-        for n in [1, 2]
-          result += [n]
-        endfor
-      else
-        for n in [3, 4]
-          result += [n]
-        endfor
-      endif
-      assert_equal([1, 2], result)
-    enddef
-    DefTrue()
-
-    def DefFalse()
-      var result = []
-      if false
-        for n in [1, 2]
-          result += [n]
-        endfor
-      else
-        for n in [3, 4]
-          result += [n]
-        endfor
-      endif
-      assert_equal([3, 4], result)
-    enddef
-    DefFalse()
-
-    def BuildDiagrams()
-      var diagrams: list<any>
-      if false
-        var max = 0
-        for v in diagrams
-          var l = 3
-          if max < l | max = l | endif
-          v->add(l)
-        endfor
-      endif
-    enddef
-    BuildDiagrams()
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_skipped_redir()
-  var lines =<< trim END
-      def Tredir()
-        if 0
-          redir => l[0]
-          redir END
-        endif
-      enddef
-      defcompile
-  END
-  v9.CheckScriptSuccess(lines)
-  delfunc g:Tredir
-
-  lines =<< trim END
-      def Tredir()
-        if 0
-          redir => l[0]
-        endif
-        echo 'executed'
-        if 0
-          redir END
-        endif
-      enddef
-      defcompile
-  END
-  v9.CheckScriptSuccess(lines)
-  delfunc g:Tredir
-
-  lines =<< trim END
-      def Tredir()
-        var l = ['']
-        if 1
-          redir => l[0]
-        endif
-        echo 'executed'
-        if 0
-          redir END
-        else
-          redir END
-        endif
-      enddef
-      defcompile
-  END
-  v9.CheckScriptSuccess(lines)
-  delfunc g:Tredir
-
-  lines =<< trim END
-      let doit = 1
-      def Tredir()
-        var l = ['']
-        if g:doit
-          redir => l[0]
-        endif
-        echo 'executed'
-        if g:doit
-          redir END
-        endif
-      enddef
-      defcompile
-  END
-  v9.CheckScriptSuccess(lines)
-  delfunc g:Tredir
-enddef
-
-def Test_for_loop()
-  var lines =<< trim END
-      var result = ''
-      for cnt in range(7)
-        if cnt == 4
-          break
-        endif
-        if cnt == 2
-          continue
-        endif
-        result ..= cnt .. '_'
-      endfor
-      assert_equal('0_1_3_', result)
-
-      var concat = ''
-      for str in eval('["one", "two"]')
-        concat ..= str
-      endfor
-      assert_equal('onetwo', concat)
-
-      var total = 0
-      for nr in
-          [1, 2, 3]
-        total += nr
-      endfor
-      assert_equal(6, total)
-
-      total = 0
-      for nr
-        in [1, 2, 3]
-        total += nr
-      endfor
-      assert_equal(6, total)
-
-      total = 0
-      for nr
-        in
-        [1, 2, 3]
-        total += nr
-      endfor
-      assert_equal(6, total)
-
-      # with type
-      total = 0
-      for n: number in [1, 2, 3]
-        total += n
-      endfor
-      assert_equal(6, total)
-
-      total = 0
-      for b in 0z010203
-        total += b
-      endfor
-      assert_equal(6, total)
-
-      var chars = ''
-      for s: string in 'foobar'
-        chars ..= s
-      endfor
-      assert_equal('foobar', chars)
-
-      chars = ''
-      for x: string in {a: 'a', b: 'b'}->values()
-        chars ..= x
-      endfor
-      assert_equal('ab', chars)
-
-      # unpack with type
-      var res = ''
-      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
-        res ..= n .. s
-      endfor
-      assert_equal('1a2b', res)
-
-      # unpack with one var
-      var reslist = []
-      for [x] in [['aaa'], ['bbb']]
-        reslist->add(x)
-      endfor
-      assert_equal(['aaa', 'bbb'], reslist)
-
-      # loop over string
-      res = ''
-      for c in 'aéc̀d'
-        res ..= c .. '-'
-      endfor
-      assert_equal('a-é-c̀-d-', res)
-
-      res = ''
-      for c in ''
-        res ..= c .. '-'
-      endfor
-      assert_equal('', res)
-
-      res = ''
-      for c in test_null_string()
-        res ..= c .. '-'
-      endfor
-      assert_equal('', res)
-
-      total = 0
-      for c in null_list
-        total += 1
-      endfor
-      assert_equal(0, total)
-
-      for c in null_blob
-        total += 1
-      endfor
-      assert_equal(0, total)
-
-      var foo: list<dict<any>> = [
-              {a: 'Cat'}
-            ]
-      for dd in foo
-        dd.counter = 12
-      endfor
-      assert_equal([{a: 'Cat', counter: 12}], foo)
-
-      reslist = []
-      for _ in range(3)
-        reslist->add('x')
-      endfor
-      assert_equal(['x', 'x', 'x'], reslist)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_for_loop_list_of_lists()
-  # loop variable is final, not const
-  var lines =<< trim END
-      # Filter out all odd numbers in each sublist
-      var list: list<list<number>> = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
-      for i in list
-          filter(i, (_, n: number): bool => n % 2 == 0)
-      endfor
-
-      assert_equal([[], [2], [2], [2, 4]], list)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_for_loop_with_closure()
-  # using the loop variable in a closure results in the last used value
-  var lines =<< trim END
-      var flist: list<func>
-      for i in range(5)
-        flist[i] = () => i
-      endfor
-      for i in range(5)
-        assert_equal(4, flist[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # also works when the loop variable is used only once halfway the loops
-  lines =<< trim END
-      var Clo: func
-      for i in range(5)
-        if i == 3
-          Clo = () => i
-        endif
-      endfor
-      assert_equal(4, Clo())
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # using a local variable set to the loop variable in a closure results in the
-  # value at that moment
-  lines =<< trim END
-      var flist: list<func>
-      for i in range(5)
-        var inloop = i
-        flist[i] = () => inloop
-      endfor
-      for i in range(5)
-        assert_equal(i, flist[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # also with an extra block level
-  lines =<< trim END
-      var flist: list<func>
-      for i in range(5)
-        {
-          var inloop = i
-          flist[i] = () => inloop
-        }
-      endfor
-      for i in range(5)
-        assert_equal(i, flist[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # and declaration in higher block
-  lines =<< trim END
-      var flist: list<func>
-      for i in range(5)
-        var inloop = i
-        {
-          flist[i] = () => inloop
-        }
-      endfor
-      for i in range(5)
-        assert_equal(i, flist[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  lines =<< trim END
-      var flist: list<func>
-      for i in range(5)
-        var inloop = i
-        flist[i] = () => {
-              return inloop
-            }
-      endfor
-      for i in range(5)
-        assert_equal(i, flist[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # Also works for a nested loop
-  lines =<< trim END
-      var flist: list<func>
-      var n = 0
-      for i in range(3)
-        var ii = i
-        for a in ['a', 'b', 'c']
-          var aa = a
-          flist[n] = () => ii .. aa
-          ++n
-        endfor
-      endfor
-
-      n = 0
-      for i in range(3)
-        for a in ['a', 'b', 'c']
-          assert_equal(i .. a, flist[n]())
-          ++n
-        endfor
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # using two loop variables
-  lines =<< trim END
-      var lv_list: list<func>
-      var copy_list: list<func>
-      for [idx, c] in items('word')
-        var lidx = idx
-        var lc = c
-        lv_list[idx] = () => {
-              return idx .. c
-            }
-        copy_list[idx] = () => {
-              return lidx .. lc
-            }
-      endfor
-      for [i, c] in items('word')
-        assert_equal(3 .. 'd', lv_list[i]())
-        assert_equal(i .. c, copy_list[i]())
-      endfor
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_define_global_closure_in_loops()
-  var lines =<< trim END
-      vim9script
-
-      def Func()
-        for i in range(3)
-          var ii = i
-          for a in ['a', 'b', 'c']
-            var aa = a
-            if ii == 0 && aa == 'a'
-              def g:Global_0a(): string
-                return ii .. aa
-              enddef
-            endif
-            if ii == 1 && aa == 'b'
-              def g:Global_1b(): string
-                return ii .. aa
-              enddef
-            endif
-            if ii == 2 && aa == 'c'
-              def g:Global_2c(): string
-                return ii .. aa
-              enddef
-            endif
-          endfor
-        endfor
-      enddef
-      Func()
-  END
-  v9.CheckScriptSuccess(lines)
-  assert_equal("0a", g:Global_0a())
-  assert_equal("1b", g:Global_1b())
-  assert_equal("2c", g:Global_2c())
-
-  delfunc g:Global_0a
-  delfunc g:Global_1b
-  delfunc g:Global_2c
-enddef
-
-def Test_for_loop_fails()
-  v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:'])
-  v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:'])
-  v9.CheckDefAndScriptFailure(['for x in'], ['E1097:', 'E15:'])
-  v9.CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
-  v9.CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
-  v9.CheckDefAndScriptFailure(['var x = 5', 'for x in range(5)', 'endfor'], ['E1017:', 'E1041:'])
-  v9.CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
-  v9.CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
-  delfunc! g:Func
-  v9.CheckDefFailure(['for i in xxx'], 'E1001:')
-  v9.CheckDefFailure(['endfor'], 'E588:')
-  v9.CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
-
-  # wrong type detected at compile time
-  v9.CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
-
-  # wrong type detected at runtime
-  g:adict = {a: 1}
-  v9.CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
-  unlet g:adict
-
-  var lines =<< trim END
-      var d: list<dict<any>> = [{a: 0}]
-      for e in d
-        e = {a: 0, b: ''}
-      endfor
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E1018:', 'E46:'], 3)
-
-  lines =<< trim END
-      for nr: number in ['foo']
-      endfor
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
-
-  lines =<< trim END
-      for n : number in [1, 2]
-        echo n
-      endfor
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1059:', 1)
-
-  lines =<< trim END
-      var d: dict<number> = {a: 1, b: 2}
-      for [k: job, v: job] in d->items()
-        echo k v
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 1: type mismatch, expected job but got string', 'E1012: Type mismatch; expected job but got string'], 2)
-
-  lines =<< trim END
-      var i = 0
-      for i in [1, 2, 3]
-        echo i
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, ['E1017:', 'E1041:'])
-
-  lines =<< trim END
-      var l = [0]
-      for l[0] in [1, 2, 3]
-        echo l[0]
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:'])
-
-  lines =<< trim END
-      var d = {x: 0}
-      for d.x in [1, 2, 3]
-        echo d.x
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:'])
-
-  lines =<< trim END
-      var l: list<dict<any>> = [{a: 1, b: 'x'}]
-      for item: dict<number> in l
-        echo item
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<number> but got dict<any>')
-
-  lines =<< trim END
-      var l: list<dict<any>> = [{n: 1}]
-      for item: dict<number> in l
-        var d = {s: ''}
-        d->extend(item)
-      endfor
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<string> but got dict<number>')
-
-  lines =<< trim END
-      for a in range(3)
-        while a > 3
-          for b in range(2)
-            while b < 0
-              for c in range(5)
-                while c > 6
-                  while c < 0
-                    for d in range(1)
-                      for e in range(3)
-                        while e > 3
-                        endwhile
-                      endfor
-                    endfor
-                  endwhile
-                endwhile
-              endfor
-            endwhile
-          endfor
-        endwhile
-      endfor
-  END
-  v9.CheckDefSuccess(lines)
-
-  v9.CheckDefFailure(['for x in range(3)'] + lines + ['endfor'], 'E1306:')
-enddef
-
-def Test_for_loop_script_var()
-  # cannot use s:var in a :def function
-  v9.CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1254:')
-
-  # can use s:var in Vim9 script, with or without s:
-  var lines =<< trim END
-    vim9script
-    var total = 0
-    for s:var in [1, 2, 3]
-      total += s:var
-    endfor
-    assert_equal(6, total)
-
-    total = 0
-    for var in [1, 2, 3]
-      total += var
-    endfor
-    assert_equal(6, total)
-  END
-enddef
-
-def Test_for_loop_unpack()
-  var lines =<< trim END
-      var result = []
-      for [v1, v2] in [[1, 2], [3, 4]]
-        result->add(v1)
-        result->add(v2)
-      endfor
-      assert_equal([1, 2, 3, 4], result)
-
-      result = []
-      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
-        result->add(v1)
-        result->add(v2)
-        result->add(v3)
-      endfor
-      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
-
-      result = []
-      for [&ts, &sw] in [[1, 2], [3, 4]]
-        result->add(&ts)
-        result->add(&sw)
-      endfor
-      assert_equal([1, 2, 3, 4], result)
-
-      var slist: list<string>
-      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
-        slist->add($LOOPVAR)
-        slist->add(@r)
-        slist->add(v:errmsg)
-      endfor
-      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
-
-      slist = []
-      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
-        slist->add(g:globalvar)
-        slist->add(b:bufvar)
-        slist->add(w:winvar)
-        slist->add(t:tabvar)
-      endfor
-      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
-      unlet! g:globalvar b:bufvar w:winvar t:tabvar
-
-      var res = []
-      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
-        res->add(n)
-      endfor
-      assert_equal([2, 5], res)
-
-      var text: list<string> = ["hello there", "goodbye now"]
-      var splitted = ''
-      for [first; next] in mapnew(text, (i, v) => split(v))
-          splitted ..= string(first) .. string(next) .. '/'
-      endfor
-      assert_equal("'hello'['there']/'goodbye'['now']/", splitted)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  lines =<< trim END
-      for [v1, v2] in [[1, 2, 3], [3, 4]]
-        echo v1 v2
-      endfor
-  END
-  v9.CheckDefExecFailure(lines, 'E710:', 1)
-
-  lines =<< trim END
-      for [v1, v2] in [[1], [3, 4]]
-        echo v1 v2
-      endfor
-  END
-  v9.CheckDefExecFailure(lines, 'E711:', 1)
-
-  lines =<< trim END
-      for [v1, v1] in [[1, 2], [3, 4]]
-        echo v1
-      endfor
-  END
-  v9.CheckDefExecFailure(lines, 'E1017:', 1)
-
-  lines =<< trim END
-      for [a, b] in g:listlist
-        echo a
-      endfor
-  END
-  g:listlist = [1, 2, 3]
-  v9.CheckDefExecFailure(lines, 'E1140:', 1)
-enddef
-
-def Test_for_loop_with_try_continue()
-  var lines =<< trim END
-      var looped = 0
-      var cleanup = 0
-      for i in range(3)
-        looped += 1
-        try
-          eval [][0]
-        catch
-          continue
-        finally
-          cleanup += 1
-        endtry
-      endfor
-      assert_equal(3, looped)
-      assert_equal(3, cleanup)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_while_skipped_block()
-  # test skipped blocks at outside of function
-  var lines =<< trim END
-    var result = []
-    var n = 0
-    if true
-      n = 1
-      while n < 3
-        result += [n]
-        n += 1
-      endwhile
-    else
-      n = 3
-      while n < 5
-        result += [n]
-        n += 1
-      endwhile
-    endif
-    assert_equal([1, 2], result)
-
-    result = []
-    if false
-      n = 1
-      while n < 3
-        result += [n]
-        n += 1
-      endwhile
-    else
-      n = 3
-      while n < 5
-        result += [n]
-        n += 1
-      endwhile
-    endif
-    assert_equal([3, 4], result)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-
-  # test skipped blocks at inside of function
-  lines =<< trim END
-    def DefTrue()
-      var result = []
-      var n = 0
-      if true
-        n = 1
-        while n < 3
-          result += [n]
-          n += 1
-        endwhile
-      else
-        n = 3
-        while n < 5
-          result += [n]
-          n += 1
-        endwhile
-      endif
-      assert_equal([1, 2], result)
-    enddef
-    DefTrue()
-
-    def DefFalse()
-      var result = []
-      var n = 0
-      if false
-        n = 1
-        while n < 3
-          result += [n]
-          n += 1
-        endwhile
-      else
-        n = 3
-        while n < 5
-          result += [n]
-          n += 1
-        endwhile
-      endif
-      assert_equal([3, 4], result)
-    enddef
-    DefFalse()
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-def Test_while_loop()
-  var result = ''
-  var cnt = 0
-  while cnt < 555
-    if cnt == 3
-      break
-    endif
-    cnt += 1
-    if cnt == 2
-      continue
-    endif
-    result ..= cnt .. '_'
-  endwhile
-  assert_equal('1_3_', result)
-
-  var s = ''
-  while s == 'x' # {comment}
-  endwhile
-enddef
-
-def Test_while_loop_in_script()
-  var lines =<< trim END
-      vim9script
-      var result = ''
-      var cnt = 0
-      while cnt < 3
-        var s = 'v' .. cnt
-        result ..= s
-        cnt += 1
-      endwhile
-      assert_equal('v0v1v2', result)
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_while_loop_fails()
-  v9.CheckDefFailure(['while xxx'], 'E1001:')
-  v9.CheckDefFailure(['endwhile'], 'E588:')
-  v9.CheckDefFailure(['continue'], 'E586:')
-  v9.CheckDefFailure(['if true', 'continue'], 'E586:')
-  v9.CheckDefFailure(['break'], 'E587:')
-  v9.CheckDefFailure(['if true', 'break'], 'E587:')
-  v9.CheckDefFailure(['while 1', 'echo 3'], 'E170:')
-
-  var lines =<< trim END
-      var s = ''
-      while s = ''
-      endwhile
-  END
-  v9.CheckDefFailure(lines, 'E488:')
-enddef
-
-def Test_interrupt_loop()
-  var caught = false
-  var x = 0
-  try
-    while 1
-      x += 1
-      if x == 100
-        feedkeys("\<C-C>", 'Lt')
-      endif
-    endwhile
-  catch
-    caught = true
-    assert_equal(100, x)
-  endtry
-  assert_true(caught, 'should have caught an exception')
-  # consume the CTRL-C
-  getchar(0)
-enddef
-
-def Test_automatic_line_continuation()
-  var mylist = [
-      'one',
-      'two',
-      'three',
-      ] # comment
-  assert_equal(['one', 'two', 'three'], mylist)
-
-  var mydict = {
-      ['one']: 1,
-      ['two']: 2,
-      ['three']:
-          3,
-      } # comment
-  assert_equal({one: 1, two: 2, three: 3}, mydict)
-  mydict = {
-      one: 1,  # comment
-      two:     # comment
-           2,  # comment
-      three: 3 # comment
-      }
-  assert_equal({one: 1, two: 2, three: 3}, mydict)
-  mydict = {
-      one: 1, 
-      two: 
-           2, 
-      three: 3 
-      }
-  assert_equal({one: 1, two: 2, three: 3}, mydict)
-
-  assert_equal(
-        ['one', 'two', 'three'],
-        split('one two three')
-        )
-enddef
-
-def Test_vim9_comment()
-  v9.CheckScriptSuccess([
-      'vim9script',
-      '# something',
-      '#something',
-      '#{{something',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      '#{something',
-      ], 'E1170:')
-
-  split Xv9cfile
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'edit #something',
-      ])
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'edit #{something',
-      ])
-  close
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      ':# something',
-      ], 'E488:')
-  v9.CheckScriptFailure([
-      '# something',
-      ], 'E488:')
-  v9.CheckScriptFailure([
-      ':# something',
-      ], 'E488:')
-
-  { # block start
-  } # block end
-  v9.CheckDefFailure([
-      '{# comment',
-      ], 'E488:')
-  v9.CheckDefFailure([
-      '{',
-      '}# comment',
-      ], 'E488:')
-
-  echo "yes" # comment
-  v9.CheckDefFailure([
-      'echo "yes"# comment',
-      ], 'E488:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'echo "yes" # something',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'echo "yes"# something',
-      ], 'E121:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'echo# something',
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'echo "yes" # something',
-      ], 'E121:')
-
-  exe "echo" # comment
-  v9.CheckDefFailure([
-      'exe "echo"# comment',
-      ], 'E488:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'exe "echo" # something',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'exe "echo"# something',
-      ], 'E121:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'exe# something',
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'exe "echo" # something',
-      ], 'E121:')
-
-  v9.CheckDefFailure([
-      'try# comment',
-      '  echo "yes"',
-      'catch',
-      'endtry',
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'try# comment',
-      'echo "yes"',
-      ], 'E1144:')
-  v9.CheckDefFailure([
-      'try',
-      '  throw#comment',
-      'catch',
-      'endtry',
-      ], 'E1144:')
-  v9.CheckDefFailure([
-      'try',
-      '  throw "yes"#comment',
-      'catch',
-      'endtry',
-      ], 'E488:')
-  v9.CheckDefFailure([
-      'try',
-      '  echo "yes"',
-      'catch# comment',
-      'endtry',
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'try',
-      '  echo "yes"',
-      'catch# comment',
-      'endtry',
-      ], 'E1144:')
-  v9.CheckDefFailure([
-      'try',
-      '  echo "yes"',
-      'catch /pat/# comment',
-      'endtry',
-      ], 'E488:')
-  v9.CheckDefFailure([
-      'try',
-      'echo "yes"',
-      'catch',
-      'endtry# comment',
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'try',
-      '  echo "yes"',
-      'catch',
-      'endtry# comment',
-      ], 'E1144:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'hi # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'hi# comment',
-      ], 'E1144:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'hi Search # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'hi Search# comment',
-      ], 'E416:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'hi link This Search # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'hi link This That# comment',
-      ], 'E413:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'hi clear This # comment',
-      'hi clear # comment',
-      ])
-  # not tested, because it doesn't give an error but a warning:
-  # hi clear This# comment',
-  v9.CheckScriptFailure([
-      'vim9script',
-      'hi clear# comment',
-      ], 'E416:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'hi Group term=bold',
-      'match Group /todo/ # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'hi Group term=bold',
-      'match Group /todo/# comment',
-      ], 'E488:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'match # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'match# comment',
-      ], 'E1144:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'match none # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'match none# comment',
-      ], 'E475:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'menutrans clear # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'menutrans clear# comment text',
-      ], 'E474:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax clear # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax clear# comment text',
-      ], 'E28:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax keyword Word some',
-      'syntax clear Word # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax keyword Word some',
-      'syntax clear Word# comment text',
-      ], 'E28:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax list # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax list# comment text',
-      ], 'E28:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax match Word /pat/ oneline # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax match Word /pat/ oneline# comment',
-      ], 'E475:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax keyword Word word # comm[ent',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax keyword Word word# comm[ent',
-      ], 'E789:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax match Word /pat/ # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax match Word /pat/# comment',
-      ], 'E402:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax match Word /pat/ contains=Something # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax match Word /pat/ contains=Something# comment',
-      ], 'E475:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax match Word /pat/ contains= # comment',
-      ], 'E406:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax match Word /pat/ contains=# comment',
-      ], 'E475:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax region Word start=/pat/ end=/pat/ # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax region Word start=/pat/ end=/pat/# comment',
-      ], 'E402:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax sync # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax sync# comment',
-      ], 'E404:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax sync ccomment # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax sync ccomment# comment',
-      ], 'E404:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'syntax cluster Some contains=Word # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'syntax cluster Some contains=Word# comment',
-      ], 'E475:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'command Echo echo # comment',
-      'command Echo # comment',
-      'delcommand Echo',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'command Echo echo# comment',
-      'Echo',
-      ], 'E1144:')
-  delcommand Echo
-
-  var curdir = getcwd()
-  v9.CheckScriptSuccess([
-      'command Echo cd " comment',
-      'Echo',
-      'delcommand Echo',
-      ])
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'command Echo cd # comment',
-      'Echo',
-      'delcommand Echo',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'command Echo cd " comment',
-      'Echo',
-      ], 'E344:')
-  delcommand Echo
-  chdir(curdir)
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'command Echo# comment',
-      ], 'E182:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'command Echo echo',
-      'command Echo# comment',
-      ], 'E182:')
-  delcommand Echo
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'function # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'function " comment',
-      ], 'E129:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'function# comment',
-      ], 'E1144:')
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'import "./vim9.vim" as v9',
-      'function v9.CheckScriptSuccess # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'import "./vim9.vim" as v9',
-      'function v9.CheckScriptSuccess# comment',
-      ], 'E1048: Item not found in script: CheckScriptSuccess#')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'func g:DeleteMeA()',
-      'endfunc',
-      'delfunction g:DeleteMeA # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'func g:DeleteMeB()',
-      'endfunc',
-      'delfunction g:DeleteMeB# comment',
-      ], 'E488:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'call execute("ls") # comment',
-      ])
-  v9.CheckScriptFailure([
-      'vim9script',
-      'call execute("ls")# comment',
-      ], 'E488:')
-
-  v9.CheckScriptFailure([
-      'def Test() " comment',
-      'enddef',
-      ], 'E488:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'def Test() " comment',
-      'enddef',
-      ], 'E488:')
-
-  v9.CheckScriptSuccess([
-      'func Test() " comment',
-      'endfunc',
-      'delfunc Test',
-      ])
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'func Test() " comment',
-      'endfunc',
-      ])
-
-  v9.CheckScriptSuccess([
-      'def Test() # comment',
-      'enddef',
-      ])
-  v9.CheckScriptFailure([
-      'func Test() # comment',
-      'endfunc',
-      ], 'E488:')
-
-  var lines =<< trim END
-      vim9script
-      syn region Text
-      \ start='foo'
-      #\ comment
-      \ end='bar'
-      syn region Text start='foo'
-      #\ comment
-      \ end='bar'
-  END
-  v9.CheckScriptSuccess(lines)
-
-  lines =<< trim END
-      vim9script
-      syn region Text
-      \ start='foo'
-      "\ comment
-      \ end='bar'
-  END
-  v9.CheckScriptFailure(lines, 'E399:')
-enddef
-
-def Test_vim9_comment_gui()
-  CheckCanRunGui
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'gui#comment'
-      ], 'E1144:')
-  v9.CheckScriptFailure([
-      'vim9script',
-      'gui -f#comment'
-      ], 'E194:')
-enddef
-
-def Test_vim9_comment_not_compiled()
-  au TabEnter *.vim g:entered = 1
-  au TabEnter *.x g:entered = 2
-
-  edit test.vim
-  doautocmd TabEnter #comment
-  assert_equal(1, g:entered)
-
-  doautocmd TabEnter f.x
-  assert_equal(2, g:entered)
-
-  g:entered = 0
-  doautocmd TabEnter f.x #comment
-  assert_equal(2, g:entered)
-
-  assert_fails('doautocmd Syntax#comment', 'E216:')
-
-  au! TabEnter
-  unlet g:entered
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'g:var = 123',
-      'b:var = 456',
-      'w:var = 777',
-      't:var = 888',
-      'unlet g:var w:var # something',
-      ])
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'let var = 123',
-      ], 'E1126: Cannot use :let in Vim9 script')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var g:var = 123',
-      ], 'E1016: Cannot declare a global variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var b:var = 123',
-      ], 'E1016: Cannot declare a buffer variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var w:var = 123',
-      ], 'E1016: Cannot declare a window variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var t:var = 123',
-      ], 'E1016: Cannot declare a tab variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var v:version = 123',
-      ], 'E1016: Cannot declare a v: variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var $VARIABLE = "text"',
-      ], 'E1016: Cannot declare an environment variable:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'g:var = 123',
-      'unlet g:var# comment1',
-      ], 'E108:')
-
-  v9.CheckScriptFailure([
-      'let g:var = 123',
-      'unlet g:var # something',
-      ], 'E488:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'if 1 # comment2',
-      '  echo "yes"',
-      'elseif 2 #comment',
-      '  echo "no"',
-      'endif',
-      ])
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'if 1# comment3',
-      '  echo "yes"',
-      'endif',
-      ], 'E488:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'if 0 # comment4',
-      '  echo "yes"',
-      'elseif 2#comment',
-      '  echo "no"',
-      'endif',
-      ], 'E488:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'var v = 1 # comment5',
-      ])
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'var v = 1# comment6',
-      ], 'E488:')
-
-  v9.CheckScriptSuccess([
-      'vim9script',
-      'new',
-      'setline(1, ["# define pat", "last"])',
-      ':$',
-      'dsearch /pat/ #comment',
-      'bwipe!',
-      ])
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'new',
-      'setline(1, ["# define pat", "last"])',
-      ':$',
-      'dsearch /pat/#comment',
-      'bwipe!',
-      ], 'E488:')
-
-  v9.CheckScriptFailure([
-      'vim9script',
-      'func! SomeFunc()',
-      ], 'E477:')
-enddef
-
-def Test_finish()
-  var lines =<< trim END
-    vim9script
-    g:res = 'one'
-    if v:false | finish | endif
-    g:res = 'two'
-    finish
-    g:res = 'three'
-  END
-  writefile(lines, 'Xfinished', 'D')
-  source Xfinished
-  assert_equal('two', g:res)
-
-  unlet g:res
-enddef
-
-def Test_forward_declaration()
-  var lines =<< trim END
-    vim9script
-    def GetValue(): string
-      return theVal
-    enddef
-    var theVal = 'something'
-    g:initVal = GetValue()
-    theVal = 'else'
-    g:laterVal = GetValue()
-  END
-  writefile(lines, 'Xforward', 'D')
-  source Xforward
-  assert_equal('something', g:initVal)
-  assert_equal('else', g:laterVal)
-
-  unlet g:initVal
-  unlet g:laterVal
-enddef
-
-def Test_declare_script_var_in_func()
-  var lines =<< trim END
-      vim9script
-      func Declare()
-        let s:local = 123
-      endfunc
-      Declare()
-  END
-  v9.CheckScriptFailure(lines, 'E1269:')
-enddef
-
-def Test_lock_script_var()
-  var lines =<< trim END
-      vim9script
-      var local = 123
-      assert_equal(123, local)
-
-      var error: string
-      try
-        local = 'asdf'
-      catch
-        error = v:exception
-      endtry
-      assert_match('E1012: Type mismatch; expected number but got string', error)
-
-      lockvar local
-      try
-        local = 999
-      catch
-        error = v:exception
-      endtry
-      assert_match('E741: Value is locked: local', error)
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-
-func Test_vim9script_not_global()
-  " check that items defined in Vim9 script are script-local, not global
-  let vim9lines =<< trim END
-    vim9script
-    var name = 'local'
-    func TheFunc()
-      echo 'local'
-    endfunc
-    def DefFunc()
-      echo 'local'
-    enddef
-  END
-  call writefile(vim9lines, 'Xvim9script.vim', 'D')
-  source Xvim9script.vim
-  try
-    echo g:var
-    assert_report('did not fail')
-  catch /E121:/
-    " caught
-  endtry
-  try
-    call TheFunc()
-    assert_report('did not fail')
-  catch /E117:/
-    " caught
-  endtry
-  try
-    call DefFunc()
-    assert_report('did not fail')
-  catch /E117:/
-    " caught
-  endtry
-endfunc
-
-def Test_vim9_copen()
-  # this was giving an error for setting w:quickfix_title
-  copen
-  quit
-enddef
-
-def Test_script_var_in_autocmd()
-  # using a script variable from an autocommand, defined in a :def function in a
-  # legacy Vim script, cannot check the variable type.
-  var lines =<< trim END
-    let s:counter = 1
-    def s:Func()
-      au! CursorHold
-      au CursorHold * s:counter += 1
-    enddef
-    call s:Func()
-    doau CursorHold
-    call assert_equal(2, s:counter)
-    au! CursorHold
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-def Test_error_in_autoload_script()
-  var save_rtp = &rtp
-  var dir = getcwd() .. '/Xruntime'
-  &rtp = dir
-  mkdir(dir .. '/autoload', 'pR')
-
-  var lines =<< trim END
-      vim9script noclear
-      export def Autoloaded()
-      enddef
-      def Broken()
-        var x: any = ''
-        eval x != 0
-      enddef
-      Broken()
-  END
-  writefile(lines, dir .. '/autoload/script.vim')
-
-  lines =<< trim END
-      vim9script
-      def CallAutoloaded()
-        script#Autoloaded()
-      enddef
-
-      function Legacy()
-        try
-          call s:CallAutoloaded()
-        catch
-          call assert_match('E1030: Using a String as a Number', v:exception)
-        endtry
-      endfunction
-
-      Legacy()
-  END
-  v9.CheckScriptSuccess(lines)
-
-  &rtp = save_rtp
-enddef
-
-def Test_error_in_autoload_script_foldexpr()
-  var save_rtp = &rtp
-  mkdir('Xvim/autoload', 'pR')
-  &runtimepath = 'Xvim'
-
-  var lines =<< trim END
-      vim9script
-      eval [][0]
-      echomsg 'no error'
-  END
-  lines->writefile('Xvim/autoload/script.vim')
-
-  lines =<< trim END
-      vim9script
-      import autoload 'script.vim'
-      &foldmethod = 'expr'
-      &foldexpr = 'script.Func()'
-      redraw
-  END
-  v9.CheckScriptFailure(lines, 'E684: List index out of range: 0')
-enddef
-
-def Test_invalid_sid()
-  assert_fails('func <SNR>1234_func', 'E123:')
-
-  if g:RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
-    assert_equal([], readfile('Xdidit'))
-  endif
-  delete('Xdidit')
-enddef
-
-def Test_restoring_cpo()
-  writefile(['vim9script', 'set nocp'], 'Xsourced', 'D')
-  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose', 'D')
-  if g:RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
-    assert_equal(['done'], readfile('Xdone'))
-  endif
-  delete('Xdone')
-
-  writefile(['vim9script', 'g:cpoval = &cpo'], 'XanotherScript', 'D')
-  set cpo=aABceFsMny>
-  edit XanotherScript
-  so %
-  assert_equal('aABceFsMny>', &cpo)
-  assert_equal('aABceFs', g:cpoval)
-  :1del
-  setline(1, 'let g:cpoval = &cpo')
-  w
-  so %
-  assert_equal('aABceFsMny>', &cpo)
-  assert_equal('aABceFsMny>', g:cpoval)
-
-  set cpo&vim
-  unlet g:cpoval
-
-  if has('unix')
-    # 'cpo' is not restored in main vimrc
-    var save_HOME = $HOME
-    $HOME = getcwd() .. '/Xhome'
-    mkdir('Xhome', 'R')
-    var lines =<< trim END
-        vim9script
-        writefile(['before: ' .. &cpo], 'Xrporesult')
-        set cpo+=M
-        writefile(['after: ' .. &cpo], 'Xrporesult', 'a')
-    END
-    writefile(lines, 'Xhome/.vimrc')
-
-    lines =<< trim END
-        call writefile(['later: ' .. &cpo], 'Xrporesult', 'a')
-    END
-    writefile(lines, 'Xlegacy', 'D')
-
-    lines =<< trim END
-        vim9script
-        call writefile(['vim9: ' .. &cpo], 'Xrporesult', 'a')
-        qa
-    END
-    writefile(lines, 'Xvim9', 'D')
-
-    var cmd = g:GetVimCommand() .. " -S Xlegacy -S Xvim9"
-    cmd = substitute(cmd, '-u NONE', '', '')
-    exe "silent !" .. cmd
-
-    assert_equal([
-        'before: aABceFs',
-        'after: aABceFsM',
-        'later: aABceFsM',
-        'vim9: aABceFs'], readfile('Xrporesult'))
-
-    $HOME = save_HOME
-    delete('Xrporesult')
-  endif
-enddef
-
-" Use :function so we can use Check commands
-func Test_no_redraw_when_restoring_cpo()
-  CheckScreendump
-  CheckFeature timers
-  call Run_test_no_redraw_when_restoring_cpo()
-endfunc
-
-def Run_test_no_redraw_when_restoring_cpo()
-  var lines =<< trim END
-    vim9script
-    export def Func()
-    enddef
-  END
-  mkdir('Xnordir/autoload', 'pR')
-  writefile(lines, 'Xnordir/autoload/script.vim')
-
-  lines =<< trim END
-      vim9script
-      set cpo+=M
-      exe 'set rtp^=' .. getcwd() .. '/Xnordir'
-      au CmdlineEnter : ++once timer_start(0, (_) => script#Func())
-      setline(1, 'some text')
-  END
-  writefile(lines, 'XTest_redraw_cpo', 'D')
-  var buf = g:RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
-  term_sendkeys(buf, "V:")
-  g:VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
-
-  # clean up
-  term_sendkeys(buf, "\<Esc>u")
-  g:StopVimInTerminal(buf)
-enddef
-
-func Test_reject_declaration()
-  CheckScreendump
-  call Run_test_reject_declaration()
-endfunc
-
-def Run_test_reject_declaration()
-  var buf = g:RunVimInTerminal('', {'rows': 6})
-  term_sendkeys(buf, ":vim9cmd var x: number\<CR>")
-  g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_1', {})
-  term_sendkeys(buf, ":\<CR>")
-  term_sendkeys(buf, ":vim9cmd g:foo = 123 | echo g:foo\<CR>")
-  g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_2', {})
-
-  # clean up
-  g:StopVimInTerminal(buf)
-enddef
-
-def Test_minimal_command_name_length()
-  var names = [
-       'cons',
-       'brea',
-       'cat',
-       'catc',
-       'con',
-       'cont',
-       'conti',
-       'contin',
-       'continu',
-       'el',
-       'els',
-       'elsei',
-       'endfo',
-       'en',
-       'end',
-       'endi',
-       'endw',
-       'endt',
-       'endtr',
-       'exp',
-       'expo',
-       'expor',
-       'fina',
-       'finall',
-       'fini',
-       'finis',
-       'imp',
-       'impo',
-       'impor',
-       'retu',
-       'retur',
-       'th',
-       'thr',
-       'thro',
-       'wh',
-       'whi',
-       'whil',
-      ]
-  for name in names
-    v9.CheckDefAndScriptFailure([name .. ' '], 'E1065:')
-  endfor
-
-  var lines =<< trim END
-      vim9script
-      def SomeFunc()
-      endd
-  END
-  v9.CheckScriptFailure(lines, 'E1065:')
-  lines =<< trim END
-      vim9script
-      def SomeFunc()
-      endde
-  END
-  v9.CheckScriptFailure(lines, 'E1065:')
-enddef
-
-def Test_unset_any_variable()
-  var lines =<< trim END
-    var name: any
-    assert_equal(0, name)
-  END
-  v9.CheckDefAndScriptSuccess(lines)
-enddef
-
-func Test_define_func_at_command_line()
-  CheckRunVimInTerminal
-
-  " call indirectly to avoid compilation error for missing functions
-  call Run_Test_define_func_at_command_line()
-endfunc
-
-def Run_Test_define_func_at_command_line()
-  # run in a separate Vim instance to avoid the script context
-  var lines =<< trim END
-    func CheckAndQuit()
-      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
-      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
-    endfunc
-  END
-  writefile([''], 'Xdidcmd', 'D')
-  writefile(lines, 'XcallFunc', 'D')
-  var buf = g:RunVimInTerminal('-S XcallFunc', {rows: 6})
-  # define Afunc() on the command line
-  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
-  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
-  g:WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
-
-  call g:StopVimInTerminal(buf)
-enddef
-
-def Test_script_var_scope()
-  var lines =<< trim END
-      vim9script
-      if true
-        if true
-          var one = 'one'
-          echo one
-        endif
-        echo one
-      endif
-  END
-  v9.CheckScriptFailure(lines, 'E121:', 7)
-
-  lines =<< trim END
-      vim9script
-      if true
-        if false
-          var one = 'one'
-          echo one
-        else
-          var one = 'one'
-          echo one
-        endif
-        echo one
-      endif
-  END
-  v9.CheckScriptFailure(lines, 'E121:', 10)
-
-  lines =<< trim END
-      vim9script
-      while true
-        var one = 'one'
-        echo one
-        break
-      endwhile
-      echo one
-  END
-  v9.CheckScriptFailure(lines, 'E121:', 7)
-
-  lines =<< trim END
-      vim9script
-      for i in range(1)
-        var one = 'one'
-        echo one
-      endfor
-      echo one
-  END
-  v9.CheckScriptFailure(lines, 'E121:', 6)
-
-  lines =<< trim END
-      vim9script
-      {
-        var one = 'one'
-        assert_equal('one', one)
-      }
-      assert_false(exists('one'))
-      assert_false(exists('s:one'))
-  END
-  v9.CheckScriptSuccess(lines)
-
-  lines =<< trim END
-      vim9script
-      {
-        var one = 'one'
-        echo one
-      }
-      echo one
-  END
-  v9.CheckScriptFailure(lines, 'E121:', 6)
-enddef
-
-def Test_catch_exception_in_callback()
-  var lines =<< trim END
-    vim9script
-    def Callback(...l: list<any>)
-      try
-        var x: string
-        var y: string
-        # this error should be caught with CHECKLEN
-        var sl = ['']
-        [x, y] = sl
-      catch
-        g:caught = 'yes'
-      endtry
-    enddef
-    popup_menu('popup', {callback: Callback})
-    feedkeys("\r", 'xt')
-  END
-  v9.CheckScriptSuccess(lines)
-
-  unlet g:caught
-enddef
-
-def Test_no_unknown_error_after_error()
-  if !has('unix') || !has('job')
-    throw 'Skipped: not unix of missing +job feature'
-  endif
-  # FIXME: this check should not be needed
-  if has('win32')
-    throw 'Skipped: does not work on MS-Windows'
-  endif
-  var lines =<< trim END
-      vim9script
-      var source: list<number>
-      def Out_cb(...l: list<any>)
-          eval [][0]
-      enddef
-      def Exit_cb(...l: list<any>)
-          sleep 1m
-          g:did_call_exit_cb = true
-          source += l
-      enddef
-      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
-      while job_status(myjob) == 'run'
-        sleep 10m
-      endwhile
-      # wait for Exit_cb() to be called
-      for x in range(100)
-        if exists('g:did_call_exit_cb')
-          unlet g:did_call_exit_cb
-          break
-        endif
-        sleep 10m
-      endfor
-  END
-  writefile(lines, 'Xdef', 'D')
-  # Either the exit or out callback is called first, accept them in any order
-  assert_fails('so Xdef', ['E684:\|E1012:', 'E1012:\|E684:'])
-enddef
-
-def InvokeNormal()
-  exe "norm! :m+1\r"
-enddef
-
-def Test_invoke_normal_in_visual_mode()
-  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
-  new
-  setline(1, ['aaa', 'bbb'])
-  feedkeys("V\<F3>", 'xt')
-  assert_equal(['bbb', 'aaa'], getline(1, 2))
-  xunmap <F3>
-enddef
-
-def Test_white_space_after_command()
-  var lines =<< trim END
-    exit_cb: Func})
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1144:', 1)
-
-  lines =<< trim END
-    e#
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1144:', 1)
-enddef
-
-def Test_script_var_gone_when_sourced_twice()
-  var lines =<< trim END
-      vim9script
-      if exists('g:guard')
-        finish
-      endif
-      g:guard = 1
-      var name = 'thename'
-      def g:GetName(): string
-        return name
-      enddef
-      def g:SetName(arg: string)
-        name = arg
-      enddef
-  END
-  writefile(lines, 'XscriptTwice.vim', 'D')
-  so XscriptTwice.vim
-  assert_equal('thename', g:GetName())
-  g:SetName('newname')
-  assert_equal('newname', g:GetName())
-  so XscriptTwice.vim
-  assert_fails('call g:GetName()', 'E1149:')
-  assert_fails('call g:SetName("x")', 'E1149:')
-
-  delfunc g:GetName
-  delfunc g:SetName
-  unlet g:guard
-enddef
-
-def Test_unsupported_commands()
-  var lines =<< trim END
-      ka
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:'])
-
-  lines =<< trim END
-      :1ka
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:'])
-
-  lines =<< trim END
-      :k a
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1100:')
-
-  lines =<< trim END
-      :1k a
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E481:')
-
-  lines =<< trim END
-    t
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1100:')
-
-  lines =<< trim END
-    x
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1100:')
-
-  lines =<< trim END
-    xit
-  END
-  v9.CheckDefAndScriptFailure(lines, 'E1100:')
-
-  lines =<< trim END
-    Print
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: Print', 'E492: Not an editor command: Print'])
-
-  lines =<< trim END
-    mode 4
-  END
-  v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: mode 4', 'E492: Not an editor command: mode 4'])
-enddef
-
-def Test_mapping_line_number()
-  var lines =<< trim END
-      vim9script
-      def g:FuncA()
-          # Some comment
-          FuncB(0)
-      enddef
-          # Some comment
-      def FuncB(
-          # Some comment
-          n: number
-      )
-          exe 'nno '
-              # Some comment
-              .. '<F3> a'
-              .. 'b'
-              .. 'c'
-      enddef
-  END
-  v9.CheckScriptSuccess(lines)
-  var res = execute('verbose nmap <F3>')
-  assert_match('No mapping found', res)
-
-  g:FuncA()
-  res = execute('verbose nmap <F3>')
-  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
-
-  nunmap <F3>
-  delfunc g:FuncA
-enddef
-
-def Test_option_set()
-  # legacy script allows for white space
-  var lines =<< trim END
-      set foldlevel  =11
-      call assert_equal(11, &foldlevel)
-  END
-  v9.CheckScriptSuccess(lines)
-
-  set foldlevel
-  set foldlevel=12
-  assert_equal(12, &foldlevel)
-  set foldlevel+=2
-  assert_equal(14, &foldlevel)
-  set foldlevel-=3
-  assert_equal(11, &foldlevel)
-
-  lines =<< trim END
-      set foldlevel =1
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
-
-  lines =<< trim END
-      set foldlevel +=1
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
-
-  lines =<< trim END
-      set foldlevel ^=1
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
-
-  lines =<< trim END
-      set foldlevel -=1
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
-
-  set foldlevel&
-enddef
-
-def Test_option_modifier()
-  # legacy script allows for white space
-  var lines =<< trim END
-      set hlsearch &  hlsearch  !
-      call assert_equal(1, &hlsearch)
-  END
-  v9.CheckScriptSuccess(lines)
-
-  set hlsearch
-  set hlsearch!
-  assert_equal(false, &hlsearch)
-
-  set hlsearch
-  set hlsearch&
-  assert_equal(false, &hlsearch)
-
-  lines =<< trim END
-      set hlsearch &
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
-
-  lines =<< trim END
-      set hlsearch   !
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
-
-  set hlsearch&
-enddef
-
-" This must be called last, it may cause following :def functions to fail
-def Test_xxx_echoerr_line_number()
-  var lines =<< trim END
-      echoerr 'some'
-         .. ' error'
-         .. ' continued'
-  END
-  v9.CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
-enddef
-
-func Test_debug_with_lambda()
-  CheckRunVimInTerminal
-
-  " call indirectly to avoid compilation error for missing functions
-  call Run_Test_debug_with_lambda()
-endfunc
-
-def Run_Test_debug_with_lambda()
-  var lines =<< trim END
-      vim9script
-      def Func()
-        var n = 0
-        echo [0]->filter((_, v) => v == n)
-      enddef
-      breakadd func Func
-      Func()
-  END
-  writefile(lines, 'XdebugFunc', 'D')
-  var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0})
-  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
-
-  term_sendkeys(buf, "cont\<CR>")
-  g:WaitForAssert(() => assert_match('\[0\]', term_getline(buf, 5)))
-
-  g:StopVimInTerminal(buf)
-enddef
-
-func Test_debug_running_out_of_lines()
-  CheckRunVimInTerminal
-
-  " call indirectly to avoid compilation error for missing functions
-  call Run_Test_debug_running_out_of_lines()
-endfunc
-
-def Run_Test_debug_running_out_of_lines()
-  var lines =<< trim END
-      vim9script
-      def Crash()
-          #
-          #
-          #
-          #
-          #
-          #
-          #
-          if true
-              #
-          endif
-      enddef
-      breakadd func Crash
-      Crash()
-  END
-  writefile(lines, 'XdebugFunc', 'D')
-  var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0})
-  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
-
-  term_sendkeys(buf, "next\<CR>")
-  g:TermWait(buf)
-  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
-
-  term_sendkeys(buf, "cont\<CR>")
-  g:TermWait(buf)
-
-  g:StopVimInTerminal(buf)
-enddef
-
-def Test_ambiguous_command_error()
-  var lines =<< trim END
-      vim9script
-      command CmdA echomsg 'CmdA'
-      command CmdB echomsg 'CmdB'
-      Cmd
-  END
-  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 4)
-
-  lines =<< trim END
-      vim9script
-      def Func()
-        Cmd
-      enddef
-      Func()
-  END
-  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 1)
-
-  lines =<< trim END
-      vim9script
-      nnoremap <F3> <ScriptCmd>Cmd<CR>
-      feedkeys("\<F3>", 'xt')
-  END
-  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 3)
-
-  delcommand CmdA
-  delcommand CmdB
-  nunmap <F3>
-enddef
-
-" Execute this near the end, profiling doesn't stop until Vim exits.
-" This only tests that it works, not the profiling output.
-def Test_profile_with_lambda()
-  CheckFeature profile
-
-  var lines =<< trim END
-      vim9script
-
-      def ProfiledWithLambda()
-        var n = 3
-        echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
-      enddef
-
-      def ProfiledNested()
-        var x = 0
-        def Nested(): any
-            return x
-        enddef
-        Nested()
-      enddef
-
-      def g:ProfiledNestedProfiled()
-        var x = 0
-        def Nested(): any
-            return x
-        enddef
-        Nested()
-      enddef
-
-      def Profile()
-        ProfiledWithLambda()
-        ProfiledNested()
-
-        # Also profile the nested function.  Use a different function, although
-        # the contents is the same, to make sure it was not already compiled.
-        profile func *
-        g:ProfiledNestedProfiled()
-
-        profdel func *
-        profile pause
-      enddef
-
-      var result = 'done'
-      try
-        # mark functions for profiling now to avoid E1271
-        profile start Xprofile.log
-        profile func ProfiledWithLambda
-        profile func ProfiledNested
-
-        Profile()
-      catch
-        result = 'failed: ' .. v:exception
-      finally
-        writefile([result], 'Xdidprofile')
-      endtry
-  END
-  writefile(lines, 'Xprofile.vim', 'D')
-  call system(g:GetVimCommand()
-        .. ' --clean'
-        .. ' -c "so Xprofile.vim"'
-        .. ' -c "qall!"')
-  call assert_equal(0, v:shell_error)
-
-  assert_equal(['done'], readfile('Xdidprofile'))
-  assert_true(filereadable('Xprofile.log'))
-  delete('Xdidprofile')
-  delete('Xprofile.log')
-enddef
-
-func Test_misplaced_type()
-  CheckRunVimInTerminal
-  call Run_Test_misplaced_type()
-endfunc
-
-def Run_Test_misplaced_type()
-  writefile(['let g:somevar = "asdf"'], 'XTest_misplaced_type', 'D')
-  var buf = g:RunVimInTerminal('-S XTest_misplaced_type', {'rows': 6})
-  term_sendkeys(buf, ":vim9cmd echo islocked('somevar: string')\<CR>")
-  g:VerifyScreenDump(buf, 'Test_misplaced_type', {})
-
-  g:StopVimInTerminal(buf)
-enddef
-
-" Ensure echo doesn't crash when stringifying empty variables.
-def Test_echo_uninit_variables()
-  var res: string
-
-  var var_bool: bool
-  var var_num: number
-  var var_float: float
-  var Var_func: func
-  var var_string: string
-  var var_blob: blob
-  var var_list: list<any>
-  var var_dict: dict<any>
-
-  redir => res
-  echo var_bool
-  echo var_num
-  echo var_float
-  echo Var_func
-  echo var_string
-  echo var_blob
-  echo var_list
-  echo var_dict
-  redir END
-
-  assert_equal(['false', '0', '0.0', 'function()', '', '0z', '[]', '{}'], res->split('\n'))
-
-  if has('job')
-    var var_job: job
-    var var_channel: channel
-
-    redir => res
-    echo var_job
-    echo var_channel
-    redir END
-
-    assert_equal(['no process', 'channel fail'], res->split('\n'))
-  endif
-enddef
-
-def Test_free_type_before_use()
-  # this rather complicated script was freeing a type before using it
-  var lines =<< trim END
-      vim9script
-
-      def Scan(rel: list<dict<any>>): func(func(dict<any>))
-        return (Emit: func(dict<any>)) => {
-          for t in rel
-            Emit(t)
-          endfor
-        }
-      enddef
-
-      def Build(Cont: func(func(dict<any>))): list<dict<any>>
-        var rel: list<dict<any>> = []
-        Cont((t) => {
-            add(rel, t)
-        })
-        return rel
-      enddef
-
-      var R = [{A: 0}]
-      var result = Scan(R)->Build()
-      result = Scan(R)->Build()
-
-      assert_equal(R, result)
-  END
-  v9.CheckScriptSuccess(lines)
-enddef
-
-" Keep this last, it messes up highlighting.
-def Test_substitute_cmd()
-  new
-  setline(1, 'something')
-  :substitute(some(other(
-  assert_equal('otherthing', getline(1))
-  bwipe!
-
-  # also when the context is Vim9 script
-  var lines =<< trim END
-    vim9script
-    new
-    setline(1, 'something')
-    :substitute(some(other(
-    assert_equal('otherthing', getline(1))
-    bwipe!
-  END
-  writefile(lines, 'Xvim9lines', 'D')
-  source Xvim9lines
-enddef
-
-" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
+" Test various aspects of the Vim9 script language.
+
+source check.vim
+source term_util.vim
+import './vim9.vim' as v9
+source screendump.vim
+source shared.vim
+
+def Test_vim9script_feature()
+  # example from the help, here the feature is always present
+  var lines =<< trim END
+      " old style comment
+      if !has('vim9script')
+        " legacy commands would go here
+        finish
+      endif
+      vim9script
+      # Vim9 script commands go here
+      g:didit = true
+  END
+  v9.CheckScriptSuccess(lines)
+  assert_equal(true, g:didit)
+  unlet g:didit
+enddef
+
+def Test_range_only()
+  new
+  setline(1, ['blah', 'Blah'])
+  :/Blah/
+  assert_equal(2, getcurpos()[1])
+  bwipe!
+
+  # without range commands use current line
+  new
+  setline(1, ['one', 'two', 'three'])
+  :2
+  print
+  assert_equal('two', g:Screenline(&lines))
+  :3
+  list
+  assert_equal('three$', g:Screenline(&lines))
+
+  # missing command does not print the line
+  var lines =<< trim END
+    vim9script
+    :1|
+    assert_equal('three$', g:Screenline(&lines))
+    :|
+    assert_equal('three$', g:Screenline(&lines))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  bwipe!
+
+  lines =<< trim END
+      set cpo+=-
+      :1,999
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E16:', 2)
+  set cpo&vim
+
+  v9.CheckDefExecAndScriptFailure([":'x"], 'E20:', 1)
+
+  # won't generate anything
+  if false
+    :123
+  endif
+enddef
+
+def Test_invalid_range()
+  var lines =<< trim END
+      :123 eval 1 + 2
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
+
+  lines =<< trim END
+      :123 if true
+      endif
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
+
+  lines =<< trim END
+      :123 echo 'yes'
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
+
+  lines =<< trim END
+      :123 cd there
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E481:', 1)
+enddef
+
+let g:alist = [7]
+let g:astring = 'text'
+let g:anumber = 123
+
+def Test_delfunction()
+  # Check function is defined in script namespace
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'func CheckMe()',
+      '  return 123',
+      'endfunc',
+      'func DoTest()',
+      '  call assert_equal(123, s:CheckMe())',
+      'endfunc',
+      'DoTest()',
+      ])
+
+  # Check function in script namespace cannot be deleted
+  v9.CheckScriptFailure([
+      'vim9script',
+      'func DeleteMe1()',
+      'endfunc',
+      'delfunction DeleteMe1',
+      ], 'E1084:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'func DeleteMe2()',
+      'endfunc',
+      'def DoThat()',
+      '  delfunction DeleteMe2',
+      'enddef',
+      'DoThat()',
+      ], 'E1084:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'def DeleteMe3()',
+      'enddef',
+      'delfunction DeleteMe3',
+      ], 'E1084:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'def DeleteMe4()',
+      'enddef',
+      'def DoThat()',
+      '  delfunction DeleteMe4',
+      'enddef',
+      'DoThat()',
+      ], 'E1084:')
+
+  # Check that global :def function can be replaced and deleted
+  var lines =<< trim END
+      vim9script
+      def g:Global(): string
+        return "yes"
+      enddef
+      assert_equal("yes", g:Global())
+      def! g:Global(): string
+        return "no"
+      enddef
+      assert_equal("no", g:Global())
+      delfunc g:Global
+      assert_false(exists('*g:Global'))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Check that global function can be replaced by a :def function and deleted
+  lines =<< trim END
+      vim9script
+      func g:Global()
+        return "yes"
+      endfunc
+      assert_equal("yes", g:Global())
+      def! g:Global(): string
+        return "no"
+      enddef
+      assert_equal("no", g:Global())
+      delfunc g:Global
+      assert_false(exists('*g:Global'))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Check that global :def function can be replaced by a function and deleted
+  lines =<< trim END
+      vim9script
+      def g:Global(): string
+        return "yes"
+      enddef
+      assert_equal("yes", g:Global())
+      func! g:Global()
+        return "no"
+      endfunc
+      assert_equal("no", g:Global())
+      delfunc g:Global
+      assert_false(exists('*g:Global'))
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_wrong_type()
+  v9.CheckDefFailure(['var name: list<nothing>'], 'E1010:')
+  v9.CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
+  v9.CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
+  v9.CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
+
+  v9.CheckDefFailure(['var name: dict<number'], 'E1009:')
+  v9.CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
+
+  v9.CheckDefFailure(['var name: ally'], 'E1010:')
+  v9.CheckDefFailure(['var name: bram'], 'E1010:')
+  v9.CheckDefFailure(['var name: cathy'], 'E1010:')
+  v9.CheckDefFailure(['var name: dom'], 'E1010:')
+  v9.CheckDefFailure(['var name: freddy'], 'E1010:')
+  v9.CheckDefFailure(['var name: john'], 'E1010:')
+  v9.CheckDefFailure(['var name: larry'], 'E1010:')
+  v9.CheckDefFailure(['var name: ned'], 'E1010:')
+  v9.CheckDefFailure(['var name: pam'], 'E1010:')
+  v9.CheckDefFailure(['var name: sam'], 'E1010:')
+  v9.CheckDefFailure(['var name: vim'], 'E1010:')
+
+  v9.CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
+  v9.CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
+enddef
+
+def Test_script_namespace()
+  # defining a function or variable with s: is not allowed
+  var lines =<< trim END
+      vim9script
+      def s:Function()
+      enddef
+  END
+  v9.CheckScriptFailure(lines, 'E1268:')
+
+  for decl in ['var', 'const', 'final']
+    lines =<< trim END
+        vim9script
+        var s:var = 'var'
+    END
+    v9.CheckScriptFailure([
+        'vim9script',
+        decl .. ' s:var = "var"',
+        ], 'E1268:')
+  endfor
+
+  # Calling a function or using a variable with s: is not allowed at script
+  # level
+  lines =<< trim END
+      vim9script
+      def Function()
+      enddef
+      s:Function()
+  END
+  v9.CheckScriptFailure(lines, 'E1268:')
+  lines =<< trim END
+      vim9script
+      def Function()
+      enddef
+      call s:Function()
+  END
+  v9.CheckScriptFailure(lines, 'E1268:')
+  lines =<< trim END
+      vim9script
+      var var = 'var'
+      echo s:var
+  END
+  v9.CheckScriptFailure(lines, 'E1268:')
+enddef
+
+def Test_script_wrong_type()
+  var lines =<< trim END
+      vim9script
+      var dict: dict<string>
+      dict['a'] = ['x']
+  END
+  v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
+enddef
+
+def Test_const()
+  v9.CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
+  v9.CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
+  v9.CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
+  v9.CheckDefFailure(['final two'], 'E1125:')
+  v9.CheckDefFailure(['final &option'], 'E996:')
+
+  var lines =<< trim END
+    final list = [1, 2, 3]
+    list[0] = 4
+    list->assert_equal([4, 2, 3])
+    const other = [5, 6, 7]
+    other->assert_equal([5, 6, 7])
+
+    var varlist = [7, 8]
+    const constlist = [1, varlist, 3]
+    varlist[0] = 77
+    constlist[1][1] = 88
+    var cl = constlist[1]
+    cl[1] = 88
+    constlist->assert_equal([1, [77, 88], 3])
+
+    var vardict = {five: 5, six: 6}
+    const constdict = {one: 1, two: vardict, three: 3}
+    vardict['five'] = 55
+    constdict['two']['six'] = 66
+    var cd = constdict['two']
+    cd['six'] = 66
+    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # "any" type with const flag is recognized as "any"
+  lines =<< trim END
+      const dict: dict<any> = {foo: {bar: 42}}
+      const foo = dict.foo
+      assert_equal(v:t_number, type(foo.bar))
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # also when used as a builtin function argument
+  lines =<< trim END
+      vim9script
+
+      def SorterFunc(lhs: dict<string>, rhs: dict<string>): number
+        return lhs.name <# rhs.name ? -1 : 1
+      enddef
+
+      def Run(): void
+        var list =  [{name: "3"}, {name: "2"}]
+        const Sorter = get({}, "unknown", SorterFunc)
+        sort(list, Sorter)
+        assert_equal([{name: "2"}, {name: "3"}], list)
+      enddef
+
+      Run()
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_const_bang()
+  var lines =<< trim END
+      const var = 234
+      var = 99
+  END
+  v9.CheckDefExecFailure(lines, 'E1018:', 2)
+  v9.CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
+
+  lines =<< trim END
+      const ll = [2, 3, 4]
+      ll[0] = 99
+  END
+  v9.CheckDefExecFailure(lines, 'E1119:', 2)
+  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
+
+  lines =<< trim END
+      const ll = [2, 3, 4]
+      ll[3] = 99
+  END
+  v9.CheckDefExecFailure(lines, 'E1118:', 2)
+  v9.CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
+
+  lines =<< trim END
+      const dd = {one: 1, two: 2}
+      dd["one"] = 99
+  END
+  v9.CheckDefExecFailure(lines, 'E1121:', 2)
+  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
+
+  lines =<< trim END
+      const dd = {one: 1, two: 2}
+      dd["three"] = 99
+  END
+  v9.CheckDefExecFailure(lines, 'E1120:')
+  v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
+enddef
+
+def Test_range_no_colon()
+  v9.CheckDefFailure(['%s/a/b/'], 'E1050:')
+  v9.CheckDefFailure(['+ s/a/b/'], 'E1050:')
+  v9.CheckDefFailure(['- s/a/b/'], 'E1050:')
+  v9.CheckDefFailure(['. s/a/b/'], 'E1050:')
+enddef
+
+
+def Test_block()
+  var outer = 1
+  {
+    var inner = 2
+    assert_equal(1, outer)
+    assert_equal(2, inner)
+  }
+  assert_equal(1, outer)
+
+  {|echo 'yes'|}
+enddef
+
+def Test_block_failure()
+  v9.CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
+  v9.CheckDefFailure(['}'], 'E1025:')
+  v9.CheckDefFailure(['{', 'echo 1'], 'E1026:')
+enddef
+
+def Test_block_local_vars()
+  var lines =<< trim END
+      vim9script
+      v:testing = 1
+      if true
+        var text = ['hello']
+        def SayHello(): list<string>
+          return text
+        enddef
+        def SetText(v: string)
+          text = [v]
+        enddef
+      endif
+
+      if true
+        var text = ['again']
+        def SayAgain(): list<string>
+          return text
+        enddef
+      endif
+
+      # test that the "text" variables are not cleaned up
+      test_garbagecollect_now()
+
+      defcompile
+
+      assert_equal(['hello'], SayHello())
+      assert_equal(['again'], SayAgain())
+
+      SetText('foobar')
+      assert_equal(['foobar'], SayHello())
+
+      call writefile(['ok'], 'Xdidit')
+      qall!
+  END
+
+  # need to execute this with a separate Vim instance to avoid the current
+  # context gets garbage collected.
+  writefile(lines, 'Xscript', 'D')
+  g:RunVim([], [], '-S Xscript')
+  assert_equal(['ok'], readfile('Xdidit'))
+
+  delete('Xdidit')
+enddef
+
+def Test_block_local_vars_with_func()
+  var lines =<< trim END
+      vim9script
+      if true
+        var foo = 'foo'
+        if true
+          var bar = 'bar'
+          def Func(): list<string>
+            return [foo, bar]
+          enddef
+        endif
+      endif
+      # function is compiled here, after blocks have finished, can still access
+      # "foo" and "bar"
+      assert_equal(['foo', 'bar'], Func())
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+" legacy func for command that's defined later
+func s:InvokeSomeCommand()
+  SomeCommand
+endfunc
+
+def Test_autocommand_block()
+  com SomeCommand {
+      g:someVar = 'some'
+    }
+  InvokeSomeCommand()
+  assert_equal('some', g:someVar)
+
+  delcommand SomeCommand
+  unlet g:someVar
+enddef
+
+def Test_command_block()
+  au BufNew *.xml {
+      g:otherVar = 'other'
+    }
+  split other.xml
+  assert_equal('other', g:otherVar)
+
+  bwipe!
+  au! BufNew *.xml
+  unlet g:otherVar
+enddef
+
+func g:NoSuchFunc()
+  echo 'none'
+endfunc
+
+def Test_try_catch_throw()
+  var l = []
+  try # comment
+    add(l, '1')
+    throw 'wrong'
+    add(l, '2')  # "unreachable code"
+  catch # comment
+    add(l, v:exception)
+  finally # comment
+    add(l, '3')
+  endtry # comment
+  assert_equal(['1', 'wrong', '3'], l)
+
+  l = []
+  try
+    try
+      add(l, '1')
+      throw 'wrong'
+      add(l, '2')  # "unreachable code"
+    catch /right/
+      add(l, v:exception)
+    endtry
+  catch /wrong/
+    add(l, 'caught')
+  finally
+    add(l, 'finally')
+  endtry
+  assert_equal(['1', 'caught', 'finally'], l)
+
+  var n: number
+  try
+    n = l[3]
+  catch /E684:/
+    n = 99
+  endtry
+  assert_equal(99, n)
+
+  var done = 'no'
+  if 0
+    try | catch | endtry
+  else
+    done = 'yes'
+  endif
+  assert_equal('yes', done)
+
+  done = 'no'
+  if 1
+    done = 'yes'
+  else
+    try | catch | endtry
+    done = 'never'
+  endif
+  assert_equal('yes', done)
+
+  if 1
+  else
+    try | catch /pat/ | endtry
+    try | catch /pat/
+    endtry
+    try
+    catch /pat/ | endtry
+    try
+    catch /pat/
+    endtry
+  endif
+
+  try
+    # string slice returns a string, not a number
+    n = g:astring[3]
+  catch /E1012:/
+    n = 77
+  endtry
+  assert_equal(77, n)
+
+  try
+    n = l[g:astring]
+  catch /E1012:/
+    n = 88
+  endtry
+  assert_equal(88, n)
+
+  try
+    n = s:does_not_exist
+  catch /E121:/
+    n = 111
+  endtry
+  assert_equal(111, n)
+
+  try
+    n = g:does_not_exist
+  catch /E121:/
+    n = 121
+  endtry
+  assert_equal(121, n)
+
+  var d = {one: 1}
+  try
+    n = d[g:astring]
+  catch /E716:/
+    n = 222
+  endtry
+  assert_equal(222, n)
+
+  try
+    n = -g:astring
+  catch /E1012:/
+    n = 233
+  endtry
+  assert_equal(233, n)
+
+  try
+    n = +g:astring
+  catch /E1012:/
+    n = 244
+  endtry
+  assert_equal(244, n)
+
+  try
+    n = +g:alist
+  catch /E1012:/
+    n = 255
+  endtry
+  assert_equal(255, n)
+
+  var nd: dict<any>
+  try
+    nd = {[g:alist]: 1}
+  catch /E1105:/
+    n = 266
+  endtry
+  assert_equal(266, n)
+
+  l = [1, 2, 3]
+  try
+    [n] = l
+  catch /E1093:/
+    n = 277
+  endtry
+  assert_equal(277, n)
+
+  try
+    &ts = g:astring
+  catch /E1012:/
+    n = 288
+  endtry
+  assert_equal(288, n)
+
+  try
+    &backspace = 'asdf'
+  catch /E474:/
+    n = 299
+  endtry
+  assert_equal(299, n)
+
+  l = [1]
+  try
+    l[3] = 3
+  catch /E684:/
+    n = 300
+  endtry
+  assert_equal(300, n)
+
+  try
+    unlet g:does_not_exist
+  catch /E108:/
+    n = 322
+  endtry
+  assert_equal(322, n)
+
+  try
+    d = {text: 1, [g:astring]: 2}
+  catch /E721:/
+    n = 333
+  endtry
+  assert_equal(333, n)
+
+  try
+    l = g:DeletedFunc()
+  catch /E933:/
+    n = 344
+  endtry
+  assert_equal(344, n)
+
+  try
+    echo range(1, 2, 0)
+  catch /E726:/
+    n = 355
+  endtry
+  assert_equal(355, n)
+
+  var P = function('g:NoSuchFunc')
+  delfunc g:NoSuchFunc
+  try
+    echo P()
+  catch /E117:/
+    n = 366
+  endtry
+  assert_equal(366, n)
+
+  try
+    echo g:NoSuchFunc()
+  catch /E117:/
+    n = 377
+  endtry
+  assert_equal(377, n)
+
+  try
+    echo g:alist + 4
+  catch /E745:/
+    n = 388
+  endtry
+  assert_equal(388, n)
+
+  try
+    echo 4 + g:alist
+  catch /E745:/
+    n = 399
+  endtry
+  assert_equal(399, n)
+
+  try
+    echo g:alist.member
+  catch /E715:/
+    n = 400
+  endtry
+  assert_equal(400, n)
+
+  try
+    echo d.member
+  catch /E716:/
+    n = 411
+  endtry
+  assert_equal(411, n)
+
+  var counter = 0
+  for i in range(4)
+    try
+      eval [][0]
+    catch
+    endtry
+    counter += 1
+  endfor
+  assert_equal(4, counter)
+
+  # no requirement for spaces before |
+  try|echo 0|catch|endtry
+
+  # return in try with finally
+  def ReturnInTry(): number
+    var ret = 4
+    try
+      return ret
+    catch /this/
+      return -1
+    catch /that/
+      return -1
+    finally
+      # changing ret has no effect
+      ret = 7
+    endtry
+    return -2
+  enddef
+  assert_equal(4, ReturnInTry())
+
+  # return in catch with finally
+  def ReturnInCatch(): number
+    var ret = 5
+    try
+      throw 'getout'
+      return -1 # "unreachable code"
+    catch /getout/
+      # ret is evaluated here
+      return ret
+    finally
+      # changing ret later has no effect
+      ret = -3
+    endtry
+    return -2
+  enddef
+  assert_equal(5, ReturnInCatch())
+
+  # return in finally after empty catch
+  def ReturnInFinally(): number
+    try
+    finally
+      return 6
+    endtry
+  enddef
+  assert_equal(6, ReturnInFinally())
+
+  var lines =<< trim END
+      vim9script
+      try
+        acos('0.5')
+          ->setline(1)
+      catch
+        g:caught = v:exception
+      endtry
+  END
+  v9.CheckScriptSuccess(lines)
+  assert_match('E1219: Float or Number required for argument 1', g:caught)
+  unlet g:caught
+
+  # missing catch and/or finally
+  lines =<< trim END
+      vim9script
+      try
+        echo 'something'
+      endtry
+  END
+  v9.CheckScriptFailure(lines, 'E1032:')
+
+  # skipping try-finally-endtry when try-finally-endtry is used in another block
+  lines =<< trim END
+      if v:true
+        try
+        finally
+        endtry
+      else
+        try
+        finally
+        endtry
+      endif
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_unreachable_after()
+  var lines =<< trim END
+      try
+        throw 'Error'
+        echo 'not reached'
+      catch /Error/
+      endtry
+  END
+  v9.CheckDefFailure(lines, 'E1095: Unreachable code after :throw')
+
+  lines =<< trim END
+      def SomeFunc(): number
+        try
+          return 3
+          echo 'not reached'
+        catch /Error/
+        endtry
+        return 4
+      enddef
+      defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1095: Unreachable code after :return')
+enddef
+
+def Test_throw_in_nested_try()
+  var lines =<< trim END
+      vim9script
+
+      def Try(F: func(): void)
+        try
+          F()
+        catch
+        endtry
+      enddef
+
+      class X
+        def F()
+          try
+            throw 'Foobar'
+          catch
+            throw v:exception
+          endtry
+        enddef
+      endclass
+
+      def Test_TryMethod()
+        var x = X.new()
+        Try(() => x.F())
+      enddef
+
+
+      try
+        Test_TryMethod()
+      catch
+      endtry
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_try_var_decl()
+  var lines =<< trim END
+      vim9script
+      try
+        var in_try = 1
+        assert_equal(1, get(s:, 'in_try', -1))
+        throw "getout"
+      catch
+        var in_catch = 2
+        assert_equal(-1, get(s:, 'in_try', -1))
+        assert_equal(2, get(s:, 'in_catch', -1))
+      finally
+        var in_finally = 3
+        assert_equal(-1, get(s:, 'in_try', -1))
+        assert_equal(-1, get(s:, 'in_catch', -1))
+        assert_equal(3, get(s:, 'in_finally', -1))
+      endtry
+      assert_equal(-1, get(s:, 'in_try', -1))
+      assert_equal(-1, get(s:, 'in_catch', -1))
+      assert_equal(-1, get(s:, 'in_finally', -1))
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_try_ends_in_return()
+  var lines =<< trim END
+      vim9script
+      def Foo(): string
+        try
+          return 'foo'
+        catch
+          return 'caught'
+        endtry
+      enddef
+      assert_equal('foo', Foo())
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      def Foo(): string
+        try
+          return 'foo'
+        catch
+          return 'caught'
+        endtry
+        echo 'notreached'
+      enddef
+      assert_equal('foo', Foo())
+  END
+  v9.CheckScriptFailure(lines, 'E1095:')
+
+  lines =<< trim END
+      vim9script
+      def Foo(): string
+        try
+          return 'foo'
+        catch /x/
+          return 'caught'
+        endtry
+      enddef
+      assert_equal('foo', Foo())
+  END
+  v9.CheckScriptFailure(lines, 'E1027:')
+
+  lines =<< trim END
+      vim9script
+      def Foo(): string
+        try
+          echo 'foo'
+        catch
+          echo 'caught'
+        finally
+          return 'done'
+        endtry
+      enddef
+      assert_equal('done', Foo())
+  END
+  v9.CheckScriptSuccess(lines)
+
+enddef
+
+def Test_try_in_catch()
+  var lines =<< trim END
+      vim9script
+      var seq = []
+      def DoIt()
+        try
+          seq->add('throw 1')
+          eval [][0]
+          seq->add('notreached')
+        catch
+          seq->add('catch')
+          try
+            seq->add('throw 2')
+            eval [][0]
+            seq->add('notreached')
+          catch /nothing/
+            seq->add('notreached')
+          endtry
+          seq->add('done')
+        endtry
+      enddef
+      DoIt()
+      assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq)
+  END
+enddef
+
+def Test_error_in_catch()
+  var lines =<< trim END
+      try
+        eval [][0]
+      catch /E684:/
+        eval [][0]
+      endtry
+  END
+  v9.CheckDefExecFailure(lines, 'E684:', 4)
+enddef
+
+" :while at the very start of a function that :continue jumps to
+def s:TryContinueFunc()
+ while g:Count < 2
+   g:sequence ..= 't'
+    try
+      echoerr 'Test'
+    catch
+      g:Count += 1
+      g:sequence ..= 'c'
+      continue
+    endtry
+    g:sequence ..= 'e'
+    g:Count += 1
+  endwhile
+enddef
+
+def Test_continue_in_try_in_while()
+  g:Count = 0
+  g:sequence = ''
+  TryContinueFunc()
+  assert_equal('tctc', g:sequence)
+  unlet g:Count
+  unlet g:sequence
+enddef
+
+def Test_break_in_try_in_for()
+  var lines =<< trim END
+      vim9script
+      def Ls(): list<string>
+        var ls: list<string>
+        for s in ['abc', 'def']
+          for _ in [123, 456]
+            try
+              eval [][0]
+            catch
+              break
+            endtry
+          endfor
+          ls += [s]
+        endfor
+        return ls
+      enddef
+      assert_equal(['abc', 'def'], Ls())
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_nocatch_return_in_try()
+  # return in try block returns normally
+  def ReturnInTry(): string
+    try
+      return '"some message"'
+    catch
+    endtry
+    return 'not reached'
+  enddef
+  exe 'echoerr ' .. ReturnInTry()
+enddef
+
+def Test_cnext_works_in_catch()
+  var lines =<< trim END
+      vim9script
+      au BufEnter * eval 1 + 2
+      writefile(['text'], 'Xcncfile1')
+      writefile(['text'], 'Xcncfile2')
+      var items = [
+          {lnum: 1, filename: 'Xcncfile1', valid: true},
+          {lnum: 1, filename: 'Xcncfile2', valid: true}
+        ]
+      setqflist([], ' ', {items: items})
+      cwindow
+
+      def CnextOrCfirst()
+        # if cnext fails, cfirst is used
+        try
+          cnext
+        catch
+          cfirst
+        endtry
+      enddef
+
+      CnextOrCfirst()
+      CnextOrCfirst()
+      writefile([getqflist({idx: 0}).idx], 'Xcncresult')
+      qall
+  END
+  writefile(lines, 'XCatchCnext', 'D')
+  g:RunVim([], [], '--clean -S XCatchCnext')
+  assert_equal(['1'], readfile('Xcncresult'))
+
+  delete('Xcncfile1')
+  delete('Xcncfile2')
+  delete('Xcncresult')
+enddef
+
+def Test_throw_skipped()
+  if 0
+    throw dontgethere
+  endif
+enddef
+
+def Test_nocatch_throw_silenced()
+  var lines =<< trim END
+    vim9script
+    def Func()
+      throw 'error'
+    enddef
+    silent! Func()
+  END
+  writefile(lines, 'XthrowSilenced', 'D')
+  source XthrowSilenced
+enddef
+
+" g:DeletedFunc() is found when compiling Test_try_catch_throw() and then
+" deleted, this should give a runtime error.
+def DeletedFunc(): list<any>
+  return ['delete me']
+enddef
+defcompile DeletedFunc
+
+call test_override('unreachable', 1)
+defcompile Test_try_catch_throw
+call test_override('unreachable', 0)
+
+delfunc DeletedFunc
+
+def s:ThrowFromDef()
+  throw "getout" # comment
+enddef
+
+func s:CatchInFunc()
+  try
+    call s:ThrowFromDef()
+  catch
+    let g:thrown_func = v:exception
+  endtry
+endfunc
+
+def s:CatchInDef()
+  try
+    ThrowFromDef()
+  catch
+    g:thrown_def = v:exception
+  endtry
+enddef
+
+def s:ReturnFinally(): string
+  try
+    return 'intry'
+  finally
+    g:in_finally = 'finally'
+  endtry
+  return 'end'
+enddef
+
+def Test_try_catch_nested()
+  CatchInFunc()
+  assert_equal('getout', g:thrown_func)
+
+  CatchInDef()
+  assert_equal('getout', g:thrown_def)
+
+  assert_equal('intry', ReturnFinally())
+  assert_equal('finally', g:in_finally)
+
+  var l = []
+  try
+    l->add('1')
+    throw 'bad'
+    l->add('x')  # "unreachable code"
+  catch /bad/
+    l->add('2')
+    try
+      l->add('3')
+      throw 'one'
+      l->add('x')
+    catch /one/
+      l->add('4')
+      try
+        l->add('5')
+        throw 'more'
+        l->add('x')
+      catch /more/
+        l->add('6')
+      endtry
+    endtry
+  endtry
+  assert_equal(['1', '2', '3', '4', '5', '6'], l)
+
+  l = []
+  try
+    try
+      l->add('1')
+      throw 'foo'
+      l->add('x')
+    catch
+      l->add('2')
+      throw 'bar'
+      l->add('x')
+    finally
+      l->add('3')
+    endtry
+    l->add('x')
+  catch /bar/
+    l->add('4')
+  endtry
+  assert_equal(['1', '2', '3', '4'], l)
+enddef
+
+call test_override('unreachable', 1)
+defcompile Test_try_catch_nested
+call test_override('unreachable', 0)
+
+def s:TryOne(): number
+  try
+    return 0
+  catch
+  endtry
+  return 0
+enddef
+
+def s:TryTwo(n: number): string
+  try
+    var x = {}
+  catch
+  endtry
+  return 'text'
+enddef
+
+def Test_try_catch_twice()
+  assert_equal('text', TryOne()->TryTwo())
+enddef
+
+def Test_try_catch_match()
+  var seq = 'a'
+  try
+    throw 'something'
+  catch /nothing/
+    seq ..= 'x'
+  catch /some/
+    seq ..= 'b'
+  catch /asdf/
+    seq ..= 'x'
+  catch ?a\?sdf?
+    seq ..= 'y'
+  finally
+    seq ..= 'c'
+  endtry
+  assert_equal('abc', seq)
+enddef
+
+def Test_try_catch_fails()
+  v9.CheckDefFailure(['catch'], 'E603:')
+  v9.CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
+  v9.CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
+  v9.CheckDefFailure(['finally'], 'E606:')
+  v9.CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
+  v9.CheckDefFailure(['endtry'], 'E602:')
+  v9.CheckDefFailure(['while 1', 'endtry'], 'E170:')
+  v9.CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
+  v9.CheckDefFailure(['if 1', 'endtry'], 'E171:')
+  v9.CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
+
+  v9.CheckDefFailure(['throw'], 'E1143:')
+  v9.CheckDefFailure(['throw xxx'], 'E1001:')
+enddef
+
+def Try_catch_skipped()
+  var l = []
+  try
+  finally
+  endtry
+
+  if 1
+  else
+    try
+    endtry
+  endif
+enddef
+
+" The skipped try/endtry was updating the wrong instruction.
+def Test_try_catch_skipped()
+  var instr = execute('disassemble Try_catch_skipped')
+  assert_match("NEWLIST size 0\n", instr)
+enddef
+
+def Test_throw_line_number()
+  def Func()
+    eval 1 + 1
+    eval 2 + 2
+    throw 'exception'
+  enddef
+  try
+    Func()
+  catch /exception/
+    assert_match('line 3', v:throwpoint)
+  endtry
+enddef
+
+
+def Test_throw_vimscript()
+  # only checks line continuation
+  var lines =<< trim END
+      vim9script
+      try
+        throw 'one'
+              .. 'two'
+      catch
+        assert_equal('onetwo', v:exception)
+      endtry
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    @r = ''
+    def Func()
+      throw @r
+    enddef
+    var result = ''
+    try
+      Func()
+    catch /E1129:/
+      result = 'caught'
+    endtry
+    assert_equal('caught', result)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_error_in_nested_function()
+  # an error in a nested :function aborts executing in the calling :def function
+  var lines =<< trim END
+      vim9script
+      def Func()
+        Error()
+        g:test_var = 1
+      enddef
+      func Error() abort
+        eval [][0]
+      endfunc
+      Func()
+  END
+  g:test_var = 0
+  v9.CheckScriptFailure(lines, 'E684:')
+  assert_equal(0, g:test_var)
+enddef
+
+def Test_abort_after_error()
+  var lines =<< trim END
+      vim9script
+      while true
+        echo notfound
+      endwhile
+      g:gotthere = true
+  END
+  g:gotthere = false
+  v9.CheckScriptFailure(lines, 'E121:')
+  assert_false(g:gotthere)
+  unlet g:gotthere
+enddef
+
+def Test_cexpr_vimscript()
+  # only checks line continuation
+  set errorformat=File\ %f\ line\ %l
+  var lines =<< trim END
+      vim9script
+      cexpr 'File'
+                .. ' someFile' ..
+                   ' line 19'
+      assert_equal(19, getqflist()[0].lnum)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      def CexprFail()
+        au QuickfixCmdPre * echo g:doesnotexist
+        cexpr 'File otherFile line 99'
+        g:didContinue = 'yes'
+      enddef
+      CexprFail()
+      g:didContinue = 'also'
+  END
+  g:didContinue = 'no'
+  v9.CheckScriptFailure(lines, 'E121: Undefined variable: g:doesnotexist')
+  assert_equal('no', g:didContinue)
+  au! QuickfixCmdPre
+
+  lines =<< trim END
+      vim9script
+      def CexprFail()
+        cexpr g:aNumber
+        g:didContinue = 'yes'
+      enddef
+      CexprFail()
+      g:didContinue = 'also'
+  END
+  g:aNumber = 123
+  g:didContinue = 'no'
+  v9.CheckScriptFailure(lines, 'E777: String or List expected')
+  assert_equal('no', g:didContinue)
+  unlet g:didContinue
+
+  set errorformat&
+enddef
+
+def Test_statusline_syntax()
+  # legacy syntax is used for 'statusline'
+  var lines =<< trim END
+      vim9script
+      func g:Status()
+        return '%{"x" is# "x"}'
+      endfunc
+      set laststatus=2 statusline=%!Status()
+      redrawstatus
+      set laststatus statusline=
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_list_vimscript()
+  # checks line continuation and comments
+  var lines =<< trim END
+      vim9script
+      var mylist = [
+            'one',
+            # comment
+            'two', # empty line follows
+
+            'three',
+            ]
+      assert_equal(['one', 'two', 'three'], mylist)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # check all lines from heredoc are kept
+  lines =<< trim END
+      # comment 1
+      two
+      # comment 3
+
+      five
+      # comment 6
+  END
+  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
+
+  lines =<< trim END
+    [{
+      a: 0}]->string()->assert_equal("[{'a': 0}]")
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+if has('channel')
+  let someJob = test_null_job()
+
+  def FuncWithError()
+    echomsg g:someJob
+  enddef
+
+  func Test_convert_emsg_to_exception()
+    try
+      call FuncWithError()
+    catch
+      call assert_match('Vim:E908:', v:exception)
+    endtry
+  endfunc
+endif
+
+def Test_vim9script_mix()
+  var lines =<< trim END
+    if has(g:feature)
+      " legacy script
+      let g:legacy = 1
+      finish
+    endif
+    vim9script
+    g:legacy = 0
+  END
+  g:feature = 'eval'
+  g:legacy = -1
+  v9.CheckScriptSuccess(lines)
+  assert_equal(1, g:legacy)
+
+  g:feature = 'noteval'
+  g:legacy = -1
+  v9.CheckScriptSuccess(lines)
+  assert_equal(0, g:legacy)
+enddef
+
+def Test_vim9script_fails()
+  v9.CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
+  v9.CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
+
+  v9.CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
+  v9.CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
+
+  assert_fails('vim9script', 'E1038:')
+  v9.CheckDefFailure(['vim9script'], 'E1038:')
+
+  # no error when skipping
+  if has('nothing')
+    vim9script
+  endif
+enddef
+
+def Test_script_var_shadows_function()
+  var lines =<< trim END
+      vim9script
+      def Func(): number
+        return 123
+      enddef
+      var Func = 1
+  END
+  v9.CheckScriptFailure(lines, 'E1041:', 5)
+enddef
+
+def Test_function_shadows_script_var()
+  var lines =<< trim END
+      vim9script
+      var Func = 1
+      def Func(): number
+        return 123
+      enddef
+  END
+  v9.CheckScriptFailure(lines, 'E1041:', 3)
+enddef
+
+def Test_script_var_shadows_command()
+  var lines =<< trim END
+      var undo = 1
+      undo = 2
+      assert_equal(2, undo)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  lines =<< trim END
+      var undo = 1
+      undo
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1207:', 2)
+enddef
+
+def Test_vim9script_call_wrong_type()
+  var lines =<< trim END
+      vim9script
+      var Time = 'localtime'
+      Time()
+  END
+  v9.CheckScriptFailure(lines, 'E1085:')
+enddef
+
+def Test_vim9script_reload_delfunc()
+  var first_lines =<< trim END
+    vim9script
+    def FuncYes(): string
+      return 'yes'
+    enddef
+  END
+  var withno_lines =<< trim END
+    def FuncNo(): string
+      return 'no'
+    enddef
+    def g:DoCheck(no_exists: bool)
+      assert_equal('yes', FuncYes())
+      assert_equal('no', FuncNo())
+    enddef
+  END
+  var nono_lines =<< trim END
+    def g:DoCheck(no_exists: bool)
+      assert_equal('yes', FuncYes())
+      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
+    enddef
+  END
+
+  # FuncNo() is defined
+  writefile(first_lines + withno_lines, 'Xreloaded.vim', 'D')
+  source Xreloaded.vim
+  g:DoCheck(true)
+
+  # FuncNo() is not redefined
+  writefile(first_lines + nono_lines, 'Xreloaded.vim')
+  source Xreloaded.vim
+  g:DoCheck(false)
+
+  # FuncNo() is back
+  writefile(first_lines + withno_lines, 'Xreloaded.vim')
+  source Xreloaded.vim
+  g:DoCheck(false)
+enddef
+
+def Test_vim9script_reload_delvar()
+  # write the script with a script-local variable
+  var lines =<< trim END
+    vim9script
+    var name = 'string'
+  END
+  writefile(lines, 'XreloadVar.vim', 'D')
+  source XreloadVar.vim
+
+  # now write the script using the same variable locally - works
+  lines =<< trim END
+    vim9script
+    def Func()
+      var name = 'string'
+    enddef
+  END
+  writefile(lines, 'XreloadVar.vim')
+  source XreloadVar.vim
+enddef
+
+def Test_func_redefine_error()
+  var lines = [
+        'vim9script',
+        'def Func()',
+        '  eval [][0]',
+        'enddef',
+        'Func()',
+        ]
+  writefile(lines, 'Xtestscript.vim', 'D')
+
+  for count in range(3)
+    try
+      source Xtestscript.vim
+    catch /E684/
+      # function name should contain <SNR> every time
+      assert_match('E684: List index out of range', v:exception)
+      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
+    endtry
+  endfor
+enddef
+
+def Test_func_redefine_fails()
+  var lines =<< trim END
+    vim9script
+    def Func()
+      echo 'one'
+    enddef
+    def Func()
+      echo 'two'
+    enddef
+  END
+  v9.CheckScriptFailure(lines, 'E1073:')
+
+  lines =<< trim END
+    vim9script
+    def Foo(): string
+      return 'foo'
+    enddef
+    def Func()
+      var  Foo = {-> 'lambda'}
+    enddef
+    defcompile
+  END
+  v9.CheckScriptFailure(lines, 'E1073:')
+enddef
+
+def Test_lambda_split()
+  # this was using freed memory, because of the split expression
+  var lines =<< trim END
+      vim9script
+      try
+      0
+      0->(0
+        ->a.0(
+        ->u
+  END
+  v9.CheckScriptFailure(lines, 'E1050:')
+enddef
+
+def Test_fixed_size_list()
+  # will be allocated as one piece of memory, check that changes work
+  var l = [1, 2, 3, 4]
+  l->remove(0)
+  l->add(5)
+  l->insert(99, 1)
+  assert_equal([2, 99, 3, 4, 5], l)
+enddef
+
+def Test_no_insert_xit()
+  v9.CheckDefExecFailure(['a = 1'], 'E1100:')
+  v9.CheckDefExecFailure(['c = 1'], 'E1100:')
+  v9.CheckDefExecFailure(['i = 1'], 'E1100:')
+  v9.CheckDefExecFailure(['t = 1'], 'E1100:')
+  v9.CheckDefExecFailure(['x = 1'], 'E1100:')
+
+  v9.CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
+  v9.CheckScriptFailure(['vim9script', 'a'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
+  v9.CheckScriptFailure(['vim9script', 'c'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
+  v9.CheckScriptFailure(['vim9script', 'i'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 'o'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 't'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
+  v9.CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
+enddef
+
+def s:IfElse(what: number): string
+  var res = ''
+  if what == 1
+    res = "one"
+  elseif what == 2
+    res = "two"
+  else
+    res = "three"
+  endif
+  return res
+enddef
+
+def Test_if_elseif_else()
+  assert_equal('one', IfElse(1))
+  assert_equal('two', IfElse(2))
+  assert_equal('three', IfElse(3))
+enddef
+
+def Test_if_elseif_else_fails()
+  v9.CheckDefFailure(['elseif true'], 'E582:')
+  v9.CheckDefFailure(['else'], 'E581:')
+  v9.CheckDefFailure(['endif'], 'E580:')
+  v9.CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
+  v9.CheckDefFailure(['if true', 'echo 1'], 'E171:')
+
+  var lines =<< trim END
+      var s = ''
+      if s = ''
+      endif
+  END
+  v9.CheckDefFailure(lines, 'E488:')
+
+  lines =<< trim END
+      var s = ''
+      if s == ''
+      elseif s = ''
+      endif
+  END
+  v9.CheckDefFailure(lines, 'E488:')
+
+  lines =<< trim END
+      var cond = true
+      if cond
+        echo 'true'
+      elseif
+        echo 'false'
+      endif
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E1143:', 'E15:'], 4)
+enddef
+
+def Test_if_else_func_using_var()
+  var lines =<< trim END
+      vim9script
+
+      const debug = true
+      if debug
+        var mode_chars = 'something'
+        def Bits2Ascii()
+          var x = mode_chars
+          g:where = 'in true'
+        enddef
+      else
+        def Bits2Ascii()
+          g:where = 'in false'
+        enddef
+      endif
+
+      Bits2Ascii()
+  END
+  v9.CheckScriptSuccess(lines)
+  assert_equal('in true', g:where)
+  unlet g:where
+
+  lines =<< trim END
+      vim9script
+
+      const debug = false
+      if debug
+        var mode_chars = 'something'
+        def Bits2Ascii()
+          g:where = 'in true'
+        enddef
+      else
+        def Bits2Ascii()
+          var x = mode_chars
+          g:where = 'in false'
+        enddef
+      endif
+
+      Bits2Ascii()
+  END
+  v9.CheckScriptFailure(lines, 'E1001: Variable not found: mode_chars')
+enddef
+
+let g:bool_true = v:true
+let g:bool_false = v:false
+
+def Test_if_const_expr()
+  var res = false
+  if true ? true : false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  g:glob = 2
+  if false
+    execute('g:glob = 3')
+  endif
+  assert_equal(2, g:glob)
+  if true
+    execute('g:glob = 3')
+  endif
+  assert_equal(3, g:glob)
+
+  res = false
+  if g:bool_true ? true : false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if true ? g:bool_true : false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if true ? true : g:bool_false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if true ? false : true
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if false ? false : true
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if false ? true : false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if has('xyz') ? true : false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if true && true
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if true && false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if g:bool_true && false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if true && g:bool_false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if false && false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  res = false
+  if true || false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if g:bool_true || false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if true || g:bool_false
+    res = true
+  endif
+  assert_equal(true, res)
+
+  res = false
+  if false || false
+    res = true
+  endif
+  assert_equal(false, res)
+
+  # with constant "false" expression may be invalid so long as the syntax is OK
+  if false | eval 1 + 2 | endif
+  if false | eval burp + 234 | endif
+  if false | echo burp 234 'asd' | endif
+  if false
+    burp
+  endif
+
+  if 0
+    if 1
+      echo nothing
+    elseif 1
+      echo still nothing
+    endif
+  endif
+
+  # expression with line breaks skipped
+  if false
+      ('aaa'
+      .. 'bbb'
+      .. 'ccc'
+      )->setline(1)
+  endif
+enddef
+
+def Test_if_const_expr_fails()
+  v9.CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
+  v9.CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
+  v9.CheckDefFailure(["if has('aaa'"], 'E110:')
+  v9.CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
+enddef
+
+def s:RunNested(i: number): number
+  var x: number = 0
+  if i % 2
+    if 1
+      # comment
+    else
+      # comment
+    endif
+    x += 1
+  else
+    x += 1000
+  endif
+  return x
+enddef
+
+def Test_nested_if()
+  assert_equal(1, RunNested(1))
+  assert_equal(1000, RunNested(2))
+enddef
+
+def Test_execute_cmd()
+  # missing argument is ignored
+  execute
+  execute # comment
+
+  new
+  setline(1, 'default')
+  execute 'setline(1, "execute-string")'
+  assert_equal('execute-string', getline(1))
+
+  execute "setline(1, 'execute-string')"
+  assert_equal('execute-string', getline(1))
+
+  var cmd1 = 'setline(1,'
+  var cmd2 = '"execute-var")'
+  execute cmd1 cmd2 # comment
+  assert_equal('execute-var', getline(1))
+
+  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
+  assert_equal('execute-var-string', getline(1))
+
+  var cmd_first = 'call '
+  var cmd_last = 'setline(1, "execute-var-var")'
+  execute cmd_first .. cmd_last
+  assert_equal('execute-var-var', getline(1))
+  bwipe!
+
+  var n = true
+  execute 'echomsg' (n ? '"true"' : '"no"')
+  assert_match('^true$', g:Screenline(&lines))
+
+  echomsg [1, 2, 3] {a: 1, b: 2}
+  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', g:Screenline(&lines))
+
+  v9.CheckDefFailure(['execute xxx'], 'E1001:', 1)
+  v9.CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
+  v9.CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
+  if has('channel')
+    v9.CheckDefExecFailure(['execute test_null_channel()'], 'E908:', 1)
+  endif
+enddef
+
+def Test_execute_cmd_vimscript()
+  # only checks line continuation
+  var lines =<< trim END
+      vim9script
+      execute 'g:someVar'
+                .. ' = ' ..
+                   '28'
+      assert_equal(28, g:someVar)
+      unlet g:someVar
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_execute_finish()
+  # the empty lines are relevant here
+  var lines =<< trim END
+      vim9script
+
+      var vname = "g:hello"
+
+      if exists(vname) | finish | endif | execute vname '= "world"'
+
+      assert_equal('world', g:hello)
+
+      if exists(vname) | finish | endif | execute vname '= "world"'
+
+      assert_report('should not be reached')
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_echo_cmd()
+  echo 'some' # comment
+  echon 'thing'
+  assert_match('^something$', g:Screenline(&lines))
+
+  echo "some" # comment
+  echon "thing"
+  assert_match('^something$', g:Screenline(&lines))
+
+  var str1 = 'some'
+  var str2 = 'more'
+  echo str1 str2
+  assert_match('^some more$', g:Screenline(&lines))
+
+  echo "one\ntwo"
+  assert_match('^one$', g:Screenline(&lines - 1))
+  assert_match('^two$', g:Screenline(&lines))
+
+  v9.CheckDefFailure(['echo "xxx"# comment'], 'E488:')
+enddef
+
+def Test_echomsg_cmd()
+  echomsg 'some' 'more' # comment
+  assert_match('^some more$', g:Screenline(&lines))
+  echo 'clear'
+  :1messages
+  assert_match('^some more$', g:Screenline(&lines))
+
+  v9.CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
+enddef
+
+def Test_echomsg_cmd_vimscript()
+  # only checks line continuation
+  var lines =<< trim END
+      vim9script
+      echomsg 'here'
+                .. ' is ' ..
+                   'a message'
+      assert_match('^here is a message$', g:Screenline(&lines))
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_echoerr_cmd()
+  var local = 'local'
+  try
+    echoerr 'something' local 'wrong' # comment
+  catch
+    assert_match('something local wrong', v:exception)
+  endtry
+enddef
+
+def Test_echoerr_cmd_vimscript()
+  # only checks line continuation
+  var lines =<< trim END
+      vim9script
+      try
+        echoerr 'this'
+                .. ' is ' ..
+                   'wrong'
+      catch
+        assert_match('this is wrong', v:exception)
+      endtry
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_echoconsole_cmd()
+  var local = 'local'
+  echoconsole 'something' local # comment
+  # output goes anywhere
+enddef
+
+def Test_echowindow_cmd()
+  var local = 'local'
+  echowindow 'something' local # comment
+
+  # with modifier
+  unsilent echowin 'loud'
+
+  # output goes in message window
+  popup_clear()
+enddef
+
+def Test_for_outside_of_function()
+  var lines =<< trim END
+    vim9script
+    new
+    for var in range(0, 3)
+      append(line('$'), var)
+    endfor
+    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
+    bwipe!
+
+    var result = ''
+    for i in [1, 2, 3]
+      var loop = ' loop ' .. i
+      result ..= loop
+    endfor
+    assert_equal(' loop 1 loop 2 loop 3', result)
+  END
+  writefile(lines, 'Xvim9for.vim', 'D')
+  source Xvim9for.vim
+enddef
+
+def Test_for_skipped_block()
+  # test skipped blocks at outside of function
+  var lines =<< trim END
+    var result = []
+    if true
+      for n in [1, 2]
+        result += [n]
+      endfor
+    else
+      for n in [3, 4]
+        result += [n]
+      endfor
+    endif
+    assert_equal([1, 2], result)
+
+    result = []
+    if false
+      for n in [1, 2]
+        result += [n]
+      endfor
+    else
+      for n in [3, 4]
+        result += [n]
+      endfor
+    endif
+    assert_equal([3, 4], result)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # test skipped blocks at inside of function
+  lines =<< trim END
+    def DefTrue()
+      var result = []
+      if true
+        for n in [1, 2]
+          result += [n]
+        endfor
+      else
+        for n in [3, 4]
+          result += [n]
+        endfor
+      endif
+      assert_equal([1, 2], result)
+    enddef
+    DefTrue()
+
+    def DefFalse()
+      var result = []
+      if false
+        for n in [1, 2]
+          result += [n]
+        endfor
+      else
+        for n in [3, 4]
+          result += [n]
+        endfor
+      endif
+      assert_equal([3, 4], result)
+    enddef
+    DefFalse()
+
+    def BuildDiagrams()
+      var diagrams: list<any>
+      if false
+        var max = 0
+        for v in diagrams
+          var l = 3
+          if max < l | max = l | endif
+          v->add(l)
+        endfor
+      endif
+    enddef
+    BuildDiagrams()
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_skipped_redir()
+  var lines =<< trim END
+      def Tredir()
+        if 0
+          redir => l[0]
+          redir END
+        endif
+      enddef
+      defcompile
+  END
+  v9.CheckScriptSuccess(lines)
+  delfunc g:Tredir
+
+  lines =<< trim END
+      def Tredir()
+        if 0
+          redir => l[0]
+        endif
+        echo 'executed'
+        if 0
+          redir END
+        endif
+      enddef
+      defcompile
+  END
+  v9.CheckScriptSuccess(lines)
+  delfunc g:Tredir
+
+  lines =<< trim END
+      def Tredir()
+        var l = ['']
+        if 1
+          redir => l[0]
+        endif
+        echo 'executed'
+        if 0
+          redir END
+        else
+          redir END
+        endif
+      enddef
+      defcompile
+  END
+  v9.CheckScriptSuccess(lines)
+  delfunc g:Tredir
+
+  lines =<< trim END
+      let doit = 1
+      def Tredir()
+        var l = ['']
+        if g:doit
+          redir => l[0]
+        endif
+        echo 'executed'
+        if g:doit
+          redir END
+        endif
+      enddef
+      defcompile
+  END
+  v9.CheckScriptSuccess(lines)
+  delfunc g:Tredir
+enddef
+
+def Test_for_loop()
+  var lines =<< trim END
+      var result = ''
+      for cnt in range(7)
+        if cnt == 4
+          break
+        endif
+        if cnt == 2
+          continue
+        endif
+        result ..= cnt .. '_'
+      endfor
+      assert_equal('0_1_3_', result)
+
+      var concat = ''
+      for str in eval('["one", "two"]')
+        concat ..= str
+      endfor
+      assert_equal('onetwo', concat)
+
+      var total = 0
+      for nr in
+          [1, 2, 3]
+        total += nr
+      endfor
+      assert_equal(6, total)
+
+      total = 0
+      for nr
+        in [1, 2, 3]
+        total += nr
+      endfor
+      assert_equal(6, total)
+
+      total = 0
+      for nr
+        in
+        [1, 2, 3]
+        total += nr
+      endfor
+      assert_equal(6, total)
+
+      # with type
+      total = 0
+      for n: number in [1, 2, 3]
+        total += n
+      endfor
+      assert_equal(6, total)
+
+      total = 0
+      for b in 0z010203
+        total += b
+      endfor
+      assert_equal(6, total)
+
+      var chars = ''
+      for s: string in 'foobar'
+        chars ..= s
+      endfor
+      assert_equal('foobar', chars)
+
+      chars = ''
+      for x: string in {a: 'a', b: 'b'}->values()
+        chars ..= x
+      endfor
+      assert_equal('ab', chars)
+
+      # unpack with type
+      var res = ''
+      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
+        res ..= n .. s
+      endfor
+      assert_equal('1a2b', res)
+
+      # unpack with one var
+      var reslist = []
+      for [x] in [['aaa'], ['bbb']]
+        reslist->add(x)
+      endfor
+      assert_equal(['aaa', 'bbb'], reslist)
+
+      # loop over string
+      res = ''
+      for c in 'aéc̀d'
+        res ..= c .. '-'
+      endfor
+      assert_equal('a-é-c̀-d-', res)
+
+      res = ''
+      for c in ''
+        res ..= c .. '-'
+      endfor
+      assert_equal('', res)
+
+      res = ''
+      for c in test_null_string()
+        res ..= c .. '-'
+      endfor
+      assert_equal('', res)
+
+      total = 0
+      for c in null_list
+        total += 1
+      endfor
+      assert_equal(0, total)
+
+      for c in null_blob
+        total += 1
+      endfor
+      assert_equal(0, total)
+
+      var foo: list<dict<any>> = [
+              {a: 'Cat'}
+            ]
+      for dd in foo
+        dd.counter = 12
+      endfor
+      assert_equal([{a: 'Cat', counter: 12}], foo)
+
+      reslist = []
+      for _ in range(3)
+        reslist->add('x')
+      endfor
+      assert_equal(['x', 'x', 'x'], reslist)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_for_loop_list_of_lists()
+  # loop variable is final, not const
+  var lines =<< trim END
+      # Filter out all odd numbers in each sublist
+      var list: list<list<number>> = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
+      for i in list
+          filter(i, (_, n: number): bool => n % 2 == 0)
+      endfor
+
+      assert_equal([[], [2], [2], [2, 4]], list)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_for_loop_with_closure()
+  # using the loop variable in a closure results in the last used value
+  var lines =<< trim END
+      var flist: list<func>
+      for i in range(5)
+        flist[i] = () => i
+      endfor
+      for i in range(5)
+        assert_equal(4, flist[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # also works when the loop variable is used only once halfway the loops
+  lines =<< trim END
+      var Clo: func
+      for i in range(5)
+        if i == 3
+          Clo = () => i
+        endif
+      endfor
+      assert_equal(4, Clo())
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # using a local variable set to the loop variable in a closure results in the
+  # value at that moment
+  lines =<< trim END
+      var flist: list<func>
+      for i in range(5)
+        var inloop = i
+        flist[i] = () => inloop
+      endfor
+      for i in range(5)
+        assert_equal(i, flist[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # also with an extra block level
+  lines =<< trim END
+      var flist: list<func>
+      for i in range(5)
+        {
+          var inloop = i
+          flist[i] = () => inloop
+        }
+      endfor
+      for i in range(5)
+        assert_equal(i, flist[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # and declaration in higher block
+  lines =<< trim END
+      var flist: list<func>
+      for i in range(5)
+        var inloop = i
+        {
+          flist[i] = () => inloop
+        }
+      endfor
+      for i in range(5)
+        assert_equal(i, flist[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  lines =<< trim END
+      var flist: list<func>
+      for i in range(5)
+        var inloop = i
+        flist[i] = () => {
+              return inloop
+            }
+      endfor
+      for i in range(5)
+        assert_equal(i, flist[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # Also works for a nested loop
+  lines =<< trim END
+      var flist: list<func>
+      var n = 0
+      for i in range(3)
+        var ii = i
+        for a in ['a', 'b', 'c']
+          var aa = a
+          flist[n] = () => ii .. aa
+          ++n
+        endfor
+      endfor
+
+      n = 0
+      for i in range(3)
+        for a in ['a', 'b', 'c']
+          assert_equal(i .. a, flist[n]())
+          ++n
+        endfor
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # using two loop variables
+  lines =<< trim END
+      var lv_list: list<func>
+      var copy_list: list<func>
+      for [idx, c] in items('word')
+        var lidx = idx
+        var lc = c
+        lv_list[idx] = () => {
+              return idx .. c
+            }
+        copy_list[idx] = () => {
+              return lidx .. lc
+            }
+      endfor
+      for [i, c] in items('word')
+        assert_equal(3 .. 'd', lv_list[i]())
+        assert_equal(i .. c, copy_list[i]())
+      endfor
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_define_global_closure_in_loops()
+  var lines =<< trim END
+      vim9script
+
+      def Func()
+        for i in range(3)
+          var ii = i
+          for a in ['a', 'b', 'c']
+            var aa = a
+            if ii == 0 && aa == 'a'
+              def g:Global_0a(): string
+                return ii .. aa
+              enddef
+            endif
+            if ii == 1 && aa == 'b'
+              def g:Global_1b(): string
+                return ii .. aa
+              enddef
+            endif
+            if ii == 2 && aa == 'c'
+              def g:Global_2c(): string
+                return ii .. aa
+              enddef
+            endif
+          endfor
+        endfor
+      enddef
+      Func()
+  END
+  v9.CheckScriptSuccess(lines)
+  assert_equal("0a", g:Global_0a())
+  assert_equal("1b", g:Global_1b())
+  assert_equal("2c", g:Global_2c())
+
+  delfunc g:Global_0a
+  delfunc g:Global_1b
+  delfunc g:Global_2c
+enddef
+
+def Test_for_loop_fails()
+  v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:'])
+  v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:'])
+  v9.CheckDefAndScriptFailure(['for x in'], ['E1097:', 'E15:'])
+  v9.CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
+  v9.CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
+  v9.CheckDefAndScriptFailure(['var x = 5', 'for x in range(5)', 'endfor'], ['E1017:', 'E1041:'])
+  v9.CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
+  v9.CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
+  delfunc! g:Func
+  v9.CheckDefFailure(['for i in xxx'], 'E1001:')
+  v9.CheckDefFailure(['endfor'], 'E588:')
+  v9.CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
+
+  # wrong type detected at compile time
+  v9.CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
+
+  # wrong type detected at runtime
+  g:adict = {a: 1}
+  v9.CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
+  unlet g:adict
+
+  var lines =<< trim END
+      var d: list<dict<any>> = [{a: 0}]
+      for e in d
+        e = {a: 0, b: ''}
+      endfor
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E1018:', 'E46:'], 3)
+
+  lines =<< trim END
+      for nr: number in ['foo']
+      endfor
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
+
+  lines =<< trim END
+      for n : number in [1, 2]
+        echo n
+      endfor
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1059:', 1)
+
+  lines =<< trim END
+      var d: dict<number> = {a: 1, b: 2}
+      for [k: job, v: job] in d->items()
+        echo k v
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 1: type mismatch, expected job but got string', 'E1012: Type mismatch; expected job but got string'], 2)
+
+  lines =<< trim END
+      var i = 0
+      for i in [1, 2, 3]
+        echo i
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, ['E1017:', 'E1041:'])
+
+  lines =<< trim END
+      var l = [0]
+      for l[0] in [1, 2, 3]
+        echo l[0]
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:'])
+
+  lines =<< trim END
+      var d = {x: 0}
+      for d.x in [1, 2, 3]
+        echo d.x
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:'])
+
+  lines =<< trim END
+      var l: list<dict<any>> = [{a: 1, b: 'x'}]
+      for item: dict<number> in l
+        echo item
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<number> but got dict<any>')
+
+  lines =<< trim END
+      var l: list<dict<any>> = [{n: 1}]
+      for item: dict<number> in l
+        var d = {s: ''}
+        d->extend(item)
+      endfor
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<string> but got dict<number>')
+
+  lines =<< trim END
+      for a in range(3)
+        while a > 3
+          for b in range(2)
+            while b < 0
+              for c in range(5)
+                while c > 6
+                  while c < 0
+                    for d in range(1)
+                      for e in range(3)
+                        while e > 3
+                        endwhile
+                      endfor
+                    endfor
+                  endwhile
+                endwhile
+              endfor
+            endwhile
+          endfor
+        endwhile
+      endfor
+  END
+  v9.CheckDefSuccess(lines)
+
+  v9.CheckDefFailure(['for x in range(3)'] + lines + ['endfor'], 'E1306:')
+enddef
+
+def Test_for_loop_script_var()
+  # cannot use s:var in a :def function
+  v9.CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1254:')
+
+  # can use s:var in Vim9 script, with or without s:
+  var lines =<< trim END
+    vim9script
+    var total = 0
+    for s:var in [1, 2, 3]
+      total += s:var
+    endfor
+    assert_equal(6, total)
+
+    total = 0
+    for var in [1, 2, 3]
+      total += var
+    endfor
+    assert_equal(6, total)
+  END
+enddef
+
+def Test_for_loop_unpack()
+  var lines =<< trim END
+      var result = []
+      for [v1, v2] in [[1, 2], [3, 4]]
+        result->add(v1)
+        result->add(v2)
+      endfor
+      assert_equal([1, 2, 3, 4], result)
+
+      result = []
+      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
+        result->add(v1)
+        result->add(v2)
+        result->add(v3)
+      endfor
+      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
+
+      result = []
+      for [&ts, &sw] in [[1, 2], [3, 4]]
+        result->add(&ts)
+        result->add(&sw)
+      endfor
+      assert_equal([1, 2, 3, 4], result)
+
+      var slist: list<string>
+      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
+        slist->add($LOOPVAR)
+        slist->add(@r)
+        slist->add(v:errmsg)
+      endfor
+      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
+
+      slist = []
+      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
+        slist->add(g:globalvar)
+        slist->add(b:bufvar)
+        slist->add(w:winvar)
+        slist->add(t:tabvar)
+      endfor
+      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
+      unlet! g:globalvar b:bufvar w:winvar t:tabvar
+
+      var res = []
+      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
+        res->add(n)
+      endfor
+      assert_equal([2, 5], res)
+
+      var text: list<string> = ["hello there", "goodbye now"]
+      var splitted = ''
+      for [first; next] in mapnew(text, (i, v) => split(v))
+          splitted ..= string(first) .. string(next) .. '/'
+      endfor
+      assert_equal("'hello'['there']/'goodbye'['now']/", splitted)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  lines =<< trim END
+      for [v1, v2] in [[1, 2, 3], [3, 4]]
+        echo v1 v2
+      endfor
+  END
+  v9.CheckDefExecFailure(lines, 'E710:', 1)
+
+  lines =<< trim END
+      for [v1, v2] in [[1], [3, 4]]
+        echo v1 v2
+      endfor
+  END
+  v9.CheckDefExecFailure(lines, 'E711:', 1)
+
+  lines =<< trim END
+      for [v1, v1] in [[1, 2], [3, 4]]
+        echo v1
+      endfor
+  END
+  v9.CheckDefExecFailure(lines, 'E1017:', 1)
+
+  lines =<< trim END
+      for [a, b] in g:listlist
+        echo a
+      endfor
+  END
+  g:listlist = [1, 2, 3]
+  v9.CheckDefExecFailure(lines, 'E1140:', 1)
+enddef
+
+def Test_for_loop_with_try_continue()
+  var lines =<< trim END
+      var looped = 0
+      var cleanup = 0
+      for i in range(3)
+        looped += 1
+        try
+          eval [][0]
+        catch
+          continue
+        finally
+          cleanup += 1
+        endtry
+      endfor
+      assert_equal(3, looped)
+      assert_equal(3, cleanup)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_while_skipped_block()
+  # test skipped blocks at outside of function
+  var lines =<< trim END
+    var result = []
+    var n = 0
+    if true
+      n = 1
+      while n < 3
+        result += [n]
+        n += 1
+      endwhile
+    else
+      n = 3
+      while n < 5
+        result += [n]
+        n += 1
+      endwhile
+    endif
+    assert_equal([1, 2], result)
+
+    result = []
+    if false
+      n = 1
+      while n < 3
+        result += [n]
+        n += 1
+      endwhile
+    else
+      n = 3
+      while n < 5
+        result += [n]
+        n += 1
+      endwhile
+    endif
+    assert_equal([3, 4], result)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
+  # test skipped blocks at inside of function
+  lines =<< trim END
+    def DefTrue()
+      var result = []
+      var n = 0
+      if true
+        n = 1
+        while n < 3
+          result += [n]
+          n += 1
+        endwhile
+      else
+        n = 3
+        while n < 5
+          result += [n]
+          n += 1
+        endwhile
+      endif
+      assert_equal([1, 2], result)
+    enddef
+    DefTrue()
+
+    def DefFalse()
+      var result = []
+      var n = 0
+      if false
+        n = 1
+        while n < 3
+          result += [n]
+          n += 1
+        endwhile
+      else
+        n = 3
+        while n < 5
+          result += [n]
+          n += 1
+        endwhile
+      endif
+      assert_equal([3, 4], result)
+    enddef
+    DefFalse()
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+def Test_while_loop()
+  var result = ''
+  var cnt = 0
+  while cnt < 555
+    if cnt == 3
+      break
+    endif
+    cnt += 1
+    if cnt == 2
+      continue
+    endif
+    result ..= cnt .. '_'
+  endwhile
+  assert_equal('1_3_', result)
+
+  var s = ''
+  while s == 'x' # {comment}
+  endwhile
+enddef
+
+def Test_while_loop_in_script()
+  var lines =<< trim END
+      vim9script
+      var result = ''
+      var cnt = 0
+      while cnt < 3
+        var s = 'v' .. cnt
+        result ..= s
+        cnt += 1
+      endwhile
+      assert_equal('v0v1v2', result)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_while_loop_fails()
+  v9.CheckDefFailure(['while xxx'], 'E1001:')
+  v9.CheckDefFailure(['endwhile'], 'E588:')
+  v9.CheckDefFailure(['continue'], 'E586:')
+  v9.CheckDefFailure(['if true', 'continue'], 'E586:')
+  v9.CheckDefFailure(['break'], 'E587:')
+  v9.CheckDefFailure(['if true', 'break'], 'E587:')
+  v9.CheckDefFailure(['while 1', 'echo 3'], 'E170:')
+
+  var lines =<< trim END
+      var s = ''
+      while s = ''
+      endwhile
+  END
+  v9.CheckDefFailure(lines, 'E488:')
+enddef
+
+def Test_interrupt_loop()
+  var caught = false
+  var x = 0
+  try
+    while 1
+      x += 1
+      if x == 100
+        feedkeys("\<C-C>", 'Lt')
+      endif
+    endwhile
+  catch
+    caught = true
+    assert_equal(100, x)
+  endtry
+  assert_true(caught, 'should have caught an exception')
+  # consume the CTRL-C
+  getchar(0)
+enddef
+
+def Test_automatic_line_continuation()
+  var mylist = [
+      'one',
+      'two',
+      'three',
+      ] # comment
+  assert_equal(['one', 'two', 'three'], mylist)
+
+  var mydict = {
+      ['one']: 1,
+      ['two']: 2,
+      ['three']:
+          3,
+      } # comment
+  assert_equal({one: 1, two: 2, three: 3}, mydict)
+  mydict = {
+      one: 1,  # comment
+      two:     # comment
+           2,  # comment
+      three: 3 # comment
+      }
+  assert_equal({one: 1, two: 2, three: 3}, mydict)
+  mydict = {
+      one: 1, 
+      two: 
+           2, 
+      three: 3 
+      }
+  assert_equal({one: 1, two: 2, three: 3}, mydict)
+
+  assert_equal(
+        ['one', 'two', 'three'],
+        split('one two three')
+        )
+enddef
+
+def Test_vim9_comment()
+  v9.CheckScriptSuccess([
+      'vim9script',
+      '# something',
+      '#something',
+      '#{{something',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      '#{something',
+      ], 'E1170:')
+
+  split Xv9cfile
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'edit #something',
+      ])
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'edit #{something',
+      ])
+  close
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      ':# something',
+      ], 'E488:')
+  v9.CheckScriptFailure([
+      '# something',
+      ], 'E488:')
+  v9.CheckScriptFailure([
+      ':# something',
+      ], 'E488:')
+
+  { # block start
+  } # block end
+  v9.CheckDefFailure([
+      '{# comment',
+      ], 'E488:')
+  v9.CheckDefFailure([
+      '{',
+      '}# comment',
+      ], 'E488:')
+
+  echo "yes" # comment
+  v9.CheckDefFailure([
+      'echo "yes"# comment',
+      ], 'E488:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'echo "yes" # something',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'echo "yes"# something',
+      ], 'E121:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'echo# something',
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'echo "yes" # something',
+      ], 'E121:')
+
+  exe "echo" # comment
+  v9.CheckDefFailure([
+      'exe "echo"# comment',
+      ], 'E488:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'exe "echo" # something',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'exe "echo"# something',
+      ], 'E121:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'exe# something',
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'exe "echo" # something',
+      ], 'E121:')
+
+  v9.CheckDefFailure([
+      'try# comment',
+      '  echo "yes"',
+      'catch',
+      'endtry',
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'try# comment',
+      'echo "yes"',
+      ], 'E1144:')
+  v9.CheckDefFailure([
+      'try',
+      '  throw#comment',
+      'catch',
+      'endtry',
+      ], 'E1144:')
+  v9.CheckDefFailure([
+      'try',
+      '  throw "yes"#comment',
+      'catch',
+      'endtry',
+      ], 'E488:')
+  v9.CheckDefFailure([
+      'try',
+      '  echo "yes"',
+      'catch# comment',
+      'endtry',
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'try',
+      '  echo "yes"',
+      'catch# comment',
+      'endtry',
+      ], 'E1144:')
+  v9.CheckDefFailure([
+      'try',
+      '  echo "yes"',
+      'catch /pat/# comment',
+      'endtry',
+      ], 'E488:')
+  v9.CheckDefFailure([
+      'try',
+      'echo "yes"',
+      'catch',
+      'endtry# comment',
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'try',
+      '  echo "yes"',
+      'catch',
+      'endtry# comment',
+      ], 'E1144:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'hi # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'hi# comment',
+      ], 'E1144:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'hi Search # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'hi Search# comment',
+      ], 'E416:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'hi link This Search # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'hi link This That# comment',
+      ], 'E413:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'hi clear This # comment',
+      'hi clear # comment',
+      ])
+  # not tested, because it doesn't give an error but a warning:
+  # hi clear This# comment',
+  v9.CheckScriptFailure([
+      'vim9script',
+      'hi clear# comment',
+      ], 'E416:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'hi Group term=bold',
+      'match Group /todo/ # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'hi Group term=bold',
+      'match Group /todo/# comment',
+      ], 'E488:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'match # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'match# comment',
+      ], 'E1144:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'match none # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'match none# comment',
+      ], 'E475:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'menutrans clear # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'menutrans clear# comment text',
+      ], 'E474:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax clear # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax clear# comment text',
+      ], 'E28:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax keyword Word some',
+      'syntax clear Word # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax keyword Word some',
+      'syntax clear Word# comment text',
+      ], 'E28:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax list # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax list# comment text',
+      ], 'E28:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax match Word /pat/ oneline # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax match Word /pat/ oneline# comment',
+      ], 'E475:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax keyword Word word # comm[ent',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax keyword Word word# comm[ent',
+      ], 'E789:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax match Word /pat/ # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax match Word /pat/# comment',
+      ], 'E402:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax match Word /pat/ contains=Something # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax match Word /pat/ contains=Something# comment',
+      ], 'E475:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax match Word /pat/ contains= # comment',
+      ], 'E406:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax match Word /pat/ contains=# comment',
+      ], 'E475:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax region Word start=/pat/ end=/pat/ # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax region Word start=/pat/ end=/pat/# comment',
+      ], 'E402:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax sync # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax sync# comment',
+      ], 'E404:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax sync ccomment # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax sync ccomment# comment',
+      ], 'E404:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'syntax cluster Some contains=Word # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'syntax cluster Some contains=Word# comment',
+      ], 'E475:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'command Echo echo # comment',
+      'command Echo # comment',
+      'delcommand Echo',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'command Echo echo# comment',
+      'Echo',
+      ], 'E1144:')
+  delcommand Echo
+
+  var curdir = getcwd()
+  v9.CheckScriptSuccess([
+      'command Echo cd " comment',
+      'Echo',
+      'delcommand Echo',
+      ])
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'command Echo cd # comment',
+      'Echo',
+      'delcommand Echo',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'command Echo cd " comment',
+      'Echo',
+      ], 'E344:')
+  delcommand Echo
+  chdir(curdir)
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'command Echo# comment',
+      ], 'E182:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'command Echo echo',
+      'command Echo# comment',
+      ], 'E182:')
+  delcommand Echo
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'function # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'function " comment',
+      ], 'E129:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'function# comment',
+      ], 'E1144:')
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'import "./vim9.vim" as v9',
+      'function v9.CheckScriptSuccess # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'import "./vim9.vim" as v9',
+      'function v9.CheckScriptSuccess# comment',
+      ], 'E1048: Item not found in script: CheckScriptSuccess#')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'func g:DeleteMeA()',
+      'endfunc',
+      'delfunction g:DeleteMeA # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'func g:DeleteMeB()',
+      'endfunc',
+      'delfunction g:DeleteMeB# comment',
+      ], 'E488:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'call execute("ls") # comment',
+      ])
+  v9.CheckScriptFailure([
+      'vim9script',
+      'call execute("ls")# comment',
+      ], 'E488:')
+
+  v9.CheckScriptFailure([
+      'def Test() " comment',
+      'enddef',
+      ], 'E488:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'def Test() " comment',
+      'enddef',
+      ], 'E488:')
+
+  v9.CheckScriptSuccess([
+      'func Test() " comment',
+      'endfunc',
+      'delfunc Test',
+      ])
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'func Test() " comment',
+      'endfunc',
+      ])
+
+  v9.CheckScriptSuccess([
+      'def Test() # comment',
+      'enddef',
+      ])
+  v9.CheckScriptFailure([
+      'func Test() # comment',
+      'endfunc',
+      ], 'E488:')
+
+  var lines =<< trim END
+      vim9script
+      syn region Text
+      \ start='foo'
+      #\ comment
+      \ end='bar'
+      syn region Text start='foo'
+      #\ comment
+      \ end='bar'
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      syn region Text
+      \ start='foo'
+      "\ comment
+      \ end='bar'
+  END
+  v9.CheckScriptFailure(lines, 'E399:')
+enddef
+
+def Test_vim9_comment_gui()
+  CheckCanRunGui
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'gui#comment'
+      ], 'E1144:')
+  v9.CheckScriptFailure([
+      'vim9script',
+      'gui -f#comment'
+      ], 'E194:')
+enddef
+
+def Test_vim9_comment_not_compiled()
+  au TabEnter *.vim g:entered = 1
+  au TabEnter *.x g:entered = 2
+
+  edit test.vim
+  doautocmd TabEnter #comment
+  assert_equal(1, g:entered)
+
+  doautocmd TabEnter f.x
+  assert_equal(2, g:entered)
+
+  g:entered = 0
+  doautocmd TabEnter f.x #comment
+  assert_equal(2, g:entered)
+
+  assert_fails('doautocmd Syntax#comment', 'E216:')
+
+  au! TabEnter
+  unlet g:entered
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'g:var = 123',
+      'b:var = 456',
+      'w:var = 777',
+      't:var = 888',
+      'unlet g:var w:var # something',
+      ])
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'let var = 123',
+      ], 'E1126: Cannot use :let in Vim9 script')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var g:var = 123',
+      ], 'E1016: Cannot declare a global variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var b:var = 123',
+      ], 'E1016: Cannot declare a buffer variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var w:var = 123',
+      ], 'E1016: Cannot declare a window variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var t:var = 123',
+      ], 'E1016: Cannot declare a tab variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var v:version = 123',
+      ], 'E1016: Cannot declare a v: variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var $VARIABLE = "text"',
+      ], 'E1016: Cannot declare an environment variable:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'g:var = 123',
+      'unlet g:var# comment1',
+      ], 'E108:')
+
+  v9.CheckScriptFailure([
+      'let g:var = 123',
+      'unlet g:var # something',
+      ], 'E488:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'if 1 # comment2',
+      '  echo "yes"',
+      'elseif 2 #comment',
+      '  echo "no"',
+      'endif',
+      ])
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'if 1# comment3',
+      '  echo "yes"',
+      'endif',
+      ], 'E488:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'if 0 # comment4',
+      '  echo "yes"',
+      'elseif 2#comment',
+      '  echo "no"',
+      'endif',
+      ], 'E488:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'var v = 1 # comment5',
+      ])
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'var v = 1# comment6',
+      ], 'E488:')
+
+  v9.CheckScriptSuccess([
+      'vim9script',
+      'new',
+      'setline(1, ["# define pat", "last"])',
+      ':$',
+      'dsearch /pat/ #comment',
+      'bwipe!',
+      ])
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'new',
+      'setline(1, ["# define pat", "last"])',
+      ':$',
+      'dsearch /pat/#comment',
+      'bwipe!',
+      ], 'E488:')
+
+  v9.CheckScriptFailure([
+      'vim9script',
+      'func! SomeFunc()',
+      ], 'E477:')
+enddef
+
+def Test_finish()
+  var lines =<< trim END
+    vim9script
+    g:res = 'one'
+    if v:false | finish | endif
+    g:res = 'two'
+    finish
+    g:res = 'three'
+  END
+  writefile(lines, 'Xfinished', 'D')
+  source Xfinished
+  assert_equal('two', g:res)
+
+  unlet g:res
+enddef
+
+def Test_forward_declaration()
+  var lines =<< trim END
+    vim9script
+    def GetValue(): string
+      return theVal
+    enddef
+    var theVal = 'something'
+    g:initVal = GetValue()
+    theVal = 'else'
+    g:laterVal = GetValue()
+  END
+  writefile(lines, 'Xforward', 'D')
+  source Xforward
+  assert_equal('something', g:initVal)
+  assert_equal('else', g:laterVal)
+
+  unlet g:initVal
+  unlet g:laterVal
+enddef
+
+def Test_declare_script_var_in_func()
+  var lines =<< trim END
+      vim9script
+      func Declare()
+        let s:local = 123
+      endfunc
+      Declare()
+  END
+  v9.CheckScriptFailure(lines, 'E1269:')
+enddef
+
+def Test_lock_script_var()
+  var lines =<< trim END
+      vim9script
+      var local = 123
+      assert_equal(123, local)
+
+      var error: string
+      try
+        local = 'asdf'
+      catch
+        error = v:exception
+      endtry
+      assert_match('E1012: Type mismatch; expected number but got string', error)
+
+      lockvar local
+      try
+        local = 999
+      catch
+        error = v:exception
+      endtry
+      assert_match('E741: Value is locked: local', error)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+
+func Test_vim9script_not_global()
+  " check that items defined in Vim9 script are script-local, not global
+  let vim9lines =<< trim END
+    vim9script
+    var name = 'local'
+    func TheFunc()
+      echo 'local'
+    endfunc
+    def DefFunc()
+      echo 'local'
+    enddef
+  END
+  call writefile(vim9lines, 'Xvim9script.vim', 'D')
+  source Xvim9script.vim
+  try
+    echo g:var
+    assert_report('did not fail')
+  catch /E121:/
+    " caught
+  endtry
+  try
+    call TheFunc()
+    assert_report('did not fail')
+  catch /E117:/
+    " caught
+  endtry
+  try
+    call DefFunc()
+    assert_report('did not fail')
+  catch /E117:/
+    " caught
+  endtry
+endfunc
+
+def Test_vim9_copen()
+  # this was giving an error for setting w:quickfix_title
+  copen
+  quit
+enddef
+
+def Test_script_var_in_autocmd()
+  # using a script variable from an autocommand, defined in a :def function in a
+  # legacy Vim script, cannot check the variable type.
+  var lines =<< trim END
+    let s:counter = 1
+    def s:Func()
+      au! CursorHold
+      au CursorHold * s:counter += 1
+    enddef
+    call s:Func()
+    doau CursorHold
+    call assert_equal(2, s:counter)
+    au! CursorHold
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+def Test_error_in_autoload_script()
+  var save_rtp = &rtp
+  var dir = getcwd() .. '/Xruntime'
+  &rtp = dir
+  mkdir(dir .. '/autoload', 'pR')
+
+  var lines =<< trim END
+      vim9script noclear
+      export def Autoloaded()
+      enddef
+      def Broken()
+        var x: any = ''
+        eval x != 0
+      enddef
+      Broken()
+  END
+  writefile(lines, dir .. '/autoload/script.vim')
+
+  lines =<< trim END
+      vim9script
+      def CallAutoloaded()
+        script#Autoloaded()
+      enddef
+
+      function Legacy()
+        try
+          call s:CallAutoloaded()
+        catch
+          call assert_match('E1030: Using a String as a Number', v:exception)
+        endtry
+      endfunction
+
+      Legacy()
+  END
+  v9.CheckScriptSuccess(lines)
+
+  &rtp = save_rtp
+enddef
+
+def Test_error_in_autoload_script_foldexpr()
+  var save_rtp = &rtp
+  mkdir('Xvim/autoload', 'pR')
+  &runtimepath = 'Xvim'
+
+  var lines =<< trim END
+      vim9script
+      eval [][0]
+      echomsg 'no error'
+  END
+  lines->writefile('Xvim/autoload/script.vim')
+
+  lines =<< trim END
+      vim9script
+      import autoload 'script.vim'
+      &foldmethod = 'expr'
+      &foldexpr = 'script.Func()'
+      redraw
+  END
+  v9.CheckScriptFailure(lines, 'E684: List index out of range: 0')
+enddef
+
+def Test_invalid_sid()
+  assert_fails('func <SNR>1234_func', 'E123:')
+
+  if g:RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
+    assert_equal([], readfile('Xdidit'))
+  endif
+  delete('Xdidit')
+enddef
+
+def Test_restoring_cpo()
+  writefile(['vim9script', 'set nocp'], 'Xsourced', 'D')
+  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose', 'D')
+  if g:RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
+    assert_equal(['done'], readfile('Xdone'))
+  endif
+  delete('Xdone')
+
+  writefile(['vim9script', 'g:cpoval = &cpo'], 'XanotherScript', 'D')
+  set cpo=aABceFsMny>
+  edit XanotherScript
+  so %
+  assert_equal('aABceFsMny>', &cpo)
+  assert_equal('aABceFs', g:cpoval)
+  :1del
+  setline(1, 'let g:cpoval = &cpo')
+  w
+  so %
+  assert_equal('aABceFsMny>', &cpo)
+  assert_equal('aABceFsMny>', g:cpoval)
+
+  set cpo&vim
+  unlet g:cpoval
+
+  if has('unix')
+    # 'cpo' is not restored in main vimrc
+    var save_HOME = $HOME
+    $HOME = getcwd() .. '/Xhome'
+    mkdir('Xhome', 'R')
+    var lines =<< trim END
+        vim9script
+        writefile(['before: ' .. &cpo], 'Xrporesult')
+        set cpo+=M
+        writefile(['after: ' .. &cpo], 'Xrporesult', 'a')
+    END
+    writefile(lines, 'Xhome/.vimrc')
+
+    lines =<< trim END
+        call writefile(['later: ' .. &cpo], 'Xrporesult', 'a')
+    END
+    writefile(lines, 'Xlegacy', 'D')
+
+    lines =<< trim END
+        vim9script
+        call writefile(['vim9: ' .. &cpo], 'Xrporesult', 'a')
+        qa
+    END
+    writefile(lines, 'Xvim9', 'D')
+
+    var cmd = g:GetVimCommand() .. " -S Xlegacy -S Xvim9"
+    cmd = substitute(cmd, '-u NONE', '', '')
+    exe "silent !" .. cmd
+
+    assert_equal([
+        'before: aABceFs',
+        'after: aABceFsM',
+        'later: aABceFsM',
+        'vim9: aABceFs'], readfile('Xrporesult'))
+
+    $HOME = save_HOME
+    delete('Xrporesult')
+  endif
+enddef
+
+" Use :function so we can use Check commands
+func Test_no_redraw_when_restoring_cpo()
+  CheckScreendump
+  CheckFeature timers
+  call Run_test_no_redraw_when_restoring_cpo()
+endfunc
+
+def Run_test_no_redraw_when_restoring_cpo()
+  var lines =<< trim END
+    vim9script
+    export def Func()
+    enddef
+  END
+  mkdir('Xnordir/autoload', 'pR')
+  writefile(lines, 'Xnordir/autoload/script.vim')
+
+  lines =<< trim END
+      vim9script
+      set cpo+=M
+      exe 'set rtp^=' .. getcwd() .. '/Xnordir'
+      au CmdlineEnter : ++once timer_start(0, (_) => script#Func())
+      setline(1, 'some text')
+  END
+  writefile(lines, 'XTest_redraw_cpo', 'D')
+  var buf = g:RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
+  term_sendkeys(buf, "V:")
+  g:VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
+
+  # clean up
+  term_sendkeys(buf, "\<Esc>u")
+  g:StopVimInTerminal(buf)
+enddef
+
+func Test_reject_declaration()
+  CheckScreendump
+  call Run_test_reject_declaration()
+endfunc
+
+def Run_test_reject_declaration()
+  var buf = g:RunVimInTerminal('', {'rows': 6})
+  term_sendkeys(buf, ":vim9cmd var x: number\<CR>")
+  g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_1', {})
+  term_sendkeys(buf, ":\<CR>")
+  term_sendkeys(buf, ":vim9cmd g:foo = 123 | echo g:foo\<CR>")
+  g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_2', {})
+
+  # clean up
+  g:StopVimInTerminal(buf)
+enddef
+
+def Test_minimal_command_name_length()
+  var names = [
+       'cons',
+       'brea',
+       'cat',
+       'catc',
+       'con',
+       'cont',
+       'conti',
+       'contin',
+       'continu',
+       'el',
+       'els',
+       'elsei',
+       'endfo',
+       'en',
+       'end',
+       'endi',
+       'endw',
+       'endt',
+       'endtr',
+       'exp',
+       'expo',
+       'expor',
+       'fina',
+       'finall',
+       'fini',
+       'finis',
+       'imp',
+       'impo',
+       'impor',
+       'retu',
+       'retur',
+       'th',
+       'thr',
+       'thro',
+       'wh',
+       'whi',
+       'whil',
+      ]
+  for name in names
+    v9.CheckDefAndScriptFailure([name .. ' '], 'E1065:')
+  endfor
+
+  var lines =<< trim END
+      vim9script
+      def SomeFunc()
+      endd
+  END
+  v9.CheckScriptFailure(lines, 'E1065:')
+  lines =<< trim END
+      vim9script
+      def SomeFunc()
+      endde
+  END
+  v9.CheckScriptFailure(lines, 'E1065:')
+enddef
+
+def Test_unset_any_variable()
+  var lines =<< trim END
+    var name: any
+    assert_equal(0, name)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+enddef
+
+func Test_define_func_at_command_line()
+  CheckRunVimInTerminal
+
+  " call indirectly to avoid compilation error for missing functions
+  call Run_Test_define_func_at_command_line()
+endfunc
+
+def Run_Test_define_func_at_command_line()
+  # run in a separate Vim instance to avoid the script context
+  var lines =<< trim END
+    func CheckAndQuit()
+      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
+      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
+    endfunc
+  END
+  writefile([''], 'Xdidcmd', 'D')
+  writefile(lines, 'XcallFunc', 'D')
+  var buf = g:RunVimInTerminal('-S XcallFunc', {rows: 6})
+  # define Afunc() on the command line
+  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
+  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
+  g:WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
+
+  call g:StopVimInTerminal(buf)
+enddef
+
+def Test_script_var_scope()
+  var lines =<< trim END
+      vim9script
+      if true
+        if true
+          var one = 'one'
+          echo one
+        endif
+        echo one
+      endif
+  END
+  v9.CheckScriptFailure(lines, 'E121:', 7)
+
+  lines =<< trim END
+      vim9script
+      if true
+        if false
+          var one = 'one'
+          echo one
+        else
+          var one = 'one'
+          echo one
+        endif
+        echo one
+      endif
+  END
+  v9.CheckScriptFailure(lines, 'E121:', 10)
+
+  lines =<< trim END
+      vim9script
+      while true
+        var one = 'one'
+        echo one
+        break
+      endwhile
+      echo one
+  END
+  v9.CheckScriptFailure(lines, 'E121:', 7)
+
+  lines =<< trim END
+      vim9script
+      for i in range(1)
+        var one = 'one'
+        echo one
+      endfor
+      echo one
+  END
+  v9.CheckScriptFailure(lines, 'E121:', 6)
+
+  lines =<< trim END
+      vim9script
+      {
+        var one = 'one'
+        assert_equal('one', one)
+      }
+      assert_false(exists('one'))
+      assert_false(exists('s:one'))
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      {
+        var one = 'one'
+        echo one
+      }
+      echo one
+  END
+  v9.CheckScriptFailure(lines, 'E121:', 6)
+enddef
+
+def Test_catch_exception_in_callback()
+  var lines =<< trim END
+    vim9script
+    def Callback(...l: list<any>)
+      try
+        var x: string
+        var y: string
+        # this error should be caught with CHECKLEN
+        var sl = ['']
+        [x, y] = sl
+      catch
+        g:caught = 'yes'
+      endtry
+    enddef
+    popup_menu('popup', {callback: Callback})
+    feedkeys("\r", 'xt')
+  END
+  v9.CheckScriptSuccess(lines)
+
+  unlet g:caught
+enddef
+
+def Test_no_unknown_error_after_error()
+  if !has('unix') || !has('job')
+    throw 'Skipped: not unix of missing +job feature'
+  endif
+  # FIXME: this check should not be needed
+  if has('win32')
+    throw 'Skipped: does not work on MS-Windows'
+  endif
+  var lines =<< trim END
+      vim9script
+      var source: list<number>
+      def Out_cb(...l: list<any>)
+          eval [][0]
+      enddef
+      def Exit_cb(...l: list<any>)
+          sleep 1m
+          g:did_call_exit_cb = true
+          source += l
+      enddef
+      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
+      while job_status(myjob) == 'run'
+        sleep 10m
+      endwhile
+      # wait for Exit_cb() to be called
+      for x in range(100)
+        if exists('g:did_call_exit_cb')
+          unlet g:did_call_exit_cb
+          break
+        endif
+        sleep 10m
+      endfor
+  END
+  writefile(lines, 'Xdef', 'D')
+  # Either the exit or out callback is called first, accept them in any order
+  assert_fails('so Xdef', ['E684:\|E1012:', 'E1012:\|E684:'])
+enddef
+
+def InvokeNormal()
+  exe "norm! :m+1\r"
+enddef
+
+def Test_invoke_normal_in_visual_mode()
+  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
+  new
+  setline(1, ['aaa', 'bbb'])
+  feedkeys("V\<F3>", 'xt')
+  assert_equal(['bbb', 'aaa'], getline(1, 2))
+  xunmap <F3>
+enddef
+
+def Test_white_space_after_command()
+  var lines =<< trim END
+    exit_cb: Func})
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1144:', 1)
+
+  lines =<< trim END
+    e#
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1144:', 1)
+enddef
+
+def Test_script_var_gone_when_sourced_twice()
+  var lines =<< trim END
+      vim9script
+      if exists('g:guard')
+        finish
+      endif
+      g:guard = 1
+      var name = 'thename'
+      def g:GetName(): string
+        return name
+      enddef
+      def g:SetName(arg: string)
+        name = arg
+      enddef
+  END
+  writefile(lines, 'XscriptTwice.vim', 'D')
+  so XscriptTwice.vim
+  assert_equal('thename', g:GetName())
+  g:SetName('newname')
+  assert_equal('newname', g:GetName())
+  so XscriptTwice.vim
+  assert_fails('call g:GetName()', 'E1149:')
+  assert_fails('call g:SetName("x")', 'E1149:')
+
+  delfunc g:GetName
+  delfunc g:SetName
+  unlet g:guard
+enddef
+
+def Test_unsupported_commands()
+  var lines =<< trim END
+      ka
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:'])
+
+  lines =<< trim END
+      :1ka
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:'])
+
+  lines =<< trim END
+      :k a
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1100:')
+
+  lines =<< trim END
+      :1k a
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E481:')
+
+  lines =<< trim END
+    t
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1100:')
+
+  lines =<< trim END
+    x
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1100:')
+
+  lines =<< trim END
+    xit
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E1100:')
+
+  lines =<< trim END
+    Print
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: Print', 'E492: Not an editor command: Print'])
+
+  lines =<< trim END
+    mode 4
+  END
+  v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: mode 4', 'E492: Not an editor command: mode 4'])
+enddef
+
+def Test_mapping_line_number()
+  var lines =<< trim END
+      vim9script
+      def g:FuncA()
+          # Some comment
+          FuncB(0)
+      enddef
+          # Some comment
+      def FuncB(
+          # Some comment
+          n: number
+      )
+          exe 'nno '
+              # Some comment
+              .. '<F3> a'
+              .. 'b'
+              .. 'c'
+      enddef
+  END
+  v9.CheckScriptSuccess(lines)
+  var res = execute('verbose nmap <F3>')
+  assert_match('No mapping found', res)
+
+  g:FuncA()
+  res = execute('verbose nmap <F3>')
+  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
+
+  nunmap <F3>
+  delfunc g:FuncA
+enddef
+
+def Test_option_set()
+  # legacy script allows for white space
+  var lines =<< trim END
+      set foldlevel  =11
+      call assert_equal(11, &foldlevel)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  set foldlevel
+  set foldlevel=12
+  assert_equal(12, &foldlevel)
+  set foldlevel+=2
+  assert_equal(14, &foldlevel)
+  set foldlevel-=3
+  assert_equal(11, &foldlevel)
+
+  lines =<< trim END
+      set foldlevel =1
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
+
+  lines =<< trim END
+      set foldlevel +=1
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
+
+  lines =<< trim END
+      set foldlevel ^=1
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
+
+  lines =<< trim END
+      set foldlevel -=1
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
+
+  set foldlevel&
+enddef
+
+def Test_option_modifier()
+  # legacy script allows for white space
+  var lines =<< trim END
+      set hlsearch &  hlsearch  !
+      call assert_equal(1, &hlsearch)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  set hlsearch
+  set hlsearch!
+  assert_equal(false, &hlsearch)
+
+  set hlsearch
+  set hlsearch&
+  assert_equal(false, &hlsearch)
+
+  lines =<< trim END
+      set hlsearch &
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
+
+  lines =<< trim END
+      set hlsearch   !
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
+
+  set hlsearch&
+enddef
+
+" This must be called last, it may cause following :def functions to fail
+def Test_xxx_echoerr_line_number()
+  var lines =<< trim END
+      echoerr 'some'
+         .. ' error'
+         .. ' continued'
+  END
+  v9.CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
+enddef
+
+func Test_debug_with_lambda()
+  CheckRunVimInTerminal
+
+  " call indirectly to avoid compilation error for missing functions
+  call Run_Test_debug_with_lambda()
+endfunc
+
+def Run_Test_debug_with_lambda()
+  var lines =<< trim END
+      vim9script
+      def Func()
+        var n = 0
+        echo [0]->filter((_, v) => v == n)
+      enddef
+      breakadd func Func
+      Func()
+  END
+  writefile(lines, 'XdebugFunc', 'D')
+  var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0})
+  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
+
+  term_sendkeys(buf, "cont\<CR>")
+  g:WaitForAssert(() => assert_match('\[0\]', term_getline(buf, 5)))
+
+  g:StopVimInTerminal(buf)
+enddef
+
+func Test_debug_running_out_of_lines()
+  CheckRunVimInTerminal
+
+  " call indirectly to avoid compilation error for missing functions
+  call Run_Test_debug_running_out_of_lines()
+endfunc
+
+def Run_Test_debug_running_out_of_lines()
+  var lines =<< trim END
+      vim9script
+      def Crash()
+          #
+          #
+          #
+          #
+          #
+          #
+          #
+          if true
+              #
+          endif
+      enddef
+      breakadd func Crash
+      Crash()
+  END
+  writefile(lines, 'XdebugFunc', 'D')
+  var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0})
+  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
+
+  term_sendkeys(buf, "next\<CR>")
+  g:TermWait(buf)
+  g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6)))
+
+  term_sendkeys(buf, "cont\<CR>")
+  g:TermWait(buf)
+
+  g:StopVimInTerminal(buf)
+enddef
+
+def Test_ambiguous_command_error()
+  var lines =<< trim END
+      vim9script
+      command CmdA echomsg 'CmdA'
+      command CmdB echomsg 'CmdB'
+      Cmd
+  END
+  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 4)
+
+  lines =<< trim END
+      vim9script
+      def Func()
+        Cmd
+      enddef
+      Func()
+  END
+  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 1)
+
+  lines =<< trim END
+      vim9script
+      nnoremap <F3> <ScriptCmd>Cmd<CR>
+      feedkeys("\<F3>", 'xt')
+  END
+  v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 3)
+
+  delcommand CmdA
+  delcommand CmdB
+  nunmap <F3>
+enddef
+
+" Execute this near the end, profiling doesn't stop until Vim exits.
+" This only tests that it works, not the profiling output.
+def Test_profile_with_lambda()
+  CheckFeature profile
+
+  var lines =<< trim END
+      vim9script
+
+      def ProfiledWithLambda()
+        var n = 3
+        echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
+      enddef
+
+      def ProfiledNested()
+        var x = 0
+        def Nested(): any
+            return x
+        enddef
+        Nested()
+      enddef
+
+      def g:ProfiledNestedProfiled()
+        var x = 0
+        def Nested(): any
+            return x
+        enddef
+        Nested()
+      enddef
+
+      def Profile()
+        ProfiledWithLambda()
+        ProfiledNested()
+
+        # Also profile the nested function.  Use a different function, although
+        # the contents is the same, to make sure it was not already compiled.
+        profile func *
+        g:ProfiledNestedProfiled()
+
+        profdel func *
+        profile pause
+      enddef
+
+      var result = 'done'
+      try
+        # mark functions for profiling now to avoid E1271
+        profile start Xprofile.log
+        profile func ProfiledWithLambda
+        profile func ProfiledNested
+
+        Profile()
+      catch
+        result = 'failed: ' .. v:exception
+      finally
+        writefile([result], 'Xdidprofile')
+      endtry
+  END
+  writefile(lines, 'Xprofile.vim', 'D')
+  call system(g:GetVimCommand()
+        .. ' --clean'
+        .. ' -c "so Xprofile.vim"'
+        .. ' -c "qall!"')
+  call assert_equal(0, v:shell_error)
+
+  assert_equal(['done'], readfile('Xdidprofile'))
+  assert_true(filereadable('Xprofile.log'))
+  delete('Xdidprofile')
+  delete('Xprofile.log')
+enddef
+
+func Test_misplaced_type()
+  CheckRunVimInTerminal
+  call Run_Test_misplaced_type()
+endfunc
+
+def Run_Test_misplaced_type()
+  writefile(['let g:somevar = "asdf"'], 'XTest_misplaced_type', 'D')
+  var buf = g:RunVimInTerminal('-S XTest_misplaced_type', {'rows': 6})
+  term_sendkeys(buf, ":vim9cmd echo islocked('somevar: string')\<CR>")
+  g:VerifyScreenDump(buf, 'Test_misplaced_type', {})
+
+  g:StopVimInTerminal(buf)
+enddef
+
+" Ensure echo doesn't crash when stringifying empty variables.
+def Test_echo_uninit_variables()
+  var res: string
+
+  var var_bool: bool
+  var var_num: number
+  var var_float: float
+  var Var_func: func
+  var var_string: string
+  var var_blob: blob
+  var var_list: list<any>
+  var var_dict: dict<any>
+
+  redir => res
+  echo var_bool
+  echo var_num
+  echo var_float
+  echo Var_func
+  echo var_string
+  echo var_blob
+  echo var_list
+  echo var_dict
+  redir END
+
+  assert_equal(['false', '0', '0.0', 'function()', '', '0z', '[]', '{}'], res->split('\n'))
+
+  if has('job')
+    var var_job: job
+    var var_channel: channel
+
+    redir => res
+    echo var_job
+    echo var_channel
+    redir END
+
+    assert_equal(['no process', 'channel fail'], res->split('\n'))
+  endif
+enddef
+
+def Test_free_type_before_use()
+  # this rather complicated script was freeing a type before using it
+  var lines =<< trim END
+      vim9script
+
+      def Scan(rel: list<dict<any>>): func(func(dict<any>))
+        return (Emit: func(dict<any>)) => {
+          for t in rel
+            Emit(t)
+          endfor
+        }
+      enddef
+
+      def Build(Cont: func(func(dict<any>))): list<dict<any>>
+        var rel: list<dict<any>> = []
+        Cont((t) => {
+            add(rel, t)
+        })
+        return rel
+      enddef
+
+      var R = [{A: 0}]
+      var result = Scan(R)->Build()
+      result = Scan(R)->Build()
+
+      assert_equal(R, result)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+" Keep this last, it messes up highlighting.
+def Test_substitute_cmd()
+  new
+  setline(1, 'something')
+  :substitute(some(other(
+  assert_equal('otherthing', getline(1))
+  bwipe!
+
+  # also when the context is Vim9 script
+  var lines =<< trim END
+    vim9script
+    new
+    setline(1, 'something')
+    :substitute(some(other(
+    assert_equal('otherthing', getline(1))
+    bwipe!
+  END
+  writefile(lines, 'Xvim9lines', 'D')
+  source Xvim9lines
+enddef
+
+" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker