Mercurial > vim
diff src/vim9compile.c @ 22236:3d0632b260fd v8.2.1667
patch 8.2.1667: local function name cannot shadow a global function name
Commit: https://github.com/vim/vim/commit/0f769815c82bf93812842e1ad56fcc52c10ff3e5
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 12 18:32:34 2020 +0200
patch 8.2.1667: local function name cannot shadow a global function name
Problem: Local function name cannot shadow a global function name.
Solution: Ignore global functions when checking a script-local or scoped
function name. (closes #6926)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 12 Sep 2020 18:45:04 +0200 |
parents | f9b4576a618b |
children | d7c1e3efa88e |
line wrap: on
line diff
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -292,12 +292,14 @@ lookup_script(char_u *name, size_t len, /* * Check if "p[len]" is already defined, either in script "import_sid" or in * compilation context "cctx". + * Does not check the global namespace. * Return FAIL and give an error if it defined. */ int check_defined(char_u *p, size_t len, cctx_T *cctx) { - int c = p[len]; + int c = p[len]; + ufunc_T *ufunc = NULL; p[len] = NUL; if (lookup_script(p, len, FALSE) == OK @@ -305,11 +307,16 @@ check_defined(char_u *p, size_t len, cct && (lookup_local(p, len, cctx) != NULL || lookup_arg(p, len, NULL, NULL, NULL, cctx) == OK)) || find_imported(p, len, cctx) != NULL - || find_func_even_dead(p, FALSE, cctx) != NULL) - { - p[len] = c; - semsg(_(e_name_already_defined_str), p); - return FAIL; + || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL) + { + // A local or script-local function can shadow a global function. + if (ufunc == NULL || !func_is_global(ufunc) + || (p[0] == 'g' && p[1] == ':')) + { + p[len] = c; + semsg(_(e_name_already_defined_str), p); + return FAIL; + } } p[len] = c; return OK; @@ -2114,10 +2121,16 @@ generate_funcref(cctx_T *cctx, char_u *n /* * Compile a variable name into a load instruction. * "end" points to just after the name. + * "is_expr" is TRUE when evaluating an expression, might be a funcref. * When "error" is FALSE do not give an error when not found. */ static int -compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) +compile_load( + char_u **arg, + char_u *end_arg, + cctx_T *cctx, + int is_expr, + int error) { type_T *type; char_u *name = NULL; @@ -2214,10 +2227,11 @@ compile_load(char_u **arg, char_u *end_a || find_imported(name, 0, cctx) != NULL) res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE); - // When the name starts with an uppercase letter or "x:" it - // can be a user defined function. + // When evaluating an expression and the name starts with an + // uppercase letter or "x:" it can be a user defined function. // TODO: this is just guessing - if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':')) + if (res == FAIL && is_expr + && (ASCII_ISUPPER(*name) || name[1] == ':')) res = generate_funcref(cctx, name); } } @@ -2368,8 +2382,9 @@ compile_call( } // If we can find the function by name generate the right call. + // Skip global functions here, a local funcref takes precedence. ufunc = find_func(name, FALSE, cctx); - if (ufunc != NULL) + if (ufunc != NULL && !func_is_global(ufunc)) { res = generate_CALL(cctx, ufunc, argcount); goto theend; @@ -2380,7 +2395,7 @@ compile_call( // Not for eome#Func(), it will be loaded later. p = namebuf; if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload - && compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) + && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) { garray_T *stack = &cctx->ctx_type_stack; type_T *type; @@ -2390,6 +2405,13 @@ compile_call( goto theend; } + // If we can find a global function by name generate the right call. + if (ufunc != NULL) + { + res = generate_CALL(cctx, ufunc, argcount); + goto theend; + } + // A global function may be defined only later. Need to figure out at // runtime. Also handles a FuncRef at runtime. if (STRNCMP(namebuf, "g:", 2) == 0 || is_autoload) @@ -3548,7 +3570,7 @@ compile_expr7( { if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; - r = compile_load(arg, p, cctx, TRUE); + r = compile_load(arg, p, cctx, TRUE, TRUE); } if (r == FAIL) return FAIL; @@ -5002,6 +5024,11 @@ compile_assignment(char_u *arg, exarg_T : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (lvar != NULL && (is_decl || !has_type)) { + if ((stacktype->tt_type == VAR_FUNC + || stacktype->tt_type == VAR_PARTIAL) + && var_wrong_func_name(name, TRUE)) + goto theend; + if (new_local && !has_type) { if (stacktype->tt_type == VAR_VOID) @@ -5009,12 +5036,6 @@ compile_assignment(char_u *arg, exarg_T emsg(_(e_cannot_use_void_value)); goto theend; } - else if ((stacktype->tt_type == VAR_FUNC - || stacktype->tt_type == VAR_PARTIAL) - && var_wrong_func_name(name, TRUE)) - { - goto theend; - } else { // An empty list or dict has a &t_void member,