patch 8.1.1816: cannot use a user defined function as a method

Problem:    Cannot use a user defined function as a method.
Solution:   Pass the base as the first argument to the user defined function
            after "->". (partly by FUJIWARA Takuya)
diff --git a/src/eval.c b/src/eval.c
index 7875ede..16ced40 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -4734,7 +4734,7 @@
     *arg = skipwhite(*arg);
 
     /* Handle following '[', '(' and '.' for expr[expr], expr.name,
-     * expr(expr). */
+     * expr(expr), expr->name(expr) */
     if (ret == OK)
 	ret = handle_subscript(arg, rettv, evaluate, TRUE);
 
@@ -4824,7 +4824,7 @@
 
     // Locate the method name.
     name = *arg;
-    for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; ++len)
+    for (len = 0; eval_isnamec(name[len]); ++len)
 	;
     if (len == 0)
     {
@@ -4842,6 +4842,8 @@
     }
     *arg += len;
 
+    // TODO: if "name" is a function reference, resolve it.
+
     vim_memset(&funcexe, 0, sizeof(funcexe));
     funcexe.evaluate = evaluate;
     funcexe.basetv = &base;
diff --git a/src/testdir/sautest/autoload/foo.vim b/src/testdir/sautest/autoload/foo.vim
index d7dcd5c..298e727 100644
--- a/src/testdir/sautest/autoload/foo.vim
+++ b/src/testdir/sautest/autoload/foo.vim
@@ -5,3 +5,7 @@
 func foo#bar.echo()
   let g:called_foo_bar_echo += 1
 endfunc
+
+func foo#addFoo(head)
+  return a:head .. 'foo'
+endfunc
diff --git a/src/testdir/test_autoload.vim b/src/testdir/test_autoload.vim
index 7396c22..b8c4fa2 100644
--- a/src/testdir/test_autoload.vim
+++ b/src/testdir/test_autoload.vim
@@ -8,6 +8,8 @@
   call g:foo#bar.echo()
   call assert_equal(1, g:loaded_foo_vim)
   call assert_equal(1, g:called_foo_bar_echo)
+
+  eval 'bar'->g:foo#addFoo()->assert_equal('barfoo')
 endfunc
 
 func Test_source_autoload()
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
index 666c06c..4b4a276 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/testdir/test_user_func.vim
@@ -47,7 +47,7 @@
 endfunc
 
 func Test_user_func()
-  let g:FuncRef=function("FuncWithRef")
+  let g:FuncRef = function("FuncWithRef")
   let g:counter = 0
   inoremap <expr> ( ListItem()
   inoremap <expr> [ ListReset()
@@ -62,6 +62,14 @@
   call assert_equal(9, g:retval)
   call assert_equal(333, g:FuncRef(333))
 
+  let g:retval = "nop"
+  call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf"))
+  call assert_equal('fail', 45->Compute(0, "retval"))
+  call assert_equal('nop', g:retval)
+  call assert_equal('ok', 45->Compute(5, "retval"))
+  call assert_equal(9, g:retval)
+  " call assert_equal(333, 333->g:FuncRef())
+
   enew
 
   normal oXX+-XX
@@ -144,3 +152,11 @@
 	\ .. "   endfunction",
 	\ execute('func Args2'))
 endfunc
+
+func s:addFoo(lead)
+  return a:lead .. 'foo'
+endfunc
+
+func Test_user_method()
+  eval 'bar'->s:addFoo()->assert_equal('barfoo')
+endfunc
diff --git a/src/userfunc.c b/src/userfunc.c
index 8e834a3..a609196 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1495,7 +1495,8 @@
     int		argcount = argcount_in;
     typval_T	*argvars = argvars_in;
     dict_T	*selfdict = funcexe->selfdict;
-    typval_T	argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
+    typval_T	argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
+					 // "funcexe->basetv" is not NULL
     int		argv_clear = 0;
     partial_T	*partial = funcexe->partial;
 
@@ -1554,10 +1555,7 @@
 	    /*
 	     * User defined function.
 	     */
-	    if (funcexe->basetv != NULL)
-		// TODO: support User function: base->Method()
-		fp = NULL;
-	    else if (partial != NULL && partial->pt_func != NULL)
+	    if (partial != NULL && partial->pt_func != NULL)
 		fp = partial->pt_func;
 	    else
 		fp = find_func(rfname);
@@ -1586,6 +1584,16 @@
 		    argcount = funcexe->argv_func(argcount, argvars,
 							   fp->uf_args.ga_len);
 
+		if (funcexe->basetv != NULL)
+		{
+		    // Method call: base->Method()
+		    mch_memmove(&argv[1], argvars, sizeof(typval_T) * argcount);
+		    argv[0] = *funcexe->basetv;
+		    argcount++;
+		}
+		else
+		    memcpy(argv, argvars, sizeof(typval_T) * argcount);
+
 		if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL)
 		    *funcexe->doesrange = TRUE;
 		if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len)
@@ -1613,7 +1621,7 @@
 			did_save_redo = TRUE;
 		    }
 		    ++fp->uf_calls;
-		    call_user_func(fp, argcount, argvars, rettv,
+		    call_user_func(fp, argcount, argv, rettv,
 					 funcexe->firstline, funcexe->lastline,
 				  (fp->uf_flags & FC_DICT) ? selfdict : NULL);
 		    if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
@@ -1630,7 +1638,8 @@
 	else if (funcexe->basetv != NULL)
 	{
 	    /*
-	     * Find the method name in the table, call its implementation.
+	     * expr->method(): Find the method name in the table, call its
+	     * implementation with the base as one of the arguments.
 	     */
 	    error = call_internal_method(fname, argcount, argvars, rettv,
 							      funcexe->basetv);
diff --git a/src/version.c b/src/version.c
index 43e692a..5c806a8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -774,6 +774,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1816,
+/**/
     1815,
 /**/
     1814,