@Override
    public PsiType visitClassType(@NotNull PsiClassType classType) {
      PsiClassType.ClassResolveResult result = classType.resolveGenerics();
      PsiClass aClass = result.getElement();
      if (aClass != null) {
        PsiManager manager = aClass.getManager();
        if (aClass instanceof PsiTypeParameter) {
          PsiTypeParameter typeParameter = (PsiTypeParameter)aClass;
          if (TypeConversionUtil.isFreshVariable(typeParameter)) {
            PsiType upperBound = TypeConversionUtil.getInferredUpperBoundForSynthetic(typeParameter);
            return ObjectUtils.notNull(PsiSubstitutor.EMPTY.put(typeParameter, PsiWildcardType.createUnbounded(manager)).substitute(upperBound), 
                                       classType);
          }
        }
        PsiSubstitutor targetSubstitutor = PsiSubstitutor.EMPTY;
        PsiSubstitutor substitutor = result.getSubstitutor();
        for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aClass)) {
          PsiType ai = substitutor.substitute(parameter);
          targetSubstitutor = targetSubstitutor.put(parameter, ai);
          if (ai != null && mentionsRestrictedTypeVariables(ai)) {
            if (ai instanceof PsiWildcardType) {

              if (((PsiWildcardType)ai).isExtends()) {
                targetSubstitutor = targetSubstitutor.put(parameter,
                                                          PsiWildcardType.createExtends(manager, ((PsiWildcardType)ai).getExtendsBound().accept(this)));
              }

              if (((PsiWildcardType)ai).isSuper()) {
                targetSubstitutor = targetSubstitutor.put(parameter, createDownwardProjection(manager, ((PsiWildcardType)ai).getSuperBound()));
              }

            }
            else {
              PsiType U = RecursionManager.doPreventingRecursion(ai, true, () -> ai.accept(this));
              if (U == null) {
                targetSubstitutor = targetSubstitutor.put(parameter, PsiWildcardType.createUnbounded(manager));
              }
              else if (!U.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && tryUpperBound(aClass, parameter, U)) {
                targetSubstitutor = targetSubstitutor.put(parameter, PsiWildcardType.createExtends(manager, U));
              }
              else {
                targetSubstitutor = targetSubstitutor.put(parameter, createDownwardProjection(manager, ai));
              }
            }
          }
        }
        return JavaPsiFacade.getElementFactory(aClass.getProject()).createType(aClass, targetSubstitutor);
      }
      return classType;
    }
@Override
    public PsiType visitClassType(@NotNull PsiClassType classType)