From 828cb5a1a2503f99ec10e0b2a1a4dffe219c0e33 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 24 Feb 2014 13:41:58 +0100 Subject: [PATCH] new inference: erase return type if unchecked conversion was performed --- .../graphInference/InferenceSession.java | 17 ++++++++++++----- .../tree/java/PsiMethodCallExpressionImpl.java | 7 +++++++ .../constraints/UncheckedBoundsWithErasure.java | 4 ++-- 3 files changed, 21 insertions(+), 7 deletions(-) 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 59089f5c16eb..ea0c8081d25e 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 @@ -49,6 +49,8 @@ public class InferenceSession { private static final Logger LOG = Logger.getInstance("#" + InferenceSession.class.getName()); public static final Key LOWER_BOUND = Key.create("LowBound"); + private static final Key ERASED = Key.create("UNCHECKED_CONVERSION"); + private final Map myInferenceVariables = new LinkedHashMap(); private final List myConstraints = new ArrayList(); @@ -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 bounds = inferenceVariable.getBounds(InferenceBound.LOWER); final Processor> differentParameterizationProcessor = new Processor>() { @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(); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index 36013c3625a3..dc204b4ae315 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -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)) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java index a106da75fa7e..49753a7bcdac 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java @@ -7,8 +7,8 @@ public class Sample { B bar(G gb) {return null;} void f(G1 g1) { - G l11 = bar(g1); - String l1 = bar(g1); + G l11 = bar(g1); + String l1 = bar(g1); Object o = bar(g1); } }