mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
new inference: lambda functional type detection
This commit is contained in:
+55
-55
@@ -196,7 +196,7 @@ public class InferenceSession {
|
||||
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
if (parentMethod != null) {
|
||||
initReturnTypeConstraint(parentMethod, parent);
|
||||
if (!repeatInferencePhases(true)) {
|
||||
return prepareSubstitution();
|
||||
@@ -251,7 +251,12 @@ public class InferenceSession {
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent) {
|
||||
final Pair<PsiMethod, PsiCallExpression> pair = getPair(parent);
|
||||
final PsiSubstitutor subst = tryToInfer(parameters, args, pair != null ? pair.second : null, pair != null ? pair.first : null);
|
||||
return infer(parameters, args, parent, pair != null ? pair.first : null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor infer(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod parentMethod) {
|
||||
final PsiSubstitutor subst = tryToInfer(parameters, args, parent instanceof PsiCallExpression ? ((PsiCallExpression)parent) : null, parentMethod);
|
||||
if (subst != null) {
|
||||
return subst;
|
||||
}
|
||||
@@ -268,7 +273,7 @@ public class InferenceSession {
|
||||
} else {
|
||||
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
|
||||
}
|
||||
|
||||
|
||||
return prepareSubstitution();
|
||||
}
|
||||
|
||||
@@ -340,11 +345,10 @@ public class InferenceSession {
|
||||
returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context);
|
||||
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context);
|
||||
if (targetType == null) {
|
||||
final PsiType finalReturnType = returnType;
|
||||
targetType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, false, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return getTargetType(context, finalReturnType);
|
||||
return getTargetType(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -466,7 +470,7 @@ public class InferenceSession {
|
||||
return false;
|
||||
}
|
||||
|
||||
private PsiType getTargetType(final PsiExpression context, PsiType returnType) {
|
||||
private PsiType getTargetType(final PsiExpression context) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent());
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiElement gParent = parent.getParent();
|
||||
@@ -474,49 +478,50 @@ public class InferenceSession {
|
||||
final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final Pair<PsiMethod, PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
if (pair == null) {
|
||||
final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) {
|
||||
@Override
|
||||
protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) {
|
||||
if (argumentList != null) {
|
||||
final PsiExpression[] expressions = argumentList.getExpressions();
|
||||
final int idx = LambdaUtil.getLambdaIdx(argumentList, context);
|
||||
final PsiType[] types = PsiType.createArray(expressions.length);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
if (i != idx) {
|
||||
types[i] = expressions[i].getType();
|
||||
}
|
||||
else {
|
||||
types[i] = PsiType.NULL;
|
||||
}
|
||||
final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) {
|
||||
@Override
|
||||
protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) {
|
||||
if (argumentList != null) {
|
||||
final PsiExpression[] expressions = argumentList.getExpressions();
|
||||
final int idx = LambdaUtil.getLambdaIdx(argumentList, context);
|
||||
final PsiType[] types = PsiType.createArray(expressions.length);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
if (i != idx) {
|
||||
types[i] = expressions[i].getType();
|
||||
}
|
||||
else {
|
||||
types[i] = PsiType.NULL;
|
||||
}
|
||||
return types;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return types;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
try {
|
||||
PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false);
|
||||
}
|
||||
catch (MethodProcessorSetupFailedException e) {
|
||||
return null;
|
||||
}
|
||||
final JavaResolveResult[] results = processor.getResult();
|
||||
return results.length == 1 ? getTypeByMethod(context, argumentList, null, results[0], results[0].getElement()) : null;
|
||||
};
|
||||
try {
|
||||
PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false);
|
||||
}
|
||||
return getTypeByMethod(context, argumentList, pair, null, pair.first);
|
||||
catch (MethodProcessorSetupFailedException e) {
|
||||
return null;
|
||||
}
|
||||
final JavaResolveResult[] results = processor.getResult();
|
||||
return results.length == 1 ? getTypeByMethod(context, argumentList, pair, results[0], results[0].getElement()) : null;
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof PsiConditionalExpression) {
|
||||
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent);
|
||||
if (targetType == null) {
|
||||
targetType = getTargetType((PsiExpression)parent, returnType);
|
||||
targetType = getTargetType((PsiExpression)parent);
|
||||
}
|
||||
return targetType;
|
||||
}
|
||||
else if (parent instanceof PsiLambdaExpression) {
|
||||
if (PsiUtil.skipParenthesizedExprUp(parent.getParent()) instanceof PsiExpressionList) {
|
||||
final PsiType typeTypeByParentCall = getTargetType((PsiLambdaExpression)parent);
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(FunctionalInterfaceParameterizationUtil.getGroundTargetType(typeTypeByParentCall, (PsiLambdaExpression)parent));
|
||||
}
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
|
||||
}
|
||||
return null;
|
||||
@@ -537,28 +542,23 @@ public class InferenceSession {
|
||||
}
|
||||
final int i = ArrayUtilRt.find(args, arg);
|
||||
if (i < 0) return null;
|
||||
if (pair != null) {
|
||||
return getParameterType(parameters, args, i, pair.second);
|
||||
final PsiCallExpression callExpression = (PsiCallExpression)argumentList.getParent();
|
||||
if (callExpression.getTypeArguments().length > 0) {
|
||||
return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor());
|
||||
}
|
||||
else {
|
||||
final PsiCallExpression callExpression = (PsiCallExpression)argumentList.getParent();
|
||||
if (callExpression.getTypeArguments().length > 0) {
|
||||
return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor());
|
||||
}
|
||||
final PsiType parameterType = getParameterType(parameters, args, i, PsiSubstitutor.EMPTY);
|
||||
args[i] = null;
|
||||
final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters();
|
||||
final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList);
|
||||
session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod);
|
||||
if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) {
|
||||
return null;
|
||||
}
|
||||
final Collection<PsiTypeParameter> params = session.getTypeParams();
|
||||
initBounds(params.toArray(new PsiTypeParameter[params.size()]));
|
||||
liftBounds(session.getInferenceVariables());
|
||||
final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor();
|
||||
return substitutor.substitute(parameterType);
|
||||
final PsiType parameterType = getParameterType(parameters, args, i, pair != null ? pair.second : PsiSubstitutor.EMPTY);
|
||||
args[i] = null;
|
||||
final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters();
|
||||
final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList);
|
||||
session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod);
|
||||
if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) {
|
||||
return null;
|
||||
}
|
||||
final Collection<PsiTypeParameter> params = session.getTypeParams();
|
||||
initBounds(params.toArray(new PsiTypeParameter[params.size()]));
|
||||
liftBounds(session.getInferenceVariables());
|
||||
final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor();
|
||||
return substitutor.substitute(parameterType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
}
|
||||
|
||||
final PsiType exprType = myExpression.getType();
|
||||
if (exprType != null) {
|
||||
if (exprType != null && exprType != PsiType.NULL) {
|
||||
constraints.add(new TypeCompatibilityConstraint(myT, exprType));
|
||||
}
|
||||
return true;
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Optional.of;
|
||||
|
||||
class MatchTest {
|
||||
|
||||
{
|
||||
Match<String, Integer> match = match((String s) -> s.equals("1") ? of(1) : null, s -> 1);
|
||||
}
|
||||
|
||||
private <M>Optional<M> bar() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T1, V1, W1> Match<T1, V1> match(Extractor<T1, W1> e, Function<W1, V1> c) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class Match<T, V> {}
|
||||
|
||||
interface Extractor<T, W> {
|
||||
Optional<W> unapply(T t);
|
||||
}
|
||||
}
|
||||
+4
@@ -110,6 +110,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testAdditionalConstraintSubstitution() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
public void testFunctionalInterfacesCalculation() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
|
||||
Reference in New Issue
Block a user