Skip to content

Commit a629495

Browse files
committed
patch 8.2.2225: Vim9: error when using :import in legacy script twice
Problem: Vim9: error when using :import in legacy script twice. Solution: Make it possible to redefine an import when reloading.
1 parent 07a65d2 commit a629495

7 files changed

Lines changed: 116 additions & 43 deletions

File tree

src/evalvars.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2531,7 +2531,7 @@ eval_variable(
25312531
rettv->vval.v_string = vim_strsave(import->imp_funcname);
25322532
}
25332533
}
2534-
else if (import->imp_all)
2534+
else if (import->imp_flags & IMP_FLAGS_STAR)
25352535
{
25362536
emsg("Sorry, 'import * as X' not implemented yet");
25372537
ret = FAIL;

src/proto/vim9script.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ void ex_vim9script(exarg_T *eap);
44
int not_in_vim9(exarg_T *eap);
55
void ex_export(exarg_T *eap);
66
void free_imports_and_script_vars(int sid);
7+
void mark_imports_for_reload(int sid);
78
void ex_import(exarg_T *eap);
89
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
910
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);

src/structs.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,17 +1778,19 @@ typedef struct {
17781778
char_u *imp_name; // name imported as (allocated)
17791779
int imp_sid; // script ID of "from"
17801780

1781-
// for "import * as Name", "imp_name" is "Name"
1782-
int imp_all;
1781+
int imp_flags; // IMP_FLAGS_ values
17831782

1784-
// for variable
1783+
// for a variable
17851784
type_T *imp_type;
17861785
int imp_var_vals_idx; // index in sn_var_vals of "from"
17871786

1788-
// for function
1787+
// for a function
17891788
char_u *imp_funcname; // user func name (NOT allocated)
17901789
} imported_T;
17911790

1791+
#define IMP_FLAGS_STAR 1 // using "import * as Name"
1792+
#define IMP_FLAGS_RELOAD 2 // script reloaded, OK to redefine
1793+
17921794
/*
17931795
* Info about an already sourced scripts.
17941796
*/

src/testdir/test_vim9_script.vim

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,16 @@ def Test_vim9_import_export()
899899
writefile(import_star_as_lines_dot_space, 'Ximport.vim')
900900
assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
901901

902+
var import_star_as_duplicated =<< trim END
903+
vim9script
904+
import * as Export from './Xexport.vim'
905+
var some = 'other'
906+
import * as Export from './Xexport.vim'
907+
defcompile
908+
END
909+
writefile(import_star_as_duplicated, 'Ximport.vim')
910+
assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
911+
902912
var import_star_as_lines_missing_name =<< trim END
903913
vim9script
904914
import * as Export from './Xexport.vim'
@@ -1160,9 +1170,15 @@ enddef
11601170

11611171
def Test_vim9script_reload_noclear()
11621172
var lines =<< trim END
1173+
vim9script
1174+
export var exported = 'thexport'
1175+
END
1176+
writefile(lines, 'XExportReload')
1177+
lines =<< trim END
11631178
vim9script noclear
11641179
g:loadCount += 1
11651180
var s:reloaded = 'init'
1181+
import exported from './XExportReload'
11661182

11671183
def Again(): string
11681184
return 'again'
@@ -1174,7 +1190,7 @@ def Test_vim9script_reload_noclear()
11741190
var s:notReloaded = 'yes'
11751191
s:reloaded = 'first'
11761192
def g:Values(): list<string>
1177-
return [s:reloaded, s:notReloaded, Again(), Once()]
1193+
return [s:reloaded, s:notReloaded, Again(), Once(), exported]
11781194
enddef
11791195

11801196
def Once(): string
@@ -1185,15 +1201,16 @@ def Test_vim9script_reload_noclear()
11851201
g:loadCount = 0
11861202
source XReloaded
11871203
assert_equal(1, g:loadCount)
1188-
assert_equal(['first', 'yes', 'again', 'once'], g:Values())
1204+
assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
11891205
source XReloaded
11901206
assert_equal(2, g:loadCount)
1191-
assert_equal(['init', 'yes', 'again', 'once'], g:Values())
1207+
assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
11921208
source XReloaded
11931209
assert_equal(3, g:loadCount)
1194-
assert_equal(['init', 'yes', 'again', 'once'], g:Values())
1210+
assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
11951211

11961212
delete('Xreloaded')
1213+
delete('XExportReload')
11971214
delfunc g:Values
11981215
unlet g:loadCount
11991216
enddef
@@ -2762,6 +2779,17 @@ def Test_forward_declaration()
27622779
enddef
27632780

27642781
def Test_source_vim9_from_legacy()
2782+
var vim9_lines =<< trim END
2783+
vim9script
2784+
var local = 'local'
2785+
g:global = 'global'
2786+
export var exported = 'exported'
2787+
export def GetText(): string
2788+
return 'text'
2789+
enddef
2790+
END
2791+
writefile(vim9_lines, 'Xvim9_script.vim')
2792+
27652793
var legacy_lines =<< trim END
27662794
source Xvim9_script.vim
27672795

@@ -2783,19 +2811,7 @@ def Test_source_vim9_from_legacy()
27832811
END
27842812
writefile(legacy_lines, 'Xlegacy_script.vim')
27852813

2786-
var vim9_lines =<< trim END
2787-
vim9script
2788-
var local = 'local'
2789-
g:global = 'global'
2790-
export var exported = 'exported'
2791-
export def GetText(): string
2792-
return 'text'
2793-
enddef
2794-
END
2795-
writefile(vim9_lines, 'Xvim9_script.vim')
2796-
27972814
source Xlegacy_script.vim
2798-
27992815
assert_equal('global', g:global)
28002816
unlet g:global
28012817

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2225,
753755
/**/
754756
2224,
755757
/**/

