changeset 31424:e31fc75f6aff v9.0.1045

patch 9.0.1045: in a class object members cannot be initialized Commit: https://github.com/vim/vim/commit/7ce7daf6cd6a7ed27eac060699026640b4b239a8 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Dec 10 18:42:12 2022 +0000 patch 9.0.1045: in a class object members cannot be initialized Problem: In a class object members cannot be initialized. Solution: Support initializing object members. Make "dissassemble" work on an object method.
author Bram Moolenaar <Bram@vim.org>
date Sat, 10 Dec 2022 19:45:04 +0100
parents 66c85efdf4b0
children f283f0df8f36
files src/eval.c src/proto/vim9class.pro src/proto/vim9instr.pro src/structs.h src/testdir/test_vim9_class.vim src/userfunc.c src/version.c src/vim9.h src/vim9class.c src/vim9compile.c src/vim9execute.c src/vim9expr.c src/vim9instr.c
diffstat 13 files changed, 280 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -1193,9 +1193,8 @@ get_lval(
     var2.v_type = VAR_UNKNOWN;
     while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
     {
-	int r = OK;
-
-	if (*p == '.' && lp->ll_tv->v_type != VAR_DICT)
+	if (*p == '.' && lp->ll_tv->v_type != VAR_DICT
+		      && lp->ll_tv->v_type != VAR_CLASS)
 	{
 	    if (!quiet)
 		semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
@@ -1203,7 +1202,8 @@ get_lval(
 	}
 	if (lp->ll_tv->v_type != VAR_LIST
 		&& lp->ll_tv->v_type != VAR_DICT
-		&& lp->ll_tv->v_type != VAR_BLOB)
+		&& lp->ll_tv->v_type != VAR_BLOB
+		&& lp->ll_tv->v_type != VAR_CLASS)
 	{
 	    if (!quiet)
 		emsg(_(e_can_only_index_list_dictionary_or_blob));
@@ -1211,6 +1211,7 @@ get_lval(
 	}
 
 	// A NULL list/blob works like an empty list/blob, allocate one now.
+	int r = OK;
 	if (lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
 	    r = rettv_list_alloc(lp->ll_tv);
 	else if (lp->ll_tv->v_type == VAR_BLOB
@@ -1463,7 +1464,7 @@ get_lval(
 	    lp->ll_tv = NULL;
 	    break;
 	}
-	else
+	else if (lp->ll_tv->v_type == VAR_LIST)
 	{
 	    /*
 	     * Get the number and item for the only or first index of the List.
@@ -1508,6 +1509,11 @@ get_lval(
 
 	    lp->ll_tv = &lp->ll_li->li_tv;
 	}
+	else  // v_type == VAR_CLASS
+	{
+	    // TODO: check object members and methods if
+	    // "key" points name start, "p" to the end
+	}
     }
 
     clear_tv(&var1);
--- a/src/proto/vim9class.pro
+++ b/src/proto/vim9class.pro
@@ -5,6 +5,7 @@ void ex_interface(exarg_T *eap);
 void ex_enum(exarg_T *eap);
 void ex_type(exarg_T *eap);
 int class_object_index(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose);
+ufunc_T *find_class_func(char_u **arg);
 void copy_object(typval_T *from, typval_T *to);
 void object_unref(object_T *obj);
 void copy_class(typval_T *from, typval_T *to);
--- a/src/proto/vim9instr.pro
+++ b/src/proto/vim9instr.pro
@@ -4,7 +4,8 @@ isn_T *generate_instr_drop(cctx_T *cctx,
 isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
 isn_T *generate_instr_debug(cctx_T *cctx);
 int generate_CONSTRUCT(cctx_T *cctx, class_T *cl);
-int generate_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
+int generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type);
+int generate_STORE_THIS(cctx_T *cctx, int idx);
 int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
 int generate_add_instr(cctx_T *cctx, vartype_T vartype, type_T *type1, type_T *type2, exprtype_T expr_type);
 vartype_T operator_type(type_T *type1, type_T *type2);
--- a/src/structs.h
+++ b/src/structs.h
@@ -1463,8 +1463,9 @@ typedef struct {
  * Entry for an object member variable.
  */
 typedef struct {
-    char_u	*om_name;  // allocated
+    char_u	*om_name;   // allocated
     type_T	*om_type;
+    char_u	*om_init;   // allocated
 } objmember_T;
 
 // "class_T": used for v_class of typval of VAR_CLASS
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -129,7 +129,7 @@ def Test_class_basic()
 
       class TextPosition
         this.lnum: number
-	this.col: number
+        this.col: number
 
         def ToString(): string
           return $'({this.lnum}, {this.col})'
@@ -147,5 +147,40 @@ def Test_class_basic()
   v9.CheckScriptSuccess(lines)
 enddef
 
+def Test_class_member_initializer()
+  var lines =<< trim END
+      vim9script
+
+      class TextPosition
+        this.lnum: number = 1
+        this.col: number = 1
+
+        def new(lnum: number)
+          this.lnum = lnum
+        enddef
+      endclass
+
+      var pos = TextPosition.new(3)
+      assert_equal(3, pos.lnum)
+      assert_equal(1, pos.col)
+
+      var instr = execute('disassemble TextPosition.new')
+      assert_match('new\_s*' ..
+            '0 NEW TextPosition size 72\_s*' ..
+            '\d PUSHNR 1\_s*' ..
+            '\d STORE_THIS 0\_s*' ..
+            '\d PUSHNR 1\_s*' ..
+            '\d STORE_THIS 1\_s*' ..
+            'this.lnum = lnum\_s*' ..
+            '\d LOAD arg\[-1]\_s*' ..
+            '\d PUSHNR 0\_s*' ..
+            '\d LOAD $0\_s*' ..
+            '\d\+ STOREINDEX object\_s*' ..
+            '\d\+ RETURN object.*',
+            instr)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -4047,6 +4047,12 @@ trans_function_name(
 	    name = vim_strsave(lv.ll_tv->vval.v_string);
 	    *pp = end;
 	}
+	else if (lv.ll_tv->v_type == VAR_CLASS
+					     && lv.ll_tv->vval.v_class != NULL)
+	{
+	    name = vim_strsave(lv.ll_tv->vval.v_class->class_name);
+	    *pp = end;
+	}
 	else if (lv.ll_tv->v_type == VAR_PARTIAL
 					  && lv.ll_tv->vval.v_partial != NULL)
 	{
@@ -5240,8 +5246,17 @@ find_func_by_name(char_u *name, compilet
 	fname = vim_strnsave(name, arg - name);
     }
     else
+    {
+	// First try finding a method in a class, find_func_by_name() will give
+	// an error if the function is not found.
+	ufunc = find_class_func(&arg);
+	if (ufunc != NULL)
+	    return ufunc;
+
 	fname = trans_function_name(&arg, &is_global, FALSE,
-		      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
+		      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DECL,
+		      NULL, NULL, NULL);
+    }
     if (fname == NULL)
     {
 	semsg(_(e_invalid_argument_str), name);
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1045,
+/**/
     1044,
 /**/
     1043,
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -33,7 +33,9 @@ typedef enum {
     ISN_SOURCE,	    // source autoload script, isn_arg.number is the script ID
     ISN_INSTR,	    // instructions compiled from expression
     ISN_CONSTRUCT,  // construct an object, using contstruct_T
-    ISN_OBJ_MEMBER, // object member, index is isn_arg.number
+    ISN_GET_OBJ_MEMBER, // object member, index is isn_arg.number
+    ISN_STORE_THIS, // store value in "this" object member, index is
+		    // isn_arg.number
 
     // get and set variables
     ISN_LOAD,	    // push local variable isn_arg.number
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -147,12 +147,30 @@ ex_class(exarg_T *eap)
 	    if (type == NULL)
 		break;
 
+	    char_u *expr_start = skipwhite(type_arg);
+	    if (*expr_start == '=' && (!VIM_ISWHITE(expr_start[-1])
+					       || !VIM_ISWHITE(expr_start[1])))
+	    {
+		semsg(_(e_white_space_required_before_and_after_str_at_str),
+								"=", type_arg);
+		break;
+	    }
+	    expr_start = skipwhite(expr_start + 1);
+
+	    char_u *expr_end = expr_start;
+	    evalarg_T	evalarg;
+	    init_evalarg(&evalarg);
+	    skip_expr(&expr_end, &evalarg);
+	    clear_evalarg(&evalarg, NULL);
+
 	    if (ga_grow(&objmembers, 1) == FAIL)
 		break;
 	    objmember_T *m = ((objmember_T *)objmembers.ga_data)
 							  + objmembers.ga_len;
 	    m->om_name = vim_strnsave(varname, varname_end - varname);
 	    m->om_type = type;
+	    if (expr_end > expr_start)
+		m->om_init = vim_strnsave(expr_start, expr_end - expr_start);
 	    ++objmembers.ga_len;
 	}
 
@@ -190,6 +208,9 @@ ex_class(exarg_T *eap)
 	    // TODO: how about errors?
 	    if (uf != NULL && ga_grow(&objmethods, 1) == OK)
 	    {
+		if (STRNCMP(uf->uf_name, "new", 3) == 0)
+		    uf->uf_flags |= FC_NEW;
+
 		((ufunc_T **)objmethods.ga_data)[objmethods.ga_len] = uf;
 		++objmethods.ga_len;
 	    }
@@ -333,6 +354,7 @@ cleanup:
     {
 	objmember_T *m = ((objmember_T *)objmembers.ga_data) + i;
 	vim_free(m->om_name);
+	vim_free(m->om_init);
     }
     ga_clear(&objmembers);
 
@@ -520,6 +542,52 @@ class_object_index(
 }
 
 /*
+ * If "arg" points to a class or object method, return it.
+ * Otherwise return NULL.
+ */
+    ufunc_T *
+find_class_func(char_u **arg)
+{
+    char_u *name = *arg;
+    char_u *name_end = find_name_end(name, NULL, NULL, FNE_CHECK_START);
+    if (name_end == name || *name_end != '.')
+	return NULL;
+
+    size_t len = name_end - name;
+    typval_T tv;
+    tv.v_type = VAR_UNKNOWN;
+    if (eval_variable(name, len, 0, &tv, NULL, EVAL_VAR_NOAUTOLOAD) == FAIL)
+	return NULL;
+    if (tv.v_type != VAR_CLASS && tv.v_type != VAR_OBJECT)
+    {
+	clear_tv(&tv);
+	return NULL;
+    }
+
+    class_T *cl = tv.v_type == VAR_CLASS ? tv.vval.v_class
+						 : tv.vval.v_object->obj_class;
+    if (cl == NULL)
+	return NULL;
+    char_u *fname = name_end + 1;
+    char_u *fname_end = find_name_end(fname, NULL, NULL, FNE_CHECK_START);
+    if (fname_end == fname)
+	return NULL;
+    len = fname_end - fname;
+
+    for (int i = 0; i < cl->class_obj_method_count; ++i)
+    {
+	ufunc_T *fp = cl->class_obj_methods[i];
+	// Use a separate pointer to avoid that ASAN complains about
+	// uf_name[] only being 4 characters.
+	char_u *ufname = (char_u *)fp->uf_name;
+	if (STRNCMP(fname, ufname, len) == 0 && ufname[len] == NUL)
+	    return fp;
+    }
+
+    return NULL;
+}
+
+/*
  * Make a copy of an object.
  */
     void
@@ -585,6 +653,7 @@ class_unref(class_T *cl)
 	{
 	    objmember_T *m = &cl->class_obj_members[i];
 	    vim_free(m->om_name);
+	    vim_free(m->om_init);
 	}
 	vim_free(cl->class_obj_members);
 
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2118,6 +2118,71 @@ compile_assign_unlet(
 }
 
 /*
+ * Generate an instruction to push the default value for "vartype".
+ * if "dest_local" is TRUE then for some types no instruction is generated.
+ * "skip_store" is set to TRUE if no PUSH instruction is generated.
+ * Returns OK or FAIL.
+ */
+    static int
+push_default_value(
+	cctx_T	    *cctx,
+	vartype_T   vartype,
+	int	    dest_is_local,
+	int	    *skip_store)
+{
+    int r = OK;
+
+    switch (vartype)
+    {
+	case VAR_BOOL:
+	    r = generate_PUSHBOOL(cctx, VVAL_FALSE);
+	    break;
+	case VAR_FLOAT:
+	    r = generate_PUSHF(cctx, 0.0);
+	    break;
+	case VAR_STRING:
+	    r = generate_PUSHS(cctx, NULL);
+	    break;
+	case VAR_BLOB:
+	    r = generate_PUSHBLOB(cctx, blob_alloc());
+	    break;
+	case VAR_FUNC:
+	    r = generate_PUSHFUNC(cctx, NULL, &t_func_void, TRUE);
+	    break;
+	case VAR_LIST:
+	    r = generate_NEWLIST(cctx, 0, FALSE);
+	    break;
+	case VAR_DICT:
+	    r = generate_NEWDICT(cctx, 0, FALSE);
+	    break;
+	case VAR_JOB:
+	    r = generate_PUSHJOB(cctx);
+	    break;
+	case VAR_CHANNEL:
+	    r = generate_PUSHCHANNEL(cctx);
+	    break;
+	case VAR_NUMBER:
+	case VAR_UNKNOWN:
+	case VAR_ANY:
+	case VAR_PARTIAL:
+	case VAR_VOID:
+	case VAR_INSTR:
+	case VAR_CLASS:
+	case VAR_OBJECT:
+	case VAR_SPECIAL:  // cannot happen
+	    // This is skipped for local variables, they are always
+	    // initialized to zero.  But in a "for" or "while" loop
+	    // the value may have been changed.
+	    if (dest_is_local && !inside_loop_scope(cctx))
+		*skip_store = TRUE;
+	    else
+		r = generate_PUSHNR(cctx, 0);
+	    break;
+    }
+    return r;
+}
+
+/*
  * Compile declaration and assignment:
  * "let name"
  * "var name = expr"
@@ -2462,62 +2527,12 @@ compile_assignment(char_u *arg, exarg_T 
 	    }
 	    else
 	    {
-		int r = OK;
-
 		// variables are always initialized
 		if (GA_GROW_FAILS(instr, 1))
 		    goto theend;
-		switch (lhs.lhs_member_type->tt_type)
-		{
-		    case VAR_BOOL:
-			r = generate_PUSHBOOL(cctx, VVAL_FALSE);
-			break;
-		    case VAR_FLOAT:
-			r = generate_PUSHF(cctx, 0.0);
-			break;
-		    case VAR_STRING:
-			r = generate_PUSHS(cctx, NULL);
-			break;
-		    case VAR_BLOB:
-			r = generate_PUSHBLOB(cctx, blob_alloc());
-			break;
-		    case VAR_FUNC:
-			r = generate_PUSHFUNC(cctx, NULL, &t_func_void, TRUE);
-			break;
-		    case VAR_LIST:
-			r = generate_NEWLIST(cctx, 0, FALSE);
-			break;
-		    case VAR_DICT:
-			r = generate_NEWDICT(cctx, 0, FALSE);
-			break;
-		    case VAR_JOB:
-			r = generate_PUSHJOB(cctx);
-			break;
-		    case VAR_CHANNEL:
-			r = generate_PUSHCHANNEL(cctx);
-			break;
-		    case VAR_NUMBER:
-		    case VAR_UNKNOWN:
-		    case VAR_ANY:
-		    case VAR_PARTIAL:
-		    case VAR_VOID:
-		    case VAR_INSTR:
-		    case VAR_CLASS:
-		    case VAR_OBJECT:
-		    case VAR_SPECIAL:  // cannot happen
-			// This is skipped for local variables, they are always
-			// initialized to zero.  But in a "for" or "while" loop
-			// the value may have been changed.
-			if (lhs.lhs_dest == dest_local
-						   && !inside_loop_scope(cctx))
-			    skip_store = TRUE;
-			else
-			{
-			    instr_count = instr->ga_len;
-			    r = generate_PUSHNR(cctx, 0);
-			}
-			break;
-		}
+		instr_count = instr->ga_len;
+		int r = push_default_value(cctx, lhs.lhs_member_type->tt_type,
+				      lhs.lhs_dest == dest_local, &skip_store);
 		if (r == FAIL)
 		    goto theend;
 	    }
@@ -2946,9 +2961,32 @@ compile_def_function(
 						 vim_strsave((char_u *)"this");
 	++dfunc->df_var_names.ga_len;
 
-	// In the constructor allocate memory for the object.
+	// In the constructor allocate memory for the object and initialize the
+	// object members.
 	if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
+	{
 	    generate_CONSTRUCT(&cctx, ufunc->uf_class);
+
+	    for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
+	    {
+		objmember_T *m = &ufunc->uf_class->class_obj_members[i];
+		if (m->om_init != NULL)
+		{
+		    char_u *expr = m->om_init;
+		    if (compile_expr0(&expr, &cctx) == FAIL)
+			goto erret;
+		    if (!ends_excmd2(m->om_init, expr))
+		    {
+			semsg(_(e_trailing_characters_str), expr);
+			goto erret;
+		    }
+		}
+		else
+		    push_default_value(&cctx, m->om_type->tt_type,
+								  FALSE, NULL);
+		generate_STORE_THIS(&cctx, i);
+	    }
+	}
     }
 
     if (ufunc->uf_def_args.ga_len > 0)
@@ -3564,7 +3602,10 @@ nextline:
 	// Return void if there is no return at the end.
 	// For a constructor return the object.
 	if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
+	{
 	    generate_instr(&cctx, ISN_RETURN_OBJECT);
+	    ufunc->uf_ret_type = &ufunc->uf_class->class_object_type;
+	}
 	else
 	    generate_instr(&cctx, ISN_RETURN_VOID);
     }
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -3009,7 +3009,7 @@ exec_instructions(ectx_T *ectx)
 	iptr = &ectx->ec_instr[ectx->ec_iidx++];
 	switch (iptr->isn_type)
 	{
-	    // Constructor, new() method.
+	    // Constructor, first instruction in a new() method.
 	    case ISN_CONSTRUCT:
 		// "this" is always the local variable at index zero
 		tv = STACK_TV_VAR(0);
@@ -5114,7 +5114,7 @@ exec_instructions(ectx_T *ectx)
 		}
 		break;
 
-	    case ISN_OBJ_MEMBER:
+	    case ISN_GET_OBJ_MEMBER:
 		{
 		    tv = STACK_TV_BOT(-1);
 		    if (tv->v_type != VAR_OBJECT)
@@ -5143,6 +5143,18 @@ exec_instructions(ectx_T *ectx)
 		}
 		break;
 
+	    case ISN_STORE_THIS:
+		{
+		    int idx = iptr->isn_arg.number;
+		    object_T *obj = STACK_TV_VAR(0)->vval.v_object;
+		    // the members are located right after the object struct
+		    typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
+		    clear_tv(mtv);
+		    *mtv = *STACK_TV_BOT(-1);
+		    --ectx->ec_stack.ga_len;
+		}
+		break;
+
 	    case ISN_CLEARDICT:
 		dict_stack_drop();
 		break;
@@ -6805,7 +6817,9 @@ list_instructions(char *pfx, isn_T *inst
 	    case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
 	    case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
 						  iptr->isn_arg.string); break;
-	    case ISN_OBJ_MEMBER: smsg("%s%4d OBJ_MEMBER %d", pfx, current,
+	    case ISN_GET_OBJ_MEMBER: smsg("%s%4d OBJ_MEMBER %d", pfx, current,
+					     (int)iptr->isn_arg.number); break;
+	    case ISN_STORE_THIS: smsg("%s%4d STORE_THIS %d", pfx, current,
 					     (int)iptr->isn_arg.number); break;
 	    case ISN_CLEARDICT: smsg("%s%4d CLEARDICT", pfx, current); break;
 	    case ISN_USEDICT: smsg("%s%4d USEDICT", pfx, current); break;
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -253,7 +253,6 @@ compile_member(int is_slice, int *keepin
 /*
  * Compile ".member" coming after an object or class.
  */
-
     static int
 compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
 {
@@ -282,7 +281,7 @@ compile_class_object_index(cctx_T *cctx,
 	    objmember_T *m = &cl->class_obj_members[i];
 	    if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
 	    {
-		generate_OBJ_MEMBER(cctx, i, m->om_type);
+		generate_GET_OBJ_MEMBER(cctx, i, m->om_type);
 
 		*arg = name_end;
 		return OK;
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -132,15 +132,16 @@ generate_CONSTRUCT(cctx_T *cctx, class_T
 }
 
 /*
- * Generate ISN_OBJ_MEMBER - access object member by indes.
+ * Generate ISN_GET_OBJ_MEMBER - access member of object at bottom of stack by
+ * index.
  */
     int
-generate_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
+generate_GET_OBJ_MEMBER(cctx_T *cctx, int idx, type_T *type)
 {
     RETURN_OK_IF_SKIP(cctx);
 
     // drop the object type
-    isn_T *isn = generate_instr_drop(cctx, ISN_OBJ_MEMBER, 1);
+    isn_T *isn = generate_instr_drop(cctx, ISN_GET_OBJ_MEMBER, 1);
     if (isn == NULL)
 	return FAIL;
 
@@ -149,6 +150,24 @@ generate_OBJ_MEMBER(cctx_T *cctx, int id
 }
 
 /*
+ * Generate ISN_STORE_THIS - store value in member of "this" object with member
+ * index "idx".
+ */
+    int
+generate_STORE_THIS(cctx_T *cctx, int idx)
+{
+    RETURN_OK_IF_SKIP(cctx);
+
+    // drop the value type
+    isn_T *isn = generate_instr_drop(cctx, ISN_STORE_THIS, 1);
+    if (isn == NULL)
+	return FAIL;
+
+    isn->isn_arg.number = idx;
+    return OK;
+}
+
+/*
  * If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
  * But only for simple types.
  * When "tolerant" is TRUE convert most types to string, e.g. a List.
@@ -2458,6 +2477,7 @@ delete_instr(isn_T *isn)
 	case ISN_FINISH:
 	case ISN_FOR:
 	case ISN_GETITEM:
+	case ISN_GET_OBJ_MEMBER:
 	case ISN_JUMP:
 	case ISN_JUMP_IF_ARG_SET:
 	case ISN_LISTAPPEND:
@@ -2477,7 +2497,6 @@ delete_instr(isn_T *isn)
 	case ISN_NEWDICT:
 	case ISN_NEWLIST:
 	case ISN_NEWPARTIAL:
-	case ISN_OBJ_MEMBER:
 	case ISN_OPANY:
 	case ISN_OPFLOAT:
 	case ISN_OPNR:
@@ -2495,8 +2514,8 @@ delete_instr(isn_T *isn)
 	case ISN_REDIREND:
 	case ISN_REDIRSTART:
 	case ISN_RETURN:
+	case ISN_RETURN_OBJECT:
 	case ISN_RETURN_VOID:
-	case ISN_RETURN_OBJECT:
 	case ISN_SHUFFLE:
 	case ISN_SLICE:
 	case ISN_SOURCE:
@@ -2504,6 +2523,7 @@ delete_instr(isn_T *isn)
 	case ISN_STOREINDEX:
 	case ISN_STORENR:
 	case ISN_STOREOUTER:
+	case ISN_STORE_THIS:
 	case ISN_STORERANGE:
 	case ISN_STOREREG:
 	case ISN_STOREV: