]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.1236: Vim9: a few errors not caught by try/catch v8.2.1236
authorBram Moolenaar <Bram@vim.org>
Sat, 18 Jul 2020 13:17:02 +0000 (15:17 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 18 Jul 2020 13:17:02 +0000 (15:17 +0200)
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.

src/testdir/test_vim9_script.vim
src/version.c
src/vim9compile.c
src/vim9execute.c

index 035ea0b8487b8ed85c9f849ec0053db038158a55..a646de9785fc2bb8367dddb2f4cba60f87c0f8e2 100644 (file)
@@ -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
index a65bf1a9ae22b0281ec53c7adaafc5709ecc4ecb..d8353cc4a770001be9e0fb3a70ec3a1f9f612021 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1236,
 /**/
     1235,
 /**/
index 8c2de343a145a2f4d8dfc6b5a47d00ad7b9d68fc..634706b508fef51d910c5ff7f2aa350440774c63 100644 (file)
@@ -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)
index 88979afa4d53e26db8f8559784ec9bf6c0892b5f..ce127816702ebf270bc792e9574f09e0608863a0 100644 (file)
@@ -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