private boolean matchType(@NotNull PsiElement patternType, PsiElement matchedType) {
    PsiElement patternElement = getInnermostComponent(patternType);
    PsiElement matchedElement = patternElement instanceof PsiTypeElement && ((PsiTypeElement)patternElement).isInferredType()
                                ? matchedType
                                : getInnermostComponent(matchedType);

    PsiElement[] typeParameters = null;
    if (matchedElement instanceof PsiJavaCodeReferenceElement referenceElement) {
      typeParameters = getTypeParameters(referenceElement, shouldReplaceDiamondWithExplicitTypes(patternElement));
    }
    else if (matchedElement instanceof PsiTypeParameter) {
      matchedElement = ((PsiTypeParameter)matchedElement).getNameIdentifier();
    }
    else if (matchedElement instanceof PsiClass && ((PsiClass)matchedElement).hasTypeParameters()) {
      typeParameters = ((PsiClass)matchedElement).getTypeParameters();
      matchedElement = ((PsiClass)matchedElement).getNameIdentifier();
    }
    else if (matchedElement instanceof PsiMethod && ((PsiMethod)matchedElement).hasTypeParameters()) {
      typeParameters = ((PsiMethod)matchedElement).getTypeParameters();
      matchedElement = ((PsiMethod)matchedElement).getNameIdentifier();
    }

    if (patternElement instanceof PsiTypeElement && matchedElement instanceof PsiTypeElement) {
      final PsiType type1 = ((PsiTypeElement)patternElement).getType();
      final PsiType type2 = ((PsiTypeElement)matchedElement).getType();
      if (type1 instanceof PsiWildcardType wildcardType1 && type2 instanceof PsiWildcardType wildcardType2) {
        if (wildcardType1.equals(wildcardType2)) return true;
        if (wildcardType1.isExtends() && (wildcardType2.isExtends() || !wildcardType2.isBounded())) {
          if (wildcardType2.isExtends()) {
            return myMatchingVisitor.match(patternElement.getLastChild(), matchedElement.getLastChild());
          }
          else {
            return myMatchingVisitor.matchOptionally(patternElement.getLastChild(), null);
          }
        }
        else if (wildcardType1.isSuper() && wildcardType2.isSuper()) {
          return myMatchingVisitor.match(patternElement.getLastChild(), matchedElement.getLastChild());
        }
      }
    }
    if (patternElement instanceof PsiJavaCodeReferenceElement referenceElement) {
      final PsiReferenceParameterList list = referenceElement.getParameterList();
      boolean typeParametersMatched = false;
      if (list != null) {
        final PsiTypeElement[] elements = list.getTypeParameterElements();
        if (elements.length > 0) {
          typeParametersMatched = true;
          if (!myMatchingVisitor.matchSequentially(elements, (typeParameters == null) ? PsiElement.EMPTY_ARRAY : typeParameters)) {
            return false;
          }
        }
      }
      patternElement = referenceElement.getReferenceNameElement();
      if (typeParametersMatched && matchedElement instanceof PsiJavaCodeReferenceElement) {
        matchedElement = ((PsiJavaCodeReferenceElement)matchedElement).getReferenceNameElement();
      }
    }

    final int matchedArrayDimensions = getArrayDimensions(matchedType);
    final int patternArrayDimensions = getArrayDimensions(patternType);

    if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternElement)) {
      final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(patternElement);

      RegExpPredicate regExpPredicate = null;

      boolean fullTypeResult = false;
      if (patternArrayDimensions != 0) {
        if (patternArrayDimensions != matchedArrayDimensions) {
          return false;
        }
      }
      else if (matchedArrayDimensions != 0) {
        regExpPredicate = handler.findPredicate(RegExpPredicate.class);

        if (regExpPredicate != null) {
          regExpPredicate.setNodeTextGenerator(
            element -> StructuralSearchUtil.getMeaningfulText(element) + "[]".repeat(matchedArrayDimensions));
        }
        fullTypeResult = true;
      }

      try {
        final boolean result = (handler.isSubtype() || handler.isStrictSubtype())
                               ? matchWithinHierarchy(patternElement, matchedElement, handler)
                               : handler.validate(matchedElement, myMatchingVisitor.getMatchContext());
        if (result) handler.addResult(fullTypeResult ? matchedType : matchedElement, myMatchingVisitor.getMatchContext());
        return result;
      }
      finally {
        if (regExpPredicate != null) regExpPredicate.setNodeTextGenerator(null);
      }
    }

    if (matchedArrayDimensions != patternArrayDimensions) {
      return false;
    }

    if (patternElement instanceof PsiIdentifier) {
      final PsiElement parent = patternElement.getParent();
      if (parent instanceof PsiJavaCodeReferenceElement) {
        patternElement = parent;
      }
    }
    if (matchedElement instanceof PsiIdentifier) {
      final PsiElement parent = matchedElement.getParent();
      if (parent instanceof PsiJavaCodeReferenceElement) {
        matchedElement = parent;
      }
    }
    final String text = getText(patternElement);
    final String text2 = getText(matchedElement);
    final boolean caseSensitive = myMatchingVisitor.getMatchContext().getOptions().isCaseSensitiveMatch();
    final boolean equalsIgnorePackage = MatchUtils.compareWithNoDifferenceToPackage(text, text2, !caseSensitive);
    if (equalsIgnorePackage || !(matchedElement instanceof PsiJavaReference)) {
      return equalsIgnorePackage;
    }
    else {
      final PsiElement element2 = ((PsiJavaReference)matchedElement).resolve();

      if (!(element2 instanceof PsiClass)) {
        return false;
      }
      final String name = ((PsiClass)element2).getQualifiedName();
      return caseSensitive ? text.equals(name) : text.equalsIgnoreCase(name);
    }
  }
private boolean matchType(@NotNull PsiElement patternType, PsiElement matchedType)