Patch 8.2.2864
Problem:    Vim9: crash when using inline function.
Solution:   Check for NULL pointer. Make using inline function work inside
            lambda. (closes #8217)
Files:      src/userfunc.c, src/testdir/test_vim9_func.vim


*** ../vim-8.2.2863/src/userfunc.c      2021-04-14 17:06:39.924955017 +0200
--- src/userfunc.c      2021-05-18 00:41:41.049212208 +0200
***************
*** 606,611 ****
--- 606,612 ----
  
  /*
   * Read the body of a function, put every line in "newlines".
+  * This stops at "}", "endfunction" or "enddef".
   * "newlines" must already have been initialized.
   * "eap->cmdidx" is CMD_function, CMD_def or CMD_block;
   */
***************
*** 945,953 ****
            line_arg = NULL;
      }
  
!     // Don't define the function when skipping commands or when an error was
!     // detected.
!     if (!eap->skip && !did_emsg)
        ret = OK;
  
  theend:
--- 946,953 ----
            line_arg = NULL;
      }
  
!     // Return OK when no error was detected.
!     if (!did_emsg)
        ret = OK;
  
  theend:
***************
*** 960,965 ****
--- 960,966 ----
  /*
   * Handle the body of a lambda.  *arg points to the "{", process statements
   * until the matching "}".
+  * When not evaluating "newargs" is NULL.
   * When successful "rettv" is set to a funcref.
   */
      static int
***************
*** 974,979 ****
--- 975,981 ----
        char_u      *ret_type)
  {
      int               evaluate = (evalarg->eval_flags & EVAL_EVALUATE);
+     garray_T  *gap = &evalarg->eval_ga;
      ufunc_T   *ufunc = NULL;
      exarg_T   eap;
      garray_T  newlines;
***************
*** 1010,1015 ****
--- 1012,1063 ----
        vim_free(cmdline);
        goto erret;
      }
