summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-18 15:17:02 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-18 15:17:02 +0200
commite859312e748297bde67a053fd3c486fc2c14b532 (patch)
tree54c9085cc2d7e8fce75f916b3a163fbf8ff68cc3
parent2764d06ab7140c95b6317e344d853e4a32c76e9a (diff)
downloadvim-git-e859312e748297bde67a053fd3c486fc2c14b532.tar.gz
patch 8.2.1236: Vim9: a few errors not caught by try/catchv8.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.
-rw-r--r--src/testdir/test_vim9_script.vim78
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c12
-rw-r--r--src/vim9execute.c40
4 files changed, 113 insertions, 19 deletions
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 035ea0b84..a646de978 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -511,6 +511,22 @@ def Test_try_catch()
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,14 +607,62 @@ def Test_try_catch()
endtry
assert_equal(277, n)
- # TODO: make this work
- # try
- # &ts = g:astring
- # catch /E1093:/
- # n = 288
- # endtry
- # assert_equal(288, 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<any>
+ return ['delete me']
enddef
+defcompile
+delfunc DeletedFunc
def ThrowFromDef()
throw "getout" # comment
diff --git a/src/version.c b/src/version.c
index a65bf1a9a..d8353cc4a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1236,
+/**/
1235,
/**/
1234,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 8c2de343a..634706b50 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4961,6 +4961,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
}
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,6 +6540,7 @@ compile_finally(char_u *arg, cctx_T *cctx)
// 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,8 +6586,18 @@ compile_endtry(char_u *arg, cctx_T *cctx)
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)
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 88979afa4..ce1278167 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1241,7 +1241,7 @@ call_def_function(
if (msg != NULL)
{
emsg(_(msg));
- goto failed;
+ goto on_error;
}
}
break;
@@ -1272,7 +1272,8 @@ call_def_function(
--ectx.ec_stack.ga_len;
if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
== FAIL)
- goto failed;
+ // should not happen, type is checked when compiling
+ goto on_error;
break;
// store g:/b:/w:/t: variable
@@ -1335,7 +1336,7 @@ call_def_function(
if (lidx < 0 || lidx > list->lv_len)
{
semsg(_(e_listidx), lidx);
- goto failed;
+ goto on_error;
}
tv = STACK_TV_BOT(-3);
if (lidx < list->lv_len)
@@ -1348,7 +1349,7 @@ call_def_function(
}
else
{
- // append to list
+ // append to list, only fails when out of memory
if (list_append_tv(list, tv) == FAIL)
goto failed;
clear_tv(tv);
@@ -1371,18 +1372,19 @@ call_def_function(
if (key == NULL || *key == NUL)
{
emsg(_(e_emptykey));
- goto failed;
+ 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
+ // add to dict, only fails when out of memory
if (dict_add_tv(dict, (char *)key, tv) == FAIL)
goto failed;
clear_tv(tv);
@@ -1465,7 +1467,7 @@ call_def_function(
case ISN_UNLET:
if (do_unlet(iptr->isn_arg.unlet.ul_name,
iptr->isn_arg.unlet.ul_forceit) == FAIL)
- goto failed;
+ goto on_error;
break;
case ISN_UNLETENV:
vim_unsetenv(iptr->isn_arg.unlet.ul_name);
@@ -1481,24 +1483,38 @@ call_def_function(
// 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;
+ 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
+ // 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,7 +1535,7 @@ call_def_function(
if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
iptr->isn_arg.dfunc.cdf_argcount,
&ectx) == FAIL)
- goto failed;
+ goto on_error;
break;
// call a builtin function