erasure method call type if unchecked assignment was applied during applicability check (IDEA-67862)

(cherry picked from commit f106f813559768f90952caac6a2eec4cfeed7103)
This commit is contained in:
Anna Kozlova
2014-10-17 21:07:43 +02:00
parent 763ba4e270
commit 9fce6c0640
3 changed files with 49 additions and 3 deletions
@@ -28,6 +28,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.ElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTypesUtil;
@@ -197,7 +198,7 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements
ret = ((PsiClassType)ret).setLanguageLevel(languageLevel);
}
if (is15OrHigher) {
return captureReturnType(call, method, ret, result.getSubstitutor());
return captureReturnType(call, method, ret, result, languageLevel);
}
return TypeConversionUtil.erasure(ret);
}
@@ -206,15 +207,34 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements
public static PsiType captureReturnType(PsiMethodCallExpression call,
PsiMethod method,
PsiType ret,
PsiSubstitutor substitutor) {
JavaResolveResult result,
LanguageLevel languageLevel) {
PsiSubstitutor substitutor = result.getSubstitutor();
PsiType substitutedReturnType = substitutor.substitute(ret);
if (substitutedReturnType == null) return TypeConversionUtil.erasure(ret);
if (substitutedReturnType == null) {
return TypeConversionUtil.erasure(ret);
}
if (InferenceSession.wasUncheckedConversionPerformed(call)) {
// 18.5.2
// if unchecked conversion was necessary, then this substitution provides the parameter types of the invocation type,
// while the return type and thrown types are given by the erasure of m's type (without applying θ').
return TypeConversionUtil.erasure(substitutedReturnType);
}
//15.12.2.6. Method Invocation Type
// If unchecked conversion was necessary for the method to be applicable,
// the parameter types of the invocation type are the parameter types of the method's type,
// and the return type and thrown types are given by the erasures of the return type and thrown types of the method's type.
if (result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isApplicable()) {
final PsiType[] args = call.getArgumentList().getExpressionTypes();
final boolean allowUncheckedConversion = false;
final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, args, languageLevel, allowUncheckedConversion, true);
if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
return TypeConversionUtil.erasure(substitutedReturnType);
}
}
if (PsiUtil.isRawSubstitutor(method, substitutor)) {
final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret);
if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) {
@@ -0,0 +1,22 @@
import java.util.Collection;
import java.util.List;
class Main1 {
static <T> Collection<Collection<T>> foo(Collection<Collection<T>> x) { return x; }
public static void main(String[] args) {
List x = null;
foo(x).iterator().next().<error descr="Cannot resolve method 'iterator()'">iterator</error>();
}
}
class Main {
static <T> List<String> foo(Collection<String> x) { return null; }
public static void main(String[] args) {
List x = null;
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String s = foo(x).get(0);</error>
foo(x).iterator().next().<error descr="Cannot resolve method 'toLowerCase()'">toLowerCase</error>();
}
}
@@ -410,6 +410,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
}
public void testMethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck() {
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
}
public void testInferredParameterInBoundsInRecursiveGenerics() {
doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false);
}