]> granicus.if.org Git - vim/commitdiff
patch 9.0.0627: "const" and "final" both make the type a constant v9.0.0627
authorBram Moolenaar <Bram@vim.org>
Fri, 30 Sep 2022 10:04:50 +0000 (11:04 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 30 Sep 2022 10:04:50 +0000 (11:04 +0100)
Problem:    "const" and "final" both make the type a constant. (Daniel
            Steinberg)
Solution:   Only have "const" make the type a constant.

src/testdir/test_vim9_builtin.vim
src/version.c
src/vim.h
src/vim9.h
src/vim9cmds.c
src/vim9compile.c

index 4ebf65a1de7995fe44814810d29251d11d221d4a..151ffedbfe2e471929a91cf569a122c3e7cc6480 100644 (file)
@@ -191,6 +191,13 @@ def Test_add_const()
   END
   v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list<number>')
 
+  lines =<< trim END
+      final l = [1, 2]
+      add(l, 3)
+      assert_equal([1, 2, 3], l)
+  END
+  v9.CheckDefSuccess(lines)
+
   lines =<< trim END
       const b = 0z0102
       add(b,  0z03)
@@ -1209,6 +1216,13 @@ def Test_extend_const()
   END
   v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict<number>')
 
+  lines =<< trim END
+      final d = {a: 1, b: 2}
+      extend(d, {c: 3})
+      assert_equal({a: 1, b: 2, c: 3}, d)
+  END
+  v9.CheckDefSuccess(lines)
+
   # item in a for loop is const
   lines =<< trim END
       var l: list<dict<any>> = [{n: 1}]
index 40dad238d0512121b6dac21b4d894f48b5bad2f1..a2e66b2d4fee352721b0593e0bf0cf056bb83ee0 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    627,
 /**/
     626,
 /**/
index 8f1bf3335b1f35205d3ae15502c59309b18d4d19..14f67f7b24255bcc3947141e02890becdb8f1720 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2250,6 +2250,7 @@ typedef enum {
 } estack_arg_T;
 
 // Flags for assignment functions.
+#define ASSIGN_VAR     0     // ":var" (nothing special)
 #define ASSIGN_FINAL   0x01  // ":final"
 #define ASSIGN_CONST   0x02  // ":const"
 #define ASSIGN_NO_DECL 0x04  // "name = expr" without ":let"/":const"/":final"
index 176fc642a4d4a0d23719720135cdc29c8b9a5aa9..fe193b1d616d4d4397223f73db59710d70fbf1b4 100644 (file)
@@ -697,7 +697,9 @@ typedef struct {
     int                lv_loop_depth;  // depth for variable inside a loop or -1
     int                lv_loop_idx;    // index of first variable inside a loop or -1
     int                lv_from_outer;  // nesting level, using ctx_outer scope
-    int                lv_const;       // when TRUE cannot be assigned to
+    int                lv_const;       // ASSIGN_VAR (can be assigned to),
+                               // ASSIGN_FINAL (no assignment) or ASSIGN_CONST
+                               // (value cannot be changed)
     int                lv_arg;         // when TRUE this is an argument
 } lvar_T;
 
index c9c222c470c471ddbf32043546c9e213bfd881c3..3c561d1ef55ad51b2d599c2611ee7e3e974c20ec 100644 (file)
@@ -881,7 +881,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
 
     // Reserve a variable to store the loop iteration counter and initialize it
     // to -1.
-    loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
+    loop_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
     if (loop_lvar == NULL)
     {
        drop_scope(cctx);
@@ -894,7 +894,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
     // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
     // The variable index is always the loop var index plus one.
     // It is not used when no closures are encountered, we don't know yet.
-    funcref_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
+    funcref_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
     if (funcref_lvar == NULL)
     {
        drop_scope(cctx);
@@ -1050,7 +1050,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
                        && need_type_where(item_type, lhs_type, -1,
                                            where, cctx, FALSE, FALSE) == FAIL)
                    goto failed;
-               var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
+               var_lvar = reserve_local(cctx, arg, varlen, ASSIGN_CONST,
+                                                                    lhs_type);
                if (var_lvar == NULL)
                    // out of memory or used as an argument
                    goto failed;
@@ -1182,7 +1183,7 @@ compile_while(char_u *arg, cctx_T *cctx)
 
     // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
     // It is not used when no closures are encountered, we don't know yet.
-    funcref_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
+    funcref_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
     if (funcref_lvar == NULL)
     {
        drop_scope(cctx);
index 522534597634a9090c20e99eaadaa35a926e3be7..53c8e5a7ff02549f73d49df01dae45ed68939753 100644 (file)
@@ -471,7 +471,7 @@ set_var_type(lvar_T *lvar, type_T *type_arg, cctx_T *cctx)
 {
     type_T     *type = type_arg;
 
-    if (lvar->lv_const && (type->tt_flags & TTFLAG_CONST) == 0)
+    if (lvar->lv_const == ASSIGN_CONST && (type->tt_flags & TTFLAG_CONST) == 0)
     {
        if (type->tt_flags & TTFLAG_STATIC)
            // entry in static_types[] is followed by const type
@@ -487,6 +487,8 @@ set_var_type(lvar_T *lvar, type_T *type_arg, cctx_T *cctx)
 
 /*
  * Reserve space for a local variable.
+ * "assign" can be ASSIGN_VAR for :var, ASSIGN_CONST for :const and
+ * ASSIGN_FINAL for :final.
  * Return the variable or NULL if it failed.
  */
     lvar_T *
@@ -494,7 +496,7 @@ reserve_local(
        cctx_T  *cctx,
        char_u  *name,
        size_t  len,
-       int     isConst,
+       int     assign,
        type_T  *type)
 {
     lvar_T  *lvar;
@@ -519,7 +521,7 @@ reserve_local(
     lvar->lv_idx = dfunc->df_var_names.ga_len;
 
     lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
-    lvar->lv_const = isConst;
+    lvar->lv_const = assign;
     if (type == &t_unknown || type == &t_any)
        // type not known yet, may be inferred from RHS
        lvar->lv_type = type;
@@ -993,7 +995,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free)
     {
        // Define a local variable for the function reference.
        lvar = reserve_local(cctx, func_name, name_end - name_start,
-                                                   TRUE, ufunc->uf_func_type);
+                                           ASSIGN_CONST, ufunc->uf_func_type);
        if (lvar == NULL)
            goto theend;
        if (generate_FUNCREF(cctx, ufunc, &funcref_isn) == FAIL)
@@ -1691,8 +1693,10 @@ compile_lhs(
            return FAIL;
 
        // New local variable.
+       int assign = cmdidx == CMD_final ? ASSIGN_FINAL
+                            : cmdidx == CMD_const ? ASSIGN_CONST : ASSIGN_VAR;
        lhs->lhs_lvar = reserve_local(cctx, var_start, lhs->lhs_varlen,
-                   cmdidx == CMD_final || cmdidx == CMD_const, lhs->lhs_type);
+                                                       assign, lhs->lhs_type);
        if (lhs->lhs_lvar == NULL)
            return FAIL;
        lhs->lhs_new_local = TRUE;
@@ -1769,7 +1773,8 @@ compile_assign_lhs(
        return FAIL;
     }
     if (!is_decl && lhs->lhs_lvar != NULL
-                          && lhs->lhs_lvar->lv_const && !lhs->lhs_has_index)
+                          && lhs->lhs_lvar->lv_const != ASSIGN_VAR
+                          && !lhs->lhs_has_index)
     {
        semsg(_(e_cannot_assign_to_constant), lhs->lhs_name);
        return FAIL;