]> granicus.if.org Git - vim/commitdiff
patch 8.2.4698: Vim9: script variable has no flag that it was set v8.2.4698
authorBram Moolenaar <Bram@vim.org>
Tue, 5 Apr 2022 20:40:38 +0000 (21:40 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 5 Apr 2022 20:40:38 +0000 (21:40 +0100)
Problem:    Vim9: script variable has no flag that it was set.
Solution:   Add a flag that it was set, to avoid giving it a value when used.
            (closes #10088)

src/evalvars.c
src/structs.h
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_builtin.vim
src/version.c
src/vim9execute.c
src/vim9script.c

index c1ec5b0bab578a64b30b5eb11dad0ad42288fa41..0ee4b08d5cebd5d8a583b3c897efae6c84777f25 100644 (file)
@@ -2828,13 +2828,18 @@ eval_variable(
        }
        else if (rettv != NULL)
        {
+           svar_T  *sv = NULL;
+           int     was_assigned = FALSE;
+
            if (ht != NULL && ht == get_script_local_ht()
                    && tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
            {
-               svar_T *sv = find_typval_in_script(tv, 0, TRUE);
-
+               sv = find_typval_in_script(tv, 0, TRUE);
                if (sv != NULL)
+               {
                    type = sv->sv_type;
+                   was_assigned = sv->sv_flags & SVFLAG_ASSIGNED;
+               }
            }
 
            // If a list or dict variable wasn't initialized and has meaningful
@@ -2843,7 +2848,7 @@ eval_variable(
            if (ht != &globvarht)
            {
                if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
-                         && ((type != NULL && type != &t_dict_empty)
+                                           && ((type != NULL && !was_assigned)
                                                          || !in_vim9script()))
                {
                    tv->vval.v_dict = dict_alloc();
@@ -2851,10 +2856,12 @@ eval_variable(
                    {
                        ++tv->vval.v_dict->dv_refcount;
                        tv->vval.v_dict->dv_type = alloc_type(type);
+                       if (sv != NULL)
+                           sv->sv_flags |= SVFLAG_ASSIGNED;
                    }
                }
                else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL
-                                   && ((type != NULL && type != &t_list_empty)
+                                           && ((type != NULL && !was_assigned)
                                                          || !in_vim9script()))
                {
                    tv->vval.v_list = list_alloc();
@@ -2862,15 +2869,21 @@ eval_variable(
                    {
                        ++tv->vval.v_list->lv_refcount;
                        tv->vval.v_list->lv_type = alloc_type(type);
+                       if (sv != NULL)
+                           sv->sv_flags |= SVFLAG_ASSIGNED;
                    }
                }
                else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
-                                   && ((type != NULL && type != &t_blob_null)
+                                           && ((type != NULL && !was_assigned)
                                                          || !in_vim9script()))
                {
                    tv->vval.v_blob = blob_alloc();
                    if (tv->vval.v_blob != NULL)
+                   {
                        ++tv->vval.v_blob->bv_refcount;
+                       if (sv != NULL)
+                           sv->sv_flags |= SVFLAG_ASSIGNED;
+                   }
                }
            }
            copy_tv(tv, rettv);
@@ -3587,6 +3600,7 @@ set_var_const(
                        goto failed;
                    if (type == NULL)
                        type = sv->sv_type;
+                   sv->sv_flags |= SVFLAG_ASSIGNED;
                }
            }
 
index 9f1e11d6600f28be46ca95f4d6e8a939c9fa3899..5a76a599da4e112f4025cae8829279054ff548fa 100644 (file)
@@ -1807,6 +1807,10 @@ struct sallvar_S {
 #define HIKEY2SAV(p)  ((sallvar_T *)(p - offsetof(sallvar_T, sav_key)))
 #define HI2SAV(hi)     HIKEY2SAV((hi)->hi_key)
 
+#define SVFLAG_TYPE_ALLOCATED  1  // call free_type() for "sv_type"
+#define SVFLAG_EXPORTED                2  // "export let var = val"
+#define SVFLAG_ASSIGNED                4  // assigned a value
+
 /*
  * Entry for "sn_var_vals".  Used for script-local variables.
  */
@@ -1814,9 +1818,8 @@ struct svar_S {
     char_u     *sv_name;       // points into "sn_all_vars" di_key
     typval_T   *sv_tv;         // points into "sn_vars" or "sn_all_vars" di_tv
     type_T     *sv_type;
-    int                sv_type_allocated;  // call free_type() for sv_type
+    int                sv_flags;       // SVFLAG_ values above
     int                sv_const;       // 0, ASSIGN_CONST or ASSIGN_FINAL
-    int                sv_export;      // "export let var = val"
 };
 
 typedef struct {
index 57d205ceef3bddf1b9896b1b54c28c14c0a81e02..7e382c22b2c63afbab3469d069d5d07050ca27b7 100644 (file)
@@ -740,6 +740,7 @@ def Test_init_in_for_loop()
 enddef
 
 def Test_extend_list()
+  # using uninitilaized list assigns empty list
   var lines =<< trim END
       var l1: list<number>
       var l2 = l1
@@ -757,7 +758,7 @@ def Test_extend_list()
   END
   v9.CheckDefAndScriptSuccess(lines)
 
-  # appending to NULL list from a function
+  # appending to uninitialzed list from a function works
   lines =<< trim END
       vim9script
       var list: list<string>
@@ -779,13 +780,30 @@ def Test_extend_list()
   END
   v9.CheckScriptSuccess(lines)
 
+  # initialized to null, with type, does not default to empty list
   lines =<< trim END
       vim9script
       var l: list<string> = test_null_list()
       extend(l, ['x'])
-      assert_equal(['x'], l)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckScriptFailure(lines, 'E1134:', 3)
+
+  # initialized to null, without type, does not default to empty list
+  lines =<< trim END
+      vim9script
+      var l = null_list
+      extend(l, ['x'])
+  END
+  v9.CheckScriptFailure(lines, 'E1134:', 3)
+
+  # assigned null, does not default to empty list
+  lines =<< trim END
+      vim9script
+      var l: list<string>
+      l = null_list
+      extend(l, ['x'])
+  END
+  v9.CheckScriptFailure(lines, 'E1134:', 4)
 
   lines =<< trim END
       vim9script
@@ -838,9 +856,8 @@ def Test_extend_dict()
       vim9script
       var d: dict<string> = test_null_dict()
       extend(d, {a: 'x'})
-      assert_equal({a: 'x'}, d)
   END
-  v9.CheckScriptSuccess(lines)
+  v9.CheckScriptFailure(lines, 'E1133:', 3)
 
   lines =<< trim END
       vim9script
index b20ff144ca087fbe7c4a56e1bafccc5f6f0dbf18..9e60666d3dc3ed78ccb37cffafb83eb317284740 100644 (file)
@@ -153,14 +153,22 @@ def Test_add_list()
   END
   v9.CheckDefExecFailure(lines, 'E1130:', 2)
 
-  # Getting variable with NULL list allocates a new list at script level
+  # Getting an uninitialized variable allocates a new list at script level
   lines =<< trim END
       vim9script
-      var l: list<number> = test_null_list()
+      var l: list<number>
       add(l, 123)
   END
   v9.CheckScriptSuccess(lines)
 
+  # Adding to a variable set to a NULL list fails
+  lines =<< trim END
+      vim9script
+      var l: list<number> = test_null_list()
+      add(l, 123)
+  END
+  v9.CheckScriptFailure(lines, 'E1130:', 3)
+
   lines =<< trim END
       vim9script
       var l: list<string> = ['a']
index 9e1b5c7ef748e408df03809333c1b2e0369fd5de..23b2a1e2bcec19343ed9a9f5ea096cd9fdbf0a14 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4698,
 /**/
     4697,
 /**/
index 99135eadd25aff858933ecc6dcf6f54cc43abed5..0e8a1dd951a2b0c2384bc47a5f0de5b168c1fe59 100644 (file)
@@ -1514,7 +1514,8 @@ get_script_svar(scriptref_T *sref, int dfunc_idx)
        return NULL;
     }
 
-    if (!sv->sv_export && sref->sref_sid != current_sctx.sc_sid)
+    if ((sv->sv_flags & SVFLAG_EXPORTED) == 0
+                                     && sref->sref_sid != current_sctx.sc_sid)
     {
        if (dfunc != NULL)
            semsg(_(e_item_not_exported_in_script_str), sv->sv_name);
@@ -2952,7 +2953,7 @@ exec_instructions(ectx_T *ectx)
                            {
                                sv = ((svar_T *)SCRIPT_ITEM(sid)
                                                  ->sn_var_vals.ga_data) + idx;
-                               if (!sv->sv_export)
+                               if ((sv->sv_flags & SVFLAG_EXPORTED) == 0)
                                {
                                    SOURCING_LNUM = iptr->isn_lnum;
                                    semsg(_(e_item_not_exported_in_script_str),
@@ -3117,7 +3118,7 @@ exec_instructions(ectx_T *ectx)
                                svar_T  *sv = ((svar_T *)SCRIPT_ITEM(sid)
                                                  ->sn_var_vals.ga_data) + idx;
 
-                               if (!sv->sv_export)
+                               if ((sv->sv_flags & SVFLAG_EXPORTED) == 0)
                                {
                                    semsg(_(e_item_not_exported_in_script_str),
                                                                         name);
index adb01e8b97a0faf085204df00d4d45427b34b1ab..68b83884c03e8579fef993f3ee6cd6d40cac905b 100644 (file)
@@ -334,7 +334,7 @@ free_all_script_vars(scriptitem_T *si)
     {
        svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
 
-       if (sv->sv_type_allocated)
+       if (sv->sv_flags & SVFLAG_TYPE_ALLOCATED)
            free_type(sv->sv_type);
     }
     ga_clear(&si->sn_var_vals);
@@ -721,7 +721,7 @@ find_exported(
     {
        sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
        *ufunc = NULL;
-       if (!sv->sv_export)
+       if ((sv->sv_flags & SVFLAG_EXPORTED) == 0)
        {
            if (verbose)
                semsg(_(e_item_not_exported_in_script_str), name);
@@ -871,7 +871,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
  * with a hashtable) and sn_var_vals (lookup by index).
  * When "create" is TRUE this is a new variable, otherwise find and update an
  * existing variable.
- * "flags" can have ASSIGN_FINAL or ASSIGN_CONST.
+ * "flags" can have ASSIGN_FINAL, ASSIGN_CONST or ASSIGN_INIT.
  * When "*type" is NULL use "tv" for the type and update "*type".  If
  * "do_member" is TRUE also use the member type, otherwise use "any".
  */
@@ -938,7 +938,9 @@ update_vim9_script_var(
            sv->sv_tv = &di->di_tv;
            sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
                                   : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
-           sv->sv_export = is_export;
+           sv->sv_flags = is_export ? SVFLAG_EXPORTED : 0;
+           if ((flags & ASSIGN_INIT) == 0)
+               sv->sv_flags |= SVFLAG_ASSIGNED;
            newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
            ++si->sn_var_vals.ga_len;
            STRCPY(&newsav->sav_key, name);
@@ -970,7 +972,7 @@ update_vim9_script_var(
            // "var b: blob = null_blob" has a different type.
            *type = &t_blob_null;
        }
-       if (sv->sv_type_allocated)
+       if (sv->sv_flags & SVFLAG_TYPE_ALLOCATED)
            free_type(sv->sv_type);
        if (*type != NULL && ((*type)->tt_type == VAR_FUNC
                                           || (*type)->tt_type == VAR_PARTIAL))
@@ -979,12 +981,12 @@ update_vim9_script_var(
            // function is freed, but the script variable may keep the type.
            // Make a copy to avoid using freed memory.
            sv->sv_type = alloc_type(*type);
-           sv->sv_type_allocated = TRUE;
+           sv->sv_flags |= SVFLAG_TYPE_ALLOCATED;
        }
        else
        {
            sv->sv_type = *type;
-           sv->sv_type_allocated = FALSE;
+           sv->sv_flags &= ~SVFLAG_TYPE_ALLOCATED;
        }
     }