def matches(
        self,
        exception: BaseException | None,
    ) -> bool:
        """Check if an exception matches the requirements of this RaisesGroup.
        If it fails, `RaisesGroup.fail_reason` will be set.

        Example::

            with pytest.raises(TypeError) as excinfo:
                ...
            assert RaisesGroup(ValueError).matches(excinfo.value.__cause__)
            # the above line is equivalent to
            myexc = excinfo.value.__cause
            assert isinstance(myexc, BaseExceptionGroup)
            assert len(myexc.exceptions) == 1
            assert isinstance(myexc.exceptions[0], ValueError)
        """
        self._fail_reason = None
        if exception is None:
            self._fail_reason = "exception is None"
            return False
        if not isinstance(exception, BaseExceptionGroup):
            # we opt to only print type of the exception here, as the repr would
            # likely be quite long
            not_group_msg = f"`{type(exception).__name__}()` is not an exception group"
            if len(self.expected_exceptions) > 1:
                self._fail_reason = not_group_msg
                return False
            # if we have 1 expected exception, check if it would work even if
            # allow_unwrapped is not set
            res = self._check_expected(self.expected_exceptions[0], exception)
            if res is None and self.allow_unwrapped:
                return True

            if res is None:
                self._fail_reason = (
                    f"{not_group_msg}, but would match with `allow_unwrapped=True`"
                )
            elif self.allow_unwrapped:
                self._fail_reason = res
            else:
                self._fail_reason = not_group_msg
            return False

        actual_exceptions: Sequence[BaseException] = exception.exceptions
        if self.flatten_subgroups:
            actual_exceptions = self._unroll_exceptions(actual_exceptions)

        if not self._check_match(exception):
            self._fail_reason = cast(str, self._fail_reason)
            old_reason = self._fail_reason
            if (
                len(actual_exceptions) == len(self.expected_exceptions) == 1
                and isinstance(expected := self.expected_exceptions[0], type)
                and isinstance(actual := actual_exceptions[0], expected)
                and self._check_match(actual)
            ):
                assert self.match is not None, "can't be None if _check_match failed"
                assert self._fail_reason is old_reason is not None
                self._fail_reason += (
                    f"\n"
                    f" but matched the expected `{self._repr_expected(expected)}`.\n"
                    f" You might want "
                    f"`RaisesGroup(RaisesExc({expected.__name__}, match={_match_pattern(self.match)!r}))`"
                )
            else:
                self._fail_reason = old_reason
            return False

        # do the full check on expected exceptions
        if not self._check_exceptions(
            exception,
            actual_exceptions,
        ):
            self._fail_reason = cast(str, self._fail_reason)
            assert self._fail_reason is not None
            old_reason = self._fail_reason
            # if we're not expecting a nested structure, and there is one, do a second
            # pass where we try flattening it
            if (
                not self.flatten_subgroups
                and not any(
                    isinstance(e, RaisesGroup) for e in self.expected_exceptions
                )
                and any(isinstance(e, BaseExceptionGroup) for e in actual_exceptions)
                and self._check_exceptions(
                    exception,
                    self._unroll_exceptions(exception.exceptions),
                )
            ):
                # only indent if it's a single-line reason. In a multi-line there's already
                # indented lines that this does not belong to.
                indent = "  " if "\n" not in self._fail_reason else ""
                self._fail_reason = (
                    old_reason
                    + f"\n{indent}Did you mean to use `flatten_subgroups=True`?"
                )
            else:
                self._fail_reason = old_reason
            return False

        # Only run `self.check` once we know `exception` is of the correct type.
        if not self._check_check(exception):
            reason = (
                cast(str, self._fail_reason) + f" on the {type(exception).__name__}"
            )
            if (
                len(actual_exceptions) == len(self.expected_exceptions) == 1
                and isinstance(expected := self.expected_exceptions[0], type)
                # we explicitly break typing here :)
                and self._check_check(actual_exceptions[0])  # type: ignore[arg-type]
            ):
                self._fail_reason = reason + (
                    f", but did return True for the expected {self._repr_expected(expected)}."
                    f" You might want RaisesGroup(RaisesExc({expected.__name__}, check=<...>))"
                )
            else:
                self._fail_reason = reason
            return False

        return True
Check if an exception matches the requirements of this RaisesGroup.
        If it fails, `RaisesGroup.fail_reason` will be set.

        Example::

            with pytest.raises(TypeError) as excinfo:
                ...
            assert RaisesGroup(ValueError).matches(excinfo.value.__cause__)
            # the above line is equivalent to
            myexc = excinfo.value.__cause
            assert isinstance(myexc, BaseExceptionGroup)
            assert len(myexc.exceptions) == 1
            assert isinstance(myexc.exceptions[0], ValueError)
        
src/_pytest/raises.py