KT-1457 Subtyping doesn't work when type parameter is used indirectly in supertype declaration

This commit is contained in:
Andrey Breslav
2012-02-27 15:34:57 +04:00
parent 2e0d00c45b
commit 963557f3c8
3 changed files with 79 additions and 2 deletions
@@ -87,9 +87,11 @@ public class TypeCheckingProcedure {
}
for (int i = 0; i < type1Arguments.size(); i++) {
TypeParameterDescriptor typeParameter1 = constructor1.getParameters().get(i);
TypeProjection typeProjection1 = type1Arguments.get(i);
TypeParameterDescriptor typeParameter2 = constructor2.getParameters().get(i);
TypeProjection typeProjection2 = type2Arguments.get(i);
if (typeProjection1.getProjectionKind() != typeProjection2.getProjectionKind()) {
if (getEffectiveProjectionKind(typeParameter1, typeProjection1) != getEffectiveProjectionKind(typeParameter2, typeProjection2)) {
return false;
}
@@ -100,6 +102,58 @@ public class TypeCheckingProcedure {
return true;
}
private enum EnrichedProjectionKind {
IN, OUT, INV, STAR;
@NotNull
public static EnrichedProjectionKind fromVariance(@NotNull Variance variance) {
switch (variance) {
case INVARIANT:
return INV;
case IN_VARIANCE:
return IN;
case OUT_VARIANCE:
return OUT;
}
throw new IllegalStateException("Unknown variance");
}
}
// If class C<out T> then C<T> and C<out T> mean the same
// out * out = out
// out * in = *
// out * inv = out
//
// in * out = *
// in * in = in
// in * inv = in
//
// inv * out = out
// inv * in = out
// inv * inv = inv
private EnrichedProjectionKind getEffectiveProjectionKind(@NotNull TypeParameterDescriptor typeParameter, @NotNull TypeProjection typeArgument) {
Variance a = typeParameter.getVariance();
Variance b = typeArgument.getProjectionKind();
// If they are not both invariant, let's make b not invariant for sure
if (b == INVARIANT) {
Variance t = a;
a = b;
b = t;
}
// Opposites yield STAR
if (a == IN_VARIANCE && b == OUT_VARIANCE) {
return EnrichedProjectionKind.STAR;
}
if (a == OUT_VARIANCE && b == IN_VARIANCE) {
return EnrichedProjectionKind.STAR;
}
// If they are not opposite, return b, because b is either equal to a or b is in/out and a is inv
return EnrichedProjectionKind.fromVariance(b);
}
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) {
return true;
@@ -127,7 +181,7 @@ public class TypeCheckingProcedure {
List<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
List<TypeParameterDescriptor> parameters = constructor.getParameters();
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
for (int i = 0; i < parameters.size(); i++) {
TypeParameterDescriptor parameter = parameters.get(i);