To: vim_dev@googlegroups.com Subject: Patch 8.2.0650 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0650 Problem: Vim9: script function can be deleted. Solution: Disallow deleting script function. Delete functions when sourcing a script again. Files: src/userfunc.c, src/proto/userfunc.pro, src/evalfunc.c, src/vim9compile.c, src/vim9execute.c, src/vim9script.c, src/scriptfile.c, src/testing.c, src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_func.vim, src/testdir/test_vim9_script.vim *** ../vim-8.2.0649/src/userfunc.c 2020-04-23 22:23:09.098417372 +0200 --- src/userfunc.c 2020-04-27 22:27:10.352646535 +0200 *************** *** 25,30 **** --- 25,31 ---- #define FC_DEAD 0x80 // function kept only for reference to dfunc #define FC_EXPORT 0x100 // "export def Func()" #define FC_NOARGS 0x200 // no a: variables in lambda + #define FC_VIM9 0x400 // defined in vim9 script file /* * All user-defined functions are found in this hashtable. *************** *** 710,725 **** /* * Find a function by name, return pointer to it in ufuncs. * Return NULL for unknown function. */ static ufunc_T * ! find_func_even_dead(char_u *name, cctx_T *cctx) { hashitem_T *hi; ufunc_T *func; imported_T *imported; ! if (in_vim9script()) { // Find script-local function before global one. func = find_func_with_sid(name, current_sctx.sc_sid); --- 711,727 ---- /* * Find a function by name, return pointer to it in ufuncs. + * When "is_global" is true don't find script-local or imported functions. * Return NULL for unknown function. */ static ufunc_T * ! find_func_even_dead(char_u *name, int is_global, cctx_T *cctx) { hashitem_T *hi; ufunc_T *func; imported_T *imported; ! if (in_vim9script() && !is_global) { // Find script-local function before global one. func = find_func_with_sid(name, current_sctx.sc_sid); *************** *** 750,758 **** * Return NULL for unknown or dead function. */ ufunc_T * ! find_func(char_u *name, cctx_T *cctx) { ! ufunc_T *fp = find_func_even_dead(name, cctx); if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0) return fp; --- 752,760 ---- * Return NULL for unknown or dead function. */ ufunc_T * ! find_func(char_u *name, int is_global, cctx_T *cctx) { ! ufunc_T *fp = find_func_even_dead(name, is_global, cctx); if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0) return fp; *************** *** 1575,1580 **** --- 1577,1614 ---- return current_funccal; } + /* + * Mark all functions of script "sid" as deleted. + */ + void + delete_script_functions(int sid) + { + hashitem_T *hi; + ufunc_T *fp; + long_u todo; + char buf[30]; + size_t len; + + buf[0] = K_SPECIAL; + buf[1] = KS_EXTRA; + buf[2] = (int)KE_SNR; + sprintf(buf + 3, "%d_", sid); + len = STRLEN(buf); + + todo = func_hashtab.ht_used; + for (hi = func_hashtab.ht_array; todo > 0; ++hi) + if (!HASHITEM_EMPTY(hi)) + { + if (STRNCMP(fp->uf_name, buf, len) == 0) + { + fp = HI2UF(hi); + fp->uf_flags |= FC_DEAD; + func_clear(fp, TRUE); + } + --todo; + } + } + #if defined(EXITFREE) || defined(PROTO) void free_all_functions(void) *************** *** 1884,1905 **** * User defined function. */ if (fp == NULL) ! fp = find_func(rfname, NULL); // Trigger FuncUndefined event, may load the function. if (fp == NULL && apply_autocmds(EVENT_FUNCUNDEFINED, ! rfname, rfname, TRUE, NULL) && !aborting()) { // executed an autocommand, search for the function again ! fp = find_func(rfname, NULL); } // Try loading a package. if (fp == NULL && script_autoload(rfname, TRUE) && !aborting()) { // loaded a package, search for the function again ! fp = find_func(rfname, NULL); } if (fp == NULL) { --- 1918,1939 ---- * User defined function. */ if (fp == NULL) ! fp = find_func(rfname, FALSE, NULL); // Trigger FuncUndefined event, may load the function. if (fp == NULL && apply_autocmds(EVENT_FUNCUNDEFINED, ! rfname, rfname, TRUE, NULL) && !aborting()) { // executed an autocommand, search for the function again ! fp = find_func(rfname, FALSE, NULL); } // Try loading a package. if (fp == NULL && script_autoload(rfname, TRUE) && !aborting()) { // loaded a package, search for the function again ! fp = find_func(rfname, FALSE, NULL); } if (fp == NULL) { *************** *** 1908,1914 **** // If using Vim9 script try not local to the script. // TODO: should not do this if the name started with "s:". if (p != NULL) ! fp = find_func(p, NULL); } if (fp != NULL && (fp->uf_flags & FC_DELETED)) --- 1942,1948 ---- // If using Vim9 script try not local to the script. // TODO: should not do this if the name started with "s:". if (p != NULL) ! fp = find_func(p, FALSE, NULL); } if (fp != NULL && (fp->uf_flags & FC_DELETED)) *************** *** 2079,2084 **** --- 2113,2120 ---- * Get a function name, translating "" and "". * Also handles a Funcref in a List or Dictionary. * Returns the function name in allocated memory, or NULL for failure. + * Set "*is_global" to TRUE when the function must be global, unless + * "is_global" is NULL. * flags: * TFN_INT: internal function name OK * TFN_QUIET: be quiet *************** *** 2089,2094 **** --- 2125,2131 ---- char_u * trans_function_name( char_u **pp, + int *is_global, int skip, // only find the end, don't evaluate int flags, funcdict_T *fdp, // return: info about dictionary used *************** *** 2239,2245 **** --- 2276,2286 ---- { // skip over "s:" and "g:" if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':')) + { + if (is_global != NULL && lv.ll_name[0] == 'g') + *is_global = TRUE; lv.ll_name += 2; + } len = (int)(end - lv.ll_name); } *************** *** 2347,2352 **** --- 2388,2394 ---- int saved_did_emsg; int saved_wait_return = need_wait_return; char_u *name = NULL; + int is_global = FALSE; char_u *p; char_u *arg; char_u *line_arg = NULL; *************** *** 2463,2469 **** * g:func global function name, same as "func" */ p = eap->arg; ! name = trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL); paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { --- 2505,2512 ---- * g:func global function name, same as "func" */ p = eap->arg; ! name = trans_function_name(&p, &is_global, eap->skip, ! TFN_NO_AUTOLOAD, &fudi, NULL); paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { *************** *** 2503,2509 **** *p = NUL; if (!eap->skip && !got_int) { ! fp = find_func(name, NULL); if (fp == NULL && ASCII_ISUPPER(*eap->arg)) { char_u *up = untrans_function_name(name); --- 2546,2552 ---- *p = NUL; if (!eap->skip && !got_int) { ! fp = find_func(name, is_global, NULL); if (fp == NULL && ASCII_ISUPPER(*eap->arg)) { char_u *up = untrans_function_name(name); *************** *** 2511,2517 **** // With Vim9 script the name was made script-local, if not // found try again with the original name. if (up != NULL) ! fp = find_func(up, NULL); } if (fp != NULL) --- 2554,2560 ---- // With Vim9 script the name was made script-local, if not // found try again with the original name. if (up != NULL) ! fp = find_func(up, FALSE, NULL); } if (fp != NULL) *************** *** 2675,2681 **** { if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) emsg(_(e_funcdict)); ! else if (name != NULL && find_func(name, NULL) != NULL) emsg_funcname(e_funcexts, name); } --- 2718,2724 ---- { if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) emsg(_(e_funcdict)); ! else if (name != NULL && find_func(name, is_global, NULL) != NULL) emsg_funcname(e_funcexts, name); } *************** *** 2825,2831 **** if (*p == '!') p = skipwhite(p + 1); p += eval_fname_script(p); ! vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL)); if (*skipwhite(p) == '(') { if (nesting == MAX_FUNC_NESTING - 1) --- 2868,2874 ---- if (*p == '!') p = skipwhite(p + 1); p += eval_fname_script(p); ! vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, NULL)); if (*skipwhite(p) == '(') { if (nesting == MAX_FUNC_NESTING - 1) *************** *** 2963,2969 **** goto erret; } ! fp = find_func_even_dead(name, NULL); if (fp != NULL) { int dead = fp->uf_flags & FC_DEAD; --- 3006,3012 ---- goto erret; } ! fp = find_func_even_dead(name, is_global, NULL); if (fp != NULL) { int dead = fp->uf_flags & FC_DEAD; *************** *** 3208,3213 **** --- 3251,3258 ---- fp->uf_varargs = varargs; if (sandbox) flags |= FC_SANDBOX; + if (in_vim9script() && !ASCII_ISUPPER(*fp->uf_name)) + flags |= FC_VIM9; fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_cleared = FALSE; *************** *** 3261,3271 **** } int ! translated_function_exists(char_u *name) { if (builtin_function(name, -1)) return has_internal_func(name); ! return find_func(name, NULL) != NULL; } /* --- 3306,3316 ---- } int ! translated_function_exists(char_u *name, int is_global) { if (builtin_function(name, -1)) return has_internal_func(name); ! return find_func(name, is_global, NULL) != NULL; } /* *************** *** 3289,3305 **** char_u *p; int n = FALSE; int flag; flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; if (no_deref) flag |= TFN_NO_DEREF; ! p = trans_function_name(&nm, FALSE, flag, NULL, NULL); nm = skipwhite(nm); // Only accept "funcname", "funcname ", "funcname (..." and // "funcname(...", not "funcname!...". if (p != NULL && (*nm == NUL || *nm == '(')) ! n = translated_function_exists(p); vim_free(p); return n; } --- 3334,3351 ---- char_u *p; int n = FALSE; int flag; + int is_global = FALSE; flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; if (no_deref) flag |= TFN_NO_DEREF; ! p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL); nm = skipwhite(nm); // Only accept "funcname", "funcname ", "funcname (..." and // "funcname(...", not "funcname!...". if (p != NULL && (*nm == NUL || *nm == '(')) ! n = translated_function_exists(p, is_global); vim_free(p); return n; } *************** *** 3310,3321 **** { char_u *nm = name; char_u *p; ! p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL); ! if (p != NULL && *nm == NUL) ! if (!check || translated_function_exists(p)) ! return p; vim_free(p); return NULL; --- 3356,3369 ---- { char_u *nm = name; char_u *p; + int is_global = FALSE; ! p = trans_function_name(&nm, &is_global, FALSE, ! TFN_INT|TFN_QUIET, NULL, NULL); ! if (p != NULL && *nm == NUL ! && (!check || translated_function_exists(p, is_global))) ! return p; vim_free(p); return NULL; *************** *** 3376,3384 **** char_u *p; char_u *name; funcdict_T fudi; p = eap->arg; ! name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); vim_free(fudi.fd_newkey); if (name == NULL) { --- 3424,3433 ---- char_u *p; char_u *name; funcdict_T fudi; + int is_global = FALSE; p = eap->arg; ! name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, NULL); vim_free(fudi.fd_newkey); if (name == NULL) { *************** *** 3397,3403 **** *p = NUL; if (!eap->skip) ! fp = find_func(name, NULL); vim_free(name); if (!eap->skip) --- 3446,3452 ---- *p = NUL; if (!eap->skip) ! fp = find_func(name, is_global, NULL); vim_free(name); if (!eap->skip) *************** *** 3413,3418 **** --- 3462,3472 ---- semsg(_("E131: Cannot delete function %s: It is in use"), eap->arg); return; } + if (fp->uf_flags & FC_VIM9) + { + semsg(_("E1084: Cannot delete Vim9 script function %s"), eap->arg); + return; + } if (fudi.fd_dict != NULL) { *************** *** 3452,3458 **** if (name == NULL || !func_name_refcount(name)) return; ! fp = find_func(name, NULL); if (fp == NULL && isdigit(*name)) { #ifdef EXITFREE --- 3506,3512 ---- if (name == NULL || !func_name_refcount(name)) return; ! fp = find_func(name, FALSE, NULL); if (fp == NULL && isdigit(*name)) { #ifdef EXITFREE *************** *** 3495,3501 **** if (name == NULL || !func_name_refcount(name)) return; ! fp = find_func(name, NULL); if (fp != NULL) ++fp->uf_refcount; else if (isdigit(*name)) --- 3549,3555 ---- if (name == NULL || !func_name_refcount(name)) return; ! fp = find_func(name, FALSE, NULL); if (fp != NULL) ++fp->uf_refcount; else if (isdigit(*name)) *************** *** 3611,3617 **** return; } ! tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. --- 3665,3672 ---- return; } ! tofree = trans_function_name(&arg, NULL, eap->skip, ! TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. *************** *** 3969,3975 **** : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. fname = fname_trans_sid(fname, fname_buf, &tofree, &error); ! fp = find_func(fname, NULL); vim_free(tofree); } --- 4024,4030 ---- : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. fname = fname_trans_sid(fname, fname_buf, &tofree, &error); ! fp = find_func(fname, FALSE, NULL); vim_free(tofree); } *************** *** 4391,4397 **** if (fp_in == NULL) { fname = fname_trans_sid(name, fname_buf, &tofree, &error); ! fp = find_func(fname, NULL); } if (fp != NULL) { --- 4446,4452 ---- if (fp_in == NULL) { fname = fname_trans_sid(name, fname_buf, &tofree, &error); ! fp = find_func(fname, FALSE, NULL); } if (fp != NULL) { *** ../vim-8.2.0649/src/proto/userfunc.pro 2020-04-18 19:53:24.535912281 +0200 --- src/proto/userfunc.pro 2020-04-27 22:27:14.284639586 +0200 *************** *** 7,17 **** void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ! ufunc_T *find_func(char_u *name, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); void restore_funccal(void); funccall_T *get_current_funccal(void); void free_all_functions(void); int builtin_function(char_u *name, int len); int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv); --- 7,18 ---- void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ! ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); void restore_funccal(void); funccall_T *get_current_funccal(void); + void delete_script_functions(int sid); void free_all_functions(void); int builtin_function(char_u *name, int len); int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv); *************** *** 19,29 **** int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); ! char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); void ex_function(exarg_T *eap); int eval_fname_script(char_u *p); ! int translated_function_exists(char_u *name); int has_varargs(ufunc_T *ufunc); int function_exists(char_u *name, int no_deref); char_u *get_expanded_name(char_u *name, int check); --- 20,30 ---- int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); ! char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); void ex_function(exarg_T *eap); int eval_fname_script(char_u *p); ! int translated_function_exists(char_u *name, int is_global); int has_varargs(ufunc_T *ufunc); int function_exists(char_u *name, int no_deref); char_u *get_expanded_name(char_u *name, int check); *** ../vim-8.2.0649/src/evalfunc.c 2020-04-18 19:53:24.531912284 +0200 --- src/evalfunc.c 2020-04-27 21:55:06.020110104 +0200 *************** *** 2679,2684 **** --- 2679,2685 ---- int use_string = FALSE; partial_T *arg_pt = NULL; char_u *trans_name = NULL; + int is_global = FALSE; if (argvars[0].v_type == VAR_FUNC) { *************** *** 2702,2722 **** if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; ! trans_name = trans_function_name(&name, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (*name != NUL) s = NULL; - else if (trans_name != NULL - && ASCII_ISUPPER(*s) - && current_sctx.sc_version == SCRIPT_VERSION_VIM9 - && find_func(trans_name, NULL) == NULL) - { - // With Vim9 script "MyFunc" can be script-local to the current - // script or global. The script-local name is not found, assume - // global. - vim_free(trans_name); - trans_name = vim_strsave(s); - } } if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) --- 2703,2712 ---- if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; ! trans_name = trans_function_name(&name, &is_global, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (*name != NUL) s = NULL; } if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) *************** *** 2724,2731 **** semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s); // Don't check an autoload name for existence here. else if (trans_name != NULL && (is_funcref ! ? find_func(trans_name, NULL) == NULL ! : !translated_function_exists(trans_name))) semsg(_("E700: Unknown function: %s"), s); else { --- 2714,2721 ---- semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s); // Don't check an autoload name for existence here. else if (trans_name != NULL && (is_funcref ! ? find_func(trans_name, is_global, NULL) == NULL ! : !translated_function_exists(trans_name, is_global))) semsg(_("E700: Unknown function: %s"), s); else { *************** *** 2862,2868 **** } else if (is_funcref) { ! pt->pt_func = find_func(trans_name, NULL); func_ptr_ref(pt->pt_func); vim_free(name); } --- 2852,2858 ---- } else if (is_funcref) { ! pt->pt_func = find_func(trans_name, is_global, NULL); func_ptr_ref(pt->pt_func); vim_free(name); } *** ../vim-8.2.0649/src/vim9compile.c 2020-04-26 14:29:53.450969744 +0200 --- src/vim9compile.c 2020-04-27 21:50:09.064705648 +0200 *************** *** 2210,2216 **** static int generate_funcref(cctx_T *cctx, char_u *name) { ! ufunc_T *ufunc = find_func(name, cctx); if (ufunc == NULL) return FAIL; --- 2210,2216 ---- static int generate_funcref(cctx_T *cctx, char_u *name) { ! ufunc_T *ufunc = find_func(name, FALSE, cctx); if (ufunc == NULL) return FAIL; *************** *** 2452,2458 **** } // If we can find the function by name generate the right call. ! ufunc = find_func(name, cctx); if (ufunc != NULL) { res = generate_CALL(cctx, ufunc, argcount); --- 2452,2458 ---- } // If we can find the function by name generate the right call. ! ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) { res = generate_CALL(cctx, ufunc, argcount); *** ../vim-8.2.0649/src/vim9execute.c 2020-04-26 13:50:38.432096840 +0200 --- src/vim9execute.c 2020-04-27 21:57:16.195835167 +0200 *************** *** 400,406 **** return call_bfunc(func_idx, argcount, ectx); } ! ufunc = find_func(name, NULL); if (ufunc != NULL) return call_ufunc(ufunc, argcount, ectx, iptr); --- 400,406 ---- return call_bfunc(func_idx, argcount, ectx); } ! ufunc = find_func(name, FALSE, NULL); if (ufunc != NULL) return call_ufunc(ufunc, argcount, ectx, iptr); *************** *** 1944,1951 **** int current; int line_idx = 0; int prev_current = 0; ! fname = trans_function_name(&arg, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (fname == NULL) { --- 1944,1952 ---- int current; int line_idx = 0; int prev_current = 0; + int is_global = FALSE; ! fname = trans_function_name(&arg, &is_global, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (fname == NULL) { *************** *** 1953,1966 **** return; } ! ufunc = find_func(fname, NULL); if (ufunc == NULL) { char_u *p = untrans_function_name(fname); if (p != NULL) // Try again without making it script-local. ! ufunc = find_func(p, NULL); } vim_free(fname); if (ufunc == NULL) --- 1954,1967 ---- return; } ! ufunc = find_func(fname, is_global, NULL); if (ufunc == NULL) { char_u *p = untrans_function_name(fname); if (p != NULL) // Try again without making it script-local. ! ufunc = find_func(p, FALSE, NULL); } vim_free(fname); if (ufunc == NULL) *** ../vim-8.2.0649/src/vim9script.c 2020-03-20 18:39:42.981273170 +0100 --- src/vim9script.c 2020-04-27 21:50:32.780660148 +0200 *************** *** 217,223 **** funcname[1] = KS_EXTRA; funcname[2] = (int)KE_SNR; sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); ! *ufunc = find_func(funcname, NULL); if (funcname != buffer) vim_free(funcname); --- 217,223 ---- funcname[1] = KS_EXTRA; funcname[2] = (int)KE_SNR; sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); ! *ufunc = find_func(funcname, FALSE, NULL); if (funcname != buffer) vim_free(funcname); *** ../vim-8.2.0649/src/scriptfile.c 2020-04-13 21:16:18.039292270 +0200 --- src/scriptfile.c 2020-04-27 22:19:16.981380400 +0200 *************** *** 1275,1280 **** --- 1275,1281 ---- hashitem_T *hi; dictitem_T *di; int todo; + int is_vim9 = si->sn_version == SCRIPT_VERSION_VIM9; // loading the same script again si->sn_had_command = FALSE; *************** *** 1293,1298 **** --- 1294,1303 ---- // old imports are no longer valid free_imports(sid); + + // in Vim9 script functions are marked deleted + if (is_vim9) + delete_script_functions(sid); } else { *** ../vim-8.2.0649/src/testing.c 2020-04-05 21:38:11.637962358 +0200 --- src/testing.c 2020-04-27 21:49:11.696813794 +0200 *************** *** 789,795 **** { ufunc_T *fp; ! fp = find_func(argvars[0].vval.v_string, NULL); if (fp != NULL) retval = fp->uf_refcount; } --- 789,795 ---- { ufunc_T *fp; ! fp = find_func(argvars[0].vval.v_string, FALSE, NULL); if (fp != NULL) retval = fp->uf_refcount; } *** ../vim-8.2.0649/src/testdir/test_vim9_expr.vim 2020-04-25 20:02:36.001096124 +0200 --- src/testdir/test_vim9_expr.vim 2020-04-27 22:05:43.290717943 +0200 *************** *** 207,218 **** assert_equal(true, g:adict == #{bbb: 8, aaa: 2}) assert_equal(false, #{ccc: 9, aaa: 2} == g:adict) ! assert_equal(true, function('Test_expr4_equal') == function('Test_expr4_equal')) ! assert_equal(false, function('Test_expr4_equal') == function('Test_expr4_is')) ! assert_equal(true, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [123])) ! assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_is', [123])) ! assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [999])) enddef " test != comperator --- 207,218 ---- assert_equal(true, g:adict == #{bbb: 8, aaa: 2}) assert_equal(false, #{ccc: 9, aaa: 2} == g:adict) ! assert_equal(true, function('g:Test_expr4_equal') == function('g:Test_expr4_equal')) ! assert_equal(false, function('g:Test_expr4_equal') == function('g:Test_expr4_is')) ! assert_equal(true, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [123])) ! assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_is', [123])) ! assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [999])) enddef " test != comperator *************** *** 274,285 **** assert_equal(false, g:adict != #{bbb: 8, aaa: 2}) assert_equal(true, #{ccc: 9, aaa: 2} != g:adict) ! assert_equal(false, function('Test_expr4_equal') != function('Test_expr4_equal')) ! assert_equal(true, function('Test_expr4_equal') != function('Test_expr4_is')) ! assert_equal(false, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [123])) ! assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_is', [123])) ! assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [999])) enddef " test > comperator --- 274,285 ---- assert_equal(false, g:adict != #{bbb: 8, aaa: 2}) assert_equal(true, #{ccc: 9, aaa: 2} != g:adict) ! assert_equal(false, function('g:Test_expr4_equal') != function('g:Test_expr4_equal')) ! assert_equal(true, function('g:Test_expr4_equal') != function('g:Test_expr4_is')) ! assert_equal(false, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [123])) ! assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_is', [123])) ! assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [999])) enddef " test > comperator *************** *** 929,943 **** def Test_expr7_trailing() " user function call ! assert_equal(123, CallMe(123)) ! assert_equal(123, CallMe( 123)) ! assert_equal(123, CallMe(123 )) ! assert_equal('yesno', CallMe2('yes', 'no')) ! assert_equal('yesno', CallMe2( 'yes', 'no' )) ! assert_equal('nothing', CallMe('nothing')) " partial call ! let Part = function('CallMe') assert_equal('yes', Part('yes')) " funcref call, using list index --- 929,943 ---- def Test_expr7_trailing() " user function call ! assert_equal(123, g:CallMe(123)) ! assert_equal(123, g:CallMe( 123)) ! assert_equal(123, g:CallMe(123 )) ! assert_equal('yesno', g:CallMe2('yes', 'no')) ! assert_equal('yesno', g:CallMe2( 'yes', 'no' )) ! assert_equal('nothing', g:CallMe('nothing')) " partial call ! let Part = function('g:CallMe') assert_equal('yes', Part('yes')) " funcref call, using list index *** ../vim-8.2.0649/src/testdir/test_vim9_func.vim 2020-04-23 22:16:49.767270674 +0200 --- src/testdir/test_vim9_func.vim 2020-04-27 22:08:36.218326931 +0200 *************** *** 353,359 **** def Test_delfunc() let lines =<< trim END vim9script ! def GoneSoon() echo 'hello' enddef --- 353,359 ---- def Test_delfunc() let lines =<< trim END vim9script ! def g:GoneSoon() echo 'hello' enddef *************** *** 361,367 **** GoneSoon() enddef ! delfunc GoneSoon CallGoneSoon() END writefile(lines, 'XToDelFunc') --- 361,367 ---- GoneSoon() enddef ! delfunc g:GoneSoon CallGoneSoon() END writefile(lines, 'XToDelFunc') *** ../vim-8.2.0649/src/testdir/test_vim9_script.vim 2020-04-25 20:02:36.001096124 +0200 --- src/testdir/test_vim9_script.vim 2020-04-27 22:39:03.507275570 +0200 *************** *** 53,59 **** endif let Funky1: func let Funky2: func = function('len') ! let Party2: func = funcref('Test_syntax') # type becomes list let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] --- 53,59 ---- endif let Funky1: func let Funky2: func = function('len') ! let Party2: func = funcref('g:Test_syntax') # type becomes list let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] *************** *** 282,287 **** --- 282,330 ---- assert_equal('', $ENVVAR) enddef + def Test_delfunction() + " Check function is defined in script namespace + CheckScriptSuccess([ + 'vim9script', + 'func CheckMe()', + ' return 123', + 'endfunc', + 'assert_equal(123, s:CheckMe())', + ]) + + " Check function in script namespace cannot be deleted + CheckScriptFailure([ + 'vim9script', + 'func DeleteMe1()', + 'endfunc', + 'delfunction DeleteMe1', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'func DeleteMe2()', + 'endfunc', + 'def DoThat()', + ' delfunction DeleteMe2', + 'enddef', + 'DoThat()', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'def DeleteMe3()', + 'enddef', + 'delfunction DeleteMe3', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'def DeleteMe4()', + 'enddef', + 'def DoThat()', + ' delfunction DeleteMe4', + 'enddef', + 'DoThat()', + ], 'E1084:') + enddef + func Test_wrong_type() call CheckDefFailure(['let var: list'], 'E1010:') call CheckDefFailure(['let var: list>'], 'E1010:') *************** *** 649,655 **** assert_fails('export something', 'E1043') enddef ! def Test_vim9script_reload() let lines =<< trim END vim9script const var = '' --- 692,698 ---- assert_fails('export something', 'E1043') enddef ! def Test_vim9script_reload_import() let lines =<< trim END vim9script const var = '' *************** *** 700,705 **** --- 743,789 ---- delete('Ximport.vim') enddef + def Test_vim9script_reload_delfunc() + let first_lines =<< trim END + vim9script + def FuncYes(): string + return 'yes' + enddef + END + let middle_lines =<< trim END + def FuncNo(): string + return 'no' + enddef + END + let final_lines =<< trim END + def g:DoCheck(no_exists: bool) + assert_equal('yes', FuncYes()) + if no_exists + assert_equal('no', FuncNo()) + else + assert_fails('call FuncNo()', 'E117:') + endif + enddef + END + + # FuncNo() is defined + writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(true) + + # FuncNo() is not redefined + writefile(first_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(false) + + # FuncNo() is back + writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(true) + + delete('Xreloaded.vim') + enddef + def Test_import_absolute() let import_lines = [ 'vim9script', *************** *** 1445,1459 **** CheckScriptSuccess([ 'vim9script', ! 'func DeleteMe()', 'endfunc', ! 'delfunction DeleteMe # comment', ]) CheckScriptFailure([ 'vim9script', ! 'func DeleteMe()', 'endfunc', ! 'delfunction DeleteMe# comment', ], 'E488:') CheckScriptSuccess([ --- 1529,1543 ---- CheckScriptSuccess([ 'vim9script', ! 'func g:DeleteMeA()', 'endfunc', ! 'delfunction g:DeleteMeA # comment', ]) CheckScriptFailure([ 'vim9script', ! 'func g:DeleteMeB()', 'endfunc', ! 'delfunction g:DeleteMeB# comment', ], 'E488:') CheckScriptSuccess([ *** ../vim-8.2.0649/src/version.c 2020-04-27 20:18:27.678560149 +0200 --- src/version.c 2020-04-27 22:39:38.303205297 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 650, /**/ -- Far back in the mists of ancient time, in the great and glorious days of the former Galactic Empire, life was wild, rich and largely tax free. Mighty starships plied their way between exotic suns, seeking adventure and reward among the furthest reaches of Galactic space. In those days, spirits were brave, the stakes were high, men were real men, women were real women and small furry creatures from Alpha Centauri were real small furry creatures from Alpha Centauri. And all dared to brave unknown terrors, to do mighty deeds, to boldly split infinitives that no man had split before -- and thus was the Empire forged. -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///