mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
method references: fix type to search (site substitution) for ReferenceType::Identifier references, where ReferenceType is raw (IDEA-135792)
This commit is contained in:
@@ -297,7 +297,7 @@ public class GenericsUtil {
|
||||
}
|
||||
else if (substituted instanceof PsiCapturedWildcardType) {
|
||||
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) {
|
||||
if (acceptExtendsBound(extendsType, extendsBound) || extendsType.equals(substitutor.substitute(extendsBound))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +175,7 @@ public class PsiMethodReferenceUtil {
|
||||
if (resolve instanceof PsiClass) {
|
||||
containingClass = (PsiClass)resolve;
|
||||
substitutor = resolveResult.getSubstitutor();
|
||||
final boolean isRawSubst = !methodReferenceExpression.isConstructor() &&
|
||||
PsiTreeUtil.isAncestor(containingClass, methodReferenceExpression, true) &&
|
||||
PsiUtil.isRawSubstitutor(containingClass, substitutor);
|
||||
return new QualifierResolveResult(containingClass, isRawSubst ? PsiSubstitutor.EMPTY : substitutor, true);
|
||||
return new QualifierResolveResult(containingClass, substitutor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -1130,11 +1130,11 @@ public class InferenceSession {
|
||||
final PsiType pType = signature.getParameterTypes()[0];
|
||||
|
||||
PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor();
|
||||
// 15.28.1 If the ReferenceType is a raw type, and there exists a parameterization of this type, T, that is a supertype of P1,
|
||||
// 15.13.1 If the ReferenceType is a raw type, and there exists a parameterization of this type, T, that is a supertype of P1,
|
||||
// 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(containingClass, qualifierResolveResult.getSubstitutor())) {
|
||||
final PsiClassType.ClassResolveResult pResult = PsiUtil.resolveGenericsClassInType(pType);
|
||||
if (PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor)) {
|
||||
final PsiClassType.ClassResolveResult pResult = PsiUtil.resolveGenericsClassInType(PsiUtil.captureToplevelWildcards(pType, myContext));
|
||||
final PsiClass pClass = pResult.getElement();
|
||||
final PsiSubstitutor receiverSubstitutor = pClass != null ? TypeConversionUtil
|
||||
.getClassSubstitutor(containingClass, pClass, pResult.getSubstitutor()) : null;
|
||||
@@ -1412,8 +1412,7 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
public PsiType substituteWithInferenceVariables(PsiType type) {
|
||||
final PsiType substituted = myInferenceSubstitution.substitute(type);
|
||||
return isProperType(substituted) ? type : substituted;
|
||||
return myInferenceSubstitution.substitute(type);
|
||||
}
|
||||
|
||||
public InferenceSession findNestedCallSession(PsiExpression arg) {
|
||||
|
||||
+36
-53
@@ -63,16 +63,10 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
|
||||
final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(myExpression);
|
||||
|
||||
if (!myExpression.isExact()) {
|
||||
for (PsiParameter parameter : targetParameters) {
|
||||
if (!session.isProperType(substitutor.substitute(parameter.getType()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (myExpression.isExact()) {
|
||||
final PsiMember applicableMember = myExpression.getPotentiallyApplicableMember();
|
||||
LOG.assertTrue(applicableMember != null);
|
||||
|
||||
|
||||
final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass();
|
||||
final PsiClass containingClass = qualifierResolveResult.getContainingClass();
|
||||
|
||||
@@ -90,7 +84,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
final PsiParameter[] parameters = applicableMember instanceof PsiMethod ? ((PsiMethod)applicableMember).getParameterList().getParameters() : PsiParameter.EMPTY_ARRAY;
|
||||
if (targetParameters.length == parameters.length + 1) {
|
||||
specialCase(session, constraints, substitutor, targetParameters, true);
|
||||
final PsiType qualifierType = PsiMethodReferenceUtil.getQualifierType(myExpression);
|
||||
final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType);
|
||||
if (qualifierClass != null) {
|
||||
session.initBounds(myExpression, qualifierClass.getTypeParameters());
|
||||
final PsiType pType = substitutor.substitute(targetParameters[0].getType());
|
||||
constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType), pType));
|
||||
}
|
||||
for (int i = 1; i < targetParameters.length; i++) {
|
||||
constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i - 1].getType())),
|
||||
substitutor.substitute(targetParameters[i].getType())));
|
||||
@@ -123,6 +123,14 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
return true;
|
||||
}
|
||||
|
||||
//------ non exact method references --------------------
|
||||
|
||||
for (PsiParameter parameter : targetParameters) {
|
||||
if (!session.isProperType(substitutor.substitute(parameter.getType()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
|
||||
final PsiType added = map.put(myExpression, session.startWithFreshVars(groundTargetType));
|
||||
final JavaResolveResult resolve;
|
||||
@@ -148,14 +156,28 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
final PsiType referencedMethodReturnType;
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
LOG.assertTrue(containingClass != null, method);
|
||||
PsiClass qContainingClass = qualifierResolveResult.getContainingClass();
|
||||
final PsiClass qContainingClass = qualifierResolveResult.getContainingClass();
|
||||
PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor();
|
||||
if (qContainingClass != null) {
|
||||
// 15.13.1 If the ReferenceType is a raw type, and there exists a parameterization of this type, T, that is a supertype of P1,
|
||||
// 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)) {
|
||||
psiSubstitutor = PsiSubstitutor.EMPTY;
|
||||
if (targetParameters.length == method.getParameterList().getParametersCount() + 1) {
|
||||
final PsiType pType = substitutor.substitute(targetParameters[0].getType());
|
||||
PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(PsiUtil.captureToplevelWildcards(pType, myExpression));
|
||||
PsiClass paramClass = resolveResult.getElement();
|
||||
LOG.assertTrue(paramClass != null);
|
||||
psiSubstitutor = TypeConversionUtil.getClassSubstitutor(qContainingClass, paramClass, resolveResult.getSubstitutor());
|
||||
LOG.assertTrue(psiSubstitutor != null);
|
||||
}
|
||||
else {
|
||||
psiSubstitutor = PsiSubstitutor.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (qContainingClass.isInheritor(containingClass, true)) {
|
||||
psiSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, PsiSubstitutor.EMPTY);
|
||||
psiSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, psiSubstitutor);
|
||||
LOG.assertTrue(psiSubstitutor != null);
|
||||
}
|
||||
}
|
||||
@@ -202,52 +224,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
}
|
||||
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (targetParameters.length == parameters.length + 1 && !method.isVarArgs() &&
|
||||
PsiPolyExpressionUtil.mentionsTypeParameters(referencedMethodReturnType, ContainerUtil.newHashSet(containingClass.getTypeParameters()))) { //todo specification bug?
|
||||
specialCase(session, constraints, substitutor, targetParameters, false);
|
||||
}
|
||||
constraints.add(new TypeCompatibilityConstraint(returnType, session.substituteWithInferenceVariables(psiSubstitutor.substitute(referencedMethodReturnType))));
|
||||
constraints.add(new TypeCompatibilityConstraint(returnType,
|
||||
session.substituteWithInferenceVariables(psiSubstitutor.substitute(referencedMethodReturnType))));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void specialCase(InferenceSession session,
|
||||
List<ConstraintFormula> constraints,
|
||||
PsiSubstitutor substitutor,
|
||||
PsiParameter[] targetParameters,
|
||||
boolean ignoreRaw) {
|
||||
final PsiElement qualifier = myExpression.getQualifier();
|
||||
PsiType qualifierType = null;
|
||||
if (qualifier instanceof PsiTypeElement) {
|
||||
qualifierType = ((PsiTypeElement)qualifier).getType();
|
||||
final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType);
|
||||
if (qualifierClass != null) {
|
||||
qualifierType = JavaPsiFacade.getElementFactory(myExpression.getProject()).createType(qualifierClass, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
}
|
||||
else if (qualifier instanceof PsiExpression) {
|
||||
qualifierType = ((PsiExpression)qualifier).getType();
|
||||
if (qualifierType == null && qualifier instanceof PsiReferenceExpression) {
|
||||
final JavaResolveResult resolveResult = ((PsiReferenceExpression)qualifier).advancedResolve(false);
|
||||
final PsiElement res = resolveResult.getElement();
|
||||
if (res instanceof PsiClass) {
|
||||
PsiClass containingClass = (PsiClass)res;
|
||||
final boolean isRawSubst = !ignoreRaw && !myExpression.isConstructor() && PsiUtil.isRawSubstitutor(containingClass, resolveResult.getSubstitutor());
|
||||
qualifierType = JavaPsiFacade.getElementFactory(res.getProject()).createType(containingClass, isRawSubst ? PsiSubstitutor.EMPTY : resolveResult.getSubstitutor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType);
|
||||
if (qualifierClass != null) {
|
||||
session.initBounds(myExpression, qualifierClass.getTypeParameters());
|
||||
constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType),
|
||||
session.substituteWithInferenceVariables(substitutor.substitute(targetParameters[0].getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(PsiSubstitutor substitutor, boolean cache) {
|
||||
myT = substitutor.substitute(myT);
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Main {
|
||||
public static void main(String[] args) {
|
||||
Stream<List<? extends Main>> listStream = new ArrayList<List<? extends Main>>().stream();
|
||||
Stream<? extends Main> l1 = listStream.flatMap(Collection::stream);
|
||||
Stream<? extends Main> l2 = listStream.flatMap(List::stream);
|
||||
}
|
||||
}
|
||||
+4
@@ -342,6 +342,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRawReferenceTypeWithReceiver() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user