forked from aniani/vim
patch 9.1.1278: Vim9: too long functions in vim9type.c
Problem: Vim9: too long functions in vim9type.c Solution: refactor into separate functions (Yegappan Lakshmanan) closes: #17056 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
2f5a8c0b5b
commit
d22f43111b
@ -704,6 +704,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 */
|
||||||
|
/**/
|
||||||
|
1278,
|
||||||
/**/
|
/**/
|
||||||
1277,
|
1277,
|
||||||
/**/
|
/**/
|
||||||
|
279
src/vim9type.c
279
src/vim9type.c
@ -1174,6 +1174,122 @@ check_tuple_type_maybe(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the expected and actual types match for a function
|
||||||
|
* Returns OK if "expected" and "actual" are matching function types.
|
||||||
|
* Returns FAIL if "expected" and "actual" are different types.
|
||||||
|
* Returns MAYBE when a runtime type check is needed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_func_type_maybe(
|
||||||
|
type_T *expected,
|
||||||
|
type_T *actual,
|
||||||
|
where_T where)
|
||||||
|
{
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
|
// If the return type is unknown it can be anything, including
|
||||||
|
// nothing, thus there is no point in checking.
|
||||||
|
if (expected->tt_member != &t_unknown)
|
||||||
|
{
|
||||||
|
if (actual->tt_member != NULL
|
||||||
|
&& actual->tt_member != &t_unknown)
|
||||||
|
{
|
||||||
|
where_T func_where = where;
|
||||||
|
|
||||||
|
func_where.wt_kind = WT_METHOD_RETURN;
|
||||||
|
ret = check_type_maybe(expected->tt_member,
|
||||||
|
actual->tt_member, FALSE,
|
||||||
|
func_where);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = MAYBE;
|
||||||
|
}
|
||||||
|
if (ret != FAIL
|
||||||
|
&& ((expected->tt_flags & TTFLAG_VARARGS)
|
||||||
|
!= (actual->tt_flags & TTFLAG_VARARGS))
|
||||||
|
&& expected->tt_argcount != -1)
|
||||||
|
ret = FAIL;
|
||||||
|
if (ret != FAIL && expected->tt_argcount != -1
|
||||||
|
&& actual->tt_min_argcount != -1
|
||||||
|
&& (actual->tt_argcount == -1
|
||||||
|
|| (actual->tt_argcount < expected->tt_min_argcount
|
||||||
|
|| actual->tt_argcount > expected->tt_argcount)))
|
||||||
|
ret = FAIL;
|
||||||
|
if (ret != FAIL && expected->tt_args != NULL
|
||||||
|
&& actual->tt_args != NULL)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < expected->tt_argcount
|
||||||
|
&& i < actual->tt_argcount; ++i)
|
||||||
|
{
|
||||||
|
where_T func_where = where;
|
||||||
|
func_where.wt_kind = WT_METHOD_ARG;
|
||||||
|
|
||||||
|
// Allow for using "any" argument type, lambda's have them.
|
||||||
|
if (actual->tt_args[i] != &t_any && check_type(
|
||||||
|
expected->tt_args[i], actual->tt_args[i], FALSE,
|
||||||
|
func_where) == FAIL)
|
||||||
|
{
|
||||||
|
ret = FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret == OK && expected->tt_argcount >= 0
|
||||||
|
&& actual->tt_argcount == -1)
|
||||||
|
// check the argument count at runtime
|
||||||
|
ret = MAYBE;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the expected and actual types match for an object
|
||||||
|
* Returns OK if "expected" and "actual" are matching object types.
|
||||||
|
* Returns FAIL if "expected" and "actual" are different types.
|
||||||
|
* Returns MAYBE when a runtime type check is needed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_object_type_maybe(
|
||||||
|
type_T *expected,
|
||||||
|
type_T *actual,
|
||||||
|
where_T where)
|
||||||
|
{
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
|
if (actual->tt_type == VAR_ANY)
|
||||||
|
return MAYBE; // use runtime type check
|
||||||
|
if (actual->tt_type != VAR_OBJECT)
|
||||||
|
return FAIL; // don't use tt_class
|
||||||
|
if (actual->tt_class == NULL) // null object
|
||||||
|
return OK;
|
||||||
|
// t_object_any matches any object except for an enum item
|
||||||
|
if (expected == &t_object_any && !IS_ENUM(actual->tt_class))
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
// For object method arguments, do a invariant type check in
|
||||||
|
// an extended class. For all others, do a covariance type check.
|
||||||
|
if (where.wt_kind == WT_METHOD_ARG)
|
||||||
|
{
|
||||||
|
if (actual->tt_class != expected->tt_class)
|
||||||
|
ret = FAIL;
|
||||||
|
}
|
||||||
|
else if (!class_instance_of(actual->tt_class, expected->tt_class))
|
||||||
|
{
|
||||||
|
// Check if this is an up-cast, if so we'll have to check the type at
|
||||||
|
// runtime.
|
||||||
|
if (where.wt_kind == WT_CAST &&
|
||||||
|
class_instance_of(expected->tt_class, actual->tt_class))
|
||||||
|
ret = MAYBE;
|
||||||
|
else
|
||||||
|
ret = FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
@ -1246,91 +1362,9 @@ check_type_maybe(
|
|||||||
else if (expected->tt_type == VAR_TUPLE && actual != &t_any)
|
else if (expected->tt_type == VAR_TUPLE && actual != &t_any)
|
||||||
ret = check_tuple_type_maybe(expected, actual, where);
|
ret = check_tuple_type_maybe(expected, actual, where);
|
||||||
else if (expected->tt_type == VAR_FUNC && actual != &t_any)
|
else if (expected->tt_type == VAR_FUNC && actual != &t_any)
|
||||||
{
|
ret = check_func_type_maybe(expected, actual, where);
|
||||||
// If the return type is unknown it can be anything, including
|
|
||||||
// nothing, thus there is no point in checking.
|
|
||||||
if (expected->tt_member != &t_unknown)
|
|
||||||
{
|
|
||||||
if (actual->tt_member != NULL
|
|
||||||
&& actual->tt_member != &t_unknown)
|
|
||||||
{
|
|
||||||
where_T func_where = where;
|
|
||||||
|
|
||||||
func_where.wt_kind = WT_METHOD_RETURN;
|
|
||||||
ret = check_type_maybe(expected->tt_member,
|
|
||||||
actual->tt_member, FALSE,
|
|
||||||
func_where);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = MAYBE;
|
|
||||||
}
|
|
||||||
if (ret != FAIL
|
|
||||||
&& ((expected->tt_flags & TTFLAG_VARARGS)
|
|
||||||
!= (actual->tt_flags & TTFLAG_VARARGS))
|
|
||||||
&& expected->tt_argcount != -1)
|
|
||||||
ret = FAIL;
|
|
||||||
if (ret != FAIL && expected->tt_argcount != -1
|
|
||||||
&& actual->tt_min_argcount != -1
|
|
||||||
&& (actual->tt_argcount == -1
|
|
||||||
|| (actual->tt_argcount < expected->tt_min_argcount
|
|
||||||
|| actual->tt_argcount > expected->tt_argcount)))
|
|
||||||
ret = FAIL;
|
|
||||||
if (ret != FAIL && expected->tt_args != NULL
|
|
||||||
&& actual->tt_args != NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < expected->tt_argcount
|
|
||||||
&& i < actual->tt_argcount; ++i)
|
|
||||||
{
|
|
||||||
where_T func_where = where;
|
|
||||||
func_where.wt_kind = WT_METHOD_ARG;
|
|
||||||
|
|
||||||
// Allow for using "any" argument type, lambda's have them.
|
|
||||||
if (actual->tt_args[i] != &t_any && check_type(
|
|
||||||
expected->tt_args[i], actual->tt_args[i], FALSE,
|
|
||||||
func_where) == FAIL)
|
|
||||||
{
|
|
||||||
ret = FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret == OK && expected->tt_argcount >= 0
|
|
||||||
&& actual->tt_argcount == -1)
|
|
||||||
// check the argument count at runtime
|
|
||||||
ret = MAYBE;
|
|
||||||
}
|
|
||||||
else if (expected->tt_type == VAR_OBJECT)
|
else if (expected->tt_type == VAR_OBJECT)
|
||||||
{
|
ret = check_object_type_maybe(expected, actual, where);
|
||||||
if (actual->tt_type == VAR_ANY)
|
|
||||||
return MAYBE; // use runtime type check
|
|
||||||
if (actual->tt_type != VAR_OBJECT)
|
|
||||||
return FAIL; // don't use tt_class
|
|
||||||
if (actual->tt_class == NULL) // null object
|
|
||||||
return OK;
|
|
||||||
// t_object_any matches any object except for an enum item
|
|
||||||
if (expected == &t_object_any && !IS_ENUM(actual->tt_class))
|
|
||||||
return OK;
|
|
||||||
|
|
||||||
// For object method arguments, do a invariant type check in
|
|
||||||
// an extended class. For all others, do a covariance type check.
|
|
||||||
if (where.wt_kind == WT_METHOD_ARG)
|
|
||||||
{
|
|
||||||
if (actual->tt_class != expected->tt_class)
|
|
||||||
ret = FAIL;
|
|
||||||
}
|
|
||||||
else if (!class_instance_of(actual->tt_class, expected->tt_class))
|
|
||||||
{
|
|
||||||
// Check if this is an up-cast, if so we'll have to check the type at
|
|
||||||
// runtime.
|
|
||||||
if (where.wt_kind == WT_CAST &&
|
|
||||||
class_instance_of(expected->tt_class, actual->tt_class))
|
|
||||||
ret = MAYBE;
|
|
||||||
else
|
|
||||||
ret = FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == FAIL && give_msg)
|
if (ret == FAIL && give_msg)
|
||||||
type_mismatch_where(expected, actual, where);
|
type_mismatch_where(expected, actual, where);
|
||||||
@ -1412,24 +1446,13 @@ check_argument_types(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip over a type definition and return a pointer to just after it.
|
* Skip over type in list<type>, dict<type> or tuple<type>.
|
||||||
* When "optional" is TRUE then a leading "?" is accepted.
|
* Returns a pointer to the character after the type. "syn_error" is set to
|
||||||
|
* TRUE on syntax error.
|
||||||
*/
|
*/
|
||||||
char_u *
|
static char_u *
|
||||||
skip_type(char_u *start, int optional)
|
skip_member_type(char_u *start, char_u *p, int *syn_error)
|
||||||
{
|
{
|
||||||
char_u *p = start;
|
|
||||||
|
|
||||||
if (optional && *p == '?')
|
|
||||||
++p;
|
|
||||||
|
|
||||||
// Also skip over "." for imported classes: "import.ClassName".
|
|
||||||
while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.')
|
|
||||||
++p;
|
|
||||||
|
|
||||||
// Skip over "<type>"; this is permissive about white space.
|
|
||||||
if (*skipwhite(p) == '<')
|
|
||||||
{
|
|
||||||
if (STRNCMP("tuple", start, 5) == 0)
|
if (STRNCMP("tuple", start, 5) == 0)
|
||||||
{
|
{
|
||||||
// handle tuple<{type1}, {type2}, ....<type>>
|
// handle tuple<{type1}, {type2}, ....<type>>
|
||||||
@ -1442,7 +1465,10 @@ skip_type(char_u *start, int optional)
|
|||||||
p += 3;
|
p += 3;
|
||||||
p = skip_type(p, TRUE);
|
p = skip_type(p, TRUE);
|
||||||
if (p == sp)
|
if (p == sp)
|
||||||
|
{
|
||||||
|
*syn_error = TRUE;
|
||||||
return p; // syntax error
|
return p; // syntax error
|
||||||
|
}
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
p = skipwhite(p + 1);
|
p = skipwhite(p + 1);
|
||||||
}
|
}
|
||||||
@ -1457,10 +1483,17 @@ skip_type(char_u *start, int optional)
|
|||||||
if (*p == '>')
|
if (*p == '>')
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ((*p == '(' || (*p == ':' && VIM_ISWHITE(p[1])))
|
return p;
|
||||||
&& STRNCMP("func", start, 4) == 0)
|
}
|
||||||
{
|
|
||||||
|
/*
|
||||||
|
* Skip over a function type. Returns a pointer to the character after the
|
||||||
|
* type. "syn_error" is set to TRUE on syntax error.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
skip_func_type(char_u *p, int *syn_error)
|
||||||
|
{
|
||||||
if (*p == '(')
|
if (*p == '(')
|
||||||
{
|
{
|
||||||
// handle func(args): type
|
// handle func(args): type
|
||||||
@ -1473,7 +1506,10 @@ skip_type(char_u *start, int optional)
|
|||||||
p += 3;
|
p += 3;
|
||||||
p = skip_type(p, TRUE);
|
p = skip_type(p, TRUE);
|
||||||
if (p == sp)
|
if (p == sp)
|
||||||
|
{
|
||||||
|
*syn_error = TRUE;
|
||||||
return p; // syntax error
|
return p; // syntax error
|
||||||
|
}
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
p = skipwhite(p + 1);
|
p = skipwhite(p + 1);
|
||||||
}
|
}
|
||||||
@ -1490,6 +1526,41 @@ skip_type(char_u *start, int optional)
|
|||||||
// handle func: return_type
|
// handle func: return_type
|
||||||
p = skip_type(skipwhite(p + 1), FALSE);
|
p = skip_type(skipwhite(p + 1), FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip over a type definition and return a pointer to just after it.
|
||||||
|
* When "optional" is TRUE then a leading "?" is accepted.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
skip_type(char_u *start, int optional)
|
||||||
|
{
|
||||||
|
char_u *p = start;
|
||||||
|
int syn_error = FALSE;
|
||||||
|
|
||||||
|
if (optional && *p == '?')
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// Also skip over "." for imported classes: "import.ClassName".
|
||||||
|
while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.')
|
||||||
|
++p;
|
||||||
|
|
||||||
|
// Skip over "<type>"; this is permissive about white space.
|
||||||
|
if (*skipwhite(p) == '<')
|
||||||
|
{
|
||||||
|
p = skip_member_type(start, p, &syn_error);
|
||||||
|
if (syn_error)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
else if ((*p == '(' || (*p == ':' && VIM_ISWHITE(p[1])))
|
||||||
|
&& STRNCMP("func", start, 4) == 0)
|
||||||
|
{
|
||||||
|
// skip over function type
|
||||||
|
p = skip_func_type(p, &syn_error);
|
||||||
|
if (syn_error)
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user