comparison src/evalvars.c @ 25284:29191571eceb v8.2.3179

patch 8.2.3179: Vim9: cannot assign to an imported variable at script level Commit: https://github.com/vim/vim/commit/24e9316560bd5c9ea2e5a963335aedff025e7f66 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 18 20:40:33 2021 +0200 patch 8.2.3179: Vim9: cannot assign to an imported variable at script level Problem: Vim9: cannot assign to an imported variable at script level. Solution: Lookup imported items when assigning.
author Bram Moolenaar <Bram@vim.org>
date Sun, 18 Jul 2021 20:45:04 +0200
parents 346002a63bc6
children 946ef64ede70
comparison
equal deleted inserted replaced
25283:dbf77501fe00 25284:29191571eceb
3199 int var_idx) // index for ":let [a, b] = list" 3199 int var_idx) // index for ":let [a, b] = list"
3200 { 3200 {
3201 typval_T *tv = tv_arg; 3201 typval_T *tv = tv_arg;
3202 typval_T bool_tv; 3202 typval_T bool_tv;
3203 dictitem_T *di; 3203 dictitem_T *di;
3204 typval_T *dest_tv = NULL;
3204 char_u *varname; 3205 char_u *varname;
3205 hashtab_T *ht; 3206 hashtab_T *ht;
3206 int is_script_local; 3207 int is_script_local;
3207 int vim9script = in_vim9script(); 3208 int vim9script = in_vim9script();
3208 int var_in_vim9script; 3209 int var_in_vim9script;
3239 goto failed; 3240 goto failed;
3240 } 3241 }
3241 3242
3242 di = find_var_in_ht(ht, 0, varname, TRUE); 3243 di = find_var_in_ht(ht, 0, varname, TRUE);
3243 3244
3244 // Search in parent scope which is possible to reference from lambda 3245 if (di == NULL && var_in_vim9script)
3245 if (di == NULL) 3246 {
3246 di = find_var_in_scoped_ht(name, TRUE); 3247 imported_T *import = find_imported(varname, 0, NULL);
3247 3248
3248 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) 3249 if (import != NULL)
3249 && var_wrong_func_name(name, di == NULL)) 3250 {
3250 goto failed; 3251 scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
3251 3252 svar_T *sv;
3252 if (need_convert_to_bool(type, tv)) 3253
3253 { 3254 // imported variable from another script
3254 // Destination is a bool and the value is not, but it can be converted. 3255 if ((flags & ASSIGN_NO_DECL) == 0)
3255 CLEAR_FIELD(bool_tv); 3256 {
3256 bool_tv.v_type = VAR_BOOL; 3257 semsg(_(e_redefining_imported_item_str), name);
3257 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
3258 tv = &bool_tv;
3259 }
3260
3261 if (di != NULL)
3262 {
3263 // Item already exists. Allowed to replace when reloading.
3264 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
3265 {
3266 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
3267 && (flags & ASSIGN_FOR_LOOP) == 0)
3268 {
3269 emsg(_(e_cannot_mod));
3270 goto failed; 3258 goto failed;
3271 } 3259 }
3272 3260 sv = ((svar_T *)si->sn_var_vals.ga_data)
3273 if (is_script_local && vim9script 3261 + import->imp_var_vals_idx;
3274 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) 3262 // TODO: check the type
3263 // TODO: check for const and locked
3264 dest_tv = sv->sv_tv;
3265 }
3266 }
3267
3268 if (dest_tv == NULL)
3269 {
3270 // Search in parent scope which is possible to reference from lambda
3271 if (di == NULL)
3272 di = find_var_in_scoped_ht(name, TRUE);
3273
3274 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
3275 && var_wrong_func_name(name, di == NULL))
3276 goto failed;
3277
3278 if (need_convert_to_bool(type, tv))
3279 {
3280 // Destination is a bool and the value is not, but it can be converted.
3281 CLEAR_FIELD(bool_tv);
3282 bool_tv.v_type = VAR_BOOL;
3283 bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
3284 tv = &bool_tv;
3285 }
3286
3287 if (di != NULL)
3288 {
3289 // Item already exists. Allowed to replace when reloading.
3290 if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
3291 {
3292 if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
3293 && (flags & ASSIGN_FOR_LOOP) == 0)
3294 {
3295 emsg(_(e_cannot_mod));
3296 goto failed;
3297 }
3298
3299 if (is_script_local && vim9script
3300 && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0)
3301 {
3302 semsg(_(e_redefining_script_item_str), name);
3303 goto failed;
3304 }
3305
3306 if (var_in_vim9script)
3307 {
3308 where_T where;
3309
3310 // check the type and adjust to bool if needed
3311 where.wt_index = var_idx;
3312 where.wt_variable = TRUE;
3313 if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL)
3314 goto failed;
3315 }
3316
3317 if (var_check_permission(di, name) == FAIL)
3318 goto failed;
3319 }
3320 else
3321 {
3322 // can only redefine once
3323 di->di_flags &= ~DI_FLAGS_RELOAD;
3324
3325 // A Vim9 script-local variable is also present in sn_all_vars and
3326 // sn_var_vals. It may set "type" from "tv".
3327 if (var_in_vim9script)
3328 update_vim9_script_var(FALSE, di, flags, tv, &type,
3329 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3330 }
3331
3332 // existing variable, need to clear the value
3333
3334 // Handle setting internal di: variables separately where needed to
3335 // prevent changing the type.
3336 if (ht == &vimvarht)
3337 {
3338 if (di->di_tv.v_type == VAR_STRING)
3339 {
3340 VIM_CLEAR(di->di_tv.vval.v_string);
3341 if (copy || tv->v_type != VAR_STRING)
3342 {
3343 char_u *val = tv_get_string(tv);
3344
3345 // Careful: when assigning to v:errmsg and tv_get_string()
3346 // causes an error message the variable will already be set.
3347 if (di->di_tv.vval.v_string == NULL)
3348 di->di_tv.vval.v_string = vim_strsave(val);
3349 }
3350 else
3351 {
3352 // Take over the string to avoid an extra alloc/free.
3353 di->di_tv.vval.v_string = tv->vval.v_string;
3354 tv->vval.v_string = NULL;
3355 }
3356 goto failed;
3357 }
3358 else if (di->di_tv.v_type == VAR_NUMBER)
3359 {
3360 di->di_tv.vval.v_number = tv_get_number(tv);
3361 if (STRCMP(varname, "searchforward") == 0)
3362 set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
3363 #ifdef FEAT_SEARCH_EXTRA
3364 else if (STRCMP(varname, "hlsearch") == 0)
3365 {
3366 no_hlsearch = !di->di_tv.vval.v_number;
3367 redraw_all_later(SOME_VALID);
3368 }
3369 #endif
3370 goto failed;
3371 }
3372 else if (di->di_tv.v_type != tv->v_type)
3373 {
3374 semsg(_("E963: setting %s to value with wrong type"), name);
3375 goto failed;
3376 }
3377 }
3378
3379 clear_tv(&di->di_tv);
3380 }
3381 else
3382 {
3383 // Item not found, check if a function already exists.
3384 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
3385 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
3275 { 3386 {
3276 semsg(_(e_redefining_script_item_str), name); 3387 semsg(_(e_redefining_script_item_str), name);
3277 goto failed; 3388 goto failed;
3278 } 3389 }
3279 3390
3391 // add a new variable
3392 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
3393 {
3394 semsg(_(e_unknown_variable_str), name);
3395 goto failed;
3396 }
3397
3398 // Can't add "v:" or "a:" variable.
3399 if (ht == &vimvarht || ht == get_funccal_args_ht())
3400 {
3401 semsg(_(e_illvar), name);
3402 goto failed;
3403 }
3404
3405 // Make sure the variable name is valid. In Vim9 script an autoload
3406 // variable must be prefixed with "g:".
3407 if (!valid_varname(varname, !vim9script
3408 || STRNCMP(name, "g:", 2) == 0))
3409 goto failed;
3410
3411 di = alloc(sizeof(dictitem_T) + STRLEN(varname));
3412 if (di == NULL)
3413 goto failed;
3414 STRCPY(di->di_key, varname);
3415 if (hash_add(ht, DI2HIKEY(di)) == FAIL)
3416 {
3417 vim_free(di);
3418 goto failed;
3419 }
3420 di->di_flags = DI_FLAGS_ALLOC;
3421 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
3422 di->di_flags |= DI_FLAGS_LOCK;
3423
3424 // A Vim9 script-local variable is also added to sn_all_vars and
3425 // sn_var_vals. It may set "type" from "tv".
3280 if (var_in_vim9script) 3426 if (var_in_vim9script)
3281 { 3427 update_vim9_script_var(TRUE, di, flags, tv, &type,
3282 where_T where; 3428 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3283 3429 }
3284 // check the type and adjust to bool if needed 3430
3285 where.wt_index = var_idx; 3431 dest_tv = &di->di_tv;
3286 where.wt_variable = TRUE; 3432 }
3287 if (check_script_var_type(&di->di_tv, tv, name, where) == FAIL) 3433
3288 goto failed; 3434 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
3289 } 3435 copy_tv(tv, dest_tv);
3290
3291 if (var_check_permission(di, name) == FAIL)
3292 goto failed;
3293 }
3294 else
3295 {
3296 // can only redefine once
3297 di->di_flags &= ~DI_FLAGS_RELOAD;
3298
3299 // A Vim9 script-local variable is also present in sn_all_vars and
3300 // sn_var_vals. It may set "type" from "tv".
3301 if (var_in_vim9script)
3302 update_vim9_script_var(FALSE, di, flags, tv, &type,
3303 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3304 }
3305
3306 // existing variable, need to clear the value
3307
3308 // Handle setting internal di: variables separately where needed to
3309 // prevent changing the type.
3310 if (ht == &vimvarht)
3311 {
3312 if (di->di_tv.v_type == VAR_STRING)
3313 {
3314 VIM_CLEAR(di->di_tv.vval.v_string);
3315 if (copy || tv->v_type != VAR_STRING)
3316 {
3317 char_u *val = tv_get_string(tv);
3318
3319 // Careful: when assigning to v:errmsg and tv_get_string()
3320 // causes an error message the variable will already be set.
3321 if (di->di_tv.vval.v_string == NULL)
3322 di->di_tv.vval.v_string = vim_strsave(val);
3323 }
3324 else
3325 {
3326 // Take over the string to avoid an extra alloc/free.
3327 di->di_tv.vval.v_string = tv->vval.v_string;
3328 tv->vval.v_string = NULL;
3329 }
3330 goto failed;
3331 }
3332 else if (di->di_tv.v_type == VAR_NUMBER)
3333 {
3334 di->di_tv.vval.v_number = tv_get_number(tv);
3335 if (STRCMP(varname, "searchforward") == 0)
3336 set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
3337 #ifdef FEAT_SEARCH_EXTRA
3338 else if (STRCMP(varname, "hlsearch") == 0)
3339 {
3340 no_hlsearch = !di->di_tv.vval.v_number;
3341 redraw_all_later(SOME_VALID);
3342 }
3343 #endif
3344 goto failed;
3345 }
3346 else if (di->di_tv.v_type != tv->v_type)
3347 {
3348 semsg(_("E963: setting %s to value with wrong type"), name);
3349 goto failed;
3350 }
3351 }
3352
3353 clear_tv(&di->di_tv);
3354 }
3355 else 3436 else
3356 { 3437 {
3357 // Item not found, check if a function already exists. 3438 *dest_tv = *tv;
3358 if (is_script_local && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 3439 dest_tv->v_lock = 0;
3359 && lookup_scriptitem(name, STRLEN(name), FALSE, NULL) == OK)
3360 {
3361 semsg(_(e_redefining_script_item_str), name);
3362 goto failed;
3363 }
3364
3365 // add a new variable
3366 if (var_in_vim9script && (flags & ASSIGN_NO_DECL))
3367 {
3368 semsg(_(e_unknown_variable_str), name);
3369 goto failed;
3370 }
3371
3372 // Can't add "v:" or "a:" variable.
3373 if (ht == &vimvarht || ht == get_funccal_args_ht())
3374 {
3375 semsg(_(e_illvar), name);
3376 goto failed;
3377 }
3378
3379 // Make sure the variable name is valid. In Vim9 script an autoload
3380 // variable must be prefixed with "g:".
3381 if (!valid_varname(varname, !vim9script
3382 || STRNCMP(name, "g:", 2) == 0))
3383 goto failed;
3384
3385 di = alloc(sizeof(dictitem_T) + STRLEN(varname));
3386 if (di == NULL)
3387 goto failed;
3388 STRCPY(di->di_key, varname);
3389 if (hash_add(ht, DI2HIKEY(di)) == FAIL)
3390 {
3391 vim_free(di);
3392 goto failed;
3393 }
3394 di->di_flags = DI_FLAGS_ALLOC;
3395 if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
3396 di->di_flags |= DI_FLAGS_LOCK;
3397
3398 // A Vim9 script-local variable is also added to sn_all_vars and
3399 // sn_var_vals. It may set "type" from "tv".
3400 if (var_in_vim9script)
3401 update_vim9_script_var(TRUE, di, flags, tv, &type,
3402 (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
3403 }
3404
3405 if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT)
3406 copy_tv(tv, &di->di_tv);
3407 else
3408 {
3409 di->di_tv = *tv;
3410 di->di_tv.v_lock = 0;
3411 init_tv(tv); 3440 init_tv(tv);
3412 } 3441 }
3413 3442
3414 if (vim9script && type != NULL) 3443 if (vim9script && type != NULL)
3415 { 3444 {
3416 if (type->tt_type == VAR_DICT && di->di_tv.vval.v_dict != NULL) 3445 if (type->tt_type == VAR_DICT && dest_tv->vval.v_dict != NULL)
3417 di->di_tv.vval.v_dict->dv_type = alloc_type(type); 3446 dest_tv->vval.v_dict->dv_type = alloc_type(type);
3418 else if (type->tt_type == VAR_LIST && di->di_tv.vval.v_list != NULL) 3447 else if (type->tt_type == VAR_LIST && dest_tv->vval.v_list != NULL)
3419 di->di_tv.vval.v_list->lv_type = alloc_type(type); 3448 dest_tv->vval.v_list->lv_type = alloc_type(type);
3420 } 3449 }
3421 3450
3422 // ":const var = value" locks the value 3451 // ":const var = value" locks the value
3423 // ":final var = value" locks "var" 3452 // ":final var = value" locks "var"
3424 if (flags & ASSIGN_CONST) 3453 if (flags & ASSIGN_CONST)
3425 // Like :lockvar! name: lock the value and what it contains, but only 3454 // Like :lockvar! name: lock the value and what it contains, but only
3426 // if the reference count is up to one. That locks only literal 3455 // if the reference count is up to one. That locks only literal
3427 // values. 3456 // values.
3428 item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); 3457 item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
3429 return; 3458 return;
3459
3430 failed: 3460 failed:
3431 if (!copy) 3461 if (!copy)
3432 clear_tv(tv_arg); 3462 clear_tv(tv_arg);
3433 } 3463 }
3434 3464