]> granicus.if.org Git - vim/commitdiff
patch 8.2.2225: Vim9: error when using :import in legacy script twice v8.2.2225
authorBram Moolenaar <Bram@vim.org>
Sun, 27 Dec 2020 12:39:50 +0000 (13:39 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 27 Dec 2020 12:39:50 +0000 (13:39 +0100)
Problem:    Vim9: error when using :import in legacy script twice.
Solution:   Make it possible to redefine an import when reloading.

src/evalvars.c
src/proto/vim9script.pro
src/structs.h
src/testdir/test_vim9_script.vim
src/version.c
src/vim9compile.c
src/vim9script.c

index 2de8b8dd5e85a43c0c126a175aed8b9912b48b52..f7982f7f99856761827b3dc185a16e331cfd96d6 100644 (file)
@@ -2531,7 +2531,7 @@ eval_variable(
                    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");
                ret = FAIL;
index 3603b0babdc7dc8a0695888e08a7bc7f0f24f5f7..c3866021e83e1d879ec3cc12bc900889b22adb37 100644 (file)
@@ -4,6 +4,7 @@ void ex_vim9script(exarg_T *eap);
 int not_in_vim9(exarg_T *eap);
 void ex_export(exarg_T *eap);
 void free_imports_and_script_vars(int sid);
+void mark_imports_for_reload(int sid);
 void ex_import(exarg_T *eap);
 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);
index 93a6b0ad521d07497a14c84e591baa6960fa415f..ba2bec650fc2730fb79f28d3dc0a3ac44929b401 100644 (file)
@@ -1778,17 +1778,19 @@ typedef struct {
     char_u     *imp_name;          // name imported as (allocated)
     int                imp_sid;            // script ID of "from"
 
-    // for "import * as Name", "imp_name" is "Name"
-    int                imp_all;
+    int                imp_flags;          // IMP_FLAGS_ values
 
-    // for variable
+    // for variable
     type_T     *imp_type;
     int                imp_var_vals_idx;   // index in sn_var_vals of "from"
 
-    // for function
+    // for function
     char_u     *imp_funcname;      // user func name (NOT allocated)
 } 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.
  */
index b577d714d2728c907c97b4b20a37dc87fe9df4b4..76899a5d0174935571aa4b43ffe8927e42f3b1a9 100644 (file)
@@ -899,6 +899,16 @@ def Test_vim9_import_export()
   writefile(import_star_as_lines_dot_space, 'Ximport.vim')
   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
     vim9script
     import * as Export from './Xexport.vim'
@@ -1160,9 +1170,15 @@ enddef
 
 def Test_vim9script_reload_noclear()
   var lines =<< trim END
+    vim9script
+    export var exported = 'thexport'
+  END
+  writefile(lines, 'XExportReload')
+  lines =<< trim END
     vim9script noclear
     g:loadCount += 1
     var s:reloaded = 'init'
+    import exported from './XExportReload'
 
     def Again(): string
       return 'again'
@@ -1174,7 +1190,7 @@ def Test_vim9script_reload_noclear()
     var s:notReloaded = 'yes'
     s:reloaded = 'first'
     def g:Values(): list<string>
-      return [s:reloaded, s:notReloaded, Again(), Once()]
+      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
     enddef
 
     def Once(): string
@@ -1185,15 +1201,16 @@ def Test_vim9script_reload_noclear()
   g:loadCount = 0
   source XReloaded
   assert_equal(1, g:loadCount)
-  assert_equal(['first', 'yes', 'again', 'once'], g:Values())
+  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
   source XReloaded
   assert_equal(2, g:loadCount)
-  assert_equal(['init', 'yes', 'again', 'once'], g:Values())
+  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
   source XReloaded
   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('XExportReload')
   delfunc g:Values
   unlet g:loadCount
 enddef
@@ -2762,6 +2779,17 @@ def Test_forward_declaration()
 enddef
 
 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
     source Xvim9_script.vim
 
@@ -2783,19 +2811,7 @@ def Test_source_vim9_from_legacy()
   END
   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
-
   assert_equal('global', g:global)
   unlet g:global
 
index 02e0757720dc68487f1707201dc17f8e020e73ac..20bf5348778bd3de1d1cdd758be88ca1f48ac7d4 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2225,
 /**/
     2224,
 /**/
index baf792355a5ed6928f7533ea67c716a006bee7a5..bd530b1e942572d8e5bb17f39d9abbdf8ac629b5 100644 (file)
@@ -2416,7 +2416,7 @@ compile_load_scriptvar(
     import = find_imported(name, 0, cctx);
     if (import != NULL)
     {
-       if (import->imp_all)
+       if (import->imp_flags & IMP_FLAGS_STAR)
        {
            char_u      *p = skipwhite(*end);
            char_u      *exp_name;
index 9db28ee3c5055feca5db1921b4ae8b3ac81b377d..e423b1c8028503ccfea4ced00fcd485b4c1f5106 100644 (file)
@@ -173,6 +173,24 @@ free_imports_and_script_vars(int sid)
     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 as Alias from 'filename'"
@@ -459,15 +477,29 @@ handle_import(
 
     if (*arg_start == '*')
     {
-       imported_T *imported = new_imported(gap != NULL ? gap
-                                       : &SCRIPT_ITEM(import_sid)->sn_imports);
+       imported_T *imported;
 
+       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)
            goto erret;
        imported->imp_name = as_name;
        as_name = NULL;
        imported->imp_sid = sid;
-       imported->imp_all = TRUE;
+       imported->imp_flags = IMP_FLAGS_STAR;
     }
     else
     {
@@ -479,6 +511,7 @@ handle_import(
        for (i = 0; i < names.ga_len; ++i)
        {
            char_u      *name = ((char_u **)names.ga_data)[i];
+           size_t      len = STRLEN(name);
            int         idx;
            imported_T  *imported;
            ufunc_T     *ufunc = NULL;
@@ -489,28 +522,47 @@ handle_import(
            if (idx < 0 && ufunc == NULL)
                goto erret;
 
-           if (check_defined(name, STRLEN(name), cctx) == FAIL)
-               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)
+           // If already imported with the same propertis and the
+           // IMP_FLAGS_RELOAD set then we keep that entry.  Otherwise create
+           // a new one (and give an error for an existing import).
+           imported = find_imported(name, len, cctx);
+           if (imported != NULL
+                   && (imported->imp_flags & IMP_FLAGS_RELOAD)
+                   && imported->imp_sid == sid
+                   && (idx >= 0
+                       ? (equal_type(imported->imp_type, type)
+                           && imported->imp_var_vals_idx == idx)
+                       : (equal_type(imported->imp_type, ufunc->uf_func_type)
+                           && STRCMP(imported->imp_funcname,
+                                                       ufunc->uf_name) == 0)))
            {
-               imported->imp_type = type;
-               imported->imp_var_vals_idx = idx;
+               imported->imp_flags &= ~IMP_FLAGS_RELOAD;
            }
            else
            {
-               imported->imp_type = ufunc->uf_func_type;
-               imported->imp_funcname = ufunc->uf_name;
+               if (check_defined(name, len, cctx) == FAIL)
+                   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;
+               }
            }
        }
     }