src/vim9compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2416,7 +2416,7 @@ compile_load_scriptvar(
24162416
import = find_imported(name, 0, cctx);
24172417
if (import != NULL)
24182418
{
2419-
if (import->imp_all)
2419+
if (import->imp_flags & IMP_FLAGS_STAR)
24202420
{
24212421
char_u *p = skipwhite(*end);
24222422
char_u *exp_name;

src/vim9script.c

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,24 @@ free_imports_and_script_vars(int sid)
173173
clear_type_list(&si->sn_type_list);
174174
}
175175

176+
/*
177+
* Mark all imports as possible to redefine. Used when a script is loaded
178+
* again but not cleared.
179+
*/
180+
void
181+
mark_imports_for_reload(int sid)
182+
{
183+
scriptitem_T *si = SCRIPT_ITEM(sid);
184+
int idx;
185+
186+
for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
187+
{
188+
imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
189+
190+
imp->imp_flags |= IMP_FLAGS_RELOAD;
191+
}
192+
}
193+
176194
/*
177195
* ":import Item from 'filename'"
178196
* ":import Item as Alias from 'filename'"
@@ -459,15 +477,29 @@ handle_import(
459477

460478
if (*arg_start == '*')
461479
{
462-
imported_T *imported = new_imported(gap != NULL ? gap
463-
: &SCRIPT_ITEM(import_sid)->sn_imports);
480+
imported_T *imported;
464481

482+
imported = find_imported(as_name, STRLEN(as_name), cctx);
483+
if (imported != NULL && imported->imp_sid == sid)
484+
{
485+
if (imported->imp_flags & IMP_FLAGS_RELOAD)
486+
// import already defined on a previous script load
487+
imported->imp_flags &= ~IMP_FLAGS_RELOAD;
488+
else
489+
{
490+
semsg(_(e_name_already_defined_str), as_name);
491+
goto erret;
492+
}
493+
}
494+
495+
imported = new_imported(gap != NULL ? gap
496+
: &SCRIPT_ITEM(import_sid)->sn_imports);
465497
if (imported == NULL)
466498
goto erret;
467499
imported->imp_name = as_name;
468500
as_name = NULL;
469501
imported->imp_sid = sid;
470-
imported->imp_all = TRUE;
502+
imported->imp_flags = IMP_FLAGS_STAR;
471503
}
472504
else
473505
{
@@ -479,6 +511,7 @@ handle_import(
479511
for (i = 0; i < names.ga_len; ++i)
480512
{
481513
char_u *name = ((char_u **)names.ga_data)[i];
514+
size_t len = STRLEN(name);
482515
int idx;
483516
imported_T *imported;
484517
ufunc_T *ufunc = NULL;
@@ -489,28 +522,47 @@ handle_import(
489522
if (idx < 0 && ufunc == NULL)
490523
goto erret;
491524

492-
if (check_defined(name, STRLEN(name), cctx) == FAIL)
493-
goto erret;
494-
495-
imported = new_imported(gap != NULL ? gap
496-
: &SCRIPT_ITEM(import_sid)->sn_imports);
497-
if (imported == NULL)
498-
goto erret;
499-
500-
// TODO: check for "as" following
501-
// imported->imp_name = vim_strsave(as_name);
502-
imported->imp_name = name;
503-
((char_u **)names.ga_data)[i] = NULL;
504-
imported->imp_sid = sid;
505-
if (idx >= 0)
525+
// If already imported with the same propertis and the
526+
// IMP_FLAGS_RELOAD set then we keep that entry. Otherwise create
527+
// a new one (and give an error for an existing import).
528+
imported = find_imported(name, len, cctx);
529+
if (imported != NULL
530+
&& (imported->imp_flags & IMP_FLAGS_RELOAD)
531+
&& imported->imp_sid == sid
532+
&& (idx >= 0
533+
? (equal_type(imported->imp_type, type)
534+
&& imported->imp_var_vals_idx == idx)
535+
: (equal_type(imported->imp_type, ufunc->uf_func_type)
536+
&& STRCMP(imported->imp_funcname,
537+
ufunc->uf_name) == 0)))
506538
{
507-
imported->imp_type = type;
508-
imported->imp_var_vals_idx = idx;
539+
imported->imp_flags &= ~IMP_FLAGS_RELOAD;
509540
}
510541
else
511542
{
512-
imported->imp_type = ufunc->uf_func_type;
513-
imported->imp_funcname = ufunc->uf_name;
543+
if (check_defined(name, len, cctx) == FAIL)
544+
goto erret;
545+
546+
imported = new_imported(gap != NULL ? gap
547+
: &SCRIPT_ITEM(import_sid)->sn_imports);
548+
if (imported == NULL)
549+
goto erret;
550+
551+
// TODO: check for "as" following
552+
// imported->imp_name = vim_strsave(as_name);
553+
imported->imp_name = name;
554+
((char_u **)names.ga_data)[i] = NULL;
555+
imported->imp_sid = sid;
556+
if (idx >= 0)
557+
{
558+
imported->imp_type = type;
559+
imported->imp_var_vals_idx = idx;
560+
}
561+
else
562+
{
563+
imported->imp_type = ufunc->uf_func_type;
564+
imported->imp_funcname = ufunc->uf_name;
565+
}
514566
}
515567
}
516568
}

0 commit comments

Comments
 (0)