0
0
mirror of https://github.com/vim/vim.git synced 2025-07-25 10:54:51 -04:00

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.
This commit is contained in:
Bram Moolenaar 2020-12-27 13:39:50 +01:00
parent 07a65d26e7
commit a629495530
7 changed files with 116 additions and 43 deletions

View File

@ -2531,7 +2531,7 @@ eval_variable(
rettv->vval.v_string = vim_strsave(import->imp_funcname); rettv->vval.v_string = vim_strsave(import->imp_funcname);
} }
} }
else if (import->imp_all) else if (import->imp_flags & IMP_FLAGS_STAR)
{ {
emsg("Sorry, 'import * as X' not implemented yet"); emsg("Sorry, 'import * as X' not implemented yet");
ret = FAIL; ret = FAIL;

View File

@ -4,6 +4,7 @@ void ex_vim9script(exarg_T *eap);
int not_in_vim9(exarg_T *eap); int not_in_vim9(exarg_T *eap);
void ex_export(exarg_T *eap); void ex_export(exarg_T *eap);
void free_imports_and_script_vars(int sid); void free_imports_and_script_vars(int sid);
void mark_imports_for_reload(int sid);
void ex_import(exarg_T *eap); void ex_import(exarg_T *eap);
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx); int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx);
char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx); char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx);

View File

@ -1778,17 +1778,19 @@ typedef struct {
char_u *imp_name; // name imported as (allocated) char_u *imp_name; // name imported as (allocated)
int imp_sid; // script ID of "from" int imp_sid; // script ID of "from"
// for "import * as Name", "imp_name" is "Name" int imp_flags; // IMP_FLAGS_ values
int imp_all;
// for variable // for a variable
type_T *imp_type; type_T *imp_type;
int imp_var_vals_idx; // index in sn_var_vals of "from" int imp_var_vals_idx; // index in sn_var_vals of "from"
// for function // for a function
char_u *imp_funcname; // user func name (NOT allocated) char_u *imp_funcname; // user func name (NOT allocated)
} imported_T; } imported_T;
#define IMP_FLAGS_STAR 1 // using "import * as Name"
#define IMP_FLAGS_RELOAD 2 // script reloaded, OK to redefine
/* /*
* Info about an already sourced scripts. * Info about an already sourced scripts.
*/ */

View File

