new inference: collect nested calls from lambda return statements (JDK-8038747)

This commit is contained in:
Anna Kozlova
2014-04-01 10:19:01 +02:00
parent 34f4baa8a5
commit 990094f360
4 changed files with 103 additions and 15 deletions
@@ -56,6 +56,8 @@ public class InferenceSession {
private final InferenceIncorporationPhase myIncorporationPhase = new InferenceIncorporationPhase(this);
private final PsiElement myContext;
private final PsiTypeParameter[] myParamsToInfer;
public InferenceSession(PsiTypeParameter[] typeParams,
PsiType[] leftTypes,
@@ -68,6 +70,7 @@ public class InferenceSession {
myContext = context;
initBounds(typeParams);
myParamsToInfer = typeParams;
LOG.assertTrue(leftTypes.length == rightTypes.length);
for (int i = 0; i < leftTypes.length; i++) {
@@ -87,6 +90,11 @@ public class InferenceSession {
myContext = context;
initBounds(typeParams);
myParamsToInfer = typeParams;
}
public PsiTypeParameter[] getParamsToInfer() {
return myParamsToInfer;
}
public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod method) {
@@ -217,7 +225,7 @@ public class InferenceSession {
if (parameters != null && args != null) {
final Set<ConstraintFormula> additionalConstraints = new HashSet<ConstraintFormula>();
if (parameters.length > 0) {
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs(), true);
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
@@ -250,7 +258,7 @@ public class InferenceSession {
PsiMethod parentMethod,
PsiSubstitutor siteSubstitutor,
Set<ConstraintFormula> additionalConstraints,
boolean varargs) {
boolean varargs, boolean toplevel) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
PsiType parameterType = getParameterType(parameters, i, siteSubstitutor, varargs);
@@ -262,18 +270,15 @@ public class InferenceSession {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
final PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
final JavaResolveResult result = callExpression.resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
//need to get type parameters for 2 level nested expressions (they won't be covered by expression constraints on this level?!)
initBounds(method.getTypeParameters());
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(),
additionalConstraints, ((MethodCandidateInfo)result).isVarargs());
collectAdditionalConstraints(additionalConstraints, callExpression);
} else if (args[i] instanceof PsiLambdaExpression && toplevel) {
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
if (interfaceReturnType != null) {
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)args[i]);
for (PsiExpression returnExpression : returnExpressions) {
if (returnExpression instanceof PsiCallExpression) {
final PsiCallExpression callExpression = (PsiCallExpression)returnExpression;
collectAdditionalConstraints(additionalConstraints, callExpression);
}
}
}
@@ -282,6 +287,25 @@ public class InferenceSession {
}
}
private void collectAdditionalConstraints(Set<ConstraintFormula> additionalConstraints,
PsiCallExpression callExpression) {
PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
final JavaResolveResult result = callExpression.resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
//need to get type parameters for 2 level nested expressions (they won't be covered by expression constraints on this level?!)
initBounds(method.getTypeParameters());
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(),
additionalConstraints, ((MethodCandidateInfo)result).isVarargs(), false);
}
}
}
}
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
for (InferenceVariable variable : variables) {
@@ -23,6 +23,7 @@ import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
@@ -103,7 +104,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (typeParams != null) {
final HashSet<PsiTypeParameter> oldBounds = new HashSet<PsiTypeParameter>(session.getTypeParams());
final Set<PsiTypeParameter> oldBounds = ContainerUtil.newHashSet(session.getParamsToInfer());
final boolean sameMethodCall = session.initBounds(typeParams);
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
final HashSet<InferenceVariable> variables = new HashSet<InferenceVariable>();
@@ -0,0 +1,59 @@
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;
abstract class Play {
public void main(Stream<String> stream, Stream<String> anotherStream) {
Stream<String> stringStream = stream.map(o -> foo(i -> "")).flatMap(l -> l);
}
abstract <RF > Stream<RF> foo(Function<Integer, ? extends RF> mapper);
static int foo() {
return 6;
}
}
class SimplePlay {
{
foo(y -> bar(x -> "")).substring(0);
}
interface Res<R> {
R apply(String s);
}
<T> T foo(Res<T> f) {return null;}
<K> K bar(Res<K> f) {return null;}
}
class Test19 {
interface Seq<E> extends Iterable<E> {
static <E> Seq<E> of(Iterable<? extends E> source) {
return null;
}
<R> Seq<R> map(Function<? super E, ? extends R> mapper);
<R, V> Seq<R> zip(BiFunction<? super E, ? super V, ? extends R> zipper, Seq<V> other);
}
interface S extends Seq<String> {
static S copyOf(Iterable<String> source) {
return null;
}
}
interface D extends S {
}
void test(Seq<D> dseq) {
BiFunction<D, List<Integer>, Seq<S>> f =
(d, nums) -> dseq.map(s -> s.zip((text, num) -> text + num, Seq.of(nums)))
.map(s -> S.copyOf(s));
}
}
@@ -182,6 +182,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testNestedCallsInsideLambdaReturnExpression() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}