diff options
author | Bram Moolenaar <Bram@vim.org> | 2021-08-08 14:43:22 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-08-08 14:43:22 +0200 |
commit | 267359902c8792fed13543ddeb56c6df0ae74957 (patch) | |
tree | 6bc6795fb6eb8d7be15bd5d5799218d5ccc12773 /src | |
parent | 9e2fa4bb9eb40a78a1ae1f67a4064651b5ce0aac (diff) | |
download | vim-git-267359902c8792fed13543ddeb56c6df0ae74957.tar.gz |
patch 8.2.3314: behavior of exists() in a :def function is unpredictablev8.2.3314
Problem: Behavior of exists() in a :def function is unpredictable.
Solution: Add exists_compiled().
Diffstat (limited to 'src')
-rw-r--r-- | src/errors.h | 4 | ||||
-rw-r--r-- | src/evalfunc.c | 9 | ||||
-rw-r--r-- | src/testdir/test_vim9_builtin.vim | 33 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 12 |
5 files changed, 47 insertions, 13 deletions
diff --git a/src/errors.h b/src/errors.h index 24420e43e..3b15d105f 100644 --- a/src/errors.h +++ b/src/errors.h @@ -646,3 +646,7 @@ EXTERN char e_encryption_sodium_mlock_failed[] INIT(= N_("E1230: Encryption: sodium_mlock() failed")); EXTERN char e_cannot_use_bar_to_separate_commands_here_str[] INIT(= N_("E1231: Cannot use a bar to separate commands here: %s")); +EXTERN char e_argument_of_exists_compiled_must_be_literal_string[] + INIT(= N_("E1232: Argument of exists_compiled() must be a literal string")); +EXTERN char e_exists_compiled_can_only_be_used_in_def_function[] + INIT(= N_("E1233: exists_compiled() can only be used in a :def function")); diff --git a/src/evalfunc.c b/src/evalfunc.c index 7006afa49..95ae211ee 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -49,6 +49,7 @@ static void f_escape(typval_T *argvars, typval_T *rettv); static void f_eval(typval_T *argvars, typval_T *rettv); static void f_eventhandler(typval_T *argvars, typval_T *rettv); static void f_execute(typval_T *argvars, typval_T *rettv); +static void f_exists_compiled(typval_T *argvars, typval_T *rettv); static void f_expand(typval_T *argvars, typval_T *rettv); static void f_expandcmd(typval_T *argvars, typval_T *rettv); static void f_feedkeys(typval_T *argvars, typval_T *rettv); @@ -1329,6 +1330,8 @@ static funcentry_T global_functions[] = ret_string, f_exepath}, {"exists", 1, 1, FEARG_1, arg1_string, ret_number_bool, f_exists}, + {"exists_compiled", 1, 1, FEARG_1, arg1_string, + ret_number_bool, f_exists_compiled}, {"exp", 1, 1, FEARG_1, arg1_float_or_nr, ret_float, FLOAT_FUNC(f_exp)}, {"expand", 1, 3, FEARG_1, arg3_string_bool_bool, @@ -3626,6 +3629,12 @@ f_exists(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = n; } + static void +f_exists_compiled(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + emsg(_(e_exists_compiled_can_only_be_used_in_def_function)); +} + /* * "expand()" function */ diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 4fb1df342..6ca6c7b0c 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -793,42 +793,57 @@ def Test_exists() CheckDefAndScriptFailure2(['exists(10)'], 'E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1') call assert_equal(1, exists('&tabstop')) - if exists('+newoption') + var lines =<< trim END + if exists('+newoption') + if &newoption == 'ok' + endif + endif + END + CheckDefFailure(lines, 'E113:') + CheckScriptSuccess(lines) +enddef + +def Test_exists_compiled() + call assert_equal(1, exists_compiled('&tabstop')) + CheckDefAndScriptFailure2(['exists_compiled(10)'], 'E1232:', 'E1233:') + CheckDefAndScriptFailure2(['exists_compiled(v:progname)'], 'E1232:', 'E1233:') + + if exists_compiled('+newoption') if &newoption == 'ok' endif endif - if exists('&newoption') + if exists_compiled('&newoption') if &newoption == 'ok' endif endif - if exists('+tabstop') + if exists_compiled('+tabstop') assert_equal(8, &tabstop) else assert_report('tabstop option not existing?') endif - if exists('&tabstop') + if exists_compiled('&tabstop') assert_equal(8, &tabstop) else assert_report('tabstop option not existing?') endif - if exists(':DoSomeCommand') >= 2 + if exists_compiled(':DoSomeCommand') >= 2 DoSomeCommand endif assert_equal(4, g:didSomeCommand) - if exists(':NoSuchCommand') >= 2 + if exists_compiled(':NoSuchCommand') >= 2 NoSuchCommand endif var found = false - if exists('*CheckScriptSuccess') + if exists_compiled('*CheckScriptSuccess') found = true endif assert_true(found) - if exists('*NoSuchFunction') + if exists_compiled('*NoSuchFunction') NoSuchFunction() endif - if exists('*no_such_function') + if exists_compiled('*no_such_function') no_such_function() endif enddef diff --git a/src/version.c b/src/version.c index db75af720..06c89b32d 100644 --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3314, +/**/ 3313, /**/ 3312, diff --git a/src/vim9compile.c b/src/vim9compile.c index 5effa5c71..c08aad634 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3415,9 +3415,9 @@ compile_call( int is_searchpair; // We can evaluate "has('name')" at compile time. - // We can evaluate some "exists()" values at compile time. + // We always evaluate "exists_compiled()" at compile time. if ((varlen == 3 && STRNCMP(*arg, "has", 3) == 0) - || (varlen == 6 && STRNCMP(*arg, "exists", 6) == 0)) + || (varlen == 15 && STRNCMP(*arg, "exists_compiled", 6) == 0)) { char_u *s = skipwhite(*arg + varlen + 1); typval_T argvars[2]; @@ -3431,8 +3431,7 @@ compile_call( s = skipwhite(s); if (*s == ')' && argvars[0].v_type == VAR_STRING && ((is_has && !dynamic_feature(argvars[0].vval.v_string)) - || (!is_has && vim_strchr((char_u *)"+&:*", - *argvars[0].vval.v_string)))) + || !is_has)) { typval_T *tv = &ppconst->pp_tv[ppconst->pp_used]; @@ -3449,6 +3448,11 @@ compile_call( return OK; } clear_tv(&argvars[0]); + if (!is_has) + { + emsg(_(e_argument_of_exists_compiled_must_be_literal_string)); + return FAIL; + } } if (generate_ppconst(cctx, ppconst) == FAIL) |