changeset 27171:374c7d5a096a v8.2.4114

patch 8.2.4114: Vim9: type checking for a funcref does not work for method Commit: https://github.com/vim/vim/commit/c84287d6d8dd055bb6e30605465a23a8addb6fde Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 16 18:06:21 2022 +0000 patch 8.2.4114: Vim9: type checking for a funcref does not work for method Problem: Vim9: type checking for a funcref does not work for when it is used in a method. Solution: Pass the base to where the type is checked.
author Bram Moolenaar <Bram@vim.org>
date Sun, 16 Jan 2022 19:15:03 +0100
parents 14d0c1d33701
children e3eab17e6c74
files src/proto/vim9type.pro src/testdir/test_vim9_expr.vim src/userfunc.c src/version.c src/vim9type.c
diffstat 5 files changed, 31 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/proto/vim9type.pro
+++ b/src/proto/vim9type.pro
@@ -12,12 +12,11 @@ type_T *typval2type(typval_T *tv, int co
 type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
 int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
 int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
-void type_mismatch(type_T *expected, type_T *actual);
 void arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx);
 void type_mismatch_where(type_T *expected, type_T *actual, where_T where);
 int check_type(type_T *expected, type_T *actual, int give_msg, where_T where);
 int check_type_maybe(type_T *expected, type_T *actual, int give_msg, where_T where);
-int check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u *name);
+int check_argument_types(type_T *type, typval_T *argvars, int argcount, typval_T *base_tv, char_u *name);
 char_u *skip_type(char_u *start, int optional);
 type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
 int equal_type(type_T *type1, type_T *type2, int flags);
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -3136,6 +3136,14 @@ def Test_expr7_method_call()
       var sorted = [3, 1, 2]
                     -> sort()
       assert_equal([1, 2, 3], sorted)
+
+      def SetNumber(n: number)
+        g:number = n
+      enddef
+      const Setit = SetNumber
+      len('text')->Setit()
+      assert_equal(4, g:number)
+      unlet g:number
   END
   CheckDefAndScriptSuccess(lines)
 
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3386,7 +3386,8 @@ call_func(
 						       && funcexe->fe_evaluate)
     {
 	// Check that the argument types are OK for the types of the funcref.
-	if (check_argument_types(funcexe->fe_check_type, argvars, argcount,
+	if (check_argument_types(funcexe->fe_check_type,
+					 argvars, argcount, funcexe->fe_basetv,
 				     (name != NULL) ? name : funcname) == FAIL)
 	    error = FCERR_OTHER;
     }
--- 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 */
 /**/
+    4114,
+/**/
     4113,
 /**/
     4112,
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -687,6 +687,7 @@ check_type_maybe(
 
 /*
  * Check that the arguments of "type" match "argvars[argcount]".
+ * "base_tv" is from "expr->Func()".
  * Return OK/FAIL.
  */
     int
@@ -694,19 +695,21 @@ check_argument_types(
 	type_T	    *type,
 	typval_T    *argvars,
 	int	    argcount,
+	typval_T    *base_tv,
 	char_u	    *name)
 {
     int	    varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
     int	    i;
+    int	    totcount = argcount + (base_tv == NULL ? 0 : 1);
 
     if (type->tt_type != VAR_FUNC && type->tt_type != VAR_PARTIAL)
 	return OK;  // just in case
-    if (argcount < type->tt_min_argcount - varargs)
+    if (totcount < type->tt_min_argcount - varargs)
     {
 	semsg(_(e_not_enough_arguments_for_function_str), name);
 	return FAIL;
     }
-    if (!varargs && type->tt_argcount >= 0 && argcount > type->tt_argcount)
+    if (!varargs && type->tt_argcount >= 0 && totcount > type->tt_argcount)
     {
 	semsg(_(e_too_many_arguments_for_function_str), name);
 	return FAIL;
@@ -715,15 +718,25 @@ check_argument_types(
 	return OK;  // cannot check
 
 
-    for (i = 0; i < argcount; ++i)
+    for (i = 0; i < totcount; ++i)
     {
-	type_T	*expected;
+	type_T	    *expected;
+	typval_T    *tv;
 
+	if (base_tv != NULL)
+	{
+	    if (i == 0)
+		tv = base_tv;
+	    else
+		tv = &argvars[i - 1];
+	}
+	else
+	    tv = &argvars[i];
 	if (varargs && i >= type->tt_argcount - 1)
 	    expected = type->tt_args[type->tt_argcount - 1]->tt_member;
 	else
 	    expected = type->tt_args[i];
-	if (check_typval_arg_type(expected, &argvars[i], NULL, i + 1) == FAIL)
+	if (check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
 	    return FAIL;
     }
     return OK;