inference for method references: register new variables for raw access

IDEA-189883, IDEA-188976: according to the 15.13.1 search for member is performed in the parameterization (non-raw) type which is a subtype of the first parameter type, in this case no additional variables are required as the type contains type arguments
This commit is contained in:
Anna.Kozlova
2018-04-11 10:19:16 +02:00
parent 6a3df23040
commit 74f6d68ea3
3 changed files with 53 additions and 8 deletions
@@ -208,8 +208,12 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
}
}
if (PsiUtil.isRawSubstitutor(containingClass, qualifierResolveResult.getSubstitutor())) {
session.initBounds(myExpression, containingClass.getTypeParameters());
PsiClass qContainingClass = qualifierResolveResult.getContainingClass();
if (qContainingClass != null && PsiUtil.isRawSubstitutor(qContainingClass, qualifierResolveResult.getSubstitutor())) {
//15.13.1 If there exist a parameterization, then it would be used to search, the *raw type* would be used otherwise
if (getParameterization(signature, qualifierResolveResult, method, myExpression, qContainingClass) == null) {
session.initBounds(myExpression, qContainingClass.getTypeParameters());
}
}
referencedMethodReturnType = psiSubstitutor.substitute(referencedMethodReturnType);
@@ -233,12 +237,9 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
// the type to search is the result of capture conversion (5.1.10) applied to T;
// otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference.
if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) {
PsiClassType subclassType;
if (member instanceof PsiMethod &&
PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, methodReferenceExpression) &&
(subclassType = StrictSubtypingConstraint.getSubclassType(qContainingClass, signature.getParameterTypes()[0], true)) != null &&
!subclassType.isRaw()) {
final PsiType pType = PsiUtil.captureToplevelWildcards(subclassType, methodReferenceExpression);
PsiClassType parameterization = getParameterization(signature, qualifierResolveResult, member, methodReferenceExpression, qContainingClass);
if (parameterization != null) {
final PsiType pType = PsiUtil.captureToplevelWildcards(parameterization, methodReferenceExpression);
psiSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(qContainingClass, (PsiClassType)pType);
}
else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
@@ -278,6 +279,21 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
return psiSubstitutor;
}
private static PsiClassType getParameterization(MethodSignature signature,
PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult,
PsiMember member,
PsiMethodReferenceExpression methodReferenceExpression,
PsiClass qContainingClass) {
if (member instanceof PsiMethod &&
PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, methodReferenceExpression)) {
PsiClassType subclassType = StrictSubtypingConstraint.getSubclassType(qContainingClass, signature.getParameterTypes()[0], true);
if (subclassType != null && !subclassType.isRaw()) {
return subclassType;
}
}
return null;
}
@Override
public void apply(PsiSubstitutor substitutor, boolean cache) {
myT = substitutor.substitute(myT);
@@ -0,0 +1,28 @@
import java.util.stream.Stream;
import java.util.Optional;
class SomeClass<T> {
private T id;
public T getId() {
return id;
}
public void n(final Optional<SomeClass<T>> o) {
T otherId = o.map(SomeClass::getId).orElse(null);
}
}
class A {
interface Base<T> {
T foo();
}
interface Sub<S> extends Base<S> { }
void m(Stream<Sub> stream) {
stream.map( Sub::foo);
}
}
@@ -180,6 +180,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testMethodReferenceSwallowedErrors() { doTest(); }
public void testConflictingVarargsFromFirstSearchWithNArityOfTheSecondSearch() { doTest(); }
public void testSkipInferenceForInapplicableMethodReference() { doTest(); }
public void testRegisterVariablesForNonFoundParameterizations() { doTest(); }
public void testPreferErrorOnTopLevelToFailedSubstitutorOnNestedLevel() { doTest(); }