mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.3844: Vim9: no type error if assigning func(number) to func(string)
Problem: Vim9: no type error if assigning a value with type func(number) to a variable of type func(string). Solution: Use check_type_maybe(): return MAYBE if a runtime type check is useful. (issue #8492)
This commit is contained in:
parent
647ab4cede
commit
44a8977de4
@ -16,6 +16,7 @@ void type_mismatch(type_T *expected, type_T *actual);
|
|||||||
void arg_type_mismatch(type_T *expected, type_T *actual, int arg_idx);
|
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);
|
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(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, char_u *name);
|
||||||
char_u *skip_type(char_u *start, int optional);
|
char_u *skip_type(char_u *start, int optional);
|
||||||
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
|
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
|
||||||
|
@ -2146,6 +2146,23 @@ def Test_script_funcref_case()
|
|||||||
CheckScriptFailure(lines, 'E704:')
|
CheckScriptFailure(lines, 'E704:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_script_funcref_runtime_type_check()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
def FuncWithNumberArg(n: number)
|
||||||
|
enddef
|
||||||
|
def Test()
|
||||||
|
var Ref: func(string) = function(FuncWithNumberArg)
|
||||||
|
enddef
|
||||||
|
defcompile
|
||||||
|
END
|
||||||
|
# OK at compile time
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
# Type check fails at runtime
|
||||||
|
CheckScriptFailure(lines + ['Test()'], 'E1012: Type mismatch; expected func(string) but got func(number)')
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_inc_dec()
|
def Test_inc_dec()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
var nr = 7
|
var nr = 7
|
||||||
|
@ -749,6 +749,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3844,
|
||||||
/**/
|
/**/
|
||||||
3843,
|
3843,
|
||||||
/**/
|
/**/
|
||||||
|
@ -1061,6 +1061,8 @@ need_type_where(
|
|||||||
int silent,
|
int silent,
|
||||||
int actual_is_const)
|
int actual_is_const)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (expected == &t_bool && actual != &t_bool
|
if (expected == &t_bool && actual != &t_bool
|
||||||
&& (actual->tt_flags & TTFLAG_BOOL_OK))
|
&& (actual->tt_flags & TTFLAG_BOOL_OK))
|
||||||
{
|
{
|
||||||
@ -1070,13 +1072,14 @@ need_type_where(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_type(expected, actual, FALSE, where) == OK)
|
ret = check_type_maybe(expected, actual, FALSE, where);
|
||||||
|
if (ret == OK)
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
// If the actual type can be the expected type add a runtime check.
|
// If the actual type can be the expected type add a runtime check.
|
||||||
// If it's a constant a runtime check makes no sense.
|
// If it's a constant a runtime check makes no sense.
|
||||||
if ((!actual_is_const || actual == &t_any)
|
if (ret == MAYBE || ((!actual_is_const || actual == &t_any)
|
||||||
&& use_typecheck(actual, expected))
|
&& use_typecheck(actual, expected)))
|
||||||
{
|
{
|
||||||
generate_TYPECHECK(cctx, expected, offset, where.wt_index);
|
generate_TYPECHECK(cctx, expected, offset, where.wt_index);
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -531,9 +531,31 @@ type_mismatch_where(type_T *expected, type_T *actual, where_T where)
|
|||||||
* Check if the expected and actual types match.
|
* Check if the expected and actual types match.
|
||||||
* Does not allow for assigning "any" to a specific type.
|
* Does not allow for assigning "any" to a specific type.
|
||||||
* When "argidx" > 0 it is included in the error message.
|
* When "argidx" > 0 it is included in the error message.
|
||||||
|
* Return OK if types match.
|
||||||
|
* Return FAIL if types do not match.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
check_type(type_T *expected, type_T *actual, int give_msg, where_T where)
|
check_type(
|
||||||
|
type_T *expected,
|
||||||
|
type_T *actual,
|
||||||
|
int give_msg,
|
||||||
|
where_T where)
|
||||||
|
{
|
||||||
|
int ret = check_type_maybe(expected, actual, give_msg, where);
|
||||||
|
|
||||||
|
return ret == MAYBE ? OK : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As check_type() but return MAYBE when a runtime type check should be used
|
||||||
|
* when compiling.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
check_type_maybe(
|
||||||
|
type_T *expected,
|
||||||
|
type_T *actual,
|
||||||
|
int give_msg,
|
||||||
|
where_T where)
|
||||||
{
|
{
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
@ -568,17 +590,21 @@ check_type(type_T *expected, type_T *actual, int give_msg, where_T where)
|
|||||||
{
|
{
|
||||||
// If the return type is unknown it can be anything, including
|
// If the return type is unknown it can be anything, including
|
||||||
// nothing, thus there is no point in checking.
|
// nothing, thus there is no point in checking.
|
||||||
if (expected->tt_member != &t_unknown
|
if (expected->tt_member != &t_unknown)
|
||||||
&& actual->tt_member != &t_unknown)
|
{
|
||||||
ret = check_type(expected->tt_member, actual->tt_member,
|
if (actual->tt_member != &t_unknown)
|
||||||
|
ret = check_type(expected->tt_member, actual->tt_member,
|
||||||
FALSE, where);
|
FALSE, where);
|
||||||
if (ret == OK && expected->tt_argcount != -1
|
else
|
||||||
|
ret = MAYBE;
|
||||||
|
}
|
||||||
|
if (ret != FAIL && expected->tt_argcount != -1
|
||||||
&& actual->tt_min_argcount != -1
|
&& actual->tt_min_argcount != -1
|
||||||
&& (actual->tt_argcount == -1
|
&& (actual->tt_argcount == -1
|
||||||
|| (actual->tt_argcount < expected->tt_min_argcount
|
|| (actual->tt_argcount < expected->tt_min_argcount
|
||||||
|| actual->tt_argcount > expected->tt_argcount)))
|
|| actual->tt_argcount > expected->tt_argcount)))
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
if (ret == OK && expected->tt_args != NULL
|
if (ret != FAIL && expected->tt_args != NULL
|
||||||
&& actual->tt_args != NULL)
|
&& actual->tt_args != NULL)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -593,10 +619,21 @@ check_type(type_T *expected, type_T *actual, int give_msg, where_T where)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret == OK && expected->tt_argcount >= 0
|
||||||
|
&& actual->tt_argcount == -1)
|
||||||
|
// check the argument count at runtime
|
||||||
|
ret = MAYBE;
|
||||||
}
|
}
|
||||||
if (ret == FAIL && give_msg)
|
if (ret == FAIL && give_msg)
|
||||||
type_mismatch_where(expected, actual, where);
|
type_mismatch_where(expected, actual, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == OK && expected->tt_type != VAR_UNKNOWN
|
||||||
|
&& expected->tt_type != VAR_ANY
|
||||||
|
&& (actual->tt_type == VAR_UNKNOWN || actual->tt_type == VAR_ANY))
|
||||||
|
// check the type at runtime
|
||||||
|
ret = MAYBE;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user