Patch 8.2.4642
Problem:    Vim9: in :def function script var cannot be null.
Solution:   Only initialize a script variable when not set to a null value.
            (closes #10034)
Files:      src/vim9execute.c, src/vim9type.c, src/globals.h, src/evalvars.c,
            src/vim.h, src/vim9script.c, src/testdir/test_vim9_expr.vim


*** ../vim-8.2.4641/src/vim9execute.c   2022-03-27 16:29:49.880153368 +0100
--- src/vim9execute.c   2022-03-28 14:19:53.145273413 +0100
***************
*** 1336,1355 ****
   * When the value of "sv" is a null list of dict, allocate it.
   */
      static void
! allocate_if_null(typval_T *tv)
  {
      switch (tv->v_type)
      {
        case VAR_LIST:
!           if (tv->vval.v_list == NULL)
                (void)rettv_list_alloc(tv);
            break;
        case VAR_DICT:
!           if (tv->vval.v_dict == NULL)
                (void)rettv_dict_alloc(tv);
            break;
        case VAR_BLOB:
!           if (tv->vval.v_blob == NULL)
                (void)rettv_blob_alloc(tv);
            break;
        default:
--- 1336,1357 ----
   * When the value of "sv" is a null list of dict, allocate it.
   */
      static void
! allocate_if_null(svar_T *sv)
  {
+     typval_T *tv = sv->sv_tv;
+ 
      switch (tv->v_type)
      {
        case VAR_LIST:
!           if (tv->vval.v_list == NULL && sv->sv_type != &t_list_empty)
                (void)rettv_list_alloc(tv);
            break;
        case VAR_DICT:
!           if (tv->vval.v_dict == NULL && sv->sv_type != &t_dict_empty)
                (void)rettv_dict_alloc(tv);
            break;
        case VAR_BLOB:
!           if (tv->vval.v_blob == NULL && sv->sv_type != &t_blob_null)
                (void)rettv_blob_alloc(tv);
            break;
        default:
***************
*** 2891,2897 ****
                    sv = get_script_svar(sref, ectx->ec_dfunc_idx);
                    if (sv == NULL)
                        goto theend;
!                   allocate_if_null(sv->sv_tv);
                    if (GA_GROW_FAILS(&ectx->ec_stack, 1))
                        goto theend;
                    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
--- 2893,2899 ----
                    sv = get_script_svar(sref, ectx->ec_dfunc_idx);
                    if (sv == NULL)
                        goto theend;
!                   allocate_if_null(sv);
                    if (GA_GROW_FAILS(&ectx->ec_stack, 1))
                        goto theend;
                    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
*** ../vim-8.2.4641/src/vim9type.c      2022-03-12 21:28:18.528257721 +0000
--- src/vim9type.c      2022-03-28 14:15:16.026051733 +0100
***************
*** 337,343 ****
--- 337,347 ----
      if (tv->v_type == VAR_STRING)
        return &t_string;
      if (tv->v_type == VAR_BLOB)
+     {
+       if (tv->vval.v_blob == NULL)
+           return &t_blob_null;
        return &t_blob;
+     }
  
      if (tv->v_type == VAR_LIST)
      {
*** ../vim-8.2.4641/src/globals.h       2022-03-27 20:04:16.025188554 +0100
--- src/globals.h       2022-03-28 14:16:23.977844545 +0100
***************
*** 405,410 ****
--- 405,411 ----
  EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
+ EXTERN type_T t_blob_null INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, &t_void, NULL);
  EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
  EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
  
*** ../vim-8.2.4641/src/evalvars.c      2022-03-27 16:50:58.925557951 +0100
--- src/evalvars.c      2022-03-28 14:59:44.060297207 +0100
***************
*** 2823,2829 ****
            {
                if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
                          && ((type != NULL && type != &t_dict_empty)
!                                                          || !in_vim9script()))
                {
                    tv->vval.v_dict = dict_alloc();
                    if (tv->vval.v_dict != NULL)
--- 2823,2829 ----
            {
                if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
                          && ((type != NULL && type != &t_dict_empty)
!                                                         || !in_vim9script()))
                {
                    tv->vval.v_dict = dict_alloc();
                    if (tv->vval.v_dict != NULL)
***************
*** 2843,2848 ****
--- 2843,2856 ----
                        tv->vval.v_list->lv_type = alloc_type(type);
                    }
                }
+               else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
+                                   && ((type != NULL && type != &t_blob_null)
+                                                         || !in_vim9script()))
+               {
+                   tv->vval.v_blob = blob_alloc();
+                   if (tv->vval.v_blob != NULL)
+                       ++tv->vval.v_blob->bv_refcount;
+               }
            }
            copy_tv(tv, rettv);
        }
*** ../vim-8.2.4641/src/vim.h   2022-03-27 20:04:16.029188564 +0100
--- src/vim.h   2022-03-28 14:59:26.124294565 +0100
***************
*** 2229,2234 ****
--- 2229,2235 ----
  #define ASSIGN_UNPACK 0x10  // using [a, b] = list
  #define ASSIGN_NO_MEMBER_TYPE 0x20 // use "any" for list and dict member type
  #define ASSIGN_FOR_LOOP 0x40 // assigning to loop variable
+ #define ASSIGN_INIT   0x80 // not assigning a value, just a declaration
  
  #include "ex_cmds.h"      // Ex command defines
  #include "spell.h"        // spell checking stuff
*** ../vim-8.2.4641/src/vim9script.c    2022-03-22 12:13:49.147376718 +0000
--- src/vim9script.c    2022-03-28 14:59:55.024298561 +0100
***************
*** 822,828 ****
        init_tv.v_type = VAR_NUMBER;
      else
        init_tv.v_type = type->tt_type;
!     set_var_const(name, 0, type, &init_tv, FALSE, 0, 0);
  
      vim_free(name);
      return p;
--- 822,828 ----
        init_tv.v_type = VAR_NUMBER;
      else
        init_tv.v_type = type->tt_type;
!     set_var_const(name, 0, type, &init_tv, FALSE, ASSIGN_INIT, 0);
  
      vim_free(name);
      return p;
***************
*** 925,930 ****
--- 925,937 ----
        if (*type == NULL)
            *type = typval2type(tv, get_copyID(), &si->sn_type_list,
                                               do_member ? TVTT_DO_MEMBER : 0);
+       else if ((flags & ASSIGN_INIT) == 0
+               && (*type)->tt_type == VAR_BLOB && tv->v_type == VAR_BLOB
+                                                   && tv->vval.v_blob == NULL)
+       {
+           // "var b: blob = null_blob" has a different type.
+           *type = &t_blob_null;
+       }
        if (sv->sv_type_allocated)
            free_type(sv->sv_type);
        if (*type != NULL && ((*type)->tt_type == VAR_FUNC
*** ../vim-8.2.4641/src/testdir/test_vim9_expr.vim      2022-03-27 
16:29:49.880153368 +0100
--- src/testdir/test_vim9_expr.vim      2022-03-28 14:20:34.405170440 +0100
***************
*** 890,895 ****
--- 890,982 ----
    unlet g:null_dict
    unlet g:not_null_list
  
+   # variables declared at script level used in a :def function
+   lines =<< trim END
+       vim9script
+       
+       var l_decl: list<number>
+       var l_empty = []
+       var l_null = null_list
+ 
+       def TestList()
+         assert_false(l_decl == null)
+         assert_false(l_decl is null_list)
+         assert_false(l_empty == null)
+         assert_false(l_empty is null_list)
+         assert_true(l_null == null)
+         assert_true(l_null is null_list)
+         assert_true(l_null == null_list)
+ 
+         add(l_decl, 6)
+         assert_equal([6], l_decl)
+         add(l_empty, 7)
+         assert_equal([7], l_empty)
+         var caught = false
+         try
+           add(l_null, 9)
+         catch /E1130:/
+           caught = true
+         endtry
+         assert_true(caught)
+       enddef
+       TestList()
+       
+       var b_decl: blob
+       var b_empty = 0z
+       var b_null = null_blob
+ 
+       def TestBlob()
+         assert_false(b_decl == null)
+         assert_false(b_decl is null_blob)
+         assert_false(b_empty == null)
+         assert_false(b_empty is null_blob)
+         assert_true(b_null == null)
+         assert_true(b_null is null_blob)
+         assert_true(b_null == null_blob)
+ 
+         add(b_decl, 6)
+         assert_equal(0z06, b_decl)
+         add(b_empty, 7)
+         assert_equal(0z07, b_empty)
+         var caught = false
+         try
+           add(b_null, 9)
+         catch /E1131:/
+           caught = true
+         endtry
+         assert_true(caught)
+       enddef
+       TestBlob()
+       
+       var d_decl: dict<number>
+       var d_empty = {}
+       var d_null = null_dict
+ 
+       def TestDict()
+         assert_false(d_decl == null)
+         assert_false(d_decl is null_dict)
+         assert_false(d_empty == null)
+         assert_false(d_empty is null_dict)
+         assert_true(d_null == null)
+         assert_true(d_null is null_dict)
+         assert_true(d_null == null_dict)
+ 
+         d_decl['a'] = 6
+         assert_equal({a: 6}, d_decl)
+         d_empty['b'] = 7
+         assert_equal({b: 7}, d_empty)
+         var caught = false
+         try
+           d_null['c'] = 9
+         catch /E1103:/
+           caught = true
+         endtry
+         assert_true(caught)
+       enddef
+       TestDict()
+   END
+   v9.CheckScriptSuccess(lines)
+ 
    lines =<< trim END
        var d: dict<func> = {f: null_function}
        assert_equal(null_function, d.f)
*** ../vim-8.2.4641/src/version.c       2022-03-28 12:41:14.406200360 +0100
--- src/version.c       2022-03-28 15:21:26.974698823 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4642,
  /**/

-- 
5 out of 4 people have trouble with fractions.

 /// 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/20220328142307.24BDA1C0C1F%40moolenaar.net.

Raspunde prin e-mail lui