Patch 9.0.1559
Problem: Function argument types not always checked and using v:none may
cause an error.
Solution: Check argument types once the function type is known. Do not give
an error for using v:none as an argument. (closes #12200)
Files: src/userfunc.c, src/vim9type.c, src/testdir/test_vim9_func.vim
*** ../vim-9.0.1558/src/userfunc.c 2023-05-02 16:25:35.630819728 +0100
--- src/userfunc.c 2023-05-15 16:15:42.346367334 +0100
***************
*** 3596,3601 ****
--- 3596,3629 ----
}
/*
+ * Check the argument types "argvars[argcount]" for "name" using the
+ * information in "funcexe". When "base_included" then "funcexe->fe_basetv"
+ * is already included in "argvars[]".
+ * Will do nothing if "funcexe->fe_check_type" is NULL or
+ * "funcexe->fe_evaluate" is FALSE;
+ * Returns an FCERR_ value.
+ */
+ static funcerror_T
+ may_check_argument_types(
+ funcexe_T *funcexe,
+ typval_T *argvars,
+ int argcount,
+ int base_included,
+ char_u *name)
+ {
+ if (funcexe->fe_check_type != NULL && 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,
+ base_included ? NULL : funcexe->fe_basetv,
+ name) == FAIL)
+ return FCERR_OTHER;
+ }
+ return FCERR_NONE;
+ }
+
+ /*
* Call a function with its resolved parameters
*
* Return FAIL when the function can't be called, OK otherwise.
***************
*** 3691,3705 ****
}
}
! if (error == FCERR_NONE && funcexe->fe_check_type != NULL
! && 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, funcexe->fe_basetv,
! (name != NULL) ? name : funcname) == FAIL)
! error = FCERR_OTHER;
! }
if (error == FCERR_NONE && funcexe->fe_evaluate)
{
--- 3719,3728 ----
}
}
! if (error == FCERR_NONE)
! // check the argument types if possible
! error = may_check_argument_types(funcexe, argvars, argcount, FALSE,
! (name != NULL) ? name : funcname);
if (error == FCERR_NONE && funcexe->fe_evaluate)
{
***************
*** 3761,3770 ****
error = FCERR_DELETED;
else if (fp != NULL)
{
if (funcexe->fe_argv_func != NULL)
// postponed filling in the arguments, do it now
argcount = funcexe->fe_argv_func(argcount, argvars,
! argv_clear, fp);
if (funcexe->fe_basetv != NULL)
{
--- 3784,3803 ----
error = FCERR_DELETED;
else if (fp != NULL)
{
+ int need_arg_check = FALSE;
+ if (funcexe->fe_check_type == NULL)
+ {
+ funcexe->fe_check_type = fp->uf_func_type;
+ need_arg_check = TRUE;
+ }
+
if (funcexe->fe_argv_func != NULL)
+ {
// postponed filling in the arguments, do it now
argcount = funcexe->fe_argv_func(argcount, argvars,
! argv_clear, fp);
! need_arg_check = TRUE;
! }
if (funcexe->fe_basetv != NULL)
{
***************
*** 3774,3782 ****
argcount++;
argvars = argv;
argv_base = 1;
}
! error = call_user_func_check(fp, argcount, argvars, rettv,
funcexe, selfdict);
}
}
--- 3807,3822 ----
argcount++;
argvars = argv;
argv_base = 1;
+ need_arg_check = TRUE;
}
! // Check the argument types now that the function type and all
! // argument values are known, if not done above.
! if (need_arg_check)
! error = may_check_argument_types(funcexe, argvars, argcount,
! TRUE, (name != NULL) ? name : funcname);
! if (error == FCERR_NONE || error == FCERR_UNKNOWN)
! error = call_user_func_check(fp, argcount, argvars, rettv,
funcexe, selfdict);
}
}
*** ../vim-9.0.1558/src/vim9type.c 2023-03-07 17:13:47.317107770 +0000
--- src/vim9type.c 2023-05-15 15:54:10.556644165 +0100
***************
*** 970,976 ****
}
else
expected = type->tt_args[i];
! if (check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
return FAIL;
}
return OK;
--- 970,979 ----
}
else
expected = type->tt_args[i];
!
! // check the type, unless the value is v:none
! if ((tv->v_type != VAR_SPECIAL || tv->vval.v_number != VVAL_NONE)
! && check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
return FAIL;
}
return OK;
*** ../vim-9.0.1558/src/testdir/test_vim9_func.vim 2023-05-14 19:59:55.269425158 +0100
--- src/testdir/test_vim9_func.vim 2023-05-15 16:21:32.050991057 +0100
***************
*** 778,783 ****
--- 778,815 ----
END
v9.CheckScriptSuccess(lines)
+ lines =<< trim END
+ vim9script
+
+ export def Floats(x: float, y = 2.0, z = 5.0)
+ g:result = printf("%.2f %.2f %.2f", x, y, z)
+ enddef
+ END
+ writefile(lines, 'Xlib.vim', 'D')
+
+ # test using a function reference in script-local variable
+ lines =<< trim END
+ vim9script
+
+ import './Xlib.vim'
+ const Floatfunc = Xlib.Floats
+ Floatfunc(1.0, v:none, 3.0)
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_equal('1.00 2.00 3.00', g:result)
+ unlet g:result
+
+ # test calling the imported function
+ lines =<< trim END
+ vim9script
+
+ import './Xlib.vim'
+ Xlib.Floats(1.0, v:none, 3.0)
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_equal('1.00 2.00 3.00', g:result)
+ unlet g:result
+
# TODO: this should give an error for using a missing argument
# lines =<< trim END
# vim9script
*** ../vim-9.0.1558/src/version.c 2023-05-14 22:05:09.813326337 +0100
--- src/version.c 2023-05-15 16:16:43.670499323 +0100
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1559,
/**/
--
hundred-and-one symptoms of being an internet addict:
35. Your husband tells you he's had that beard for 2 months.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///