Patch 8.2.2131
Problem:    Vim9: crash when lambda uses same var as assignment.
Solution:   Do not let lookup_local change lv_from_outer, make a copy.
            (closes #7461)
Files:      src/vim9compile.c, src/ex_docmd.c, src/proto/ex_docmd.pro,
            src/evalvars.c, src/proto/evalvars.pro,
            src/testdir/test_vim9_func.vim


*** ../vim-8.2.2130/src/vim9compile.c   2020-12-10 19:43:36.629155311 +0100
--- src/vim9compile.c   2020-12-12 14:29:49.549661501 +0100
***************
*** 148,192 ****
  static void delete_def_function_contents(dfunc_T *dfunc);
  
  /*
!  * Lookup variable "name" in the local scope and return it.
!  * Return NULL if not found.
   */
!     static lvar_T *
! lookup_local(char_u *name, size_t len, cctx_T *cctx)
  {
      int           idx;
!     lvar_T  *lvar;
  
      if (len == 0)
!       return NULL;
  
      // Find local in current function scope.
      for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
      {
!       lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
!       if (STRNCMP(name, lvar->lv_name, len) == 0
!                                              && STRLEN(lvar->lv_name) == len)
        {
!           lvar->lv_from_outer = FALSE;
!           return lvar;
        }
      }
  
      // Find local in outer function scope.
      if (cctx->ctx_outer != NULL)
      {
!       lvar = lookup_local(name, len, cctx->ctx_outer);
!       if (lvar != NULL)
        {
!           // TODO: are there situations we should not mark the outer scope as
!           // used?
!           cctx->ctx_outer_used = TRUE;
!           lvar->lv_from_outer = TRUE;
!           return lvar;
        }
      }
  
!     return NULL;
  }
  
  /*
--- 148,198 ----
  static void delete_def_function_contents(dfunc_T *dfunc);
  
  /*
!  * Lookup variable "name" in the local scope and return it in "lvar".
!  * "lvar->lv_from_outer" is set accordingly.
!  * If "lvar" is NULL only check if the variable can be found.
!  * Return FAIL if not found.
   */
!     static int
! lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
  {
      int           idx;
!     lvar_T  *lvp;
  
      if (len == 0)
!       return FAIL;
  
      // Find local in current function scope.
      for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
      {
!       lvp = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
!       if (STRNCMP(name, lvp->lv_name, len) == 0
!                                              && STRLEN(lvp->lv_name) == len)
        {
!           if (lvar != NULL)
!           {
!               *lvar = *lvp;
!               lvar->lv_from_outer = FALSE;
!           }
!           return OK;
        }
      }
  
      // Find local in outer function scope.
      if (cctx->ctx_outer != NULL)
      {
!       if (lookup_local(name, len, lvar, cctx->ctx_outer) == OK)
        {
!           if (lvar != NULL)
!           {
!               cctx->ctx_outer_used = TRUE;
!               lvar->lv_from_outer = TRUE;
!           }
!           return OK;
        }
      }
  
!     return FAIL;
  }
  
  /*
***************
*** 377,383 ****
      p[len] = NUL;
      if (script_var_exists(p, len, FALSE, cctx) == OK
            || (cctx != NULL
!               && (lookup_local(p, len, cctx) != NULL
                    || arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
            || find_imported(p, len, cctx) != NULL
            || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
--- 383,389 ----
      p[len] = NUL;
      if (script_var_exists(p, len, FALSE, cctx) == OK
            || (cctx != NULL
!               && (lookup_local(p, len, NULL, cctx) == OK
                    || arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
            || find_imported(p, len, cctx) != NULL
            || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
***************
*** 2555,2567 ****
        }
        else
        {
!           lvar_T *lvar = lookup_local(*arg, len, cctx);
  
!           if (lvar != NULL)
            {
!               type = lvar->lv_type;
!               idx = lvar->lv_idx;
!               if (lvar->lv_from_outer)
                    gen_load_outer = TRUE;
                else
                    gen_load = TRUE;
--- 2561,2573 ----
        }
        else
        {
!           lvar_T lvar;
  
!           if (lookup_local(*arg, len, &lvar, cctx) == OK)
            {
!               type = lvar.lv_type;
!               idx = lvar.lv_idx;
!               if (lvar.lv_from_outer)
                    gen_load_outer = TRUE;
                else
                    gen_load = TRUE;
***************
*** 2763,2769 ****
  
      // An argument or local variable can be a function reference, this
      // overrules a function name.
!     if (lookup_local(namebuf, varlen, cctx) == NULL
            && arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
      {
        // If we can find the function by name generate the right call.
--- 2769,2775 ----
  
      // An argument or local variable can be a function reference, this
      // overrules a function name.
!     if (lookup_local(namebuf, varlen, NULL, cctx) == FAIL
            && arg_exists(namebuf, varlen, NULL, NULL, NULL, cctx) != OK)
      {
        // If we can find the function by name generate the right call.
***************
*** 5366,5371 ****
--- 5372,5378 ----
        assign_dest_T   dest = dest_local;
        int             opt_flags = 0;
        int             vimvaridx = -1;
+       lvar_T          local_lvar;
        lvar_T          *lvar = NULL;
        lvar_T          arg_lvar;
        int             has_type = FALSE;
***************
*** 5424,5431 ****
                        goto theend;
                    }
  
!               lvar = lookup_local(var_start, varlen, cctx);
!               if (lvar == NULL)
                {
                    CLEAR_FIELD(arg_lvar);
                    if (arg_exists(var_start, varlen,
--- 5431,5440 ----
                        goto theend;
                    }
  
! 
!               if (lookup_local(var_start, varlen, &local_lvar, cctx) == OK)
!                   lvar = &local_lvar;
!               else
                {
                    CLEAR_FIELD(arg_lvar);
                    if (arg_exists(var_start, varlen,
***************
*** 6579,6586 ****
        }
        else
        {
!           var_lvar = lookup_local(arg, varlen, cctx);
!           if (var_lvar != NULL)
            {
                semsg(_(e_variable_already_declared), arg);
                goto failed;
--- 6588,6594 ----
        }
        else
        {
!           if (lookup_local(arg, varlen, NULL, cctx) == OK)
            {
                semsg(_(e_variable_already_declared), arg);
                goto failed;
***************
*** 7584,7590 ****
                            || *ea.cmd == '$'
                            || *ea.cmd == '@'
                            || ((len) > 2 && ea.cmd[1] == ':')
!                           || lookup_local(ea.cmd, len, &cctx) != NULL
                            || arg_exists(ea.cmd, len, NULL, NULL,
                                                             NULL, &cctx) == OK
                            || script_var_exists(ea.cmd, len,
--- 7592,7598 ----
                            || *ea.cmd == '$'
                            || *ea.cmd == '@'
                            || ((len) > 2 && ea.cmd[1] == ':')
!                           || lookup_local(ea.cmd, len, NULL, &cctx) == OK
                            || arg_exists(ea.cmd, len, NULL, NULL,
                                                             NULL, &cctx) == OK
                            || script_var_exists(ea.cmd, len,
***************
*** 7637,7643 ****
            }
        }
        p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
!                  : (void *(*)(char_u *, size_t, cctx_T *))lookup_local,
                                                                        &cctx);
  
        if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
--- 7645,7651 ----
            }
        }
        p = find_ex_command(&ea, NULL, starts_with_colon ? NULL
!                  : (int (*)(char_u *, size_t, void *, cctx_T *))lookup_local,
                                                                        &cctx);
  
        if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
*** ../vim-8.2.2130/src/ex_docmd.c      2020-12-11 19:30:26.789393285 +0100
--- src/ex_docmd.c      2020-12-12 14:06:22.938573143 +0100
***************
*** 3271,3277 ****
  find_ex_command(
        exarg_T *eap,
        int     *full UNUSED,
!       void    *(*lookup)(char_u *, size_t, cctx_T *) UNUSED,
        cctx_T  *cctx UNUSED)
  {
      int               len;
--- 3271,3277 ----
  find_ex_command(
        exarg_T *eap,
        int     *full UNUSED,
!       int     (*lookup)(char_u *, size_t, void *, cctx_T *) UNUSED,
        cctx_T  *cctx UNUSED)
  {
      int               len;
***************
*** 3387,3393 ****
                        || *eap->cmd == '&'
                        || *eap->cmd == '$'
                        || *eap->cmd == '@'
!                       || lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
                {
                    eap->cmdidx = CMD_var;
                    return eap->cmd;
--- 3387,3393 ----
                        || *eap->cmd == '&'
                        || *eap->cmd == '$'
                        || *eap->cmd == '@'
!                       || lookup(eap->cmd, p - eap->cmd, NULL, cctx) == OK)
                {
                    eap->cmdidx = CMD_var;
                    return eap->cmd;
*** ../vim-8.2.2130/src/proto/ex_docmd.pro      2020-11-25 20:09:05.509445589 
+0100
--- src/proto/ex_docmd.pro      2020-12-12 14:07:13.978369210 +0100
***************
*** 13,19 ****
  int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
  int checkforcmd(char_u **pp, char *cmd, int len);
  char_u *skip_option_env_lead(char_u *start);
! char_u *find_ex_command(exarg_T *eap, int *full, void *(*lookup)(char_u *, 
size_t, cctx_T *), cctx_T *cctx);
  int modifier_len(char_u *cmd);
  int cmd_exists(char_u *name);
  cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
--- 13,19 ----
  int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
  int checkforcmd(char_u **pp, char *cmd, int len);
  char_u *skip_option_env_lead(char_u *start);
! char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, 
size_t, void *, cctx_T *), cctx_T *cctx);
  int modifier_len(char_u *cmd);
  int cmd_exists(char_u *name);
  cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
*** ../vim-8.2.2130/src/evalvars.c      2020-11-30 17:40:41.299714396 +0100
--- src/evalvars.c      2020-12-12 14:22:52.263035573 +0100
***************
*** 2721,2739 ****
  
  /*
   * Look for "name[len]" in script-local variables.
!  * Return a non-NULL pointer when found, NULL when not found.
   */
!     void *
! lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
  {
      hashtab_T *ht = get_script_local_ht();
      char_u    buffer[30];
      char_u    *p;
!     void      *res;
      hashitem_T        *hi;
  
      if (ht == NULL)
!       return NULL;
      if (len < sizeof(buffer) - 1)
      {
        // avoid an alloc/free for short names
--- 2721,2743 ----
  
  /*
   * Look for "name[len]" in script-local variables.
!  * Return OK when found, FAIL when not found.
   */
!     int
! lookup_scriptvar(
!       char_u  *name,
!       size_t  len,
!       void    *lvar UNUSED,
!       cctx_T  *dummy UNUSED)
  {
      hashtab_T *ht = get_script_local_ht();
      char_u    buffer[30];
      char_u    *p;
!     int               res;
      hashitem_T        *hi;
  
      if (ht == NULL)
!       return FAIL;
      if (len < sizeof(buffer) - 1)
      {
        // avoid an alloc/free for short names
***************
*** 2744,2763 ****
      {
        p = vim_strnsave(name, len);
        if (p == NULL)
!           return NULL;
      }
  
      hi = hash_find(ht, p);
!     res = HASHITEM_EMPTY(hi) ? NULL : hi;
  
      // if not script-local, then perhaps imported
!     if (res == NULL && find_imported(p, 0, NULL) != NULL)
!       res = p;
  
      if (p != buffer)
        vim_free(p);
!     // Don't return "buffer", gcc complains.
!     return res == NULL ? NULL : IObuff;
  }
  
  /*
--- 2748,2766 ----
      {
        p = vim_strnsave(name, len);
        if (p == NULL)
!           return FAIL;
      }
  
      hi = hash_find(ht, p);
!     res = HASHITEM_EMPTY(hi) ? FAIL : OK;
  
      // if not script-local, then perhaps imported
!     if (res == FAIL && find_imported(p, 0, NULL) != NULL)
!       res = OK;
  
      if (p != buffer)
        vim_free(p);
!     return res;
  }
  
  /*
*** ../vim-8.2.2130/src/proto/evalvars.pro      2020-10-10 19:07:04.187713866 
+0200
--- src/proto/evalvars.pro      2020-12-12 14:10:23.613642282 +0100
***************
*** 59,65 ****
  dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
  dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
  hashtab_T *get_script_local_ht(void);
! void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
  hashtab_T *find_var_ht(char_u *name, char_u **varname);
  char_u *get_var_value(char_u *name);
  void new_script_vars(scid_T id);
--- 59,65 ----
  dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
  dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
  hashtab_T *get_script_local_ht(void);
! int lookup_scriptvar(char_u *name, size_t len, void *lvar, cctx_T *dummy);
  hashtab_T *find_var_ht(char_u *name, char_u **varname);
  char_u *get_var_value(char_u *name);
  void new_script_vars(scid_T id);
*** ../vim-8.2.2130/src/testdir/test_vim9_func.vim      2020-12-06 
18:50:32.946220039 +0100
--- src/testdir/test_vim9_func.vim      2020-12-12 14:14:23.232774089 +0100
***************
*** 481,486 ****
--- 481,492 ----
    CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number 
but got string')
  enddef
  
+ def Test_lambda_uses_assigned_var()
+   CheckDefSuccess([
+         'var x: any = "aaa"'
+         'x = filter(["bbb"], {_, v -> v =~ x})'])
+ enddef
+ 
  " Default arg and varargs
  def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
    var res = one .. ',' .. two
*** ../vim-8.2.2130/src/version.c       2020-12-12 13:31:51.277403018 +0100
--- src/version.c       2020-12-12 14:28:18.697958507 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2131,
  /**/

-- 
Communication is one of the most compli..., eh, well, it's hard.
You know what I mean.  Not?

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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/202012121334.0BCDYeMW2786324%40masaka.moolenaar.net.

Raspunde prin e-mail lui