diff --git a/src/evalfunc.c b/src/evalfunc.c
index 0a100748d921f546dbc5db1114ee63cb1845e465..86a676ca864c43f321b2ca27da4747f625174636 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -465,8 +465,8 @@ static funcentry_T global_functions[] =
     {"acos",		1, 1, FEARG_1,	  ret_float,	FLOAT_FUNC(f_acos)},
     {"add",		2, 2, FEARG_1,	  ret_first_arg, f_add},
     {"and",		2, 2, FEARG_1,	  ret_number,	f_and},
-    {"append",		2, 2, FEARG_LAST, ret_number,	f_append},
-    {"appendbufline",	3, 3, FEARG_LAST, ret_number,	f_appendbufline},
+    {"append",		2, 2, FEARG_2,	  ret_number,	f_append},
+    {"appendbufline",	3, 3, FEARG_2,	  ret_number,	f_appendbufline},
     {"argc",		0, 1, 0,	  ret_number,	f_argc},
     {"argidx",		0, 0, 0,	  ret_number,	f_argidx},
     {"arglistid",	0, 2, 0,	  ret_number,	f_arglistid},
@@ -1191,7 +1191,9 @@ internal_func_ret_type(int idx, int argcount, type_T **argtypes)
 
 /*
  * Check the argument count to use for internal function "idx".
- * Returns OK or FAIL;
+ * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
+ * first argument, 2 if method base is second argument, etc.  9 if method base
+ * is last argument.
  */
     int
 check_internal_func(int idx, int argcount)
@@ -1204,14 +1206,14 @@ check_internal_func(int idx, int argcount)
     else if (argcount > global_functions[idx].f_max_argc)
 	res = FCERR_TOOMANY;
     else
-	return OK;
+	return global_functions[idx].f_argtype;
 
     name = internal_func_name(idx);
     if (res == FCERR_TOOMANY)
 	semsg(_(e_toomanyarg), name);
     else
 	semsg(_(e_toofewarg), name);
-    return FAIL;
+    return -1;
 }
 
     int
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 27d16a5802e904025254e1f2be52ade089af4e4c..a63779a7e89d7f12296d2afdcf387fed637de605 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -1278,4 +1278,22 @@ def Test_simplify_const_expr()
         res)
 enddef
 
+def s:CallAppend()
+  eval "some text"->append(2)
+enddef
+
+def Test_shuffle()
+  let res = execute('disass s:CallAppend')
+  assert_match('<SNR>\d*_CallAppend\_s*' ..
+        'eval "some text"->append(2)\_s*' ..
+        '\d PUSHS "some text"\_s*' ..
+        '\d PUSHNR 2\_s*' ..
+        '\d SHUFFLE 2 up 1\_s*' ..
+        '\d BCALL append(argc 2)\_s*' ..
+        '\d DROP\_s*' ..
+        '\d PUSHNR 0\_s*' ..
+        '\d RETURN',
+        res)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index b4e060494307d320741495d631dea18b535e1b31..83b7692090ac5db0d0dd347170a7ba86c03dd0cd 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -1411,6 +1411,28 @@ def Test_expr7_subscript_linebreak()
 	one)
 enddef
 
+def Test_expr7_method_call()
+  new
+  setline(1, ['first', 'last'])
+  eval 'second'->append(1)
+  assert_equal(['first', 'second', 'last'], getline(1, '$'))
+  bwipe!
+
+  let bufnr = bufnr()
+  let loclist = [#{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
+  loclist->setloclist(0)
+  assert_equal([#{bufnr: bufnr,
+  		lnum: 42,
+		col: 17,
+		text: 'wrong',
+		pattern: '',
+		valid: 1,
+		vcol: 0,
+		nr: 0,
+		type: '',
+		module: ''}
+		], getloclist(0))
+enddef
 
 func Test_expr7_trailing_fails()
   call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107')
diff --git a/src/version.c b/src/version.c
index 9fcf578ffc0bf20eb9cd6b7ed57e575398bd20a9..c607f4ededf6138569167761443147ec11dc9085 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1167,
 /**/
     1166,
 /**/
diff --git a/src/vim9.h b/src/vim9.h
index 259bdb91104dd6de50089c310370add1baff6259..10f983ca976de33962986e1f1a0c2ea058e237e6 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -124,6 +124,7 @@ typedef enum {
     ISN_CHECKTYPE,  // check value type is isn_arg.type.tc_type
     ISN_CHECKLEN,   // check list length is isn_arg.checklen.cl_min_len
 
+    ISN_SHUFFLE,    // move item on stack up or down
     ISN_DROP	    // pop stack and discard value
 } isntype_T;
 
