Mercurial > vim
diff src/vim9compile.c @ 23578:85ce241ff9e3 v8.2.2331
patch 8.2.2331: Vim9: wrong error when modifying dict declared with :final
Commit: https://github.com/vim/vim/commit/082517570d1dce2faf3baa9f752ce0858355d221
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Jan 11 21:20:18 2021 +0100
patch 8.2.2331: Vim9: wrong error when modifying dict declared with :final
Problem: Vim9: wrong error when modifying dict declared with :final.
Solution: Do not check for writable variable when an index follows.
(closes #7657)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 11 Jan 2021 21:30:03 +0100 |
parents | 4cd173b3d572 |
children | 8c5374ec8a3d |
line wrap: on
line diff
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2127,10 +2127,29 @@ free_locals(cctx_T *cctx) } /* + * If "check_writable" is ASSIGN_CONST give an error if the variable was + * defined with :final or :const, if "check_writable" is ASSIGN_FINAL give an + * error if the variable was defined with :const. + */ + static int +check_item_writable(svar_T *sv, int check_writable, char_u *name) +{ + if ((check_writable == ASSIGN_CONST && sv->sv_const != 0) + || (check_writable == ASSIGN_FINAL + && sv->sv_const == ASSIGN_CONST)) + { + semsg(_(e_readonlyvar), name); + return FAIL; + } + return OK; +} + +/* * Find "name" in script-local items of script "sid". + * Pass "check_writable" to check_item_writable(). * Returns the index in "sn_var_vals" if found. * If found but not in "sn_var_vals" returns -1. - * If not found returns -2. + * If not found or the variable is not writable returns -2. */ int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx) @@ -2151,8 +2170,8 @@ get_script_item_idx(int sid, char_u *nam return -2; idx = sav->sav_var_vals_idx; sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; - if (check_writable && sv->sv_const) - semsg(_(e_readonlyvar), name); + if (check_item_writable(sv, check_writable, name) == FAIL) + return -2; return idx; } @@ -2168,8 +2187,8 @@ get_script_item_idx(int sid, char_u *nam sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; if (sv->sv_tv == &di->di_tv) { - if (check_writable && sv->sv_const) - semsg(_(e_readonlyvar), name); + if (check_item_writable(sv, check_writable, name) == FAIL) + return -2; return idx; } } @@ -2466,7 +2485,7 @@ compile_load_scriptvar( if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) return FAIL; si = SCRIPT_ITEM(current_sctx.sc_sid); - idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE, cctx); + idx = get_script_item_idx(current_sctx.sc_sid, name, 0, cctx); if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9) { // variable is not in sn_var_vals: old style script. @@ -5475,6 +5494,11 @@ compile_lhs( lhs->lhs_name = vim_strnsave(var_start, lhs->lhs_varlen); if (lhs->lhs_name == NULL) return FAIL; + + if (lhs->lhs_dest_end > var_start + lhs->lhs_varlen) + // Something follows after the variable: "var[idx]" or "var.key". + lhs->lhs_has_index = TRUE; + if (heredoc) lhs->lhs_type = &t_list_string; else @@ -5576,9 +5600,11 @@ compile_lhs( lhs->lhs_scriptvar_sid = import->imp_sid; if (SCRIPT_ID_VALID(lhs->lhs_scriptvar_sid)) { + // Check writable only when no index follows. lhs->lhs_scriptvar_idx = get_script_item_idx( - lhs->lhs_scriptvar_sid, - rawname, TRUE, cctx); + lhs->lhs_scriptvar_sid, rawname, + lhs->lhs_has_index ? ASSIGN_FINAL : ASSIGN_CONST, + cctx); if (lhs->lhs_scriptvar_idx >= 0) { scriptitem_T *si = SCRIPT_ITEM( @@ -5665,7 +5691,7 @@ compile_lhs( } lhs->lhs_member_type = lhs->lhs_type; - if (lhs->lhs_dest_end > var_start + lhs->lhs_varlen) + if (lhs->lhs_has_index) { // Something follows after the variable: "var[idx]" or "var.key". // TODO: should we also handle "->func()" here? @@ -5700,7 +5726,6 @@ compile_lhs( lhs->lhs_type = &t_any; } - lhs->lhs_has_index = TRUE; if (lhs->lhs_type->tt_member == NULL) lhs->lhs_member_type = &t_any; else