Skip to content
Permalink
Browse files

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.
  • Loading branch information...
brammool committed Nov 10, 2018
1 parent 1bbb619 commit ded5f1bed7ff2d138b3ee0f9610d17290b62692d
Showing with 55 additions and 11 deletions.
  1. +7 −3 runtime/doc/eval.txt
  2. +1 −0 src/buffer.c
  3. +5 −4 src/ex_cmds2.c
  4. +1 −1 src/globals.h
  5. +2 −0 src/main.c
  6. +2 −1 src/option.c
  7. +1 −0 src/structs.h
  8. +27 −0 src/testdir/test_functions.vim
  9. +7 −2 src/userfunc.c
  10. +2 −0 src/version.c
@@ -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.

This comment has been minimized.

Copy link
@chdiza

chdiza Nov 10, 2018

The comment in the code suggests that this will happen at most once.

This comment has been minimized.

Copy link
@brammool

brammool via email Nov 10, 2018

Author Contributor

This comment has been minimized.

Copy link
@chdiza

chdiza Nov 10, 2018

My point was that, although the code suggests that, the documentation just added fails to make that clear. Maybe it should say "When sourcing a script for the second time (and only the second time)...".

This comment has been minimized.

Copy link
@brammool

brammool via email Nov 10, 2018

Author Contributor

This comment has been minimized.

Copy link
@chdiza

chdiza Nov 10, 2018

but how often in that script the same function is defined.

Well, that is not discernible from the just added documentation. It says "When a script is sourced again", which is about how many times that a script is sourced, not about how many times in a given script a function is defined. And as regards the latter, the just added documentation doesn't say anything about that.

Perhaps it's partly because "previously defined" is ambiguous that this is confusing. It's ambiguous between "defined during a previous sourcing" and "defined earlier in this very sourcing of this very same script".

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.
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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;

@@ -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
@@ -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;
}
@@ -792,6 +792,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
515,
/**/
514,
/**/

0 comments on commit ded5f1b

Please sign in to comment.
You can’t perform that action at this time.