]> granicus.if.org Git - vim/commitdiff
patch 8.2.2799: Vim9: type casts don't fully work at the script level v8.2.2799
authorBram Moolenaar <Bram@vim.org>
Wed, 21 Apr 2021 15:57:26 +0000 (17:57 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 21 Apr 2021 15:57:26 +0000 (17:57 +0200)
Problem:    Vim9: type casts don't fully work at the script level.
Solution:   Implement the missing piece.

src/eval.c
src/testdir/test_vim9_expr.vim
src/version.c

index 4dbbc40961426171b41f1289918b68a56aa4649a..a9f5ae65be2348132dba7bfe26603ea316a307ca 100644 (file)
@@ -51,6 +51,7 @@ static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
 static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
 static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
 static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
+static int eval7t(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
 static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
 static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp);
 
@@ -3068,7 +3069,7 @@ eval6(
     /*
      * Get the first variable.
      */
-    if (eval7(arg, rettv, evalarg, want_string) == FAIL)
+    if (eval7t(arg, rettv, evalarg, want_string) == FAIL)
        return FAIL;
 
     /*
@@ -3141,7 +3142,7 @@ eval6(
            return FAIL;
        }
        *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
-       if (eval7(arg, &var2, evalarg, FALSE) == FAIL)
+       if (eval7t(arg, &var2, evalarg, FALSE) == FAIL)
            return FAIL;
 
        if (evaluate)
@@ -3231,6 +3232,86 @@ eval6(
     return OK;
 }
 
+/*
+ * Handle a type cast before a base level expression.
+ * "arg" must point to the first non-white of the expression.
+ * "arg" is advanced to just after the recognized expression.
+ * Return OK or FAIL.
+ */
+    static int
+eval7t(
+    char_u     **arg,
+    typval_T   *rettv,
+    evalarg_T  *evalarg,
+    int                want_string)    // after "." operator
+{
+    type_T     *want_type = NULL;
+    garray_T   type_list;          // list of pointers to allocated types
+    int                res;
+    int                evaluate = evalarg == NULL ? 0
+                                      : (evalarg->eval_flags & EVAL_EVALUATE);
+
+    // Recognize <type> in Vim9 script only.
+    if (in_vim9script() && **arg == '<' && eval_isnamec1((*arg)[1]))
+    {
+       ++*arg;
+       ga_init2(&type_list, sizeof(type_T *), 10);
+       want_type = parse_type(arg, &type_list, TRUE);
+       if (want_type == NULL && (evaluate || **arg != '>'))
+       {
+           clear_type_list(&type_list);
+           return FAIL;
+       }
+
+       if (**arg != '>')
+       {
+           if (*skipwhite(*arg) == '>')
+               semsg(_(e_no_white_space_allowed_before_str_str), ">", *arg);
+           else
+               emsg(_(e_missing_gt));
+           clear_type_list(&type_list);
+           return FAIL;
+       }
+       ++*arg;
+       *arg = skipwhite_and_linebreak(*arg, evalarg);
+    }
+
+    res = eval7(arg, rettv, evalarg, want_string);
+
+    if (want_type != NULL && evaluate)
+    {
+       if (res == OK)
+       {
+           type_T *actual = typval2type(rettv, get_copyID(), &type_list, TRUE);
+
+           if (!equal_type(want_type, actual))
+           {
+               if (want_type == &t_bool && actual != &t_bool
+                                       && (actual->tt_flags & TTFLAG_BOOL_OK))
+               {
+                   int n = tv2bool(rettv);
+
+                   // can use "0" and "1" for boolean in some places
+                   clear_tv(rettv);
+                   rettv->v_type = VAR_BOOL;
+                   rettv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
+               }
+               else
+               {
+                   where_T where;
+
+                   where.wt_index = 0;
+                   where.wt_variable = TRUE;
+                   res = check_type(want_type, actual, TRUE, where);
+               }
+           }
+       }
+       clear_type_list(&type_list);
+    }
+
+    return res;
+}
+
     int
 eval_leader(char_u **arg, int vim9)
 {
index 456b42612e1365097c86efd79cd5c3b08be9b1e0..fd9b406b24ecff9f0ead75e05aa9fe8d24b79f31 100644 (file)
@@ -1575,16 +1575,25 @@ let $TESTVAR = 'testvar'
 
 " type casts
 def Test_expr7t()
-  var ls: list<string> = ['a', <string>g:string_empty]
-  var ln: list<number> = [<number>g:anint, <number>g:thefour]
-  var nr = <number>234
-  assert_equal(234, nr)
+  var lines =<< trim END
+      var ls: list<string> = ['a', <string>g:string_empty]
+      var ln: list<number> = [<number>g:anint, <number>g:thefour]
+      var nr = <number>234
+      assert_equal(234, nr)
+      var text =
+            <string>
+              'text'
+      if false
+        text = <number>'xxx'
+      endif
+  END
+  CheckDefAndScriptSuccess(lines)
 
-  CheckDefAndScriptFailure2(["var x = <nr>123"], 'E1010:', 'E15:', 1)
+  CheckDefAndScriptFailure(["var x = <nr>123"], 'E1010:', 1)
   CheckDefFailure(["var x = <number>"], 'E1097:', 3)
   CheckScriptFailure(['vim9script', "var x = <number>"], 'E15:', 2)
-  CheckDefAndScriptFailure2(["var x = <number >123"], 'E1068:', 'E15:', 1)
-  CheckDefAndScriptFailure2(["var x = <number 123"], 'E1104:', 'E15:', 1)
+  CheckDefAndScriptFailure(["var x = <number >123"], 'E1068:', 1)
+  CheckDefAndScriptFailure(["var x = <number 123"], 'E1104:', 1)
 enddef
 
 " test low level expression
index 1420e7bdae8dcf3b574c71a93e97dae141af67a8..1c33c9f34887593818566b9aca9dc1fd3ea289de 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2799,
 /**/
     2798,
 /**/