PsiType (@NotNull PsiTypeParameter typeParameter, @NotNull PsiWildcardType wildcardType, @NotNull PsiSubstitutor captureSubstitutor) { final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); PsiType originalBound = !wildcardType.isSuper() ? wildcardType.getBound() : null; PsiType glb = originalBound; for (PsiType boundType : boundTypes) { final PsiType substitutedBoundType = captureSubstitutor.substitute(boundType); //glb for array types is not specified yet if (originalBound instanceof PsiArrayType && substitutedBoundType instanceof PsiArrayType && !originalBound.isAssignableFrom(substitutedBoundType) && !substitutedBoundType.isAssignableFrom(originalBound)) { continue; } if (substitutedBoundType instanceof PsiCapturedWildcardType) { PsiType capturedWildcard = captureSubstitutor.substitute(typeParameter); if (capturedWildcard instanceof PsiCapturedWildcardType) { PsiType captureUpperBound = substitutedBoundType; while (captureUpperBound instanceof PsiCapturedWildcardType) { if (captureUpperBound == capturedWildcard) { return null; } captureUpperBound = ((PsiCapturedWildcardType)captureUpperBound).getUpperBound(); } } } if (glb == null) { glb = substitutedBoundType; } else { glb = getGreatestLowerBound(glb, substitutedBoundType, wildcardType); } } return glb; }