summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2023-10-11 21:35:11 +0200
committerChristian Brabandt <cb@256bit.org>2023-10-11 21:38:24 +0200
commit4c8da025ef8140168b7a09d9fe922ce4bb40f19d (patch)
tree73571eb4b3ba86ed7a2f00c9897796bfc92111d0 /src/eval.c
parentc97b3febc82c1ccacf5f328ed0bd81c8b850e97d (diff)
patch 9.0.2015: Vim9: does not handle islocked() from a method correctlyv9.0.2015
Problem: Vim9: does not handle islocked() from a method correctly Solution: Handle islocked() builtin from a method. - Setup `lval_root` from `f_islocked()`. - Add function `fill_exec_lval_root()` to get info about executing method. - `sync_root` added in get_lval to handle method member access. - Conservative approach to reference counting. closes: #13309 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c79
1 files changed, 63 insertions, 16 deletions
diff --git a/src/eval.c b/src/eval.c
index 8b26eb189f..4da6246ace 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1050,11 +1050,14 @@ flag_string_T glv_flag_strings[] = {
* execute_instructions: ISN_LOCKUNLOCK - sets lval_root from stack.
*/
static void
-get_lval_root(lval_T *lp, lval_root_T *lr)
+fill_lval_from_lval_root(lval_T *lp, lval_root_T *lr)
{
#ifdef LOG_LOCKVAR
- ch_log(NULL, "LKVAR: get_lval_root(): name %s", lp->ll_name);
+ ch_log(NULL, "LKVAR: fill_lval_from_lval_root(): name %s, tv %p",
+ lp->ll_name, (void*)lr->lr_tv);
#endif
+ if (lr->lr_tv == NULL)
+ return;
if (!lr->lr_is_arg && lr->lr_tv->v_type == VAR_CLASS)
{
if (lr->lr_tv->vval.v_class != NULL)
@@ -1177,15 +1180,14 @@ get_lval(
#ifdef LOG_LOCKVAR
if (lval_root == NULL)
- ch_log(NULL,
- "LKVAR: get_lval(): name %s, lval_root (nil)", name);
+ ch_log(NULL, "LKVAR: get_lval(): name: %s, lval_root (nil)", name);
else
- ch_log(NULL,
- "LKVAR: get_lval(): name %s, lr_tv %p lr_is_arg %d",
- name, (void*)lval_root->lr_tv, lval_root->lr_is_arg);
+ ch_log(NULL, "LKVAR: get_lval(): name: %s, lr_tv %p lr_is_arg %d",
+ name, (void*)lval_root->lr_tv, lval_root->lr_is_arg);
char buf[80];
- ch_log(NULL, "LKVAR: ...: GLV flags %s",
+ ch_log(NULL, "LKVAR: ...: GLV flags: %s",
flags_tostring(flags, glv_flag_strings, buf, sizeof(buf)));
+ int log_sync_root_key = FALSE;
#endif
// Clear everything in "lp".
@@ -1324,20 +1326,26 @@ get_lval(
}
}
- // Without [idx] or .key we are done.
- if ((*p != '[' && *p != '.'))
+ int sync_root = FALSE;
+ if (vim9script && lval_root != NULL)
+ {
+ cl_exec = lval_root->lr_cl_exec;
+ sync_root = lval_root->lr_sync_root;
+ }
+
+ // Without [idx] or .key we are done, unless doing sync_root.
+ if (*p != '[' && *p != '.' && (*name == NUL || !sync_root))
{
if (lval_root != NULL)
- get_lval_root(lp, lval_root);
+ fill_lval_from_lval_root(lp, lval_root);
return p;
}
- if (vim9script && lval_root != NULL)
+ if (vim9script && lval_root != NULL && lval_root->lr_tv != NULL)
{
// using local variable
lp->ll_tv = lval_root->lr_tv;
v = NULL;
- cl_exec = lval_root->lr_cl_exec;
}
else
{
@@ -1367,7 +1375,7 @@ get_lval(
*/
var1.v_type = VAR_UNKNOWN;
var2.v_type = VAR_UNKNOWN;
- while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
+ while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.') || sync_root)
{
vartype_T v_type = lp->ll_tv->v_type;
@@ -1407,6 +1415,10 @@ get_lval(
emsg(_(e_slice_must_come_last));
return NULL;
}
+#ifdef LOG_LOCKVAR
+ ch_log(NULL, "LKVAR: get_lval() loop: p: %s, type: %s", p,
+ vartype_name(v_type));
+#endif
if (vim9script && lp->ll_valtype == NULL
&& v != NULL
@@ -1417,11 +1429,29 @@ get_lval(
// Vim9 script local variable: get the type
if (sv != NULL)
+ {
lp->ll_valtype = sv->sv_type;
+#ifdef LOG_LOCKVAR
+ ch_log(NULL, "LKVAR: ... loop: vim9 assign type: %s",
+ vartype_name(lp->ll_valtype->tt_type));
+#endif
+ }
}
len = -1;
- if (*p == '.')
+ if (sync_root)
+ {
+ // For example, the first token is a member variable name and
+ // lp->ll_tv is a class/object.
+ // Process it directly without looking for "[idx]" or ".name".
+ key = name;
+ sync_root = FALSE; // only first time through
+#ifdef LOG_LOCKVAR
+ log_sync_root_key = TRUE;
+ ch_log(NULL, "LKVAR: ... loop: name: %s, sync_root", name);
+#endif
+ }
+ else if (*p == '.')
{
key = p + 1;
for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
@@ -1512,6 +1542,17 @@ get_lval(
// Skip to past ']'.
++p;
}
+#ifdef LOG_LOCKVAR
+ if (log_sync_root_key)
+ ch_log(NULL, "LKVAR: ... loop: p: %s, sync_root key: %s", p,
+ key);
+ else if (len == -1)
+ ch_log(NULL, "LKVAR: ... loop: p: %s, '[' key: %s", p,
+ empty1 ? ":" : (char*)tv_get_string(&var1));
+ else
+ ch_log(NULL, "LKVAR: ... loop: p: %s, '.' key: %s", p, key);
+ log_sync_root_key = FALSE;
+#endif
if (v_type == VAR_DICT)
{
@@ -1700,8 +1741,14 @@ get_lval(
lp->ll_list = NULL;
class_T *cl;
- if (v_type == VAR_OBJECT && lp->ll_tv->vval.v_object != NULL)
+ if (v_type == VAR_OBJECT)
{
+ if (lp->ll_tv->vval.v_object == NULL)
+ {
+ if (!quiet)
+ emsg(_(e_using_null_object));
+ return NULL;
+ }
cl = lp->ll_tv->vval.v_object->obj_class;
lp->ll_object = lp->ll_tv->vval.v_object;
}