mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
new inference: use site substitution inside one level of inference only so calls with different site substitutions are possible in one expression (IDEA-131723; IDEA-131562)
This commit is contained in:
@@ -255,41 +255,55 @@ public class GenericsUtil {
|
||||
final PsiSubstitutor substitutor,
|
||||
final PsiElement context,
|
||||
final boolean allowUncheckedConversion) {
|
||||
nextTypeParam:
|
||||
for (PsiTypeParameter typeParameter : typeParams) {
|
||||
PsiType substituted = substitutor.substitute(typeParameter);
|
||||
if (substituted == null) return null;
|
||||
if (context != null) {
|
||||
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
|
||||
PsiType boundError = findTypeParameterBoundError(typeParameter, typeParameter.getExtendsListTypes(),
|
||||
substitutor, context, allowUncheckedConversion);
|
||||
if (boundError != null) {
|
||||
return Pair.create(typeParameter, boundError);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
|
||||
for (PsiClassType type : extendsTypes) {
|
||||
PsiType extendsType = substitutor.substitute(type);
|
||||
if (substituted instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)substituted).isSuper()) {
|
||||
continue;
|
||||
}
|
||||
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) {
|
||||
continue nextTypeParam;
|
||||
}
|
||||
public static PsiType findTypeParameterBoundError(PsiTypeParameter typeParameter,
|
||||
PsiType[] extendsTypes,
|
||||
PsiSubstitutor substitutor,
|
||||
PsiElement context,
|
||||
boolean allowUncheckedConversion) {
|
||||
PsiType substituted = substitutor.substitute(typeParameter);
|
||||
if (substituted == null) return null;
|
||||
if (context != null) {
|
||||
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
|
||||
}
|
||||
|
||||
if (substituted instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)substituted).isSuper()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiType type : extendsTypes) {
|
||||
PsiType extendsType = substitutor.substitute(type);
|
||||
if (substituted instanceof PsiWildcardType) {
|
||||
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) {
|
||||
return null;
|
||||
}
|
||||
else if (substituted instanceof PsiIntersectionType) {
|
||||
for (PsiType extendsBound : ((PsiIntersectionType)substituted).getConjuncts()) {
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) continue nextTypeParam;
|
||||
}
|
||||
}
|
||||
else if (substituted instanceof PsiIntersectionType) {
|
||||
for (PsiType extendsBound : ((PsiIntersectionType)substituted).getConjuncts()) {
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) return null;
|
||||
}
|
||||
else if (substituted instanceof PsiCapturedWildcardType) {
|
||||
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) {
|
||||
continue nextTypeParam;
|
||||
}
|
||||
}
|
||||
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
|
||||
return Pair.create(typeParameter, extendsType);
|
||||
}
|
||||
else if (substituted instanceof PsiCapturedWildcardType) {
|
||||
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
|
||||
if (acceptExtendsBound(extendsType, extendsBound)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
|
||||
return extendsType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+22
-7
@@ -254,12 +254,12 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, mySiteSubstitutor);
|
||||
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, PsiSubstitutor.EMPTY);
|
||||
if (substitutor != null) {
|
||||
if (myContext != null) {
|
||||
myContext.putUserData(ERASED, myErased);
|
||||
}
|
||||
mySiteSubstitutor = substitutor;
|
||||
mySiteSubstitutor = mySiteSubstitutor.putAll(substitutor);
|
||||
for (InferenceVariable variable : myInferenceVariables) {
|
||||
variable.setInstantiation(substitutor.substitute(variable.getParameter()));
|
||||
}
|
||||
@@ -403,7 +403,7 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
|
||||
PsiSubstitutor substitutor = mySiteSubstitutor;
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
|
||||
for (InferenceVariable variable : variables) {
|
||||
final PsiType equalsBound = getEqualsBound(variable, substitutor);
|
||||
if (!(equalsBound instanceof PsiPrimitiveType)) {
|
||||
@@ -751,6 +751,22 @@ public class InferenceSession {
|
||||
return isProperType(bound) ? bound : substitutor.substitute(bound);
|
||||
}
|
||||
|
||||
private static boolean hasBoundProblems(final List<InferenceVariable> typeParams,
|
||||
final PsiSubstitutor substitutor,
|
||||
final PsiElement context) {
|
||||
for (InferenceVariable typeParameter : typeParams) {
|
||||
if (typeParameter.getCallContext() != context) {
|
||||
continue;
|
||||
}
|
||||
final List<PsiType> extendsTypes = typeParameter.getBounds(InferenceBound.UPPER);
|
||||
final PsiType[] bounds = extendsTypes.toArray(new PsiType[extendsTypes.size()]);
|
||||
if (GenericsUtil.findTypeParameterBoundError(typeParameter, bounds, substitutor, context, true) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
|
||||
PsiSubstitutor substitutor) {
|
||||
final Collection<InferenceVariable> allVars = new ArrayList<InferenceVariable>(inferenceVariables);
|
||||
@@ -759,8 +775,7 @@ public class InferenceSession {
|
||||
if (!myIncorporationPhase.hasCaptureConstraints(vars)) {
|
||||
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
|
||||
if (firstSubstitutor != null) {
|
||||
final Set<PsiTypeParameter> parameters = firstSubstitutor.getSubstitutionMap().keySet();
|
||||
if (GenericsUtil.findTypeParameterWithBoundError(parameters.toArray(new PsiTypeParameter[parameters.size()]), firstSubstitutor, myContext, true) != null) {
|
||||
if (hasBoundProblems(vars, firstSubstitutor, myContext)) {
|
||||
firstSubstitutor = null;
|
||||
}
|
||||
}
|
||||
@@ -837,7 +852,7 @@ public class InferenceSession {
|
||||
for (InferenceVariable var : vars) {
|
||||
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
|
||||
final PsiTypeParameter typeParameter = var.getParameter();
|
||||
if (substitutor.getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
|
||||
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
|
||||
continue;//todo
|
||||
}
|
||||
|
||||
@@ -849,7 +864,7 @@ public class InferenceSession {
|
||||
type = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
|
||||
}
|
||||
else {
|
||||
if (substitutor.getSubstitutionMap().get(typeParameter) != null) continue;
|
||||
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().get(typeParameter) != null) continue;
|
||||
type = myErased ? null : getUpperBound(var, substitutor);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -90,13 +90,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
if (method != null && !method.isConstructor()) {
|
||||
returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
List<PsiTypeParameter> params = new ArrayList<PsiTypeParameter>();
|
||||
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(method)) {
|
||||
params.add(parameter);
|
||||
}
|
||||
typeParams = params.toArray(new PsiTypeParameter[params.size()]);
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
} else if (myExpression instanceof PsiNewExpression) { //default constructor
|
||||
} else if (myExpression instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)myExpression).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
final PsiElement psiClass = classReference.resolve();
|
||||
@@ -108,7 +104,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
}
|
||||
|
||||
if (typeParams != null) {
|
||||
final InferenceSession callSession = new InferenceSession(typeParams, PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression);
|
||||
PsiSubstitutor siteSubstitutor =
|
||||
resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY;
|
||||
final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, myExpression.getManager(), myExpression);
|
||||
callSession.propagateVariables(session.getInferenceVariables());
|
||||
if (method != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
@@ -120,7 +118,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
if (!accepted) {
|
||||
return false;
|
||||
}
|
||||
callSession.registerReturnTypeConstraints(returnType, myT);
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), myT);
|
||||
if (callSession.repeatInferencePhases(true)) {
|
||||
session.registerNestedSession(callSession);
|
||||
} else {
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
//expected type parameter
|
||||
class Sample<V> {
|
||||
|
||||
public <K> Map<V, K> test() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> void fun(T t, V v) {
|
||||
}
|
||||
|
||||
<M> M bar() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void run(Sample<Integer> sample) {
|
||||
fun(test(), bar());
|
||||
sample.fun(test(), sample.bar());
|
||||
sample.fun(test(), bar());
|
||||
fun(test(), sample.bar());
|
||||
|
||||
fun(sample.test(), bar());
|
||||
fun(sample.test(), sample.bar());
|
||||
sample.fun(sample.test(), bar());
|
||||
sample.fun(sample.test(), sample.bar());
|
||||
}
|
||||
}
|
||||
|
||||
//expected generic type
|
||||
class Sample1<T> {
|
||||
public <S extends T> List<S> reverse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void foo(Sample1<Comparable> t)
|
||||
{
|
||||
newTreeSet(t.reverse());
|
||||
newTreeSet(reverse());
|
||||
|
||||
t.newTreeSet(t.reverse());
|
||||
t.newTreeSet(reverse());
|
||||
}
|
||||
|
||||
|
||||
public <E> void newTreeSet(List<E> comparator) {}
|
||||
}
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ class MyTest1 {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
m<error descr="Ambiguous method call: both 'MyTest1.m(I1)' and 'MyTest1.m(I2)' match">(Foo::new)</error>;
|
||||
m<error descr="Ambiguous method call: both 'MyTest1.m(I2)' and 'MyTest1.m(I3)' match">(Foo::new)</error>;
|
||||
}
|
||||
}
|
||||
class MyTest2 {
|
||||
@@ -104,6 +104,6 @@ class MyTest2 {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
m<error descr="Ambiguous method call: both 'MyTest2.m(I1)' and 'MyTest2.m(I2)' match">(Foo::new)</error>;
|
||||
m<error descr="Ambiguous method call: both 'MyTest2.m(I2)' and 'MyTest2.m(I3)' match">(Foo::new)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -172,6 +172,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSiteSubstitutionInExpressionConstraints() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIncorporationWithEqualsBoundsSubstitution() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user