Patch 8.2.1001
Problem:    Vim9: crash with nested "if" and assignment.
Solution:   Skip more of the assignment.  Do not set ctx_skip when code is
            reachable.
Files:      src/vim9compile.c, src/testdir/test_vim9_script.vim


*** ../vim-8.2.1000/src/vim9compile.c   2020-06-16 11:34:38.314223444 +0200
--- src/vim9compile.c   2020-06-18 18:13:43.064410926 +0200
***************
*** 5067,5074 ****
  
        if (!heredoc)
        {
!           if (oplen > 0)
            {
                // For "var = expr" evaluate the expression.
                if (var_count == 0)
                {
--- 5067,5085 ----
  
        if (!heredoc)
        {
!           if (cctx->ctx_skip == TRUE)
            {
+               if (oplen > 0 && var_count == 0)
+               {
+                   // skip over the "=" and the expression
+                   p = skipwhite(op + oplen);
+                   compile_expr0(&p, cctx);
+               }
+           }
+           else if (oplen > 0)
+           {
+               type_T  *stacktype;
+ 
                // For "var = expr" evaluate the expression.
                if (var_count == 0)
                {
***************
*** 5113,5164 ****
                        return FAIL;
                }
  
!               if (cctx->ctx_skip != TRUE)
                {
!                   type_T      *stacktype;
! 
!                   stacktype = stack->ga_len == 0 ? &t_void
!                             : ((type_T **)stack->ga_data)[stack->ga_len - 1];
!                   if (lvar != NULL && (is_decl || !has_type))
                    {
!                       if (new_local && !has_type)
                        {
!                           if (stacktype->tt_type == VAR_VOID)
!                           {
!                               emsg(_(e_cannot_use_void));
!                               goto theend;
!                           }
!                           else
!                           {
!                               // An empty list or dict has a &t_void member,
!                               // for a variable that implies &t_any.
!                               if (stacktype == &t_list_empty)
!                                   lvar->lv_type = &t_list_any;
!                               else if (stacktype == &t_dict_empty)
!                                   lvar->lv_type = &t_dict_any;
!                               else
!                                   lvar->lv_type = stacktype;
!                           }
                        }
                        else
                        {
!                           type_T *use_type = lvar->lv_type;
  
!                           if (has_index)
!                           {
!                               use_type = use_type->tt_member;
!                               if (use_type == NULL)
!                                   use_type = &t_void;
!                           }
!                           if (need_type(stacktype, use_type, -1, cctx)
!                                                                      == FAIL)
!                               goto theend;
                        }
                    }
-                   else if (*p != '=' && need_type(stacktype, member_type, -1,
-                                                                cctx) == FAIL)
-                       goto theend;
                }
            }
            else if (cmdidx == CMD_const)
            {
--- 5124,5170 ----
                        return FAIL;
                }
  
!               stacktype = stack->ga_len == 0 ? &t_void
!                         : ((type_T **)stack->ga_data)[stack->ga_len - 1];
!               if (lvar != NULL && (is_decl || !has_type))
                {
!                   if (new_local && !has_type)
                    {
!                       if (stacktype->tt_type == VAR_VOID)
                        {
!                           emsg(_(e_cannot_use_void));
!                           goto theend;
                        }
                        else
                        {
!                           // An empty list or dict has a &t_void member,
!                           // for a variable that implies &t_any.
!                           if (stacktype == &t_list_empty)
!                               lvar->lv_type = &t_list_any;
!                           else if (stacktype == &t_dict_empty)
!                               lvar->lv_type = &t_dict_any;
!                           else
!                               lvar->lv_type = stacktype;
!                       }
!                   }
!                   else
!                   {
!                       type_T *use_type = lvar->lv_type;
  
!                       if (has_index)
!                       {
!                           use_type = use_type->tt_member;
!                           if (use_type == NULL)
!                               use_type = &t_void;
                        }
+                       if (need_type(stacktype, use_type, -1, cctx)
+                                                                  == FAIL)
+                           goto theend;
                    }
                }
+               else if (*p != '=' && need_type(stacktype, member_type, -1,
+                                                            cctx) == FAIL)
+                   goto theend;
            }
            else if (cmdidx == CMD_const)
            {
***************
*** 5220,5225 ****
--- 5226,5235 ----
                end = p;
        }
  
+       // no need to parse more when skipping
+       if (cctx->ctx_skip == TRUE)
+           break;
+ 
        if (oplen > 0 && *op != '=')
        {
            type_T          *expected = &t_number;
***************
*** 5806,5812 ****
      }
      // Fill in the "end" label in jumps at the end of the blocks.
      compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
!     cctx->ctx_skip = FALSE;
  
      drop_scope(cctx);
      return arg;
--- 5816,5823 ----
      }
      // Fill in the "end" label in jumps at the end of the blocks.
      compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
!     // TODO: this should restore the value from before the :if
!     cctx->ctx_skip = MAYBE;
  
      drop_scope(cctx);
      return arg;
*** ../vim-8.2.1000/src/testdir/test_vim9_script.vim    2020-06-17 
20:03:33.150287410 +0200
--- src/testdir/test_vim9_script.vim    2020-06-18 17:55:39.971828998 +0200
***************
*** 1162,1167 ****
--- 1162,1187 ----
    call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
  enddef
  
+ def RunNested(i: number): number
+   let x: number = 0
+   if i % 2
+     if 1
+       " comment
+     else
+       " comment
+     endif
+     x += 1
+   else
+     x += 1000
+   endif
+   return x
+ enddef
+ 
+ def Test_nested_if()
+   assert_equal(1, RunNested(1))
+   assert_equal(1000, RunNested(2))
+ enddef
+ 
  def Test_execute_cmd()
    new
    setline(1, 'default')
*** ../vim-8.2.1000/src/version.c       2020-06-18 17:28:36.857031469 +0200
--- src/version.c       2020-06-18 18:20:54.656037243 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1001,
  /**/

-- 
MESKIMEN'S LAW
    There's never time to do it right, but always time to do it over.

 /// 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/202006181626.05IGQtxd402307%40masaka.moolenaar.net.

Raspunde prin e-mail lui