Patch 8.2.4526
Problem:    Vim9: cannot set variables to a null value.
Solution:   Add null_list, null_job, etc.
Files:      runtime/doc/vim9.txt, src/eval.c, src/proto/eval.pro,
            src/vim9expr.c, src/vim9script.c, src/vim9instr.c,
            src/vim9compile.c, src/vim9execute.c, src/vim9.h, src/vim9type.c,
            src/evalvars.c, src/testdir/test_vim9_assign.vim,
            src/testdir/test_vim9_disassemble.vim,
            src/testdir/test_vim9_func.vim, src/testdir/test_expr.vim


*** ../vim-8.2.4525/runtime/doc/vim9.txt        2022-02-22 20:42:50.382992530 
+0000
--- runtime/doc/vim9.txt        2022-03-07 21:26:34.420871466 +0000
***************
*** 94,101 ****
        def CallMe(count: number, message: string): bool
  - Call functions without `:call`: >
        writefile(['done'], 'file.txt')
! - You cannot use old Ex commands `:xit`, `:t`, `:k`, `:append`, `:change`,
!   `:insert`, `:open`, and `:s` or `:d` with only flags.
  - You cannot use curly-braces names.
  - A range before a command must be prefixed with a colon: >
        :%s/this/that
--- 94,113 ----
        def CallMe(count: number, message: string): bool
  - Call functions without `:call`: >
        writefile(['done'], 'file.txt')
! - You cannot use old Ex commands:
!       `:Print`
!       `:append`
!       `:change`
!       `:d`  directly followed by 'd' or 'p'.
!       `:insert`
!       `:k`
!       `:mode`
!       `:open`
!       `:s`  with only flags
!       `:t`
!       `:xit`
! - Some commands, especially those used for flow control, cannot be shortened.
!   E.g., `:throw` cannot be written as `:th`. *E839*
  - You cannot use curly-braces names.
  - A range before a command must be prefixed with a colon: >
        :%s/this/that
***************
*** 923,933 ****
  
  Simple types are Number, Float, Special and Bool.  For other types |string()|
  should be used.
!                                                       *false* *true* *null*
! In Vim9 script one can use "true" for v:true, "false" for v:false and "null"
! for v:null.  When converting a boolean to a string "false" and "true" are
! used, not "v:false" and "v:true" like in legacy script.  "v:none" is not
! changed, it is only used in JSON and has no equivalent in other languages.
  
  Indexing a string with [idx] or taking a slice with [idx : idx] uses character
  indexes instead of byte indexes.  Composing characters are included.
--- 966,1003 ----
  
  Simple types are Number, Float, Special and Bool.  For other types |string()|
  should be used.
!                                               *false* *true* *null* *E1034*
! In Vim9 script one can use the following predefined values: >
!       true
!       false
!       null
!       null_blob
!       null_channel
!       null_dict
!       null_function
!       null_job
!       null_list
!       null_partial
!       null_string
! `true` is the same as `v:true`, `false` the same as `v:false`, `null` the same
! as `v:null`.
! 
! While `null` has the type "special", the other "null_" types have the type
! indicated by their name.  Quite often a null value is handled the same as an
! empty value, but not always.  The values can be useful to clear a script-local
! variable, since they cannot be deleted with `:unlet`.  E.g.: >
!       var theJob = job_start(...)
!       # let the job do its work
!       theJob = null_job
! 
! The values can also be useful as the default value for an argument: >
!       def MyFunc(b: blob = null_blob)
!          if b == null_blob
!             # b argument was not given
! 
! When converting a boolean to a string `false` and `true` are used, not
! `v:false` and `v:true` like in legacy script.  `v:none` has no `none`
! replacement, it has no equivalent in other languages.
  
  Indexing a string with [idx] or taking a slice with [idx : idx] uses character
  indexes instead of byte indexes.  Composing characters are included.
*** ../vim-8.2.4525/src/eval.c  2022-02-13 21:51:02.392484124 +0000
--- src/eval.c  2022-03-07 21:40:00.798772322 +0000
***************
*** 943,948 ****
--- 943,949 ----
                    type_list = &SCRIPT_ITEM(current_sctx.sc_sid)->sn_type_list;
                else
                {
+                   // TODO: should we give an error here?
                    type_list = &tmp_type_list;
                    ga_init2(type_list, sizeof(type_T), 10);
                }
