Skip to content

Commit ded5f1b

Browse files
committed
patch 8.1.0515: reloading a script gives errors for existing functions
Problem: Reloading a script gives errors for existing functions. Solution: Allow redefining a function once when reloading a script.
1 parent 1bbb619 commit ded5f1b

10 files changed

Lines changed: 55 additions & 11 deletions

File tree

runtime/doc/eval.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9673,9 +9673,13 @@ See |:verbose-cmd| for more information.
96739673
deleted if there are no more references to it.
96749674
*E127* *E122*
96759675
When a function by this name already exists and [!] is
9676-
not used an error message is given. When [!] is used,
9677-
an existing function is silently replaced. Unless it
9678-
is currently being executed, that is an error.
9676+
not used an error message is given. There is one
9677+
exception: When sourcing a script again, a function
9678+
that was previously defined in that script will be
9679+
silently replaced.
9680+
When [!] is used, an existing function is silently
9681+
replaced. Unless it is currently being executed, that
9682+
is an error.
96799683
NOTE: Use ! wisely. If used without care it can cause
96809684
an existing function to be replaced unexpectedly,
96819685
which is hard to debug.

src/buffer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5519,6 +5519,7 @@ chk_modeline(
55195519
#ifdef FEAT_EVAL
55205520
save_current_sctx = current_sctx;
55215521
current_sctx.sc_sid = SID_MODELINE;
5522+
current_sctx.sc_seq = 0;
55225523
current_sctx.sc_lnum = 0;
55235524
#endif
55245525
retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);

src/ex_cmds2.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,6 +4344,7 @@ do_source(
43444344
#ifdef FEAT_EVAL
43454345
sctx_T save_current_sctx;
43464346
static scid_T last_current_SID = 0;
4347+
static int last_current_SID_seq = 0;
43474348
funccal_entry_T funccalp_entry;
43484349
int save_debug_break_level = debug_break_level;
43494350
scriptitem_T *si = NULL;
@@ -4508,11 +4509,11 @@ do_source(
45084509
* Also starts profiling timer for nested script. */
45094510
save_funccal(&funccalp_entry);
45104511

4511-
/*
4512-
* Check if this script was sourced before to finds its SID.
4513-
* If it's new, generate a new SID.
4514-
*/
4512+
// Check if this script was sourced before to finds its SID.
4513+
// If it's new, generate a new SID.
4514+
// Always use a new sequence number.
45154515
save_current_sctx = current_sctx;
4516+
current_sctx.sc_seq = ++last_current_SID_seq;
45164517
current_sctx.sc_lnum = 0;
45174518
# ifdef UNIX
45184519
stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);

src/globals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ EXTERN int want_garbage_collect INIT(= FALSE);
326326
EXTERN int garbage_collect_at_exit INIT(= FALSE);
327327

328328
// Script CTX being sourced or was sourced to define the current function.
329-
EXTERN sctx_T current_sctx INIT(= {0 COMMA 0});
329+
EXTERN sctx_T current_sctx INIT(= {0 COMMA 0 COMMA 0});
330330
#endif
331331

332332
EXTERN int did_source_packages INIT(= FALSE);

src/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2953,6 +2953,7 @@ exe_commands(mparm_T *parmp)
29532953
sourcing_name = (char_u *)"command line";
29542954
#ifdef FEAT_EVAL
29552955
current_sctx.sc_sid = SID_CARG;
2956+
current_sctx.sc_seq = 0;
29562957
#endif
29572958
for (i = 0; i < parmp->n_commands; ++i)
29582959
{
@@ -3183,6 +3184,7 @@ process_env(
31833184
#ifdef FEAT_EVAL
31843185
save_current_sctx = current_sctx;
31853186
current_sctx.sc_sid = SID_ENV;
3187+
current_sctx.sc_seq = 0;
31863188
current_sctx.sc_lnum = 0;
31873189
#endif
31883190
do_cmdline_cmd(initstr);

src/option.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ struct vimoption
415415
char_u *def_val[2]; // default values for variable (vi and vim)
416416
#ifdef FEAT_EVAL
417417
sctx_T script_ctx; // script context where the option was last set
418-
# define SCTX_INIT , {0, 0}
418+
# define SCTX_INIT , {0, 0, 0}
419419
#else
420420
# define SCTX_INIT
421421
#endif
@@ -5959,6 +5959,7 @@ set_string_option_direct(
59595959
else
59605960
{
59615961
script_ctx.sc_sid = set_sid;
5962+
script_ctx.sc_seq = 0;
59625963
script_ctx.sc_lnum = 0;
59635964
}
59645965
set_option_sctx_idx(idx, opt_flags, script_ctx);

src/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ typedef struct VimMenu vimmenu_T;
8484
*/
8585
typedef struct {
8686
scid_T sc_sid; // script ID
87+
int sc_seq; // sourcing sequence number
8788
linenr_T sc_lnum; // line number
8889
} sctx_T;
8990

src/testdir/test_functions.vim

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,3 +1138,30 @@ func Test_func_range_with_edit()
11381138
call delete('Xfuncrange2')
11391139
bwipe!
11401140
endfunc
1141+
1142+
func Test_func_exists_on_reload()
1143+
call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists')
1144+
call assert_equal(0, exists('*ExistingFunction'))
1145+
source Xfuncexists
1146+
call assert_equal(1, exists('*ExistingFunction'))
1147+
" Redefining a function when reloading a script is OK.
1148+
source Xfuncexists
1149+
call assert_equal(1, exists('*ExistingFunction'))
1150+
1151+
" But redefining in another script is not OK.
1152+
call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2')
1153+
call assert_fails('source Xfuncexists2', 'E122:')
1154+
1155+
delfunc ExistingFunction
1156+
call assert_equal(0, exists('*ExistingFunction'))
1157+
call writefile([
1158+
\ 'func ExistingFunction()', 'echo "yes"', 'endfunc',
1159+
\ 'func ExistingFunction()', 'echo "no"', 'endfunc',
1160+
\ ], 'Xfuncexists')
1161+
call assert_fails('source Xfuncexists', 'E122:')
1162+
call assert_equal(1, exists('*ExistingFunction'))
1163+
1164+
call delete('Xfuncexists2')
1165+
call delete('Xfuncexists')
1166+
delfunc ExistingFunction
1167+
endfunc

src/userfunc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2330,14 +2330,19 @@ ex_function(exarg_T *eap)
23302330
fp = find_func(name);
23312331
if (fp != NULL)
23322332
{
2333-
if (!eap->forceit)
2333+
// Function can be replaced with "function!" and when sourcing the
2334+
// same script again, but only once.
2335+
if (!eap->forceit
2336+
&& (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid
2337+
|| fp->uf_script_ctx.sc_seq == current_sctx.sc_seq))
23342338
{
23352339
emsg_funcname(e_funcexts, name);
23362340
goto erret;
23372341
}
23382342
if (fp->uf_calls > 0)
23392343
{
2340-
emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
2344+
emsg_funcname(
2345+
N_("E127: Cannot redefine function %s: It is in use"),
23412346
name);
23422347
goto erret;
23432348
}

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,8 @@ static char *(features[]) =
792792

793793
static int included_patches[] =
794794
{ /* Add new patch number below this line */
795+
/**/
796+
515,
795797
/**/
796798
514,
797799
/**/

0 commit comments

Comments
 (0)