@ -899,6 +899,16 @@ def Test_vim9_import_export()
writefile(import_star_as_lines_dot_space, 'Ximport.vim') writefile(import_star_as_lines_dot_space, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func') assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
var import_star_as_duplicated =<< trim END
vim9script
import * as Export from './Xexport.vim'
var some = 'other'
import * as Export from './Xexport.vim'
defcompile
END
writefile(import_star_as_duplicated, 'Ximport.vim')
assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
var import_star_as_lines_missing_name =<< trim END var import_star_as_lines_missing_name =<< trim END
vim9script vim9script
import * as Export from './Xexport.vim' import * as Export from './Xexport.vim'
@ -1160,9 +1170,15 @@ enddef
def Test_vim9script_reload_noclear() def Test_vim9script_reload_noclear()
var lines =<< trim END var lines =<< trim END
vim9script
export var exported = 'thexport'
END
writefile(lines, 'XExportReload')
lines =<< trim END
vim9script noclear vim9script noclear
g:loadCount += 1 g:loadCount += 1
var s:reloaded = 'init' var s:reloaded = 'init'
import exported from './XExportReload'
def Again(): string def Again(): string
return 'again' return 'again'
@ -1174,7 +1190,7 @@ def Test_vim9script_reload_noclear()
var s:notReloaded = 'yes' var s:notReloaded = 'yes'
s:reloaded = 'first' s:reloaded = 'first'
def g:Values(): list<string> def g:Values(): list<string>
return [s:reloaded, s:notReloaded, Again(), Once()] return [s:reloaded, s:notReloaded, Again(), Once(), exported]
enddef enddef
def Once(): string def Once(): string
@ -1185,15 +1201,16 @@ def Test_vim9script_reload_noclear()
g:loadCount = 0 g:loadCount = 0
source XReloaded source XReloaded
assert_equal(1, g:loadCount) assert_equal(1, g:loadCount)
assert_equal(['first', 'yes', 'again', 'once'], g:Values()) assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
source XReloaded source XReloaded
assert_equal(2, g:loadCount) assert_equal(2, g:loadCount)
assert_equal(['init', 'yes', 'again', 'once'], g:Values()) assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
source XReloaded source XReloaded
assert_equal(3, g:loadCount) assert_equal(3, g:loadCount)
assert_equal(['init', 'yes', 'again', 'once'], g:Values()) assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
delete('Xreloaded') delete('Xreloaded')
delete('XExportReload')
delfunc g:Values delfunc g:Values
unlet g:loadCount unlet g:loadCount
enddef enddef
@ -2762,6 +2779,17 @@ def Test_forward_declaration()
enddef enddef
def Test_source_vim9_from_legacy() def Test_source_vim9_from_legacy()
var vim9_lines =<< trim END
vim9script
var local = 'local'
g:global = 'global'
export var exported = 'exported'
export def GetText(): string
return 'text'
enddef
END
writefile(vim9_lines, 'Xvim9_script.vim')
var legacy_lines =<< trim END var legacy_lines =<< trim END
source Xvim9_script.vim source Xvim9_script.vim
@ -2783,19 +2811,7 @@ def Test_source_vim9_from_legacy()
END END
writefile(legacy_lines, 'Xlegacy_script.vim') writefile(legacy_lines, 'Xlegacy_script.vim')
var vim9_lines =<< trim END
vim9script
var local = 'local'
g:global = 'global'
export var exported = 'exported'
export def GetText(): string
return 'text'
enddef
END
writefile(vim9_lines, 'Xvim9_script.vim')
source Xlegacy_script.vim source Xlegacy_script.vim
assert_equal('global', g:global) assert_equal('global', g:global)
unlet g:global unlet g:global

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2225,
/**/ /**/
2224, 2224,
/**/ /**/

View File

@ -2416,7 +2416,7 @@ compile_load_scriptvar(
import = find_imported(name, 0, cctx); import = find_imported(name, 0, cctx);
if (import != NULL) if (import != NULL)
{ {
if (import->imp_all) if (import->imp_flags & IMP_FLAGS_STAR)
{ {
char_u *p = skipwhite(*end); char_u *p = skipwhite(*end);
char_u *exp_name; char_u *exp_name;

View File

@ -173,6 +173,24 @@ free_imports_and_script_vars(int sid)
clear_type_list(&si->sn_type_list); clear_type_list(&si->sn_type_list);
} }
/*
* Mark all imports as possible to redefine. Used when a script is loaded
* again but not cleared.
*/
void
mark_imports_for_reload(int sid)
{
scriptitem_T *si = SCRIPT_ITEM(sid);
int idx;
for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
{
imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
imp->imp_flags |= IMP_FLAGS_RELOAD;
}
}
/* /*
* ":import Item from 'filename'" * ":import Item from 'filename'"
* ":import Item as Alias from 'filename'" * ":import Item as Alias from 'filename'"
@ -459,15 +477,29 @@ handle_import(
if (*arg_start == '*') if (*arg_start == '*')
{ {
imported_T *imported = new_imported(gap != NULL ? gap imported_T *imported;
: &SCRIPT_ITEM(import_sid)->sn_imports);
imported = find_imported(as_name, STRLEN(as_name), cctx);
if (imported != NULL && imported->imp_sid == sid)
{
if (imported->imp_flags & IMP_FLAGS_RELOAD)
// import already defined on a previous script load
imported->imp_flags &= ~IMP_FLAGS_RELOAD;
else
{
semsg(_(e_name_already_defined_str), as_name);
goto erret;
}
}
imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
goto erret; goto erret;
imported->imp_name = as_name; imported->imp_name = as_name;
as_name = NULL; as_name = NULL;
imported->imp_sid = sid; imported->imp_sid = sid;
imported->imp_all = TRUE; imported->imp_flags = IMP_FLAGS_STAR;
} }
else else
{ {
@ -479,6 +511,7 @@ handle_import(
for (i = 0; i < names.ga_len; ++i) for (i = 0; i < names.ga_len; ++i)
{ {
char_u *name = ((char_u **)names.ga_data)[i]; char_u *name = ((char_u **)names.ga_data)[i];
size_t len = STRLEN(name);
int idx; int idx;
imported_T *imported; imported_T *imported;
ufunc_T *ufunc = NULL; ufunc_T *ufunc = NULL;
@ -489,28 +522,47 @@ handle_import(
if (idx < 0 && ufunc == NULL) if (idx < 0 && ufunc == NULL)
goto erret; goto erret;
if (check_defined(name, STRLEN(name), cctx) == FAIL) // If already imported with the same propertis and the
goto erret; // IMP_FLAGS_RELOAD set then we keep that entry. Otherwise create
// a new one (and give an error for an existing import).
imported = new_imported(gap != NULL ? gap imported = find_imported(name, len, cctx);
: &SCRIPT_ITEM(import_sid)->sn_imports); if (imported != NULL
if (imported == NULL) && (imported->imp_flags & IMP_FLAGS_RELOAD)
goto erret; && imported->imp_sid == sid
&& (idx >= 0
// TODO: check for "as" following ? (equal_type(imported->imp_type, type)
// imported->imp_name = vim_strsave(as_name); && imported->imp_var_vals_idx == idx)
imported->imp_name = name; : (equal_type(imported->imp_type, ufunc->uf_func_type)
((char_u **)names.ga_data)[i] = NULL; && STRCMP(imported->imp_funcname,
imported->imp_sid = sid; ufunc->uf_name) == 0)))
if (idx >= 0)
{ {
imported->imp_type = type; imported->imp_flags &= ~IMP_FLAGS_RELOAD;
imported->imp_var_vals_idx = idx;
} }
else else
{ {
imported->imp_type = ufunc->uf_func_type; if (check_defined(name, len, cctx) == FAIL)
imported->imp_funcname = ufunc->uf_name; goto erret;
imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL)
goto erret;
// TODO: check for "as" following
// imported->imp_name = vim_strsave(as_name);
imported->imp_name = name;
((char_u **)names.ga_data)[i] = NULL;
imported->imp_sid = sid;
if (idx >= 0)
{
imported->imp_type = type;
imported->imp_var_vals_idx = idx;
}
else
{
imported->imp_type = ufunc->uf_func_type;
imported->imp_funcname = ufunc->uf_name;
}
} }
} }
} }