]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2290: Vim9: unlet of global variable cannot be compiled v8.2.2290
authorBram Moolenaar <Bram@vim.org>
Sun, 3 Jan 2021 19:55:26 +0000 (20:55 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 3 Jan 2021 19:55:26 +0000 (20:55 +0100)
Problem:    Vim9: unlet of global variable cannot be compiled.
Solution:   Skip over variables that might be defined later. Give an error if
            a subscript is found. (closes #7585)

src/eval.c
src/testdir/test_vim9_assign.vim
src/version.c
src/vim.h
src/vim9compile.c

index 87da4f325d4d974937016518084bbb92297625ad..75cbca96c531e017c63ccb3b0e2c864a38f21031 100644 (file)
@@ -813,9 +813,9 @@ get_lval(
     // Clear everything in "lp".
     CLEAR_POINTER(lp);
 
-    if (skip)
+    if (skip || (flags & GLV_COMPILING))
     {
-       // When skipping just find the end of the name.
+       // When skipping or compiling just find the end of the name.
        lp->ll_name = name;
        lp->ll_name_end = find_name_end(name, NULL, NULL,
                                                      FNE_INCL_BR | fne_flags);
index 5f45b57a11a0075599feb21fb93e07172bb1449b..bdae6350a6418f6849f4eecf2c42e06cd59df7f7 100644 (file)
@@ -1340,6 +1340,15 @@ def Test_unlet()
   assert_false(exists('s:somevar'))
   unlet! s:somevar
 
+  # can compile unlet before variable exists
+  # This doesn't work yet
+  #g:someDict = {key: 'val'}
+  #var k = 'key'
+  #unlet g:someDict[k]
+  #assert_equal({}, g:someDict)
+  #unlet g:someDict
+  #assert_false(exists('g:someDict'))
+
   CheckScriptFailure([
    'vim9script',
    'var svar = 123',
index c5017a461e770946531df1b09e3c835290c56d2d..55853654441a90f5b7a8d8bbcb3839a3b782c800 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2290,
 /**/
     2289,
 /**/
index a0ee0d6b9059870d19880080fdf9d16342473c15..7ba728a3702ece302a8a9f10b97b7e7b46176701 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2544,12 +2544,14 @@ typedef enum {
 #define TFN_NO_DEREF   0x08    // do not dereference a Funcref
 #define TFN_READ_ONLY  0x10    // will not change the var
 #define TFN_NO_DECL    0x20    // only used for GLV_NO_DECL
+#define TFN_COMPILING  0x40    // only used for GLV_COMPILING
 
 // Values for get_lval() flags argument:
 #define GLV_QUIET      TFN_QUIET       // no error messages
 #define GLV_NO_AUTOLOAD        TFN_NO_AUTOLOAD // do not use script autoloading
 #define GLV_READ_ONLY  TFN_READ_ONLY   // will not change the var
 #define GLV_NO_DECL    TFN_NO_DECL     // assignment without :var or :let
+#define GLV_COMPILING  TFN_COMPILING   // variable may be defined later
 
 #define DO_NOT_FREE_CNT 99999  // refcount for dict or list that should not
                                // be freed.
index 79d28c2bbacd4e200da3a8cea0ae39d1780735a7..412f0c96cc10575db912cf4b4d9a3ed1055452a4 100644 (file)
@@ -6130,6 +6130,12 @@ compile_unlet(
 
        // Normal name.  Only supports g:, w:, t: and b: namespaces.
        *name_end = NUL;
+       if (vim_strchr(p, '.') != NULL || vim_strchr(p, '[') != NULL)
+       {
+           *name_end = cc;
+           goto failed;
+       }
+
        if (*p == '$')
            ret = generate_UNLET(cctx, ISN_UNLETENV, p + 1, eap->forceit);
        else if (check_vim9_unlet(p) == FAIL)
@@ -6141,8 +6147,11 @@ compile_unlet(
        return ret;
     }
 
+failed:
     // TODO: unlet {list}[idx]
     // TODO: unlet {dict}[key]
+    // complication: {list} can be global while "idx" is local, thus we can't
+    // call ex_unlet().
     emsg("Sorry, :unlet not fully implemented yet");
     return FAIL;
 }
@@ -6163,7 +6172,8 @@ compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
     }
 
     // TODO: this doesn't work for local variables
-    ex_unletlock(eap, p, 0, GLV_NO_AUTOLOAD, compile_unlet, cctx);
+    ex_unletlock(eap, p, 0, GLV_NO_AUTOLOAD | GLV_COMPILING,
+                                                         compile_unlet, cctx);
     return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
 }