Patch 8.2.3314
Problem:    Behavior of exists() in a :def function is unpredictable.
Solution:   Add exists_compiled().
Files:      runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/evalfunc.c,
            src/errors.h, src/vim9compile.c, src/testdir/test_vim9_builtin.vim


*** ../vim-8.2.3313/runtime/doc/eval.txt        2021-07-31 12:43:19.464837526 
+0200
--- runtime/doc/eval.txt        2021-08-08 14:12:05.788745542 +0200
***************
*** 2545,2550 ****
--- 2561,2567 ----
  execute({command})            String  execute {command} and get the output
  exepath({expr})                       String  full path of the command {expr}
  exists({expr})                        Number  |TRUE| if {expr} exists
+ exists_compiled({expr})               Number  |TRUE| if {expr} exists at 
compile time
  exp({expr})                   Float   exponential of {expr}
  expand({expr} [, {nosuf} [, {list}]])
                                any     expand special keywords in {expr}
***************
*** 4421,4426 ****
--- 4446,4455 ----
  exists({expr})        The result is a Number, which is |TRUE| if {expr} is 
defined,
                zero otherwise.
  
+               Note: In a compiled |:def| function the evaluation is done at
+               runtime.  Use `exists_compiled()` to evaluate the expression
+               at compile time.
+ 
                For checking for a supported feature use |has()|.
                For checking if a file exists use |filereadable()|.
  
***************
*** 4508,4515 ****
  
                Can also be used as a |method|: >
                        Varname()->exists()
  
! exp({expr})                                           *exp()*
                Return the exponential of {expr} as a |Float| in the range
                [0, inf].
                {expr} must evaluate to a |Float| or a |Number|.
--- 4539,4561 ----
  
                Can also be used as a |method|: >
                        Varname()->exists()
+ <
+ 
+ exists_compiled({expr})                                               
*exists()*
+               Like `exists()` but evaluated at compile time.  This is useful
+               to skip a block where a function is used that would otherwise
+               give an error: >
+                       if exists_compiled('*ThatFunction')
+                          ThatFunction('works')
+                       endif
+ <             If `exists()` were used then a compilation error would be
+               given if ThatFunction() is not defined.
  
!               {expr} must be a literal string. *E1232*
!               Can only be used in a |:def| function. *E1233*
! 
! 
! exp({expr})                                                   *exp()*
                Return the exponential of {expr} as a |Float| in the range
                [0, inf].
                {expr} must evaluate to a |Float| or a |Number|.
***************
*** 8394,8399 ****
--- 8485,8492 ----
                Lists are represented as Vim |List| type.
                Dictionaries are represented as Vim |Dictionary| type with
                keys converted to strings.
+               Note that in a `:def` function local variables are not visible
+               to {expr}.
  
                Can also be used as a |method|: >
                        GetExpr()->py3eval()
***************
*** 8409,8414 ****
--- 8502,8509 ----
                Lists are represented as Vim |List| type.
                Dictionaries are represented as Vim |Dictionary| type,
                non-string keys result in error.
+               Note that in a `:def` function local variables are not visible
+               to {expr}.
  
                Can also be used as a |method|: >
                        GetExpr()->pyeval()
*** ../vim-8.2.3313/runtime/doc/usr_41.txt      2021-07-26 21:54:00.051491580 
+0200
--- runtime/doc/usr_41.txt      2021-08-08 14:24:42.486586832 +0200
***************
*** 1174,1179 ****
--- 1182,1188 ----
        state()                 get current busy state
        visualmode()            last visual mode used
        exists()                check if a variable, function, etc. exists
+       exists_compiled()       like exists() but check at compile time
        has()                   check if a feature is supported in Vim
        changenr()              return number of most recent change
        cscope_connection()     check if a cscope connection exists
*** ../vim-8.2.3313/src/evalfunc.c      2021-08-06 21:34:34.626972208 +0200
--- src/evalfunc.c      2021-08-08 14:06:52.869871446 +0200
***************
*** 49,54 ****
--- 49,55 ----
  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,1334 ****
--- 1330,1337 ----
                        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,3631 ****
--- 3629,3640 ----
      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
   */
*** ../vim-8.2.3313/src/errors.h        2021-08-05 20:39:59.354053658 +0200
--- src/errors.h        2021-08-08 14:11:59.188767184 +0200
***************
*** 646,648 ****
--- 646,652 ----
        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"));
