lambda: replace raw inference from lambda with Object when it doesn't matter (IDEA-101788)

This commit is contained in:
anna
2013-02-25 14:12:42 +01:00
parent 8d651e0f86
commit a684c033a1
3 changed files with 79 additions and 4 deletions
@@ -205,6 +205,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
sortLambdaExpressionsLast(paramTypes, argTypes);
boolean rawType = false;
boolean nullPassed = false;
boolean lambdaRaw = false;
for (int j = 0; j < argTypes.length; j++) {
PsiType argumentType = argTypes[j];
if (argumentType == null) continue;
@@ -228,6 +229,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
if (currentSubstitution == FAILED_INFERENCE || (currentSubstitution == null && lowerBound == PsiType.NULL)) return RAW_INFERENCE;
}
if (nullPassed && currentSubstitution == null) return RAW_INFERENCE;
if (currentSubstitution != null && currentSubstitution.first == null) {
lambdaRaw = true;
}
if (currentSubstitution == null && lambdaRaw) {
return new Pair<PsiType, ConstraintType>(PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope()), ConstraintType.EQUALS);
}
} else if (argumentType instanceof PsiMethodReferenceType) {
final PsiMethodReferenceExpression referenceExpression = ((PsiMethodReferenceType)argumentType).getExpression();
currentSubstitution = inferConstraintFromFunctionalInterfaceMethod(typeParameter, referenceExpression, partialSubstitutor.substitute(parameterType), partialSubstitutor, policy);
@@ -998,7 +1005,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
return null;
}
private static Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(PsiElement parent,
private static Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(final PsiElement parent,
PsiExpression methodCall,
final PsiTypeParameter typeParameter,
PsiSubstitutor substitutor,
@@ -1065,16 +1072,24 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
}
} else if (parent instanceof PsiLambdaExpression) {
expectedType = LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
expectedType = ourGraphGuard.doPreventingRecursion(methodCall, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
}
});
if (expectedType == null) {
return getFailedInferenceConstraint(typeParameter);
return null;
}
} else if (parent instanceof PsiTypeCastExpression) {
expectedType = ((PsiTypeCastExpression)parent).getType();
} else if (parent instanceof PsiConditionalExpression) {
if (PsiUtil.isLanguageLevel8OrHigher(parent)) {
try {
return inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy);
final Pair<PsiType, ConstraintType> pair = inferFromConditionalExpression(parent, methodCall, typeParameter, substitutor, policy);
if (pair != null) {
return pair;
}
}
finally {
GraphInferencePolicy.forget(parent);
@@ -1175,6 +1190,32 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
return result;
}
private static Pair<PsiType, ConstraintType> inferFromConditionalExpression(PsiElement parent,
PsiExpression methodCall,
PsiTypeParameter typeParameter,
PsiSubstitutor substitutor,
ParameterTypeInferencePolicy policy) {
Pair<PsiType, ConstraintType> pair =
inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy);
if (pair == null) {
final PsiExpression thenExpression = ((PsiConditionalExpression)parent).getThenExpression();
final PsiExpression elseExpression = ((PsiConditionalExpression)parent).getElseExpression();
final PsiType[] paramTypes = {((PsiMethod)typeParameter.getOwner()).getReturnType()};
if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(elseExpression)) && thenExpression != null) {
final PsiType thenType = thenExpression.getType();
if (thenType != null) {
pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {thenType}, substitutor, null, policy);
}
} else if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(thenExpression)) && elseExpression != null) {
final PsiType elseType = elseExpression.getType();
if (elseType != null) {
pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {elseType}, substitutor, null, policy);
}
}
}
return pair;
}
private static final ProcessCandidateParameterTypeInferencePolicy GRAPH_INFERENCE_POLICY = new GraphInferencePolicy();
private static Pair<PsiType, ConstraintType> graphInferenceFromCallContext(@NotNull final PsiExpression methodCall,
@@ -0,0 +1,30 @@
public class CyclicReferenceTest {
void test(Match<String, Integer> match) {
Match<String, Integer> matcher = match.or(s -> Optional.empty(), i -> 2);
Match<String, Integer> matcher1 = match.or(s -> s.startsWith("_") ? Optional.of(1) : Optional.empty(), i -> 2);
}
}
class Match<T, V> {
public <W> Match<T, V> or(Extractor<T, W> e, Function<W, V> c) {
return this;
}
}
interface Extractor<T, W> {
Optional<W> unapply(T t);
}
interface Function<W, V> {
public V apply(W t);
}
class Optional<W> {
public static <T> Optional<T> empty() {
return null;
}
public static <T> Optional<T> of(T value) {
return null;
}
}
@@ -216,6 +216,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testAcceptRawSubstForLambda() throws Exception {
doTest();
}
public void testCheckFunctionalInterfaceAccess() throws Exception {
doTest();
}