]> granicus.if.org Git - vim/commitdiff
patch 8.2.1023: Vim9: redefining a function uses a new index every time v8.2.1023
authorBram Moolenaar <Bram@vim.org>
Sat, 20 Jun 2020 16:19:09 +0000 (18:19 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 20 Jun 2020 16:19:09 +0000 (18:19 +0200)
Problem:    Vim9: redefining a function uses a new index every time.
Solution:   When redefining a function clear the contents and re-use the
            index.

src/eval.c
src/evalvars.c
src/proto/vim9compile.pro
src/structs.h
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index b4e2c2fece75e212764bdf7089c6fdd70fe4ec84..38afc248947f72f04ba54f6bc3ca40257227477c 100644 (file)
@@ -253,7 +253,7 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
            return FAIL;
 
        if (partial->pt_func != NULL
-                         && partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED)
+                         && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
        {
            if (call_def_function(partial->pt_func, argc, argv,
                                                       partial, rettv) == FAIL)
index fa52e96cd362d88ed0e3410d65ba5cc4a1cba7e5..187670a6cbc99ccf789098928dcee8e5319320a3 100644 (file)
@@ -2628,7 +2628,7 @@ find_var_ht(char_u *name, char_u **varname)
     if (*name == 'v')                          // v: variable
        return &vimvarht;
     if (get_current_funccal() != NULL
-              && get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED)
+              && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
     {
        // a: and l: are only used in functions defined with ":function"
        if (*name == 'a')                       // a: function argument
index 41c688721189b6293b1ad8c8183ed6770458aa34..0db5fc7fc3013e8983349459517119a7d9daf9f0 100644 (file)
@@ -14,6 +14,6 @@ int check_vim9_unlet(char_u *name);
 int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
 void set_function_type(ufunc_T *ufunc);
 void delete_instr(isn_T *isn);
-void delete_def_function(ufunc_T *ufunc);
+void clear_def_function(ufunc_T *ufunc);
 void free_def_functions(void);
 /* vim: set ft=c : */
index 700ac543c11121c9eff9cc0ef6a11496df332169..9addf1ae19f40fecdda44c838608c4404567f5a6 100644 (file)
@@ -1531,8 +1531,11 @@ struct blobvar_S
 typedef struct funccall_S funccall_T;
 
 // values used for "uf_dfunc_idx"
-# define UF_NOT_COMPILED -2
-# define UF_TO_BE_COMPILED -1
+typedef enum {
+    UF_NOT_COMPILED,
+    UF_TO_BE_COMPILED,
+    UF_COMPILED
+} def_status_T;
 
 /*
  * Structure to hold info for a user function.
@@ -1543,7 +1546,8 @@ typedef struct
     int                uf_flags;       // FC_ flags
     int                uf_calls;       // nr of active calls
     int                uf_cleared;     // func_clear() was already called
-    int                uf_dfunc_idx;   // UF_NOT_COMPILED, UF_TO_BE_COMPILED or >= 0
+    def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
+    int                uf_dfunc_idx;   // only valid if uf_def_status is UF_COMPILED
     garray_T   uf_args;        // arguments, including optional arguments
     garray_T   uf_def_args;    // default argument expressions
 
index bd229b4d94f6aaeb7eed311b0e317fa35ff3ff6f..97c8f871af6937f529e6e3b93489da3123f028a2 100644 (file)
@@ -409,7 +409,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto errret;
-       fp->uf_dfunc_idx = UF_NOT_COMPILED;
+       fp->uf_def_status = UF_NOT_COMPILED;
        pt = ALLOC_CLEAR_ONE(partial_T);
        if (pt == NULL)
            goto errret;
@@ -1001,7 +1001,7 @@ func_remove(ufunc_T *fp)
     {
        // When there is a def-function index do not actually remove the
        // function, so we can find the index when defining the function again.
-       if (fp->uf_dfunc_idx >= 0)
+       if (fp->uf_def_status == UF_COMPILED)
            fp->uf_flags |= FC_DEAD;
        else
            hash_remove(&func_hashtab, hi);
@@ -1046,7 +1046,7 @@ func_clear(ufunc_T *fp, int force)
     // clear this function
     func_clear_items(fp);
     funccal_unref(fp->uf_scoped, fp, force);
-    delete_def_function(fp);
+    clear_def_function(fp);
 }
 
 /*
@@ -1074,7 +1074,8 @@ func_free(ufunc_T *fp, int force)
 func_clear_free(ufunc_T *fp, int force)
 {
     func_clear(fp, force);
-    func_free(fp, force);
+    if (force || fp->uf_dfunc_idx == 0)
+       func_free(fp, force);
 }
 
 
@@ -1137,7 +1138,7 @@ call_user_func(
     ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
     func_ptr_ref(fp);
 
-    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+    if (fp->uf_def_status != UF_NOT_COMPILED)
     {
        estack_push_ufunc(fp, 1);
        save_current_sctx = current_sctx;
@@ -1662,7 +1663,7 @@ free_all_functions(void)
                // clear the def function index now
                fp = HI2UF(hi);
                fp->uf_flags &= ~FC_DEAD;
-               fp->uf_dfunc_idx = UF_NOT_COMPILED;
+               fp->uf_def_status = UF_NOT_COMPILED;
 
                // Only free functions that are not refcounted, those are
                // supposed to be freed when no longer referenced.
@@ -2058,7 +2059,7 @@ list_func_head(ufunc_T *fp, int indent)
     msg_start();
     if (indent)
        msg_puts("   ");
-    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+    if (fp->uf_def_status != UF_NOT_COMPILED)
        msg_puts("def ");
     else
        msg_puts("function ");
@@ -2107,7 +2108,7 @@ list_func_head(ufunc_T *fp, int indent)
     }
     msg_putchar(')');
 
-    if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+    if (fp->uf_def_status != UF_NOT_COMPILED)
     {
        if (fp->uf_ret_type != &t_void)
        {
@@ -2624,7 +2625,7 @@ def_function(exarg_T *eap, char_u *name_arg)
                if (!got_int)
                {
                    msg_putchar('\n');
-                   if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+                   if (fp->uf_def_status != UF_NOT_COMPILED)
                        msg_puts("   enddef");
                    else
                        msg_puts("   endfunction");
@@ -3097,6 +3098,7 @@ def_function(exarg_T *eap, char_u *name_arg)
                fp->uf_profiling = FALSE;
                fp->uf_prof_initialized = FALSE;
 #endif
+               clear_def_function(fp);
            }
        }
     }
@@ -3162,7 +3164,7 @@ def_function(exarg_T *eap, char_u *name_arg)
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto erret;
-       fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
+       fp->uf_def_status = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
                                                             : UF_NOT_COMPILED;
 
        if (fudi.fd_dict != NULL)
@@ -3219,7 +3221,7 @@ def_function(exarg_T *eap, char_u *name_arg)
     {
        int     lnum_save = SOURCING_LNUM;
 
-       fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
+       fp->uf_def_status = UF_TO_BE_COMPILED;
 
        // error messages are for the first function line
        SOURCING_LNUM = sourcing_lnum_top;
@@ -3289,7 +3291,7 @@ def_function(exarg_T *eap, char_u *name_arg)
        SOURCING_LNUM = lnum_save;
     }
     else
-       fp->uf_dfunc_idx = UF_NOT_COMPILED;
+       fp->uf_def_status = UF_NOT_COMPILED;
 
     fp->uf_lines = newlines;
     if ((flags & FC_CLOSURE) != 0)
@@ -3372,7 +3374,7 @@ ex_defcompile(exarg_T *eap UNUSED)
            --todo;
            ufunc = HI2UF(hi);
            if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
-                   && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
+                   && ufunc->uf_def_status == UF_TO_BE_COMPILED)
            {
                compile_def_function(ufunc, FALSE, NULL);
 
index 870205ab0959bb3d1797b17d650749fe8d6b5515..ab618af527d0f6119d2a360cc1f1bd5ca2f70ba5 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1023,
 /**/
     1022,
 /**/
index 7329a8bd4eea8e603413064f1b4d126891c6a529..2ac7a0a5650787e102a8b91ff0324724f6a1f8ad 100644 (file)
@@ -1493,7 +1493,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
        return FAIL;
     }
 
-    if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
+    if (ufunc->uf_def_status != UF_NOT_COMPILED)
     {
        int             i;
 
@@ -1517,16 +1517,16 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
                return FAIL;
            }
        }
-       if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
+       if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
            if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
                return FAIL;
     }
 
     if ((isn = generate_instr(cctx,
-                   ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL
+                   ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
                                                         : ISN_UCALL)) == NULL)
        return FAIL;
