To: vim_dev@googlegroups.com Subject: Patch 8.2.1001 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@Moolenaar.net -- 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 ///