mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-30 02:09:59 +07:00
constructor reference: don't ignore constructor parameters during method reference inference (IDEA-185578)
GitOrigin-RevId: e836468e05db28157713e9edd3c70382f8ecdebc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fc0b6309b8
commit
5355846fe0
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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(); }
|
||||
|
||||
Reference in New Issue
Block a user