-    if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
+    if (ufunc->uf_def_status != UF_NOT_COMPILED)
     {
        isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
        isn->isn_arg.dfunc.cdf_argcount = argcount;
@@ -3042,7 +3042,7 @@ compile_lambda(char_u **arg, cctx_T *cctx)
     // Compile it into instructions.
     compile_def_function(ufunc, TRUE, cctx);
 
-    if (ufunc->uf_dfunc_idx >= 0)
+    if (ufunc->uf_def_status == UF_COMPILED)
        return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
     return FAIL;
 }
@@ -4539,7 +4539,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
 
     if (ufunc == NULL)
        return NULL;
-    if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+    if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, TRUE, cctx) == FAIL)
        return NULL;
 
@@ -6517,13 +6517,22 @@ theend:
 
 /*
  * Add a function to the list of :def functions.
- * This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
+ * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
  */
     static int
 add_def_function(ufunc_T *ufunc)
 {
     dfunc_T *dfunc;
 
+    if (def_functions.ga_len == 0)
+    {
+       // The first position is not used, so that a zero uf_dfunc_idx means it
+       // wasn't set.
+       if (ga_grow(&def_functions, 1) == FAIL)
+           return FAIL;
+       ++def_functions.ga_len;
+    }
+
     // Add the function to "def_functions".
     if (ga_grow(&def_functions, 1) == FAIL)
        return FAIL;
@@ -6563,7 +6572,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
 
     // When using a function that was compiled before: Free old instructions.
     // Otherwise add a new entry in "def_functions".
-    if (ufunc->uf_dfunc_idx >= 0)
+    if (ufunc->uf_dfunc_idx > 0)
     {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
@@ -7014,6 +7023,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
        dfunc->df_closure_count = cctx.ctx_closure_count;
        if (cctx.ctx_outer_used)
            ufunc->uf_flags |= FC_CLOSURE;
+       ufunc->uf_def_status = UF_COMPILED;
     }
 
     ret = OK;
@@ -7033,7 +7043,7 @@ erret:
        if (!dfunc->df_deleted
                            && ufunc->uf_dfunc_idx == def_functions.ga_len - 1)
            --def_functions.ga_len;
-       ufunc->uf_dfunc_idx = UF_NOT_COMPILED;
+       ufunc->uf_def_status = UF_NOT_COMPILED;
 
        while (cctx.ctx_scope != NULL)
            drop_scope(&cctx);
@@ -7261,17 +7271,19 @@ delete_def_function_contents(dfunc_T *dfunc)
 }
 
 /*
- * When a user function is deleted, delete any associated def function.
+ * When a user function is deleted, clear the contents of any associated def
+ * function.  The position in def_functions can be re-used.
  */
     void
