private int substituteToTypeParameters(PsiTypeElement typeElement,
                                         PsiType expectedType,
                                         PsiSubstitutor rawingSubstitutor,
                                         boolean toplevel) {
    final List<PsiTypeParameter> matchedParameters = matchingTypeParameters(mySubstitutor, expectedType, TYPE_STRICTLY);
    if (!matchedParameters.isEmpty()) {
      List<PsiType> types = new SmartList<>(map(matchedParameters, it -> myFactory.createType(it)));

      PsiType substituted = rawingSubstitutor.substitute(expectedType);
      if (!CommonClassNames.JAVA_LANG_OBJECT.equals(substituted.getCanonicalText()) && (toplevel || substituted.equals(expectedType))) {
        types.add(substituted);
      }

      myBuilder.replaceElement(typeElement, new TypeExpression(myProject, types));
      return toplevel ? SUBSTITUTED_IN_REF : SUBSTITUTED_IN_PARAMETERS;
    }

    final PsiTypeElement[] innerTypeElements = typeArguments(typeElement);
    if (innerTypeElements == null) return SUBSTITUTED_NONE;

    final PsiType[] expectedTypeArguments = typeArguments(expectedType);
    if (expectedTypeArguments == null) return SUBSTITUTED_NONE;

    boolean substituted = false;
    for (int i = 0; i < innerTypeElements.length; i++) {
      substituted |= substituteToTypeParameters(innerTypeElements[i], expectedTypeArguments[i],
                                                rawingSubstitutor, false) != SUBSTITUTED_NONE;
    }
    return substituted ? SUBSTITUTED_IN_PARAMETERS : SUBSTITUTED_NONE;
  }
private int substituteToTypeParameters(PsiTypeElement typeElement,
                                         PsiType expectedType,
                                         PsiSubstitutor rawingSubstitutor,
                                         boolean toplevel)