constructor reference: don't ignore constructor parameters during method reference inference (IDEA-185578)

GitOrigin-RevId: e836468e05db28157713e9edd3c70382f8ecdebc
This commit is contained in:
Anna Kozlova
2019-06-12 12:40:39 +02:00
committed by intellij-monorepo-bot
parent fc0b6309b8
commit 5355846fe0
5 changed files with 48 additions and 39 deletions

View File

@@ -27,7 +27,6 @@ import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public class PsiMethodReferenceCompatibilityConstraint implements ConstraintFormula {
@@ -170,17 +169,20 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
//if i) the method reference elides NonWildTypeArguments,
// ii) the compile-time declaration is a generic method, and
// iii) the return type of the compile-time declaration mentions at least one of the method's type parameters;
if (typeParameters.length == 0 && method.getTypeParameters().length > 0) {
final PsiClass interfaceClass = classResolveResult.getElement();
LOG.assertTrue(interfaceClass != null);
if (PsiTypesUtil.mentionsTypeParameters(referencedMethodReturnType,
ContainerUtil.newHashSet(method.getTypeParameters()))) {
session.initBounds(myExpression, psiSubstitutor, method.getTypeParameters());
//the constraint reduces to the bound set B3 which would be used to determine the method reference's invocation type
//when targeting the return type of the function type, as defined in 18.5.2.
session.collectApplicabilityConstraints(myExpression, ((MethodCandidateInfo)resolve), groundTargetType);
session.registerReturnTypeConstraints(psiSubstitutor.substitute(referencedMethodReturnType), returnType, myExpression);
return true;
if (typeParameters.length == 0) {
PsiTypeParameter[] methodTypeParameters = method.isConstructor() ? containingClass.getTypeParameters() : method.getTypeParameters();
if (methodTypeParameters.length > 0) {
final PsiClass interfaceClass = classResolveResult.getElement();
LOG.assertTrue(interfaceClass != null);
if (PsiTypesUtil.mentionsTypeParameters(referencedMethodReturnType,
ContainerUtil.newHashSet(methodTypeParameters))) {
session.initBounds(myExpression, psiSubstitutor, methodTypeParameters);
//the constraint reduces to the bound set B3 which would be used to determine the method reference's invocation type
//when targeting the return type of the function type, as defined in 18.5.2.
session.collectApplicabilityConstraints(myExpression, ((MethodCandidateInfo)resolve), groundTargetType);
session.registerReturnTypeConstraints(psiSubstitutor.substitute(referencedMethodReturnType), returnType, myExpression);
return true;
}
}
}
@@ -230,30 +232,6 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
final PsiType pType = PsiUtil.captureToplevelWildcards(parameterization, methodReferenceExpression);
psiSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(qContainingClass, (PsiClassType)pType);
}
else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
//15.13.1
//If ClassType is a raw type, but is not a non-static member type of a raw type,
//the candidate notional member methods are those specified in p15.9.3 for a class instance creation expression that uses <>
//to elide the type arguments to a class.
final PsiResolveHelper helper = JavaPsiFacade.getInstance(methodReferenceExpression.getProject()).getResolveHelper();
final PsiType[] paramTypes =
member instanceof PsiMethod ? ((PsiMethod)member).getSignature(PsiSubstitutor.EMPTY).getParameterTypes() : PsiType.EMPTY_ARRAY;
if (paramTypes.length != signature.getParameterTypes().length && !(member instanceof PsiMethod && ((PsiMethod)member).isVarArgs())) {
//inapplicable method reference
return PsiSubstitutor.EMPTY;
}
if (Arrays.deepEquals(signature.getParameterTypes(), paramTypes)) {
return PsiSubstitutor.EMPTY;
}
if (paramTypes.length == signature.getParameterTypes().length) {
psiSubstitutor = helper.inferTypeArguments(PsiTypesUtil.filterUnusedTypeParameters(qContainingClass.getTypeParameters(), paramTypes),
paramTypes,
signature.getParameterTypes(),
PsiUtil.getLanguageLevel(methodReferenceExpression));
}
}
else {
psiSubstitutor = PsiSubstitutor.EMPTY;
}

View File

@@ -117,8 +117,11 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
if (includeReturnConstraint && !PsiType.VOID.equals(interfaceMethodReturnType) && interfaceMethodReturnType != null) {
PsiSubstitutor subst = PsiMethodReferenceCompatibilityConstraint.getSubstitutor(signature, qualifierResolveResult, method, containingClass, reference);
final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, subst) : subst.substitute(method.getReturnType());
final PsiType returnType = method.isConstructor()
? composeReturnType(containingClass, substitutor)
: PsiMethodReferenceCompatibilityConstraint
.getSubstitutor(signature, qualifierResolveResult, method, containingClass, reference)
.substitute(method.getReturnType());
if (returnType != null) {
session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType, reference);
}

View File

@@ -0,0 +1,27 @@
import java.util.function.Function;
class MyTest {
{
Function<B, Try<A>> aNew = Try::new;
Try<B> bTry = new Try<>(new B());
Try<A> aTry = bTry.flatMap(Try::new);
}
private static class A { }
private static class B extends A { }
private static class Try<T> {
public Try(T t) {
}
public Try(Exception e) {
}
public <U> Try<U> flatMap(Function<? super T, Try<U>> mapper) {
return null;
}
}
}

View File

@@ -5,6 +5,6 @@ import java.util.stream.*;
class Test {
public static void test(List<String> s) {
new TreeSet<? extends String>(s).contains("abc");
new TreeSet<>(s).contains("abc");
}
}

View File

@@ -191,6 +191,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testSkipInferenceForInapplicableMethodReference() { doTest(); }
public void testRegisterVariablesForNonFoundParameterizations() { doTest(); }
public void testConstructorReferenceOnRawTypeWithInferredSubtypes() { doTest(); }
public void testPreferErrorOnTopLevelToFailedSubstitutorOnNestedLevel() { doTest(); }
public void testDontIgnoreIncompatibilitiesDuringFirstApplicabilityCheck() { doTest(); }
public void testCaptureOnDedicatedParameterOfSecondSearch() { doTest(); }