# HG changeset patch # User Bram Moolenaar # Date 1637948703 -3600 # Node ID 7351926fbe9e9eb64a22390eb4a2754743704a0b # Parent cfab63c480454900e4528ef41372544b89d0ae9e patch 8.2.3682: Vim9: assigning to a script variable drops the type Commit: https://github.com/vim/vim/commit/7824fc80f675b8098e6483ce082e287aad14b6da Author: Bram Moolenaar Date: Fri Nov 26 17:36:51 2021 +0000 patch 8.2.3682: Vim9: assigning to a script variable drops the type Problem: Vim9: assigning to a script variable drops the required type. Solution: Lookup the type of the variable and use it. (closes https://github.com/vim/vim/issues/9219) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3206,13 +3206,14 @@ set_var( void set_var_const( char_u *name, - type_T *type, + type_T *type_arg, typval_T *tv_arg, int copy, // make copy of value in "tv" int flags_arg, // ASSIGN_CONST, ASSIGN_FINAL, etc. int var_idx) // index for ":let [a, b] = list" { typval_T *tv = tv_arg; + type_T *type = type_arg; typval_T bool_tv; dictitem_T *di; typval_T *dest_tv = NULL; @@ -3334,13 +3335,18 @@ set_var_const( if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0) { where_T where = WHERE_INIT; - - // check the type and adjust to bool if needed - where.wt_index = var_idx; - where.wt_variable = TRUE; - if (check_script_var_type(&di->di_tv, tv, name, where) - == FAIL) - goto failed; + svar_T *sv = find_typval_in_script(&di->di_tv); + + if (sv != NULL) + { + // check the type and adjust to bool if needed + where.wt_index = var_idx; + where.wt_variable = TRUE; + if (check_script_var_type(sv, tv, name, where) == FAIL) + goto failed; + if (type == NULL) + type = sv->sv_type; + } } if ((flags & ASSIGN_FOR_LOOP) == 0 diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -16,6 +16,6 @@ char_u *vim9_declare_scriptvar(exarg_T * void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type, int do_member); void hide_script_var(scriptitem_T *si, int idx, int func_defined); svar_T *find_typval_in_script(typval_T *dest); -int check_script_var_type(typval_T *dest, typval_T *value, char_u *name, where_T where); +int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where); int check_reserved_name(char_u *name); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -322,6 +322,16 @@ def Test_skipped_assignment() CheckDefAndScriptSuccess(lines) enddef +def Test_assign_keep_type() + var lines =<< trim END + vim9script + var l: list = [123] + l = [123] + l->add('string') + END + CheckScriptFailure(lines, 'E1012:', 4) +enddef + def Test_assign_unpack() var lines =<< trim END var v1: number diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3682, +/**/ 3681, /**/ 3680, diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -999,35 +999,29 @@ find_typval_in_script(typval_T *dest) */ int check_script_var_type( - typval_T *dest, + svar_T *sv, typval_T *value, char_u *name, where_T where) { - svar_T *sv = find_typval_in_script(dest); int ret; - if (sv != NULL) + if (sv->sv_const != 0) + { + semsg(_(e_cannot_change_readonly_variable_str), name); + return FAIL; + } + ret = check_typval_type(sv->sv_type, value, where); + if (ret == OK && need_convert_to_bool(sv->sv_type, value)) { - if (sv->sv_const != 0) - { - semsg(_(e_cannot_change_readonly_variable_str), name); - return FAIL; - } - ret = check_typval_type(sv->sv_type, value, where); - if (ret == OK && need_convert_to_bool(sv->sv_type, value)) - { - int val = tv2bool(value); + int val = tv2bool(value); - clear_tv(value); - value->v_type = VAR_BOOL; - value->v_lock = 0; - value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE; - } - return ret; + clear_tv(value); + value->v_type = VAR_BOOL; + value->v_lock = 0; + value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE; } - - return OK; // not really + return ret; } // words that cannot be used as a variable