changeset 24518:cf334a353c30 v8.2.2799

patch 8.2.2799: Vim9: type casts don't fully work at the script level Commit: https://github.com/vim/vim/commit/459fbdbf9216bc7b4721fc192e08b35039036caa Author: Bram Moolenaar <Bram@vim.org> Date: Wed Apr 21 17:57:26 2021 +0200 patch 8.2.2799: Vim9: type casts don't fully work at the script level Problem: Vim9: type casts don't fully work at the script level. Solution: Implement the missing piece.
author Bram Moolenaar <Bram@vim.org>
date Wed, 21 Apr 2021 18:00:05 +0200
parents 9fd77d6cd43c
children da748a66a65a
files src/eval.c src/testdir/test_vim9_expr.vim src/version.c
diffstat 3 files changed, 102 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -51,6 +51,7 @@ static int eval3(char_u **arg, typval_T 
 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)
 {
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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)
-
-  CheckDefAndScriptFailure2(["var x = <nr>123"], 'E1010:', 'E15:', 1)
+  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)
+
+  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
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2799,
+/**/
     2798,
 /**/
     2797,