diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 1ac91d3db9ea..5c56af03204b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -1302,16 +1302,16 @@ public class HighlightMethodUtil { private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes(@NotNull List superMethodSignatures, @NotNull LanguageLevel languageLevel) { if (superMethodSignatures.size() < 2) return null; - MethodSignatureBackedByPsiMethod returnTypeSubstitutable = superMethodSignatures.get(0); + final MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)}; for (int i = 1; i < superMethodSignatures.size(); i++) { - PsiMethod currentMethod = returnTypeSubstitutable.getMethod(); - PsiType currentType = returnTypeSubstitutable.getSubstitutor().substitute(currentMethod.getReturnType()); + PsiMethod currentMethod = returnTypeSubstitutable[0].getMethod(); + PsiType currentType = returnTypeSubstitutable[0].getSubstitutor().substitute(currentMethod.getReturnType()); MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i); PsiMethod otherSuperMethod = otherSuperSignature.getMethod(); - PsiType otherSuperReturnType = otherSuperSignature.getSubstitutor().substitute(otherSuperMethod.getReturnType()); - - PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable, + PsiSubstitutor otherSubstitutor = otherSuperSignature.getSubstitutor(); + PsiType otherSuperReturnType = otherSubstitutor.substitute(otherSuperMethod.getReturnType()); + PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable[0], otherSuperSignature); if (unifyingSubstitutor != null) { otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType); @@ -1319,20 +1319,25 @@ public class HighlightMethodUtil { } if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) continue; - - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { - //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3 - if (!(otherSuperReturnType instanceof PsiPrimitiveType || currentType instanceof PsiPrimitiveType)) { - if (otherSuperReturnType.isAssignableFrom(currentType)) continue; - if (currentType.isAssignableFrom(otherSuperReturnType)) { - returnTypeSubstitutable = otherSuperSignature; - continue; + PsiType otherReturnType = otherSuperReturnType; + PsiType curType = currentType; + final HighlightInfo info = + LambdaUtil.performWithSubstitutedParameterBounds(otherSuperMethod.getTypeParameters(), otherSubstitutor, () -> { + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { + //http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3 + if (!(otherReturnType instanceof PsiPrimitiveType || curType instanceof PsiPrimitiveType)) { + if (otherReturnType.isAssignableFrom(curType)) return null; + if (curType.isAssignableFrom(otherReturnType)) { + returnTypeSubstitutable[0] = otherSuperSignature; + return null; + } + } + if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(curType, otherReturnType)) return null; } - } - if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(currentType, otherSuperReturnType)) continue; - } - return createIncompatibleReturnTypeMessage(otherSuperMethod, currentMethod, currentType, otherSuperReturnType, - JavaErrorMessages.message("unrelated.overriding.methods.return.types"), TextRange.EMPTY_RANGE); + return createIncompatibleReturnTypeMessage(otherSuperMethod, currentMethod, curType, otherReturnType, + JavaErrorMessages.message("unrelated.overriding.methods.return.types"), TextRange.EMPTY_RANGE); + }); + if (info != null) return info; } return null; } diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 3f5bc1359b53..3c3c60d0e88a 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -25,7 +25,10 @@ import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; import com.intellij.util.Consumer; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Producer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -821,6 +824,34 @@ public class LambdaUtil { return copyCall; } + public static T performWithSubstitutedParameterBounds(final PsiTypeParameter[] typeParameters, + final PsiSubstitutor substitutor, + final Producer producer) { + try { + for (PsiTypeParameter parameter : typeParameters) { + final PsiClassType[] types = parameter.getExtendsListTypes(); + if (types.length > 0) { + final List conjuncts = ContainerUtil.map(types, new Function() { + @Override + public PsiType fun(PsiClassType type) { + return substitutor.substitute(type); + } + }); + //don't glb to avoid flattening = Object&Interface would be preserved + //otherwise methods with different signatures could get same erasure + final PsiType upperBound = PsiIntersectionType.createIntersection(false, conjuncts.toArray(new PsiType[conjuncts.size()])); + getFunctionalTypeMap().put(parameter, upperBound); + } + } + return producer.produce(); + } + finally { + for (PsiTypeParameter parameter : typeParameters) { + getFunctionalTypeMap().remove(parameter); + } + } + } + public static class TypeParamsChecker extends PsiTypeVisitor { private PsiMethod myMethod; private final PsiClass myClass; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index d717d8192538..55843bf91337 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -32,6 +32,7 @@ import com.intellij.psi.util.*; import com.intellij.util.ArrayUtilRt; import com.intellij.util.Function; import com.intellij.util.Processor; +import com.intellij.util.Producer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -1651,36 +1652,19 @@ public class InferenceSession { /** * 18.5.4 More Specific Method Inference */ - public static boolean isMoreSpecific(PsiMethod m1, + public static boolean isMoreSpecific(final PsiMethod m1, final PsiMethod m2, - final PsiSubstitutor siteSubstitutor1, + final PsiSubstitutor siteSubstitutor1, final PsiExpression[] args, final PsiElement context, final boolean varargs) { - final PsiTypeParameter[] typeParameters = m1.getTypeParameters(); - try { - for (PsiTypeParameter parameter : typeParameters) { - final PsiClassType[] types = parameter.getExtendsListTypes(); - if (types.length > 0) { - final List conjuncts = ContainerUtil.map(types, new Function() { - @Override - public PsiType fun(PsiClassType type) { - return siteSubstitutor1.substitute(type); - } - }); - //don't glb to avoid flattening = Object&Interface would be preserved - //otherwise methods with different signatures could get same erasure - final PsiType upperBound = PsiIntersectionType.createIntersection(false, conjuncts.toArray(new PsiType[conjuncts.size()])); - LambdaUtil.getFunctionalTypeMap().put(parameter, upperBound); - } + return LambdaUtil.performWithSubstitutedParameterBounds(m1.getTypeParameters(), siteSubstitutor1, new Producer() { + @Nullable + @Override + public Boolean produce() { + return isMoreSpecificInternal(m1, m2, siteSubstitutor1, args, context, varargs); } - return isMoreSpecificInternal(m1, m2, siteSubstitutor1, args, context, varargs); - } - finally { - for (PsiTypeParameter parameter : typeParameters) { - LambdaUtil.getFunctionalTypeMap().remove(parameter); - } - } + }); } private static boolean isMoreSpecificInternal(PsiMethod m1, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked.java new file mode 100644 index 000000000000..a1a40c1a56ef --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/TypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked.java @@ -0,0 +1,12 @@ +import java.util.List; + +interface A { + String save(String world); +} + +interface Test2 extends A, CR {} +interface Test1 extends CR, A {} +interface CR { + S save(S var1); + List save(Iterable var1); +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index 87398d77f925..630785397c4b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -1005,4 +1005,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testMembersContainedInCapturedWildcardType() throws Exception { doTest(); } + + public void testTypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked() throws Exception { + doTest(); + } }