To: vim_dev@googlegroups.com Subject: Patch 8.2.1236 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1236 Problem: Vim9: a few errors not caught by try/catch. Solution: Do not bail out if an error is inside try/catch. Fix that a not matching catch doesn't jump to :endtry. Files: src/vim9compile.c, src/vim9execute.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.1235/src/vim9compile.c 2020-07-17 20:35:00.857574357 +0200 --- src/vim9compile.c 2020-07-18 14:22:38.098940707 +0200 *************** *** 4961,4966 **** --- 4961,4967 ---- } if (need_type(stacktype, &t_list_any, -1, cctx, FALSE) == FAIL) goto theend; + // TODO: check the length of a constant list here generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count, semicolon); } *************** *** 6539,6544 **** --- 6540,6546 ---- // Previous catch without match jumps here isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; isn->isn_arg.jump.jump_where = instr->ga_len; + scope->se_u.se_try.ts_catch_label = 0; } // TODO: set index in ts_finally_label jumps *************** *** 6584,6591 **** --- 6586,6603 ---- compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx); // End :catch or :finally scope: set value in ISN_TRY instruction + if (isn->isn_arg.try.try_catch == 0) + isn->isn_arg.try.try_catch = instr->ga_len; if (isn->isn_arg.try.try_finally == 0) isn->isn_arg.try.try_finally = instr->ga_len; + + if (scope->se_u.se_try.ts_catch_label != 0) + { + // Last catch without match jumps here + isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; + isn->isn_arg.jump.jump_where = instr->ga_len; + } + compile_endblock(cctx); if (generate_instr(cctx, ISN_ENDTRY) == NULL) *** ../vim-8.2.1235/src/vim9execute.c 2020-07-17 23:03:14.323640792 +0200 --- src/vim9execute.c 2020-07-18 14:58:13.527210739 +0200 *************** *** 1241,1247 **** if (msg != NULL) { emsg(_(msg)); ! goto failed; } } break; --- 1241,1247 ---- if (msg != NULL) { emsg(_(msg)); ! goto on_error; } } break; *************** *** 1272,1278 **** --ectx.ec_stack.ga_len; if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0)) == FAIL) ! goto failed; break; // store g:/b:/w:/t: variable --- 1272,1279 ---- --ectx.ec_stack.ga_len; if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0)) == FAIL) ! // should not happen, type is checked when compiling ! goto on_error; break; // store g:/b:/w:/t: variable *************** *** 1335,1341 **** if (lidx < 0 || lidx > list->lv_len) { semsg(_(e_listidx), lidx); ! goto failed; } tv = STACK_TV_BOT(-3); if (lidx < list->lv_len) --- 1336,1342 ---- if (lidx < 0 || lidx > list->lv_len) { semsg(_(e_listidx), lidx); ! goto on_error; } tv = STACK_TV_BOT(-3); if (lidx < list->lv_len) *************** *** 1348,1354 **** } else { ! // append to list if (list_append_tv(list, tv) == FAIL) goto failed; clear_tv(tv); --- 1349,1355 ---- } else { ! // append to list, only fails when out of memory if (list_append_tv(list, tv) == FAIL) goto failed; clear_tv(tv); *************** *** 1371,1388 **** if (key == NULL || *key == NUL) { emsg(_(e_emptykey)); ! goto failed; } tv = STACK_TV_BOT(-3); di = dict_find(dict, key, -1); if (di != NULL) { clear_tv(&di->di_tv); di->di_tv = *tv; } else { ! // add to dict if (dict_add_tv(dict, (char *)key, tv) == FAIL) goto failed; clear_tv(tv); --- 1372,1390 ---- if (key == NULL || *key == NUL) { emsg(_(e_emptykey)); ! goto on_error; } tv = STACK_TV_BOT(-3); di = dict_find(dict, key, -1); if (di != NULL) { + // overwrite existing value clear_tv(&di->di_tv); di->di_tv = *tv; } else { ! // add to dict, only fails when out of memory if (dict_add_tv(dict, (char *)key, tv) == FAIL) goto failed; clear_tv(tv); *************** *** 1465,1471 **** case ISN_UNLET: if (do_unlet(iptr->isn_arg.unlet.ul_name, iptr->isn_arg.unlet.ul_forceit) == FAIL) ! goto failed; break; case ISN_UNLETENV: vim_unsetenv(iptr->isn_arg.unlet.ul_name); --- 1467,1473 ---- case ISN_UNLET: if (do_unlet(iptr->isn_arg.unlet.ul_name, iptr->isn_arg.unlet.ul_forceit) == FAIL) ! goto on_error; break; case ISN_UNLETENV: vim_unsetenv(iptr->isn_arg.unlet.ul_name); *************** *** 1481,1504 **** // create a dict from items on the stack case ISN_NEWDICT: { ! int count = iptr->isn_arg.number; ! dict_T *dict = dict_alloc(); ! dictitem_T *item; if (dict == NULL) goto failed; for (idx = 0; idx < count; ++idx) { ! // check key type is VAR_STRING tv = STACK_TV_BOT(2 * (idx - count)); item = dictitem_alloc(tv->vval.v_string); clear_tv(tv); if (item == NULL) goto failed; item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); item->di_tv.v_lock = 0; if (dict_add(dict, item) == FAIL) goto failed; } if (count > 0) --- 1483,1520 ---- // create a dict from items on the stack case ISN_NEWDICT: { ! int count = iptr->isn_arg.number; ! dict_T *dict = dict_alloc(); ! dictitem_T *item; if (dict == NULL) goto failed; for (idx = 0; idx < count; ++idx) { ! // have already checked key type is VAR_STRING tv = STACK_TV_BOT(2 * (idx - count)); + // check key is unique + item = dict_find(dict, tv->vval.v_string, -1); + if (item != NULL) + { + semsg(_(e_duplicate_key), tv->vval.v_string); + dict_unref(dict); + goto on_error; + } item = dictitem_alloc(tv->vval.v_string); clear_tv(tv); if (item == NULL) + { + dict_unref(dict); goto failed; + } item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); item->di_tv.v_lock = 0; if (dict_add(dict, item) == FAIL) + { + dict_unref(dict); goto failed; + } } if (count > 0) *************** *** 1519,1525 **** if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx, iptr->isn_arg.dfunc.cdf_argcount, &ectx) == FAIL) ! goto failed; break; // call a builtin function --- 1535,1541 ---- if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx, iptr->isn_arg.dfunc.cdf_argcount, &ectx) == FAIL) ! goto on_error; break; // call a builtin function *** ../vim-8.2.1235/src/testdir/test_vim9_script.vim 2020-07-17 23:03:14.323640792 +0200 --- src/testdir/test_vim9_script.vim 2020-07-18 15:02:15.494430091 +0200 *************** *** 511,516 **** --- 511,532 ---- endtry # comment assert_equal(['1', 'wrong', '3'], l) + l = [] + try + try + add(l, '1') + throw 'wrong' + add(l, '2') + catch /right/ + add(l, v:exception) + endtry + catch /wrong/ + add(l, 'caught') + finally + add(l, 'finally') + endtry + assert_equal(['1', 'caught', 'finally'], l) + let n: number try n = l[3] *************** *** 591,604 **** endtry assert_equal(277, n) ! # TODO: make this work ! # try ! # &ts = g:astring ! # catch /E1093:/ ! # n = 288 ! # endtry ! # assert_equal(288, n) enddef def ThrowFromDef() throw "getout" # comment --- 607,668 ---- endtry assert_equal(277, n) ! try ! &ts = g:astring ! catch /E1029:/ ! n = 288 ! endtry ! assert_equal(288, n) ! ! try ! &backspace = 'asdf' ! catch /E474:/ ! n = 299 ! endtry ! assert_equal(299, n) ! ! l = [1] ! try ! l[3] = 3 ! catch /E684:/ ! n = 300 ! endtry ! assert_equal(300, n) ! ! try ! d[''] = 3 ! catch /E713:/ ! n = 311 ! endtry ! assert_equal(311, n) ! ! try ! unlet g:does_not_exist ! catch /E108:/ ! n = 322 ! endtry ! assert_equal(322, n) ! ! try ! d = {'text': 1, g:astring: 2} ! catch /E721:/ ! n = 333 ! endtry ! assert_equal(333, n) ! ! try ! l = DeletedFunc() ! catch /E933:/ ! n = 344 ! endtry ! assert_equal(344, n) ! enddef ! ! def DeletedFunc(): list ! return ['delete me'] enddef + defcompile + delfunc DeletedFunc def ThrowFromDef() throw "getout" # comment *** ../vim-8.2.1235/src/version.c 2020-07-18 12:59:16.488052332 +0200 --- src/version.c 2020-07-18 15:15:41.155676683 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1236, /**/ -- He who laughs last, thinks slowest. /// 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 ///