summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-01-03 20:55:26 +0100
committerBram Moolenaar <Bram@vim.org>2021-01-03 20:55:26 +0100
commit2ef951dd31505874ae9ac35a18513ef34ae0ea3e (patch)
treea9be93c17454efbd7edec7c520d6ebaea55f7135
parente5a2dc87fd9d63dfd0d9c379e363ee8b8c05b14c (diff)
downloadvim-git-2ef951dd31505874ae9ac35a18513ef34ae0ea3e.tar.gz
patch 8.2.2290: Vim9: unlet of global variable cannot be compiledv8.2.2290
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)
-rw-r--r--src/eval.c4
-rw-r--r--src/testdir/test_vim9_assign.vim9
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h2
-rw-r--r--src/vim9compile.c12
5 files changed, 26 insertions, 3 deletions
diff --git a/src/eval.c b/src/eval.c
index 87da4f325..75cbca96c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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);
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 5f45b57a1..bdae6350a 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -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',
diff --git a/src/version.c b/src/version.c
index c5017a461..558536544 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2290,
+/**/
2289,
/**/
2288,
diff --git a/src/vim.h b/src/vim.h
index a0ee0d6b9..7ba728a37 100644
--- 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.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 79d28c2bb..412f0c96c 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
}