]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4114: Vim9: type checking for a funcref does not work for method v8.2.4114
authorBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 18:06:21 +0000 (18:06 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 16 Jan 2022 18:06:21 +0000 (18:06 +0000)
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.

src/proto/vim9type.pro
src/testdir/test_vim9_expr.vim
src/userfunc.c
src/version.c
src/vim9type.c

index 015531c1ed3c1844220290037b90c203ccc3c9f6..1c80cbf551fa5abd911cdd6d3f4569a975df140d 100644 (file)
@@ -12,12 +12,11 @@ type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags);
 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);
index 039387dc3148caf9bfd1237da6ff0469be263008..e1b48d7db1825adb358e777d24774e7c30349e06 100644 (file)
@@ -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)
 
index 1dd5612b920e59bbb39878c18b573174785cd084..0fb042e38725768675c1eb6688b523f525080e42 100644 (file)
@@ -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;
     }
index 886267428678aa40654c1214b49ac73ec3f0e8c5..d7555595806e22e05817f3633ababd53caa5553e 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4114,
 /**/
     4113,
 /**/
index 5b85c8e53fcb8ff2c3971fd3618b3f8b89af7e60..82c1b5f453d642d81e6c468cc2b09ba7f33bd1ff 100644 (file)
@@ -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;