new inference: null upper bounds

This commit is contained in:
Anna Kozlova
2013-09-18 20:18:00 +04:00
parent 278120e99c
commit e273976e25
6 changed files with 67 additions and 58 deletions
@@ -34,7 +34,7 @@ public class InferenceIncorporationPhase {
public void incorporate() {
for (InferenceVariable inferenceVariable : mySession.getInferenceVariables()) {
if (inferenceVariable.getInstantiation() != null) continue;
if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER);
final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER);
@@ -67,7 +67,7 @@ public class InferenceIncorporationPhase {
boolean isFullyIncorporated() {
boolean needFurtherIncorporation = false;
for (InferenceVariable inferenceVariable : mySession.getInferenceVariables()) {
if (inferenceVariable.getInstantiation() != null) continue;
if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER);
final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER);
@@ -105,7 +105,7 @@ public class InferenceSession {
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation == null) {
if (instantiation == PsiType.NULL) {
//failed inference
mySiteSubstitutor = mySiteSubstitutor
.put(typeParameter, JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(typeParameter));
@@ -161,11 +161,12 @@ public class InferenceSession {
return null;
}
public boolean isProperType(@NotNull PsiType type) {
public boolean isProperType(@Nullable PsiType type) {
return collectDependencies(type, null);
}
public boolean collectDependencies(@NotNull PsiType type, @Nullable final Set<InferenceVariable> dependencies) {
public boolean collectDependencies(@Nullable PsiType type, @Nullable final Set<InferenceVariable> dependencies) {
if (type == null) return true;
final Boolean isProper = type.accept(new PsiTypeVisitor<Boolean>() {
@Nullable
@Override
@@ -240,58 +241,66 @@ public class InferenceSession {
for (List<InferenceVariable> variables : independentVars) {
for (InferenceVariable inferenceVariable : variables) {
if (inferenceVariable.getInstantiation() != null) continue;
if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
PsiType bound = null;
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
for (PsiType eqBound : eqBounds) {
eqBound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound);
if (isProperType(eqBound)) {
bound = eqBound;
break;
}
}
if (bound != null) {
inferenceVariable.setInstantiation(bound);
} else {
try {
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER);
PsiType lub = null;
for (PsiType lowerBound : lowerBounds) {
lowerBound = acceptBoundsWithRecursiveDependencies(typeParameter, lowerBound);
if (isProperType(lowerBound)) {
if (lub == null) {
lub = lowerBound;
}
else {
lub = GenericsUtil.getLeastUpperBound(lub, lowerBound, myManager);
}
final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER);
if (/*eqBounds.contains(null) || lowerBounds.contains(null) || */upperBounds.contains(null)) {
inferenceVariable.setInstantiation(null);
continue;
}
PsiType bound = null;
for (PsiType eqBound : eqBounds) {
eqBound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound);
if (isProperType(eqBound)) {
bound = eqBound;
break;
}
}
if (lub != null) {
inferenceVariable.setInstantiation(lub instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)lub).getWildcard() : lub);
}
else {
PsiType glb = null;
for (PsiType upperBound : inferenceVariable.getBounds(InferenceBound.UPPER)) {
upperBound = acceptBoundsWithRecursiveDependencies(typeParameter, upperBound);
if (isProperType(upperBound)) {
if (glb == null) {
glb = upperBound;
if (bound != null) {
inferenceVariable.setInstantiation(bound);
} else {
PsiType lub = null;
for (PsiType lowerBound : lowerBounds) {
lowerBound = acceptBoundsWithRecursiveDependencies(typeParameter, lowerBound);
if (isProperType(lowerBound)) {
if (lub == null) {
lub = lowerBound;
}
else {
glb = GenericsUtil.getGreatestLowerBound(glb, upperBound);
lub = GenericsUtil.getLeastUpperBound(lub, lowerBound, myManager);
}
}
}
if (glb != null) {
inferenceVariable.setInstantiation(glb);
if (lub != null) {
inferenceVariable.setInstantiation(lub instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)lub).getWildcard() : lub);
}
else {
PsiType glb = null;
for (PsiType upperBound : upperBounds) {
upperBound = acceptBoundsWithRecursiveDependencies(typeParameter, upperBound);
if (isProperType(upperBound)) {
if (glb == null) {
glb = upperBound;
}
else {
glb = GenericsUtil.getGreatestLowerBound(glb, upperBound);
}
}
}
if (glb != null) {
inferenceVariable.setInstantiation(glb);
}
}
}
}
final PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation != null) {
mySiteSubstitutor = mySiteSubstitutor.put(typeParameter, instantiation);
finally {
final PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation != PsiType.NULL) {
mySiteSubstitutor = mySiteSubstitutor.put(typeParameter, instantiation);
}
}
}
}
@@ -32,7 +32,7 @@ public class InferenceVariable {
private Map<InferenceBound, List<PsiType>> myBounds = new HashMap<InferenceBound, List<PsiType>>();
private PsiTypeParameter myParameter;
private PsiType myInstantiation;
private PsiType myInstantiation = PsiType.NULL;
public InferenceVariable(PsiTypeParameter parameter) {
myParameter = parameter;
}
@@ -36,7 +36,7 @@ public class InferenceVariablesOrder {
}
for (InferenceVariable var : vars) {
if (var.getInstantiation() != null) continue;
if (var.getInstantiation() != PsiType.NULL) continue;
final InferenceGraphNode<InferenceVariable> node = nodes.get(var);
for (InferenceBound inferenceBound : InferenceBound.values()) {
for (PsiType bound : var.getBounds(inferenceBound)) {
@@ -86,7 +86,8 @@ public class PsiPolyExpressionUtil {
return PsiTypesUtil.getExpectedTypeByParent(expression);
}
public static Boolean mentionsTypeParameters(PsiType returnType, final Set<PsiTypeParameter> typeParameters) {
public static Boolean mentionsTypeParameters(@Nullable PsiType returnType, final Set<PsiTypeParameter> typeParameters) {
if (returnType == null) return false;
return returnType.accept(new PsiTypeVisitor<Boolean>() {
@Nullable
@Override
@@ -32,7 +32,7 @@ public class SubtypingConstraint implements ConstraintFormula {
private PsiType myT;
private boolean myIsRefTypes;
public SubtypingConstraint(@NotNull PsiType t, @NotNull PsiType s, boolean isRefTypes) {
public SubtypingConstraint(PsiType t, PsiType s, boolean isRefTypes) {
myT = t;
myS = s;
myIsRefTypes = isRefTypes;
@@ -42,6 +42,7 @@ public class SubtypingConstraint implements ConstraintFormula {
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints, List<ConstraintFormula> delayedConstraints) {
if (myIsRefTypes) {
if (session.isProperType(myS) && session.isProperType(myT)) {
if (myT == null || myS == null) return myS == myT;
return TypeConversionUtil.isAssignable(myT, myS);
}
InferenceVariable inferenceVariable = session.getInferenceVariable(myS);
@@ -49,7 +50,7 @@ public class SubtypingConstraint implements ConstraintFormula {
inferenceVariable.addBound(myT, InferenceBound.UPPER);
return true;
}
if (myS.equals(PsiType.NULL)) return true;
if (PsiType.NULL.equals(myS)) return true;
inferenceVariable = session.getInferenceVariable(myT);
if (inferenceVariable != null) {
inferenceVariable.addBound(myS, InferenceBound.LOWER);
@@ -88,9 +89,7 @@ public class SubtypingConstraint implements ConstraintFormula {
for (PsiTypeParameter parameter : CClass.getTypeParameters()) {
final PsiType tSubstituted = tSubstitutor.substitute(parameter);
final PsiType sSubstituted = sSubstitutor.substituteWithBoundsPromotion(parameter);
if (tSubstituted != null && sSubstituted != null) {
constraints.add(new SubtypingConstraint(tSubstituted, sSubstituted, false));
}
constraints.add(new SubtypingConstraint(tSubstituted, sSubstituted, false));
}
return true;
}
@@ -105,7 +104,7 @@ public class SubtypingConstraint implements ConstraintFormula {
return true;
}
if (myT.equals(PsiType.NULL)) return false;
if (PsiType.NULL.equals(myT)) return false;
} else {
if (myT instanceof PsiWildcardType) {
final PsiType tBound = ((PsiWildcardType)myT).getBound();
@@ -160,16 +159,16 @@ public class SubtypingConstraint implements ConstraintFormula {
SubtypingConstraint that = (SubtypingConstraint)o;
if (myIsRefTypes != that.myIsRefTypes) return false;
if (!myS.equals(that.myS)) return false;
if (!myT.equals(that.myT)) return false;
if (myS != null ? !myS.equals(that.myS) : that.myS != null) return false;
if (myT != null ? !myT.equals(that.myT) : that.myT != null) return false;
return true;
}
@Override
public int hashCode() {
int result = myS.hashCode();
result = 31 * result + myT.hashCode();
int result = myS != null ? myS.hashCode() : 0;
result = 31 * result + (myT != null ? myT.hashCode() : 0);
result = 31 * result + (myIsRefTypes ? 1 : 0);
return result;
}