***************
*** 3483,3488 ****
--- 3484,3583 ----
  }
  
  /*
+  * Check for a predefined value "true", "false" and "null.*".
+  * Return OK when recognized.
+  */
+     int
+ handle_predefined(char_u *s, int len, typval_T *rettv)
+ {
+     switch (len)
+     {
+       case 4: if (STRNCMP(s, "true", 4) == 0)
+               {
+                   rettv->v_type = VAR_BOOL;
+                   rettv->vval.v_number = VVAL_TRUE;
+                   return OK;
+               }
+               if (STRNCMP(s, "null", 4) == 0)
+               {
+                   rettv->v_type = VAR_SPECIAL;
+                   rettv->vval.v_number = VVAL_NULL;
+                   return OK;
+               }
+               break;
+       case 5: if (STRNCMP(s, "false", 5) == 0)
+               {
+                   rettv->v_type = VAR_BOOL;
+                   rettv->vval.v_number = VVAL_FALSE;
+                   return OK;
+               }
+               break;
+ #ifdef FEAT_JOB_CHANNEL
+       case 8: if (STRNCMP(s, "null_job", 8) == 0)
+               {
+                   rettv->v_type = VAR_JOB;
+                   rettv->vval.v_job = NULL;
+                   return OK;
+               }
+               break;
+ #endif
+       case 9:
+               if (STRNCMP(s, "null_", 5) != 0)
+                   break;
+               if (STRNCMP(s + 5, "list", 4) == 0)
+               {
+                   rettv->v_type = VAR_LIST;
+                   rettv->vval.v_list = NULL;
+                   return OK;
+               }
+               if (STRNCMP(s + 5, "dict", 4) == 0)
+               {
+                   rettv->v_type = VAR_DICT;
+                   rettv->vval.v_dict = NULL;
+                   return OK;
+               }
+               if (STRNCMP(s + 5, "blob", 4) == 0)
+               {
+                   rettv->v_type = VAR_BLOB;
+                   rettv->vval.v_blob = NULL;
+                   return OK;
+               }
+               break;
+       case 11: if (STRNCMP(s, "null_string", 11) == 0)
+               {
+                   rettv->v_type = VAR_STRING;
+                   rettv->vval.v_string = NULL;
+                   return OK;
+               }
+               break;
+       case 12:
+ #ifdef FEAT_JOB_CHANNEL
+               if (STRNCMP(s, "null_channel", 12) == 0)
+               {
+                   rettv->v_type = VAR_CHANNEL;
+                   rettv->vval.v_channel = NULL;
+                   return OK;
+               }
+ #endif
+               if (STRNCMP(s, "null_partial", 12) == 0)
+               {
+                   rettv->v_type = VAR_PARTIAL;
+                   rettv->vval.v_partial = NULL;
+                   return OK;
+               }
+               break;
+       case 13: if (STRNCMP(s, "null_function", 13) == 0)
+               {
+                   rettv->v_type = VAR_FUNC;
+                   rettv->vval.v_string = NULL;
+                   return OK;
+               }
+               break;
+     }
+     return FAIL;
+ }
+ 
+ /*
   * Handle sixth level expression:
   *  number            number constant
   *  0zFFFFFFFF                Blob constant
***************
*** 3757,3782 ****
                ret = FAIL;
            else if (evaluate)
            {
!               // get the value of "true", "false" or a variable
!               if (len == 4 && vim9script && STRNCMP(s, "true", 4) == 0)
!               {
!                   rettv->v_type = VAR_BOOL;
!                   rettv->vval.v_number = VVAL_TRUE;
!                   ret = OK;
!               }
!               else if (len == 5 && vim9script && STRNCMP(s, "false", 5) == 0)
!               {
!                   rettv->v_type = VAR_BOOL;
!                   rettv->vval.v_number = VVAL_FALSE;
!                   ret = OK;
!               }
!               else if (len == 4 && vim9script && STRNCMP(s, "null", 4) == 0)
!               {
!                   rettv->v_type = VAR_SPECIAL;
!                   rettv->vval.v_number = VVAL_NULL;
!                   ret = OK;
!               }
!               else
                {
                    name_start = s;
                    ret = eval_variable(s, len, 0, rettv, NULL,
--- 3852,3862 ----
                ret = FAIL;
            else if (evaluate)
            {
!               // get the value of "true", "false", etc. or a variable
!               ret = FAIL;
!               if (vim9script)
!                   ret = handle_predefined(s, len, rettv);
!               if (ret == FAIL)
                {
                    name_start = s;
                    ret = eval_variable(s, len, 0, rettv, NULL,
*** ../vim-8.2.4525/src/proto/eval.pro  2022-02-02 20:01:21.957210955 +0000
--- src/proto/eval.pro  2022-03-07 21:40:03.670777363 +0000
***************
*** 42,47 ****
--- 42,48 ----
  void eval_addblob(typval_T *tv1, typval_T *tv2);
  int eval_addlist(typval_T *tv1, typval_T *tv2);
  int eval_leader(char_u **arg, int vim9);
+ int handle_predefined(char_u *s, int len, typval_T *rettv);
  int check_can_index(typval_T *rettv, int evaluate, int verbose);
  void f_slice(typval_T *argvars, typval_T *rettv);
  int eval_index_inner(typval_T *rettv, int is_range, typval_T *var1, typval_T 
*var2, int exclusive, char_u *key, int keylen, int verbose);
*** ../vim-8.2.4525/src/vim9expr.c      2022-02-22 20:42:50.382992530 +0000
--- src/vim9expr.c      2022-03-07 21:40:10.746789629 +0000
***************
*** 2107,2120 ****
                    break;
  
        /*
!        * "null" constant
         */
