@Override
    public PsiType fun(@NotNull PsiReferenceExpressionImpl expr) {
      PsiFile file = expr.getContainingFile();
      Project project = file.getProject();
      ResolveResult[] results = ResolveCache.getInstance(project).resolveWithCaching(expr, OurGenericsResolver.INSTANCE, true, false, file);
      JavaResolveResult result = results.length == 1 ? (JavaResolveResult)results[0] : null;

      PsiElement resolve = result == null ? null : result.getElement();
      if (resolve == null) {
        ASTNode refName = expr.findChildByRole(ChildRole.REFERENCE_NAME);
        if (refName != null && "length".equals(refName.getText())) {
          ASTNode qualifier = expr.findChildByRole(ChildRole.QUALIFIER);
          if (qualifier != null && ElementType.EXPRESSION_BIT_SET.contains(qualifier.getElementType())) {
            PsiType type = SourceTreeToPsiMap.<PsiExpression>treeToPsiNotNull(qualifier).getType();
            if (type instanceof PsiArrayType) {
              return PsiTypes.intType();
            }
          }
        }
        return null;
      }

      if (!(resolve instanceof PsiVariable)) return null;
      PsiType type = ((PsiVariable)resolve).getType();
      PsiType ret = type instanceof PsiEllipsisType ? ((PsiEllipsisType)type).toArrayType() : type;
      if (!ret.isValid()) {
        PsiUtil.ensureValidType(ret, "invalid type of " + resolve + " of class " + resolve.getClass() + ", valid=" + resolve.isValid());
      }
      PsiTypeParameterListOwner owner = null;
      if (resolve instanceof PsiField && !((PsiField)resolve).hasModifierProperty(PsiModifier.STATIC)) {
        owner = ((PsiField)resolve).getContainingClass();
      }

      LanguageLevel languageLevel = PsiUtil.getLanguageLevel(file);
      if (ret instanceof PsiClassType) {
        ret = ((PsiClassType)ret).setLanguageLevel(languageLevel);
      }

      if (JavaFeature.GENERICS.isSufficient(languageLevel)) {
        PsiSubstitutor substitutor = result.getSubstitutor();
        if (owner == null || !PsiUtil.isRawSubstitutor(owner, substitutor)) {
          PsiType substitutedType = substitutor.substitute(ret);
          PsiUtil.ensureValidType(substitutedType);
          PsiType normalized = PsiImplUtil.normalizeWildcardTypeByPosition(substitutedType, expr);
          PsiUtil.ensureValidType(normalized);
          return PsiClassImplUtil.correctType(normalized, expr.getResolveScope());
        }
      }

      return PsiClassImplUtil.correctType(TypeConversionUtil.erasure(ret), expr.getResolveScope());
    }
@Override
    public PsiType fun(@NotNull PsiReferenceExpressionImpl expr)