Takes a complex type (without any placeholders), gets its return values, and returns productions
    (perhaps each with multiple arguments) that produce the return values.  This method also takes
    care of ``MultiMatchNamedBasicTypes``. If one of the arguments or the return types is a multi
    match type, it gets all the substitutions of those types from ``multi_match_mapping`` and forms
    a list with all possible combinations of substitutions. If the complex type passed to this method
    has no ``MultiMatchNamedBasicTypes``, the returned list will contain a single tuple.  For
    example, if the complex is type ``<a,<<b,c>,d>>``, and ``a`` is a multi match type that matches
    ``e`` and ``f``, this gives the following list of tuples: ``[('d', 'd -> [<a,<<b,c>,d>, e,
    <b,c>]), ('d', 'd -> [<a,<<b,c>,d>, f, <b,c>])]`` Note that we assume there will be no
    productions from the multi match type, and the list above does not contain ``('d', 'd ->
    [<a,<<b,c>,d>, a, <b,c>>]')``.

def _get_complex_type_production(complex_type: ComplexType,
                                 multi_match_mapping: Dict[Type, List[Type]]) -> List[Tuple[Type, str]]:
    """
    Takes a complex type (without any placeholders), gets its return values, and returns productions
    (perhaps each with multiple arguments) that produce the return values.  This method also takes
    care of ``MultiMatchNamedBasicTypes``. If one of the arguments or the return types is a multi
    match type, it gets all the substitutions of those types from ``multi_match_mapping`` and forms
    a list with all possible combinations of substitutions. If the complex type passed to this method
    has no ``MultiMatchNamedBasicTypes``, the returned list will contain a single tuple.  For
    example, if the complex is type ``<a,<<b,c>,d>>``, and ``a`` is a multi match type that matches
    ``e`` and ``f``, this gives the following list of tuples: ``[('d', 'd -> [<a,<<b,c>,d>, e,
    <b,c>]), ('d', 'd -> [<a,<<b,c>,d>, f, <b,c>])]`` Note that we assume there will be no
    productions from the multi match type, and the list above does not contain ``('d', 'd ->
    [<a,<<b,c>,d>, a, <b,c>>]')``.
    """
    return_type = complex_type.return_type()
    if isinstance(return_type, MultiMatchNamedBasicType):
        return_types_matched = list(multi_match_mapping[return_type] if return_type in
                                    multi_match_mapping else return_type.types_to_match)
    else:
        return_types_matched = [return_type]
    arguments = complex_type.argument_types()
    argument_types_matched = []
    for argument_type in arguments:
        if isinstance(argument_type, MultiMatchNamedBasicType):
            matched_types = list(multi_match_mapping[argument_type] if argument_type in
                                 multi_match_mapping else argument_type.types_to_match)
            argument_types_matched.append(matched_types)
        else:
            argument_types_matched.append([argument_type])
    complex_type_productions: List[Tuple[Type, str]] = []
    for matched_return_type in return_types_matched:
        for matched_arguments in itertools.product(*argument_types_matched):
            complex_type_productions.append((matched_return_type,
                                             _make_production_string(return_type,
                                                                     [complex_type] + list(matched_arguments))))
    return complex_type_productions