]> granicus.if.org Git - vim/commitdiff
patch 8.2.2744: Vim9: no way to explicitly ignore an argument v8.2.2744
authorBram Moolenaar <Bram@vim.org>
Sat, 10 Apr 2021 15:18:09 +0000 (17:18 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 10 Apr 2021 15:18:09 +0000 (17:18 +0200)
Problem:    Vim9: no way to explicitly ignore an argument.
Solution:   Use the underscore as the name for an ignored argument.

runtime/doc/vim9.txt
src/errors.h
src/eval.c
src/evalvars.c
src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c

index e693cba1dfe1a42451e549aee7186e2d5245dbd3..29fdab1488d467dfd908ba5a78c27820976a185e 100644 (file)
@@ -137,18 +137,21 @@ arguments).
 Vim9 functions ~
 
 A function defined with `:def` is compiled.  Execution is many times faster,
-often 10x to 100x times.
+often 10 to 100 times.
 
 Many errors are already found when compiling, before the function is executed.
 The syntax is strict, to enforce code that is easy to read and understand.
 
-Compilation is done when either of these is encountered:
+Compilation is done when any of these is encountered:
 - the first time the function is called
-- when the `:defcompile` command is encountered in the script where the
+- when the `:defcompile` command is encountered in the script after the
   function was defined
 - `:disassemble` is used for the function.
 - a function that is compiled calls the function or uses it as a function
   reference
+                                                       *E1091*
+If compilation fails it is not tried again on the next call, instead this
+error is given: "E1091: Function is not compiled: {name}".
 
 `:def` has no options like `:function` does: "range", "abort", "dict" or
 "closure".  A `:def` function always aborts on an error (unless `:silent!` was
@@ -161,7 +164,7 @@ functions.
 
 Arguments are accessed by name, without "a:", just like any other language.
 There is no "a:" dictionary or "a:000" list.
-
+                                               *vim9-variable-arguments*
 Variable arguments are defined as the last argument, with a name and have a
 list type, similar to TypeScript.  For example, a list of numbers: >
        def MyFunc(...itemlist: list<number>)
@@ -176,6 +179,15 @@ should use its default value.  Example: >
          ...
        enddef
        MyFunc(v:none, 'LAST')  # first argument uses default value 'one'
+<
+                                               *vim9-ignored-argument*
+The argument "_" (an underscore) can be used to ignore the argument.  This is
+most useful in callbacks where you don't need it, but do need to give an
+argument to match the call.  E.g. when using map() two arguments are passed,
+the key and the value, to ignore the key: >
+       map(myList, (_, v) => v * 2)
+There is no error for using the "_" argument multiple times.  No type needs to
+be given.
 
 
 Functions and variables are script-local by default ~
@@ -433,6 +445,15 @@ But you can use a backslash to concatenate the lines before parsing: >
        filter(list, (k,
                \       v)
                \       => v > 0)
+<                                                      *vim9-lambda-arguments*
+In legacy script a lambda could be called with any number of extra arguments,
+there was no way to warn for not using them.  In Vim9 script the number of
+arguments must match.  If you do want to accept any arguments, or any further
+arguments, use "..._", which makes the function accept
+|vim9-variable-arguments|.  Example: >
+       var Callback = (..._) => 'anything'
+       echo Callback(1, 2, 3)  # displays "anything"
+
 <                                                      *inline-function*
 Additionally, a lambda can contain statements in {}: >
        var Lambda = (arg) => {
index e4836bc4acdc962c011eb1efe4266485c0f003f9..d58da735aa3d89f51e020049e566dddb5bb04d57 100644 (file)
@@ -397,3 +397,5 @@ EXTERN char e_failed_to_extract_pwd_from_str_check_your_shell_config[]
        INIT(= N_("E1179: Failed to extract PWD from %s, check your shell's config related to OSC 7"));
 EXTERN char e_variable_arguments_type_must_be_list_str[]
        INIT(= N_("E1180: Variable arguments type must be a list: %s"));
+EXTERN char e_cannot_use_underscore_here[]
+       INIT(= N_("E1181: Cannot use an underscore here"));
index 05b6584424ce216c5eecedda9cc178a736dd0030..fe9d4ec2e4c8c594a3efdae57e7c869492fb111c 100644 (file)
@@ -3514,7 +3514,12 @@ eval7(
        {
            int     flags = evalarg == NULL ? 0 : evalarg->eval_flags;
 
-           if ((in_vim9script() ? **arg : *skipwhite(*arg)) == '(')
+           if (in_vim9script() && len == 1 && *s == '_')
+           {
+               emsg(_(e_cannot_use_underscore_here));
+               ret = FAIL;
+           }
+           else if ((in_vim9script() ? **arg : *skipwhite(*arg)) == '(')
            {
                // "name(..."  recursive!
                *arg = skipwhite(*arg);
index 67abdcb1d57507a53c6d85c47a564aef7597697f..5869a82a61ab271c83caafc71e11caec1453200f 100644 (file)
@@ -3188,6 +3188,11 @@ set_var_const(
        goto failed;
     }
     var_in_vim9script = is_script_local && current_script_is_vim9();
+    if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
+    {
+       emsg(_(e_cannot_use_underscore_here));
+       goto failed;
+    }
 
     di = find_var_in_ht(ht, 0, varname, TRUE);
 
index e254f44b73ad71c0a0c660fae63b7b80c15c9722..c02a324d4c0a511f927bf12bcd068e9e3950d816 100644 (file)
@@ -2619,6 +2619,41 @@ def Test_compile_error()
   delfunc g:Broken
 enddef
 
+def Test_ignored_argument()
+  var lines =<< trim END
+      vim9script
+      def Ignore(_, _): string
+        return 'yes'
+      enddef
+      assert_equal('yes', Ignore(1, 2))
+
+      func Ok(_)
+        return a:_
+      endfunc
+      assert_equal('ok', Ok('ok'))
+
+      func Oktoo()
+        let _ = 'too'
+        return _
+      endfunc
+      assert_equal('too', Oktoo())
+  END
+  CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      def Ignore(_: string): string
+        return _
+      enddef
+      defcompile
+  END
+  CheckScriptFailure(lines, 'E1181:', 1)
+
+  lines =<< trim END
+      var _ = 1
+  END
+  CheckDefAndScriptFailure(lines, 'E1181:', 1)
+enddef
+
 
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index a22312a1518f729540967e4a88505758ad1bd2ac..d5a9dc7968a785760f2a0352b39ee6fb5a9b9e64 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2744,
 /**/
     2743,
 /**/
index e5e3068d5c9beba25bb603c09b753ed6152efd2f..b005ff23657c3093e20e398adddca23b087e4516 100644 (file)
@@ -4416,6 +4416,12 @@ compile_expr7(
 
        // "name" or "name()"
        p = to_name_end(*arg, TRUE);
+       if (p - *arg == (size_t)1 && **arg == '_')
+       {
+           emsg(_(e_cannot_use_underscore_here));
+           return FAIL;
+       }
+
        if (*p == '(')
        {
            r = compile_call(arg, p - *arg, cctx, ppconst, 0);
@@ -6378,6 +6384,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            semsg(_(e_cannot_assign_to_constant), lhs.lhs_name);
            goto theend;
        }
+       if (is_decl && lhs.lhs_name[0] == '_' && lhs.lhs_name[1] == NUL)
+       {
+           emsg(_(e_cannot_use_underscore_here));
+           goto theend;
+       }
 
        if (!heredoc)
        {