!       case 'n':   if (STRNCMP(*arg, "null", 4) == 0
!                                                  && !eval_isnamec((*arg)[4]))
                    {
!                       *arg += 4;
!                       rettv->v_type = VAR_SPECIAL;
!                       rettv->vval.v_number = VVAL_NULL;
                    }
                    else
                        ret = NOTDONE;
--- 2107,2126 ----
                    break;
  
        /*
!        * "null" or "null_*" constant
         */
!       case 'n':   if (STRNCMP(*arg, "null", 4) == 0)
                    {
!                       char_u  *p = *arg + 4;
!                       int     len;
! 
!                       for (len = 0; eval_isnamec(p[len]); ++len)
!                           ;
!                       ret = handle_predefined(*arg, len + 4, rettv);
!                       if (ret == FAIL)
!                           ret = NOTDONE;
!                       else
!                           *arg += len + 4;
                    }
                    else
                        ret = NOTDONE;
*** ../vim-8.2.4525/src/vim9script.c    2022-02-13 21:51:02.392484124 +0000
--- src/vim9script.c    2022-03-07 21:53:02.483290072 +0000
***************
*** 1062,1067 ****
--- 1062,1075 ----
      "true",
      "false",
      "null",
+     "null_blob",
+     "null_dict",
+     "null_function",
+     "null_list",
+     "null_partial",
+     "null_string",
+     "null_channel",
+     "null_job",
      "this",
      NULL
  };
*** ../vim-8.2.4525/src/vim9instr.c     2022-03-01 19:23:20.540357322 +0000
--- src/vim9instr.c     2022-03-08 11:10:13.799498306 +0000
***************
*** 570,575 ****
--- 570,609 ----
                generate_PUSHBLOB(cctx, tv->vval.v_blob);
                tv->vval.v_blob = NULL;
                break;
+           case VAR_LIST:
+               if (tv->vval.v_list != NULL)
+                   iemsg("non-empty list constant not supported");
+               generate_NEWLIST(cctx, 0);
+               break;
+           case VAR_DICT:
+               if (tv->vval.v_dict != NULL)
+                   iemsg("non-empty dict constant not supported");
+               generate_NEWDICT(cctx, 0);
+               break;
+ #ifdef FEAT_JOB_CHANNEL
+           case VAR_JOB:
+               if (tv->vval.v_job != NULL)
+                   iemsg("non-null job constant not supported");
+               generate_PUSHJOB(cctx, NULL);
+               break;
+           case VAR_CHANNEL:
+               if (tv->vval.v_channel != NULL)
+                   iemsg("non-null channel constant not supported");
+               generate_PUSHCHANNEL(cctx, NULL);
+               break;
+ #endif
+           case VAR_FUNC:
+               if (tv->vval.v_string != NULL)
+                   iemsg("non-null function constant not supported");
+               generate_PUSHFUNC(cctx, NULL, &t_func_unknown);
+               break;
+           case VAR_PARTIAL:
+               if (tv->vval.v_partial != NULL)
+                   iemsg("non-null partial constant not supported");
+               if (generate_instr_type(cctx, ISN_NEWPARTIAL, &t_func_unknown)
+                                                                      == NULL)
+                   return FAIL;
+               break;
            case VAR_STRING:
                generate_PUSHS(cctx, &tv->vval.v_string);
                tv->vval.v_string = NULL;
