# HG changeset patch # User Bram Moolenaar # Date 1642356903 -3600 # Node ID 374c7d5a096aefa941ac5ff0d16df365868be44d # Parent 14d0c1d337013b4a9bc82712ac74336334cc0029 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 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. diff --git a/src/proto/vim9type.pro b/src/proto/vim9type.pro --- 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); diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- 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) diff --git a/src/userfunc.c b/src/userfunc.c --- 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; } diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim9type.c b/src/vim9type.c --- 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;