@@ -237,6 +238,12 @@ typedef struct {
     int		cl_more_OK;	// longer is allowed
 } checklen_T;
 
+// arguments to ISN_SHUFFLE
+typedef struct {
+    int		shfl_item;	// item to move (relative to top of stack)
+    int		shfl_up;	// places to move upwards
+} shuffle_T;
+
 /*
  * Instruction
  */
@@ -270,6 +277,7 @@ struct isn_S {
 	unlet_T		    unlet;
 	funcref_T	    funcref;
 	checklen_T	    checklen;
+	shuffle_T	    shuffle;
     } isn_arg;
 };
 
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 941309ffbd2c0c96b15025b0b33db47ae6b35fba..93ab3c8c05b128c935a9d7546e7cc06ce255585e 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1445,20 +1445,31 @@ generate_FOR(cctx_T *cctx, int loop_idx)
 
 /*
  * Generate an ISN_BCALL instruction.
+ * "method_call" is TRUE for "value->method()"
  * Return FAIL if the number of arguments is wrong.
  */
     static int
-generate_BCALL(cctx_T *cctx, int func_idx, int argcount)
+generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
 {
     isn_T	*isn;
     garray_T	*stack = &cctx->ctx_type_stack;
+    int		argoff;
     type_T	*argtypes[MAX_FUNC_ARGS];
     int		i;
 
     RETURN_OK_IF_SKIP(cctx);
-    if (check_internal_func(func_idx, argcount) == FAIL)
+    argoff = check_internal_func(func_idx, argcount);
+    if (argoff < 0)
 	return FAIL;
 
+    if (method_call && argoff > 1)
+    {
+	if ((isn = generate_instr(cctx, ISN_SHUFFLE)) == NULL)
+	    return FAIL;
+	isn->isn_arg.shuffle.shfl_item = argcount;
+	isn->isn_arg.shuffle.shfl_up = argoff - 1;
+    }
+
     if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
 	return FAIL;
     isn->isn_arg.bfunc.cbf_idx = func_idx;
@@ -2930,7 +2941,7 @@ compile_call(
 	// builtin function
 	idx = find_internal_func(name);
 	if (idx >= 0)
-	    res = generate_BCALL(cctx, idx, argcount);
+	    res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
 	else
 	    semsg(_(e_unknownfunc), namebuf);
 	goto theend;
@@ -7397,6 +7408,7 @@ delete_instr(isn_T *isn)
 	case ISN_COMPARESTRING:
 	case ISN_CONCAT:
 	case ISN_DCALL:
+	case ISN_SHUFFLE:
 	case ISN_DROP:
 	case ISN_ECHO:
 	case ISN_ECHOERR:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index a3cea806ee31a668c6a142ed89dd3661fff6d0d0..544c4226b2a91e31c33f965bb7ae1e5f849f83d2 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -554,7 +554,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
 
 	if (func_idx < 0)
 	    return FAIL;
-	if (check_internal_func(func_idx, argcount) == FAIL)
+	if (check_internal_func(func_idx, argcount) < 0)
 	    return FAIL;
 	return call_bfunc(func_idx, argcount, ectx);
     }
@@ -2333,6 +2333,22 @@ call_def_function(
 		}
 		break;
 
+	    case ISN_SHUFFLE:
+		{
+		    typval_T	    tmp_tv;
+		    int		    item = iptr->isn_arg.shuffle.shfl_item;
+		    int		    up = iptr->isn_arg.shuffle.shfl_up;
+
+		    tmp_tv = *STACK_TV_BOT(-item);
+		    for ( ; up > 0 && item > 1; --up)
+		    {
+			*STACK_TV_BOT(-item) = *STACK_TV_BOT(-item + 1);
+			--item;
+		    }
+		    *STACK_TV_BOT(-item) = tmp_tv;
+		}
+		break;
+
 	    case ISN_DROP:
 		--ectx.ec_stack.ga_len;
 		clear_tv(STACK_TV_BOT(0));
@@ -2900,8 +2916,12 @@ ex_disassemble(exarg_T *eap)
 			    break;
 	    case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
 					 (long long)(iptr->isn_arg.number));
-				break;
+			      break;
 
+	    case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
+					 iptr->isn_arg.shuffle.shfl_item,
+					 iptr->isn_arg.shuffle.shfl_up);
+			      break;
 	    case ISN_DROP: smsg("%4d DROP", current); break;
 	}
     }