***************
*** 706,712 ****
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHJOB, &t_channel)) == NULL)
        return FAIL;
      isn->isn_arg.job = job;
  
--- 740,746 ----
      isn_T     *isn;
  
      RETURN_OK_IF_SKIP(cctx);
!     if ((isn = generate_instr_type(cctx, ISN_PUSHJOB, &t_job)) == NULL)
        return FAIL;
      isn->isn_arg.job = job;
  
***************
*** 2185,2190 ****
--- 2219,2225 ----
        case ISN_NEGATENR:
        case ISN_NEWDICT:
        case ISN_NEWLIST:
+       case ISN_NEWPARTIAL:
        case ISN_OPANY:
        case ISN_OPFLOAT:
        case ISN_OPNR:
*** ../vim-8.2.4525/src/vim9compile.c   2022-03-05 12:56:39.912475510 +0000
--- src/vim9compile.c   2022-03-08 11:01:04.560170373 +0000
***************
*** 403,410 ****
      if (ret == OK)
        return OK;
  
      // If the actual type can be the expected type add a runtime check.
-     // If it's a constant a runtime check makes no sense.
      if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected))
      {
        generate_TYPECHECK(cctx, expected, offset, where.wt_index);
--- 403,414 ----
      if (ret == OK)
        return OK;
  
+     // If actual a constant a runtime check makes no sense.  If it's
+     // null_function it is OK.
+     if (actual_is_const && ret == MAYBE && actual == &t_func_unknown)
+       return OK;
+ 
      // If the actual type can be the expected type add a runtime check.
      if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected))
      {
        generate_TYPECHECK(cctx, expected, offset, where.wt_index);
*** ../vim-8.2.4525/src/vim9execute.c   2022-03-01 19:23:20.544357315 +0000
--- src/vim9execute.c   2022-03-07 22:10:11.223852520 +0000
***************
*** 3440,3445 ****
--- 3440,3456 ----
                }
                break;
  
+           // create a partial with NULL value
+           case ISN_NEWPARTIAL:
+               if (GA_GROW_FAILS(&ectx->ec_stack, 1))
+                   goto theend;
+               ++ectx->ec_stack.ga_len;
+               tv = STACK_TV_BOT(-1);
+               tv->v_type = VAR_PARTIAL;
+               tv->v_lock = 0;
+               tv->vval.v_partial = NULL;
+               break;
+ 
            // call a :def function
            case ISN_DCALL:
                SOURCING_LNUM = iptr->isn_lnum;
***************
*** 5720,5725 ****
--- 5731,5739 ----
                smsg("%s%4d NEWDICT size %lld", pfx, current,
                                            
(varnumber_T)(iptr->isn_arg.number));
                break;
+           case ISN_NEWPARTIAL:
+               smsg("%s%4d NEWPARTIAL", pfx, current);
+               break;
  
            // function call
            case ISN_BCALL:
*** ../vim-8.2.4525/src/vim9.h  2022-03-01 19:23:20.544357315 +0000
--- src/vim9.h  2022-03-07 22:12:05.675987992 +0000
***************
*** 91,96 ****
--- 91,97 ----
      ISN_PUSHJOB,      // push channel isn_arg.job
      ISN_NEWLIST,      // push list from stack items, size is isn_arg.number
      ISN_NEWDICT,      // push dict from stack items, size is isn_arg.number
+     ISN_NEWPARTIAL,   // push NULL partial
  
      ISN_AUTOLOAD,     // get item from autoload import, function or variable
  
