inference: deep nested session based on existing initial substitution (IDEA-167713)

This commit is contained in:
Anna.Kozlova
2017-02-09 20:55:41 +01:00
parent a3e78bee41
commit e88322304e
3 changed files with 67 additions and 20 deletions

View File

@@ -172,33 +172,37 @@ public class InferenceSessionContainer {
if (call != null) {
initialInferenceState = compoundInitialState.getInitialState(call);
if (initialInferenceState != null) {
final int idx = LambdaUtil.getLambdaIdx(call.getArgumentList(), gParent);
final PsiMethod method = call.resolveMethod();
if (method != null && idx > -1) {
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
final PsiExpressionList argumentList = call.getArgumentList();
final int idx = LambdaUtil.getLambdaIdx(argumentList, gParent);
final JavaResolveResult result = call.resolveMethodGenerics();
final PsiElement method = result.getElement();
if (method instanceof PsiMethod && idx > -1) {
LOG.assertTrue(argumentList != null);
final PsiParameter[] methodParameters = ((PsiMethod)method).getParameterList().getParameters();
if (methodParameters.length == 0) {
break;
}
final PsiType parameterType = PsiTypesUtil.getParameterType(methodParameters, idx, true);
final PsiType parameterTypeInTermsOfSession = initialInferenceState.getInferenceSubstitutor().substitute(parameterType);
final PsiType lambdaTargetType = compoundInitialState.getInitialSubstitutor().substitute(parameterTypeInTermsOfSession);
return LambdaUtil.performWithLambdaTargetType((PsiLambdaExpression)gParent, lambdaTargetType, new Producer<PsiSubstitutor>() {
@Nullable
@Override
public PsiSubstitutor produce() {
if (call.equals(PsiTreeUtil.getParentOfType(parent, PsiCall.class, true))) {
//parent was mentioned in the top inference session
//just proceed with the target type
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, parent.getManager(), parent, policy);
inferenceSession.initExpressionConstraints(parameters, arguments, parent);
return inferenceSession.infer(parameters, arguments, parent);
if (call.equals(PsiTreeUtil.getParentOfType(parent, PsiCall.class, true))) {
return LambdaUtil.performWithLambdaTargetType((PsiLambdaExpression)gParent, partialSubstitutor.substitute(lambdaTargetType), new Producer<PsiSubstitutor>() {
@Override
public PsiSubstitutor produce() {
//parent was mentioned in the top inference session
//just proceed with the target type
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, parent.getManager(), parent, policy);
inferenceSession.initExpressionConstraints(parameters, arguments, parent);
return inferenceSession.infer(parameters, arguments, parent);
}
//one of the grand parents were found in the top inference session
//start from it as it is the top level call
final InferenceSession sessionInsideLambda = startTopLevelInference(call, policy);
return inferNested(typeParameters, parameters, arguments, partialSubstitutor, parent, policy, properties, sessionInsideLambda);
}
});
});
}
//one of the grand parents were found in the top inference session
//start from it as it is the top level call
final InferenceSession sessionInsideLambda = new InferenceSession(initialInferenceState);
sessionInsideLambda.collectAdditionalAndInfer(methodParameters, argumentList.getExpressions(), ((MethodCandidateInfo)result).createProperties(), compoundInitialState.getInitialSubstitutor());
return inferNested(typeParameters, parameters, arguments, partialSubstitutor, parent, policy, properties, sessionInsideLambda);
}
}
else {

View File

@@ -0,0 +1,39 @@
import java.util.function.BiFunction;
import java.util.function.Function;
interface DuallyParametric<A0, B0> {
<R> R match(Function<? super A0, ? extends R> aFn, Function<? super B0, ? extends R> bFn);
static <Aa, Ba> DuallyParametric<Aa, Ba> a(Aa a) {
return null;
}
<Ab, Bb> DuallyParametric<Ab, Bb> b(Bb b);
<Al, Bl> Bl foldLeft(BiFunction<? super Bl, ? super Al, ? extends Bl> fn, Bl b, Iterable<Al> as);
default <A, B> DuallyParametric<A, B> merge(DuallyParametric<A, B> first,
BiFunction<? super A, ? super A, ? extends A> aFn,
BiFunction<? super B, ? super B, ? extends B> bFn,
Iterable<DuallyParametric<A, B>> others) {
return foldLeft((x, y) -> x.match(a1 -> y.match(a2 -> a(aFn.apply(a1, a2)), b -> a(a1)),
b1 -> y.match(DuallyParametric::a, b2 -> b(bFn.apply(b1, b2)))),
first,
others);
}
}
interface DuallyParametric1<A> {
default <R> R match(Function<A, R> aFn) {
return null;
}
static <Ba> DuallyParametric1<Ba> a() {
return null;
}
<Bl> void foldLeft(Function<Bl, Bl> fn, Bl b);
default void merge() {
foldLeft((x) -> x.match(a1 -> match(a2 -> a())), this);
}
}

View File

@@ -43,6 +43,10 @@ public class NewInferenceCollectingAdditionalConstraintsTest extends LightDaemon
doTest();
}
public void testNestedLambdaExpressionsChain() throws Exception {
doTest();
}
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);