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;