*** ../vim-8.2.4525/src/vim9type.c      2022-02-21 13:13:44.923693160 +0000
--- src/vim9type.c      2022-03-08 12:25:45.602214326 +0000
***************
*** 567,588 ****
  
      if (expected == NULL)
        return OK;  // didn't expect anything.
  
!     // For some values there is no type, assume an error will be given later
!     // for an invalid value.
      if ((actual_tv->v_type == VAR_FUNC && actual_tv->vval.v_string == NULL)
            || (actual_tv->v_type == VAR_PARTIAL
                                         && actual_tv->vval.v_partial == NULL))
!     {
!       emsg(_(e_function_reference_is_not_set));
!       return FAIL;
!     }
! 
!     ga_init2(&type_list, sizeof(type_T *), 10);
! 
!     // When the actual type is list<any> or dict<any> go through the values to
!     // possibly get a more specific type.
!     actual_type = typval2type(actual_tv, get_copyID(), &type_list,
                                          TVTT_DO_MEMBER | TVTT_MORE_SPECIFIC);
      if (actual_type != NULL)
      {
--- 567,585 ----
  
      if (expected == NULL)
        return OK;  // didn't expect anything.
+                   //
+     ga_init2(&type_list, sizeof(type_T *), 10);
  
!     // A null_function and null_partial are special cases, they can be used to
!     // clear a variable.
      if ((actual_tv->v_type == VAR_FUNC && actual_tv->vval.v_string == NULL)
            || (actual_tv->v_type == VAR_PARTIAL
                                         && actual_tv->vval.v_partial == NULL))
!       actual_type = &t_func_unknown;
!     else
!       // When the actual type is list<any> or dict<any> go through the values
!       // to possibly get a more specific type.
!       actual_type = typval2type(actual_tv, get_copyID(), &type_list,
                                          TVTT_DO_MEMBER | TVTT_MORE_SPECIFIC);
      if (actual_type != NULL)
      {
*** ../vim-8.2.4525/src/evalvars.c      2022-03-05 12:56:39.912475510 +0000
--- src/evalvars.c      2022-03-08 12:35:36.801291216 +0000
***************
*** 999,1004 ****
--- 999,1009 ----
      listitem_T        *item;
      typval_T  ltv;
  
+     if (tv->v_type == VAR_VOID)
+     {
+       emsg(_(e_cannot_use_void_value));
+       return FAIL;
+     }
      if (*arg != '[')
      {
        // ":let var = expr" or ":for var in list"
*** ../vim-8.2.4525/src/testdir/test_vim9_assign.vim    2022-03-05 
11:37:43.048924316 +0000
--- src/testdir/test_vim9_assign.vim    2022-03-07 22:12:34.436017099 +0000
***************
*** 306,317 ****
  enddef
  
  def Test_reserved_name()
!   for name in ['true', 'false', 'null']
      v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' =  0'], 'E1034:')
      v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:')
    endfor
  enddef
  
  def Test_skipped_assignment()
    var lines =<< trim END
        for x in []
--- 306,349 ----
  enddef
  
  def Test_reserved_name()
!   var more_names = ['null_job', 'null_channel']
!   if !has('job')
!     more_names = []
!   endif
! 
!   for name in ['true',
!                'false',
!                'null',
!                'null_blob',
!                'null_dict',
!                'null_function',
!                'null_list',
!                'null_partial',
!                'null_string',
!                ] + more_names
      v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' =  0'], 'E1034:')
      v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:')
    endfor
  enddef
  
+ def Test_null_values()
+   var lines =<< trim END
+       var b: blob = null_blob
+       var dn: dict<number> = null_dict
+       var ds: dict<string> = null_dict
+       var ln: list<number> = null_list
+       var ls: list<string> = null_list
+       var Ff: func(string): string = null_function
+       var Fp: func(number): number = null_partial
+       var s: string = null_string
+       if has('job')
+         var j: job = null_job
+         var c: channel = null_channel
+       endif
+   END
+   v9.CheckDefAndScriptSuccess(lines)
+ enddef
+ 
  def Test_skipped_assignment()
    var lines =<< trim END
        for x in []
*** ../vim-8.2.4525/src/testdir/test_vim9_disassemble.vim       2022-03-01 
19:23:20.544357315 +0000
--- src/testdir/test_vim9_disassemble.vim       2022-03-08 11:24:09.458948621 
+0000
***************
*** 415,420 ****
--- 415,472 ----
          res)
  enddef
  
