private static boolean match(@NotNull SingleChildDescriptor childDescriptor1,
                               @NotNull SingleChildDescriptor childDescriptor2,
                               @NotNull AbstractMatchingVisitor g,
                               @NotNull Set<PsiElementRole> skippedRoles,
                               @Nullable DuplicatesProfile duplicatesProfile) {
    if (childDescriptor1.getType() != childDescriptor2.getType()) {
      return false;
    }

    final PsiElement element1 = childDescriptor1.getElement();
    final PsiElement element2 = childDescriptor2.getElement();

    if (duplicatesProfile != null) {
      final PsiElementRole role1 = element1 != null ? duplicatesProfile.getRole(element1) : null;
      final PsiElementRole role2 = element2 != null ? duplicatesProfile.getRole(element2) : null;

      if (role1 == role2 && skippedRoles.contains(role1)) {
        return true;
      }
    }

    return switch (childDescriptor1.getType()) {
      case DEFAULT -> g.match(element1, element2);
      case OPTIONALLY_IN_PATTERN, OPTIONALLY -> g.matchOptionally(element1, element2);
      case CHILDREN -> g.matchSons(element1, element2);
      case CHILDREN_OPTIONALLY_IN_PATTERN, CHILDREN_OPTIONALLY -> g.matchSonsOptionally(element1, element2);
      case CHILDREN_IN_ANY_ORDER -> g.matchSonsInAnyOrder(element1, element2);
    };
  }
private static boolean match(@NotNull SingleChildDescriptor childDescriptor1,
                               @NotNull SingleChildDescriptor childDescriptor2,
                               @NotNull AbstractMatchingVisitor g,
                               @NotNull Set<PsiElementRole> skippedRoles,
                               @Nullable DuplicatesProfile duplicatesProfile)