+ 
+     // When inside a lambda must add the function lines to evalarg.eval_ga.
+     evalarg->eval_break_count += newlines.ga_len;
+     if (gap->ga_itemsize > 0)
+     {
+       int     idx;
+       char_u  *last;
+       size_t  plen;
+       char_u  *pnl;
+ 
+       for (idx = 0; idx < newlines.ga_len; ++idx)
+       {
+           char_u  *p = skipwhite(((char_u **)newlines.ga_data)[idx]);
+ 
+           if (ga_grow(gap, 1) == FAIL)
+               goto erret;
+ 
+           // Going to concatenate the lines after parsing.  For an empty or
+           // comment line use an empty string.
+           // Insert NL characters at the start of each line, the string will
+           // be split again later in .get_lambda_tv().
+           if (*p == NUL || vim9_comment_start(p))
+               p = (char_u *)"";
+           plen = STRLEN(p);
+           pnl = vim_strnsave((char_u *)"\n", plen + 1);
+           if (pnl != NULL)
+               mch_memmove(pnl + 1, p, plen + 1);
+           ((char_u **)gap->ga_data)[gap->ga_len] = pnl;
+           ++gap->ga_len;
+       }
+       if (ga_grow(gap, 1) == FAIL)
+           goto erret;
+       if (cmdline != NULL)
+           // more is following after the "}", which was skipped
+           last = cmdline;
+       else
+           // nothing is following the "}"
+           last = (char_u *)"}";
+       plen = STRLEN(last);
+       pnl = vim_strnsave((char_u *)"\n", plen + 1);
+       if (pnl != NULL)
+           mch_memmove(pnl + 1, last, plen + 1);
+       ((char_u **)gap->ga_data)[gap->ga_len] = pnl;
+       ++gap->ga_len;
+     }
+ 
      if (cmdline != NULL)
      {
        // Something comes after the "}".
***************
*** 1022,1027 ****
--- 1070,1081 ----
      else
        *arg = (char_u *)"";
  
+     if (!evaluate)
+     {
+       ret = OK;
+       goto erret;
+     }
+ 
      name = get_lambda_name();
      ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
      if (ufunc == NULL)
***************
*** 1078,1084 ****
        SOURCING_LNUM = lnum_save;
      vim_free(line_to_free);
      ga_clear_strings(&newlines);
!     ga_clear_strings(newargs);
      ga_clear_strings(default_args);
      if (ufunc != NULL)
      {
--- 1132,1139 ----
        SOURCING_LNUM = lnum_save;
      vim_free(line_to_free);
      ga_clear_strings(&newlines);
!     if (newargs != NULL)
!       ga_clear_strings(newargs);
      ga_clear_strings(default_args);
      if (ufunc != NULL)
      {
***************
*** 1222,1227 ****
--- 1277,1283 ----
        int         len;
        int         flags = 0;
        char_u      *p;
+       char_u      *line_end;
        char_u      *name = get_lambda_name();
  
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
***************
*** 1236,1249 ****
        if (ga_grow(&newlines, 1) == FAIL)
            goto errret;
  
!       // Add "return " before the expression.
!       len = 7 + (int)(end - start) + 1;
        p = alloc(len);
        if (p == NULL)
            goto errret;
        ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
        STRCPY(p, "return ");
!       vim_strncpy(p + 7, start, end - start);
        if (strstr((char *)p + 7, "a:") == NULL)
            // No a: variables are used for sure.
            flags |= FC_NOARGS;
--- 1292,1328 ----
        if (ga_grow(&newlines, 1) == FAIL)
            goto errret;
  
!       // If there are line breaks, we need to split up the string.
!       line_end = vim_strchr(start, '\n');
!       if (line_end == NULL)
!           line_end = end;
! 
!       // Add "return " before the expression (or the first line).
!       len = 7 + (int)(line_end - start) + 1;
        p = alloc(len);
        if (p == NULL)
            goto errret;
        ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
        STRCPY(p, "return ");
!       vim_strncpy(p + 7, start, line_end - start);
! 
!       if (line_end != end)
!       {
!           // Add more lines, split by line breaks.  Thus is used when a
!           // lambda with { cmds } is encountered.
!           while (*line_end == '\n')
!           {
!               if (ga_grow(&newlines, 1) == FAIL)
!                   goto errret;
!               start = line_end + 1;
!               line_end = vim_strchr(start, '\n');
!               if (line_end == NULL)
!                   line_end = end;
!               ((char_u **)(newlines.ga_data))[newlines.ga_len++] =
!                                        vim_strnsave(start, line_end - start);
!           }
!       }
! 
        if (strstr((char *)p + 7, "a:") == NULL)
            // No a: variables are used for sure.
            flags |= FC_NOARGS;
*** ../vim-8.2.2863/src/testdir/test_vim9_func.vim      2021-04-28 
20:40:39.799852470 +0200
--- src/testdir/test_vim9_func.vim      2021-05-18 11:46:35.848516324 +0200
***************
*** 2102,2107 ****
--- 2102,2121 ----
    CheckScriptSuccess(lines)
  enddef
  
+ def Test_nested_inline_lambda()
+   # TODO: use the "text" argument
+   var lines =<< trim END
+       vim9script
+       def F(text: string): func(string): func(string): string
+         return (arg: string): func(string): string => ((sep: string): string 
=> {
+             return sep .. arg
+           })
+       enddef
+       assert_equal('--there', F('unused')('there')('--'))
+   END
+   CheckScriptSuccess(lines)
+ enddef
+ 
  def Shadowed(): list<number>
    var FuncList: list<func: number> = [() => 42]
    return FuncList->mapnew((_, Shadowed) => Shadowed())
*** ../vim-8.2.2863/src/version.c       2021-05-17 00:22:01.993641079 +0200
--- src/version.c       2021-05-17 15:52:31.845575800 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2864,
  /**/

-- 
"Intelligence has much less practical application than you'd think."
                  -- Scott Adams, Dilbert.

 /// 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/202105180948.14I9mgu04020439%40masaka.moolenaar.net.

Raspunde prin e-mail lui