Mercurial > vim
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 |