new inference: provide diagnostics on failed inference (strict subtyping constraints); don't resolve vars before incorporate - this way captures won't be opened too early

This commit is contained in:
Anna Kozlova
2015-11-23 16:55:24 +01:00
parent 24bfcbcd27
commit 138bd5a034
8 changed files with 24 additions and 21 deletions

View File

@@ -73,7 +73,6 @@ public class InferenceIncorporationPhase {
public boolean incorporate() {
final Collection<InferenceVariable> inferenceVariables = mySession.getInferenceVariables();
final PsiSubstitutor substitutor = mySession.retrieveNonPrimitiveEqualsBounds(inferenceVariables);
for (InferenceVariable inferenceVariable : inferenceVariables) {
if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
@@ -82,9 +81,9 @@ public class InferenceIncorporationPhase {
eqEq(eqBounds);
upDown(lowerBounds, upperBounds, substitutor);
upDown(eqBounds, upperBounds, substitutor);
upDown(lowerBounds, eqBounds, substitutor);
upDown(lowerBounds, upperBounds);
upDown(eqBounds, upperBounds);
upDown(lowerBounds, eqBounds);
upUp(upperBounds);
}
@@ -263,7 +262,7 @@ public class InferenceIncorporationPhase {
* or
* S <: a & a <: T imply S <: T
*/
private void upDown(List<PsiType> eqBounds, List<PsiType> upperBounds, PsiSubstitutor substitutor) {
private void upDown(List<PsiType> eqBounds, List<PsiType> upperBounds) {
for (PsiType upperBound : upperBounds) {
if (upperBound == null || PsiType.NULL.equals(upperBound) || upperBound instanceof PsiWildcardType) continue;
@@ -276,7 +275,7 @@ public class InferenceIncorporationPhase {
if (eqBound instanceof PsiCapturedWildcardType) {
eqBound = ((PsiCapturedWildcardType)eqBound).getUpperBound();
}
addConstraint(new StrictSubtypingConstraint(substitutor.substitute(upperBound), substitutor.substitute(eqBound)));
addConstraint(new StrictSubtypingConstraint(upperBound, eqBound));
}
}
}

View File

@@ -47,20 +47,20 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
@Override
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
if (!session.collectDependencies(myS, dependencies) && !session.collectDependencies(myT, dependencies)) {
if (myT == null) return myS == null || myS.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
if (myS == null) return true;
return TypeConversionUtil.isAssignable(myT, myS);
}
final boolean reduceResult = nonProperReduce(session, constraints);
final boolean reduceResult = doReduce(session, dependencies, constraints);
if (!reduceResult) {
session.registerIncompatibleErrorMessage(dependencies, myS.getPresentableText() + " conforms to " + myT.getPresentableText());
}
return reduceResult;
}
private boolean nonProperReduce(InferenceSession session, List<ConstraintFormula> constraints) {
private boolean doReduce(InferenceSession session, HashSet<InferenceVariable> dependencies, List<ConstraintFormula> constraints) {
if (!session.collectDependencies(myS, dependencies) && !session.collectDependencies(myT, dependencies)) {
if (myT == null) return myS == null || myS.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
if (myS == null) return true;
return TypeConversionUtil.isAssignable(myT, myS);
}
if (PsiType.NULL.equals(myT) || myT == null) return false;
if (PsiType.NULL.equals(myS) || myS == null || myT.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return true;

View File

@@ -1,6 +1,6 @@
class C<T extends C<? extends C<? extends T>>>{
void foo(C<?> x){
<error descr="Inferred type 'capture<?>' for type parameter 'T' is not within its bound; should extend 'C<? extends capture<?>>'">bar(x)</error>;
bar<error descr="'bar(C<T>)' in 'C' cannot be applied to '(C<capture<?>>)'">(x)</error>;
}
<T extends C<? extends T>> void bar(C<T> x){}
}

View File

@@ -87,7 +87,7 @@ class CaptureTest {
}
void foo (Class<? extends Emum<CaptureTest>> clazz) {
<error descr="Inferred type 'capture<? extends CaptureTest.Emum<CaptureTest>>' for type parameter 'T' is not within its bound; should extend 'CaptureTest.Emum<capture<? extends CaptureTest.Emum<CaptureTest>>>'">Emum.valueOf(clazz, "CCC")</error>;
<error descr="Inferred type 'java.lang.Object' for type parameter 'T' is not within its bound; should extend 'CaptureTest.Emum<java.lang.Object>'">Emum.valueOf(clazz, "CCC")</error>;
}
}

View File

@@ -12,7 +12,8 @@ class TypeArgsConsistency {
I<Integer> i1 = (i, j) -> i + j;
foo((i, j) -> i + j);
I<Integer> i2 = bar((i, j) -> i + j);
I<Integer> i3 = bar(<error descr="inference variable X has incompatible bounds:
I<Integer> i3 = bar(<error descr="no instance(s) of type variable(s) exist so that String conforms to Integer
inference variable X has incompatible bounds:
equality constraints: Integer
lower bounds: String">(i, j) -> "" + i + j</error>);
}
@@ -45,7 +46,8 @@ class TypeArgsConsistency2 {
I<Integer> i1 = bar(x -> x);
I1<Integer> i2 = bar1(x -> 1);
I2<String> aI2 = bar2(x -> "");
I2<Integer> aI28 = bar2( <error descr="inference variable T has incompatible bounds:
I2<Integer> aI28 = bar2( <error descr="no instance(s) of type variable(s) exist so that String conforms to Integer
inference variable T has incompatible bounds:
equality constraints: Integer
lower bounds: String">x-> ""</error>);
I2<Integer> i3 = bar2(x -> x);

View File

@@ -9,7 +9,8 @@ class Test {
<R> SuperFoo<R> foo(I<R> ax) { return null; }
SuperFoo<String> ls = foo(<error descr="inference variable R has incompatible bounds:
SuperFoo<String> ls = foo(<error descr="no instance(s) of type variable(s) exist so that String conforms to Number
inference variable R has incompatible bounds:
equality constraints: String
upper bounds: Object, Number">() -> new Foo<>()</error>);
SuperFoo<Integer> li = foo(() -> new Foo<>());

View File

@@ -26,7 +26,8 @@ abstract class NoFormalParamTypeInferenceNeeded {
{
map(a -> zip(text -> text));
zip(a -> zip(text -> text));
Integer zip = zip(a -> zip(<error descr="inference variable R has incompatible bounds:
Integer zip = zip(a -> zip(<error descr="no instance(s) of type variable(s) exist so that Object conforms to Integer
inference variable R has incompatible bounds:
lower bounds: Object
upper bounds: Object, R, Integer">text -> text</error>));
}

View File

@@ -32,6 +32,6 @@ class ReturnTypeCompatibility {
call((String i)->{ return i;});
call(i->{ return i;});
call(i->"");
call((int i)->{ return <error descr="Bad return type in lambda expression: int cannot be converted to P">i</error>;});
call(<error descr="no instance(s) of type variable(s) exist so that Integer conforms to int">(int i)->{ return i;}</error>);
}
}