]> granicus.if.org Git - vim/commitdiff
patch 8.1.0515: reloading a script gives errors for existing functions v8.1.0515
authorBram Moolenaar <Bram@vim.org>
Sat, 10 Nov 2018 16:33:29 +0000 (17:33 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 10 Nov 2018 16:33:29 +0000 (17:33 +0100)
Problem:    Reloading a script gives errors for existing functions.
Solution:   Allow redefining a function once when reloading a script.

runtime/doc/eval.txt
src/buffer.c
src/ex_cmds2.c
src/globals.h
src/main.c
src/option.c
src/structs.h
src/testdir/test_functions.vim
src/userfunc.c
src/version.c

index 2027c2eeb91d3379d16800614a0c54fa3302a5d5..b261d582225d6f2faa71a25d5e0ea9e65c6ec10a 100644 (file)
@@ -9673,9 +9673,13 @@ See |:verbose-cmd| for more information.
                        deleted if there are no more references to it.
                                                                *E127* *E122*
                        When a function by this name already exists and [!] is
-                       not used an error message is given.  When [!] is used,
-                       an existing function is silently replaced.  Unless it
-                       is currently being executed, that is an error.
+                       not used an error message is given.  There is one
+                       exception: When sourcing a script again, a function
+                       that was previously defined in that script will be
+                       silently replaced.
+                       When [!] is used, an existing function is silently
+                       replaced.  Unless it is currently being executed, that
+                       is an error.
                        NOTE: Use ! wisely.  If used without care it can cause
                        an existing function to be replaced unexpectedly,
                        which is hard to debug.
index cbccc7026c738b6e13fbc0bf20e68d3817217287..8e892dadf87878c41456f223cac003019b5fa690 100644 (file)
@@ -5519,6 +5519,7 @@ chk_modeline(
 #ifdef FEAT_EVAL
                save_current_sctx = current_sctx;
                current_sctx.sc_sid = SID_MODELINE;
+               current_sctx.sc_seq = 0;
                current_sctx.sc_lnum = 0;
 #endif
                retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
index 3a4bce8a26f300ae5d850c84d985c86126af2d05..d6b6f5bf89a36654748f4c63449fc5f7686cebcc 100644 (file)
@@ -4344,6 +4344,7 @@ do_source(
 #ifdef FEAT_EVAL
     sctx_T                 save_current_sctx;
     static scid_T          last_current_SID = 0;
+    static int             last_current_SID_seq = 0;
     funccal_entry_T        funccalp_entry;
     int                            save_debug_break_level = debug_break_level;
     scriptitem_T           *si = NULL;
@@ -4508,11 +4509,11 @@ do_source(
      * Also starts profiling timer for nested script. */
     save_funccal(&funccalp_entry);
 
-    /*
-     * Check if this script was sourced before to finds its SID.
-     * If it's new, generate a new SID.
-     */
+    // Check if this script was sourced before to finds its SID.
+    // If it's new, generate a new SID.
+    // Always use a new sequence number.
     save_current_sctx = current_sctx;
+    current_sctx.sc_seq = ++last_current_SID_seq;
     current_sctx.sc_lnum = 0;
 # ifdef UNIX
     stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
index 511479d862288d11c419770c796c5d95534021c8..131c13be95138ff78444a428b05de149a5bd5d5e 100644 (file)
@@ -326,7 +326,7 @@ EXTERN int  want_garbage_collect INIT(= FALSE);
 EXTERN int     garbage_collect_at_exit INIT(= FALSE);
 
 // Script CTX being sourced or was sourced to define the current function.
-EXTERN sctx_T  current_sctx INIT(= {0 COMMA 0});
+EXTERN sctx_T  current_sctx INIT(= {0 COMMA 0 COMMA 0});
 #endif
 
 EXTERN int     did_source_packages INIT(= FALSE);
index d4ff370550f0629ebb078d981054669ed126b6d2..d24eafa949e71ee85af19dae60b58652eb1ae0cc 100644 (file)
@@ -2953,6 +2953,7 @@ exe_commands(mparm_T *parmp)
     sourcing_name = (char_u *)"command line";
 #ifdef FEAT_EVAL
     current_sctx.sc_sid = SID_CARG;
+    current_sctx.sc_seq = 0;
 #endif
     for (i = 0; i < parmp->n_commands; ++i)
     {
@@ -3183,6 +3184,7 @@ process_env(
 #ifdef FEAT_EVAL
        save_current_sctx = current_sctx;
        current_sctx.sc_sid = SID_ENV;
+       current_sctx.sc_seq = 0;
        current_sctx.sc_lnum = 0;
 #endif
        do_cmdline_cmd(initstr);
index 3c54ab6422eecd7eefaca06202a7441d4cc2f767..a4a9c9711d90ed6370980a8b24f34573e2b13562 100644 (file)
@@ -415,7 +415,7 @@ struct vimoption
     char_u     *def_val[2];    // default values for variable (vi and vim)
 #ifdef FEAT_EVAL
     sctx_T     script_ctx;     // script context where the option was last set
-# define SCTX_INIT , {0, 0}
+# define SCTX_INIT , {0, 0, 0}
 #else
 # define SCTX_INIT
 #endif
@@ -5959,6 +5959,7 @@ set_string_option_direct(
            else
            {
                script_ctx.sc_sid = set_sid;
+               script_ctx.sc_seq = 0;
                script_ctx.sc_lnum = 0;
            }
            set_option_sctx_idx(idx, opt_flags, script_ctx);
index a0c06b5f25f8daf39e4913f280b3d439000ff87f..cd9b5a596fe779f55c1e88258eab831a2f0ff414 100644 (file)
@@ -84,6 +84,7 @@ typedef struct VimMenu vimmenu_T;
  */
 typedef struct {
     scid_T     sc_sid;         // script ID
+    int                sc_seq;         // sourcing sequence number
     linenr_T   sc_lnum;        // line number
 } sctx_T;
 
index ac8a27f75ad28ffc071ab6e084a20e659a75a18a..d942d07687e924cf269cc4c9a38aaa7aa1f01116 100644 (file)
@@ -1138,3 +1138,30 @@ func Test_func_range_with_edit()
   call delete('Xfuncrange2')
   bwipe!
 endfunc
+
+func Test_func_exists_on_reload()
+  call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists')
+  call assert_equal(0, exists('*ExistingFunction'))
+  source Xfuncexists
+  call assert_equal(1, exists('*ExistingFunction'))
+  " Redefining a function when reloading a script is OK.
+  source Xfuncexists
+  call assert_equal(1, exists('*ExistingFunction'))
+
+  " But redefining in another script is not OK.
+  call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2')
+  call assert_fails('source Xfuncexists2', 'E122:')
+
+  delfunc ExistingFunction
+  call assert_equal(0, exists('*ExistingFunction'))
+  call writefile([
+       \ 'func ExistingFunction()', 'echo "yes"', 'endfunc',
+       \ 'func ExistingFunction()', 'echo "no"', 'endfunc',
+       \ ], 'Xfuncexists')
+  call assert_fails('source Xfuncexists', 'E122:')
+  call assert_equal(1, exists('*ExistingFunction'))
+
+  call delete('Xfuncexists2')
+  call delete('Xfuncexists')
+  delfunc ExistingFunction
+endfunc
index f79e7f17553b35cb7bcf9f500af0cb35522317ed..8bfebec64cea31a323e72ebe720a3d137176adb5 100644 (file)
@@ -2330,14 +2330,19 @@ ex_function(exarg_T *eap)
        fp = find_func(name);
        if (fp != NULL)
        {
-           if (!eap->forceit)
+           // Function can be replaced with "function!" and when sourcing the
+           // same script again, but only once.
+           if (!eap->forceit
+                       && (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid
+                           || fp->uf_script_ctx.sc_seq == current_sctx.sc_seq))
            {
                emsg_funcname(e_funcexts, name);
                goto erret;
            }
            if (fp->uf_calls > 0)
            {
-               emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
+               emsg_funcname(
+                       N_("E127: Cannot redefine function %s: It is in use"),
                                                                        name);
                goto erret;
            }
index b611fe7301a8fbfc3b177ad8221c8da99673a118..3d728548b21dd8b4fc40005a7c1c222b34017776 100644 (file)
@@ -792,6 +792,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    515,
 /**/
     514,
 /**/