new inference: erase return type if unchecked conversion was performed

This commit is contained in:
Anna Kozlova
2014-02-24 18:59:40 +01:00
parent 01b095b77b
commit 828cb5a1a2
3 changed files with 21 additions and 7 deletions
@@ -49,6 +49,8 @@ public class InferenceSession {
private static final Logger LOG = Logger.getInstance("#" + InferenceSession.class.getName());
public static final Key<PsiType> LOWER_BOUND = Key.create("LowBound");
private static final Key<Boolean> ERASED = Key.create("UNCHECKED_CONVERSION");
private final Map<PsiTypeParameter, InferenceVariable> myInferenceVariables = new LinkedHashMap<PsiTypeParameter, InferenceVariable>();
private final List<ConstraintFormula> myConstraints = new ArrayList<ConstraintFormula>();
@@ -286,6 +288,9 @@ public class InferenceSession {
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor);
if (substitutor != null) {
if (myContext != null) {
myContext.putUserData(ERASED, myErased);
}
mySiteSubstitutor = substitutor;
for (PsiTypeParameter parameter : substitutor.getSubstitutionMap().keySet()) {
final InferenceVariable variable = getInferenceVariable(parameter);
@@ -396,9 +401,6 @@ public class InferenceSession {
myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutor.substitute(inferenceVariable.getParameter()), myContext)));
}
else {
if (targetType instanceof PsiClassType && ((PsiClassType)targetType).isRaw()) {
setErased();
}
if (FunctionalInterfaceParameterizationUtil.isWildcardParameterized(returnType)) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(returnType);
final PsiClass psiClass = resolveResult.getElement();
@@ -419,7 +421,7 @@ public class InferenceSession {
myConstraints.add(new TypeCompatibilityConstraint(targetType, substitutedCapture));
}
} else {
myConstraints.add(new TypeCompatibilityConstraint(myErased ? TypeConversionUtil.erasure(targetType) : targetType, returnType));
myConstraints.add(new TypeCompatibilityConstraint(targetType, myErased ? TypeConversionUtil.erasure(returnType) : returnType));
}
}
}
@@ -470,7 +472,7 @@ public class InferenceSession {
}
private static boolean hasWildcardParameterization(InferenceVariable inferenceVariable, PsiClassType targetType) {
if (FunctionalInterfaceParameterizationUtil.isWildcardParameterized(targetType)) {
if (!FunctionalInterfaceParameterizationUtil.isWildcardParameterized(targetType)) {
final List<PsiType> bounds = inferenceVariable.getBounds(InferenceBound.LOWER);
final Processor<Pair<PsiType, PsiType>> differentParameterizationProcessor = new Processor<Pair<PsiType, PsiType>>() {
@Override
@@ -1198,4 +1200,9 @@ public class InferenceSession {
}
}
}
public static boolean wasUncheckedConversionPerformed(PsiElement call) {
final Boolean erased = call.getUserData(ERASED);
return erased != null && erased.booleanValue();
}
}
@@ -24,6 +24,7 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.resolve.JavaResolveCache;
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;
@@ -208,6 +209,12 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements
PsiSubstitutor substitutor) {
PsiType substitutedReturnType = substitutor.substitute(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);
}
if (PsiUtil.isRawSubstitutor(method, substitutor)) {
final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret);
if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) {
@@ -7,8 +7,8 @@ public class Sample {
<B> B bar(G<B> gb) {return null;}
void f(G1 g1) {
<error descr="Incompatible types. Found: 'B', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
<error descr="Incompatible types. Found: 'B', required: 'java.lang.String'">String l1 = bar(g1);</error>
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String l1 = bar(g1);</error>
Object o = bar(g1);
}
}