-delete_def_function(ufunc_T *ufunc)
+clear_def_function(ufunc_T *ufunc)
 {
-    if (ufunc->uf_dfunc_idx >= 0)
+    if (ufunc->uf_dfunc_idx > 0)
     {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
 
        delete_def_function_contents(dfunc);
+       ufunc->uf_def_status = UF_NOT_COMPILED;
     }
 }
 
index 4271f3895bfc3349ce7491f03f3a4ff141b42c78..fda44ec08e05a2a193b55462a37dfdc6d186d28f 100644 (file)
@@ -487,10 +487,10 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
     int                error;
     int                idx;
 
-    if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+    if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return FAIL;
-    if (ufunc->uf_dfunc_idx >= 0)
+    if (ufunc->uf_def_status == UF_COMPILED)
     {
        // The function has been compiled, can call it quickly.  For a function
        // that was defined later: we can call it directly next time.
@@ -671,8 +671,8 @@ call_def_function(
 // Like STACK_TV_VAR but use the outer scope
 #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
 
-    if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
-           || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+    if (ufunc->uf_def_status == UF_NOT_COMPILED
+           || (ufunc->uf_def_status == UF_TO_BE_COMPILED
                          && compile_def_function(ufunc, FALSE, NULL) == FAIL))
     {
        if (called_emsg == called_emsg_before)
@@ -2379,10 +2379,10 @@ ex_disassemble(exarg_T *eap)
        semsg(_("E1061: Cannot find function %s"), eap->arg);
        return;
     }
-    if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+    if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return;
-    if (ufunc->uf_dfunc_idx < 0)
+    if (ufunc->uf_def_status != UF_COMPILED)
     {
        semsg(_("E1062: Function %s is not compiled"), eap->arg);
        return;