From fe090eb58fad1aaf83267d0b4ace9f024a5ba2bc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 15 Apr 2021 21:48:32 +0200 Subject: [PATCH] patch 8.2.2770: Vim9: type of loop variable is not used Problem: Vim9: type of loop variable is not used. Solution: Parse and check the variable type. (closes #8107) --- src/testdir/test_vim9_script.vim | 12 ++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 26 +++++++++++++++++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 03da2fd86..d9ae4ff67 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2343,6 +2343,12 @@ def Test_for_loop() endfor assert_equal(6, total) + var chars = '' + for s: string in 'foobar' + chars ..= s + endfor + assert_equal('foobar', chars) + # unpack with type var res = '' for [n: number, s: string] in [[1, 'a'], [2, 'b']] @@ -2408,6 +2414,12 @@ def Test_for_loop_fails() endfor END CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3) + + lines =<< trim END + for nr: number in ['foo'] + endfor + END + CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1) enddef def Test_for_loop_script_var() diff --git a/src/version.c b/src/version.c index 8c558b20e..8cbe3d36d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2770, /**/ 2769, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 78c387f42..4ae3b41ae 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -7514,12 +7514,16 @@ compile_for(char_u *arg_start, cctx_T *cctx) return NULL; } - if (vartype->tt_type == VAR_LIST && vartype->tt_member->tt_type != VAR_ANY) + if (vartype->tt_type == VAR_STRING) + item_type = &t_string; + else if (vartype->tt_type == VAR_LIST + && vartype->tt_member->tt_type != VAR_ANY) { if (var_count == 1) item_type = vartype->tt_member; else if (vartype->tt_member->tt_type == VAR_LIST && vartype->tt_member->tt_member->tt_type != VAR_ANY) + // TODO: should get the type from item_type = vartype->tt_member->tt_member; } @@ -7557,12 +7561,19 @@ compile_for(char_u *arg_start, cctx_T *cctx) int opt_flags = 0; int vimvaridx = -1; type_T *type = &t_any; + type_T *lhs_type = &t_any; + where_T where; p = skip_var_one(arg, FALSE); varlen = p - arg; name = vim_strnsave(arg, varlen); if (name == NULL) goto failed; + if (*p == ':') + { + p = skipwhite(p + 1); + lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE); + } // TODO: script var not supported? if (get_var_dest(name, &dest, CMD_for, &opt_flags, @@ -7589,8 +7600,15 @@ compile_for(char_u *arg_start, cctx_T *cctx) } // Reserve a variable to store "var". - // TODO: check for type - var_lvar = reserve_local(cctx, arg, varlen, TRUE, &t_any); + where.wt_index = var_count > 1 ? idx + 1 : 0; + where.wt_variable = TRUE; + if (lhs_type == &t_any) + lhs_type = item_type; + else if (item_type != &t_unknown + && !(var_count > 1 && item_type == &t_any) + && check_type(lhs_type, item_type, TRUE, where) == FAIL) + goto failed; + var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type); if (var_lvar == NULL) // out of memory or used as an argument goto failed; @@ -7602,8 +7620,6 @@ compile_for(char_u *arg_start, cctx_T *cctx) generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); } - if (*p == ':') - p = skip_type(skipwhite(p + 1), FALSE); if (*p == ',' || *p == ';') ++p; arg = skipwhite(p); -- 2.40.0