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>
diff --git a/src/version.c b/src/version.c
index 971133b..883367d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1278,
+/**/
1277,
/**/
1276,
diff --git a/src/vim9type.c b/src/vim9type.c
index a3881c9..a90c0cc 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -1175,6 +1175,122 @@
}
/*
+ * 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.
* Does not allow for assigning "any" to a specific type.
* When "argidx" > 0 it is included in the error message.
@@ -1246,91 +1362,9 @@
else if (expected->tt_type == VAR_TUPLE && actual != &t_any)
ret = check_tuple_type_maybe(expected, actual, where);
else if (expected->tt_type == VAR_FUNC && actual != &t_any)
- {
- // 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;
- }
+ ret = check_func_type_maybe(expected, actual, where);
else if (expected->tt_type == VAR_OBJECT)
- {
- 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;
- }
- }
+ ret = check_object_type_maybe(expected, actual, where);
if (ret == FAIL && give_msg)
type_mismatch_where(expected, actual, where);
@@ -1412,13 +1446,99 @@
}
/*
+ * Skip over type in list<type>, dict<type> or tuple<type>.
+ * Returns a pointer to the character after the type. "syn_error" is set to
+ * TRUE on syntax error.
+ */
+ static char_u *
+skip_member_type(char_u *start, char_u *p, int *syn_error)
+{
+ if (STRNCMP("tuple", start, 5) == 0)
+ {
+ // handle tuple<{type1}, {type2}, ....<type>>
+ p = skipwhite(p + 1);
+ while (*p != '>' && *p != NUL)
+ {
+ char_u *sp = p;
+
+ if (STRNCMP(p, "...", 3) == 0)
+ p += 3;
+ p = skip_type(p, TRUE);
+ if (p == sp)
+ {
+ *syn_error = TRUE;
+ return p; // syntax error
+ }
+ if (*p == ',')
+ p = skipwhite(p + 1);
+ }
+ if (*p == '>')
+ p++;
+ }
+ else
+ {
+ p = skipwhite(p);
+ p = skip_type(skipwhite(p + 1), FALSE);
+ p = skipwhite(p);
+ if (*p == '>')
+ ++p;
+ }
+
+ return p;
+}
+
+/*
+ * 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 == '(')
+ {
+ // handle func(args): type
+ ++p;
+ while (*p != ')' && *p != NUL)
+ {
+ char_u *sp = p;
+
+ if (STRNCMP(p, "...", 3) == 0)
+ p += 3;
+ p = skip_type(p, TRUE);
+ if (p == sp)
+ {
+ *syn_error = TRUE;
+ return p; // syntax error
+ }
+ if (*p == ',')
+ p = skipwhite(p + 1);
+ }
+ if (*p == ')')
+ {
+ if (p[1] == ':')
+ p = skip_type(skipwhite(p + 2), FALSE);
+ else
+ ++p;
+ }
+ }
+ else
+ {
+ // handle func: return_type
+ 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;
+ char_u *p = start;
+ int syn_error = FALSE;
if (optional && *p == '?')
++p;
@@ -1430,66 +1550,17 @@
// Skip over "<type>"; this is permissive about white space.
if (*skipwhite(p) == '<')
{
- if (STRNCMP("tuple", start, 5) == 0)
- {
- // handle tuple<{type1}, {type2}, ....<type>>
- p = skipwhite(p + 1);
- while (*p != '>' && *p != NUL)
- {
- char_u *sp = p;
-
- if (STRNCMP(p, "...", 3) == 0)
- p += 3;
- p = skip_type(p, TRUE);
- if (p == sp)
- return p; // syntax error
- if (*p == ',')
- p = skipwhite(p + 1);
- }
- if (*p == '>')
- p++;
- }
- else
- {
- p = skipwhite(p);
- p = skip_type(skipwhite(p + 1), FALSE);
- p = skipwhite(p);
- if (*p == '>')
- ++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)
{
- if (*p == '(')
- {
- // handle func(args): type
- ++p;
- while (*p != ')' && *p != NUL)
- {
- char_u *sp = p;
-
- if (STRNCMP(p, "...", 3) == 0)
- p += 3;
- p = skip_type(p, TRUE);
- if (p == sp)
- return p; // syntax error
- if (*p == ',')
- p = skipwhite(p + 1);
- }
- if (*p == ')')
- {
- if (p[1] == ':')
- p = skip_type(skipwhite(p + 2), FALSE);
- else
- ++p;
- }
- }
- else
- {
- // handle func: return_type
- p = skip_type(skipwhite(p + 1), FALSE);
- }
+ // skip over function type
+ p = skip_func_type(p, &syn_error);
+ if (syn_error)
+ return p;
}
return p;