summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-08-08 14:43:22 +0200
committerBram Moolenaar <Bram@vim.org>2021-08-08 14:43:22 +0200
commit267359902c8792fed13543ddeb56c6df0ae74957 (patch)
tree6bc6795fb6eb8d7be15bd5d5799218d5ccc12773 /src
parent9e2fa4bb9eb40a78a1ae1f67a4064651b5ce0aac (diff)
downloadvim-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.h4
-rw-r--r--src/evalfunc.c9
-rw-r--r--src/testdir/test_vim9_builtin.vim33
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c12
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)