Find all conflicts found between two selection sets.

       Includes those found via spreading in fragments. Called when determining if conflicts exist
       between the sub-fields of two overlapping fields.

def _find_conflicts_between_sub_selection_sets(
    context,  # type: ValidationContext
    cached_fields_and_fragment_names,  # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]]
    compared_fragments,  # type: PairSet
    are_mutually_exclusive,  # type: bool
    parent_type1,  # type: Union[GraphQLInterfaceType, GraphQLObjectType, None]
    selection_set1,  # type: SelectionSet
    parent_type2,  # type: Union[GraphQLInterfaceType, GraphQLObjectType, None]
    selection_set2,  # type: SelectionSet
):
    # type: (...) ->  List[Tuple[Tuple[str, str], List[Node], List[Node]]]
    """Find all conflicts found between two selection sets.

       Includes those found via spreading in fragments. Called when determining if conflicts exist
       between the sub-fields of two overlapping fields.
    """
    conflicts = []  # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]]

    field_map1, fragment_names1 = _get_fields_and_fragments_names(
        context, cached_fields_and_fragment_names, parent_type1, selection_set1
    )

    field_map2, fragment_names2 = _get_fields_and_fragments_names(
        context, cached_fields_and_fragment_names, parent_type2, selection_set2
    )

    # (H) First, collect all conflicts between these two collections of field.
    _collect_conflicts_between(
        context,
        conflicts,
        cached_fields_and_fragment_names,
        compared_fragments,
        are_mutually_exclusive,
        field_map1,
        field_map2,
    )

    # (I) Then collect conflicts between the first collection of fields and
    # those referenced by each fragment name associated with the second.
    for fragment_name2 in fragment_names2:
        _collect_conflicts_between_fields_and_fragment(
            context,
            conflicts,
            cached_fields_and_fragment_names,
            compared_fragments,
            are_mutually_exclusive,
            field_map1,
            fragment_name2,
        )

    # (I) Then collect conflicts between the second collection of fields and
    #  those referenced by each fragment name associated with the first.
    for fragment_name1 in fragment_names1:
        _collect_conflicts_between_fields_and_fragment(
            context,
            conflicts,
            cached_fields_and_fragment_names,
            compared_fragments,
            are_mutually_exclusive,
            field_map2,
            fragment_name1,
        )

    # (J) Also collect conflicts between any fragment names by the first and
    # fragment names by the second. This compares each item in the first set of
    # names to each item in the second set of names.
    for fragment_name1 in fragment_names1:
        for fragment_name2 in fragment_names2:
            _collect_conflicts_between_fragments(
                context,
                conflicts,
                cached_fields_and_fragment_names,
                compared_fragments,
                are_mutually_exclusive,
                fragment_name1,
                fragment_name2,
            )

    return conflicts