*** ../vim-8.2.3313/src/vim9compile.c   2021-08-07 18:12:35.495528716 +0200
--- src/vim9compile.c   2021-08-08 14:10:34.985049746 +0200
***************
*** 3415,3423 ****
      int               is_searchpair;
  
      // We can evaluate "has('name')" at compile time.
!     // We can evaluate some "exists()" values at compile time.
      if ((varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
!           || (varlen == 6 && STRNCMP(*arg, "exists", 6) == 0))
      {
        char_u      *s = skipwhite(*arg + varlen + 1);
        typval_T    argvars[2];
--- 3415,3423 ----
      int               is_searchpair;
  
      // We can evaluate "has('name')" at compile time.
!     // We always evaluate "exists_compiled()" at compile time.
      if ((varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
!           || (varlen == 15 && STRNCMP(*arg, "exists_compiled", 6) == 0))
      {
        char_u      *s = skipwhite(*arg + varlen + 1);
        typval_T    argvars[2];
***************
*** 3431,3438 ****
        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))))
        {
            typval_T    *tv = &ppconst->pp_tv[ppconst->pp_used];
  
--- 3431,3437 ----
        s = skipwhite(s);
        if (*s == ')' && argvars[0].v_type == VAR_STRING
               && ((is_has && !dynamic_feature(argvars[0].vval.v_string))
!                   || !is_has))
        {
            typval_T    *tv = &ppconst->pp_tv[ppconst->pp_used];
  
***************
*** 3449,3454 ****
--- 3448,3458 ----
            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)
*** ../vim-8.2.3313/src/testdir/test_vim9_builtin.vim   2021-08-05 
22:48:08.524435481 +0200
--- src/testdir/test_vim9_builtin.vim   2021-08-08 14:23:06.726837390 +0200
***************
*** 793,834 ****
    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')
      if &newoption == 'ok'
      endif
    endif
!   if exists('&newoption')
      if &newoption == 'ok'
      endif
    endif
!   if exists('+tabstop')
      assert_equal(8, &tabstop)
    else
      assert_report('tabstop option not existing?')
    endif
!   if exists('&tabstop')
      assert_equal(8, &tabstop)
    else
      assert_report('tabstop option not existing?')
    endif
  
!   if exists(':DoSomeCommand') >= 2
      DoSomeCommand
    endif
    assert_equal(4, g:didSomeCommand)
!   if exists(':NoSuchCommand') >= 2
      NoSuchCommand
    endif
  
    var found = false
!   if exists('*CheckScriptSuccess')
      found = true
    endif
    assert_true(found)
!   if exists('*NoSuchFunction')
      NoSuchFunction()
    endif
!   if exists('*no_such_function')
      no_such_function()
    endif
  enddef
--- 793,849 ----
    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'))
  
!   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_compiled('&newoption')
      if &newoption == 'ok'
      endif
    endif
!   if exists_compiled('+tabstop')
      assert_equal(8, &tabstop)
    else
      assert_report('tabstop option not existing?')
    endif
!   if exists_compiled('&tabstop')
      assert_equal(8, &tabstop)
    else
      assert_report('tabstop option not existing?')
    endif
  
!   if exists_compiled(':DoSomeCommand') >= 2
      DoSomeCommand
    endif
    assert_equal(4, g:didSomeCommand)
!   if exists_compiled(':NoSuchCommand') >= 2
      NoSuchCommand
    endif
  
    var found = false
!   if exists_compiled('*CheckScriptSuccess')
      found = true
    endif
    assert_true(found)
!   if exists_compiled('*NoSuchFunction')
      NoSuchFunction()
    endif
!   if exists_compiled('*no_such_function')
      no_such_function()
    endif
  enddef
*** ../vim-8.2.3313/src/version.c       2021-08-07 22:35:49.038237945 +0200
--- src/version.c       2021-08-08 14:28:28.978007619 +0200
***************
*** 757,758 ****
--- 757,760 ----
  {   /* Add new patch number below this line */
+ /**/
+     3314,
  /**/

-- 
I'm sure that I asked CBuilder to do a "full" install.  Looks like I got
a "fool" install, instead.              Charles E Campbell, Jr, PhD


 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202108081243.178ChrXb2107491%40masaka.moolenaar.net.

Raspunde prin e-mail lui