+ if has('job')
+   def s:StoreNull()
+     var ss = null_string
+     var bb = null_blob
+     var dd = null_dict
+     var ll = null_list
+     var Ff = null_function
+     var Pp = null_partial
+     var jj = null_job
+     var cc = null_channel
+   enddef
+ 
+   def Test_disassemble_assign_null()
+     var res = execute('disass s:StoreNull')
+     assert_match('<SNR>\d*_StoreNull\_s*' ..
+           'var ss = null_string\_s*' ..
+           '\d\+ PUSHS "\[NULL\]"\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var bb = null_blob\_s*' ..
+           '\d\+ PUSHBLOB 0z\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var dd = null_dict\_s*' ..
+           '\d\+ NEWDICT size 0\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var ll = null_list\_s*' ..
+           '\d\+ NEWLIST size 0\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var Ff = null_function\_s*' ..
+           '\d\+ PUSHFUNC "\[none\]"\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var Pp = null_partial\_s*' ..
+           '\d\+ NEWPARTIAL\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var jj = null_job\_s*' ..
+           '\d\+ PUSHJOB "no process"\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           'var cc = null_channel\_s*' ..
+           '\d\+ PUSHCHANNEL 0\_s*' ..
+           '\d\+ STORE $\d\_s*' ..
+ 
+           '\d\+ RETURN void',
+           res)
+   enddef
+ endif
+ 
  def s:ScriptFuncStoreIndex()
    var d = {dd: {}}
    d.dd[0] = 0
*** ../vim-8.2.4525/src/testdir/test_vim9_func.vim      2022-02-28 
20:54:58.129239044 +0000
--- src/testdir/test_vim9_func.vim      2022-03-08 12:36:14.337235053 +0000
***************
*** 3326,3332 ****
        var Expr: func(dict<any>): dict<any>
        const Call = Foo(Expr)
    END
!   v9.CheckScriptFailure(lines, 'E1235:')
  enddef
  
  def Test_partial_double_nested()
--- 3326,3332 ----
        var Expr: func(dict<any>): dict<any>
        const Call = Foo(Expr)
    END
!   v9.CheckScriptFailure(lines, 'E1031:')
  enddef
  
  def Test_partial_double_nested()
*** ../vim-8.2.4525/src/testdir/test_expr.vim   2022-02-26 11:46:09.510212631 
+0000
--- src/testdir/test_expr.vim   2022-03-08 13:12:08.461599684 +0000
***************
*** 157,168 ****
  
  func Test_loop_over_null_list()
    let lines =<< trim END
!       VAR null_list = test_null_list()
!       for i in null_list
          call assert_report('should not get here')
        endfor
    END
    call v9.CheckLegacyAndVim9Success(lines)
  endfunc
  
  func Test_setreg_null_list()
--- 157,184 ----
  
  func Test_loop_over_null_list()
    let lines =<< trim END
!       VAR nulllist = test_null_list()
!       for i in nulllist
          call assert_report('should not get here')
        endfor
    END
    call v9.CheckLegacyAndVim9Success(lines)
+ 
+   let lines =<< trim END
+       var nulllist = null_list
+       for i in nulllist
+         call assert_report('should not get here')
+       endfor
+   END
+   call v9.CheckDefAndScriptSuccess(lines)
+ 
+   let lines =<< trim END
+       let nulllist = null_list
+       for i in nulllist
+         call assert_report('should not get here')
+       endfor
+   END
+   call v9.CheckScriptFailure(lines, 'E121: Undefined variable: null_list')
  endfunc
  
  func Test_setreg_null_list()
*** ../vim-8.2.4525/src/version.c       2022-03-07 16:57:18.335101482 +0000
--- src/version.c       2022-03-08 12:26:16.074164231 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4526,
  /**/

-- 
Some of the well known MS-Windows errors:
        ETIME           Wrong time, wait a little while
        ECRASH          Try again...
        EDETECT         Unable to detect errors
        EOVER           You lost!  Play another game?
        ENOCLUE         Eh, what did you want?

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220308132013.BD51A1C02B3%40moolenaar.net.

Raspunde prin e-mail lui