From 459fbdbf9216bc7b4721fc192e08b35039036caa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 21 Apr 2021 17:57:26 +0200 Subject: 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. --- src/eval.c | 85 +++++++++++++++++++++++++++++++++++++++++- src/testdir/test_vim9_expr.vim | 23 ++++++++---- src/version.c | 2 + 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/eval.c b/src/eval.c index 4dbbc4096..a9f5ae65b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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 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) { diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 456b42612..fd9b406b2 100644 --- 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 = ['a', g:string_empty] - var ln: list = [g:anint, g:thefour] - var nr = 234 - assert_equal(234, nr) + var lines =<< trim END + var ls: list = ['a', g:string_empty] + var ln: list = [g:anint, g:thefour] + var nr = 234 + assert_equal(234, nr) + var text = + + 'text' + if false + text = 'xxx' + endif + END + CheckDefAndScriptSuccess(lines) - CheckDefAndScriptFailure2(["var x = 123"], 'E1010:', 'E15:', 1) + CheckDefAndScriptFailure(["var x = 123"], 'E1010:', 1) CheckDefFailure(["var x = "], 'E1097:', 3) CheckScriptFailure(['vim9script', "var x = "], 'E15:', 2) - CheckDefAndScriptFailure2(["var x = 123"], 'E1068:', 'E15:', 1) - CheckDefAndScriptFailure2(["var x = 123"], 'E1068:', 1) + CheckDefAndScriptFailure(["var x =