KT-1457 Subtyping doesn't work when type parameter is used indirectly in supertype declaration
This commit is contained in:
+56
-2
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// +JDK
|
||||
import java.util.ArrayList
|
||||
|
||||
class MyListOfPairs<T> : ArrayList<#(T, T)>() { }
|
||||
|
||||
fun test() {
|
||||
MyListOfPairs<Int> : ArrayList<#(Int, Int)>
|
||||
}
|
||||
@@ -471,6 +471,21 @@ public class JetTypeCheckerTest extends JetLiteFixture {
|
||||
assertSupertypes("Derived1_inT<Int>", "Derived_T<Int>", "Base_T<Int>", "Any", "Base_inT<Int>");
|
||||
}
|
||||
|
||||
public void testEffectiveProjectionKinds() throws Exception {
|
||||
assertSubtype("Tuple1<Int>", "Tuple1<Int>");
|
||||
assertSubtype("Tuple1<out Int>", "Tuple1<out Int>");
|
||||
assertSubtype("Tuple1<out Int>", "Tuple1<Int>");
|
||||
assertSubtype("Tuple1<Int>", "Tuple1<out Int>");
|
||||
assertSubtype("Tuple1<in Int>", "Tuple1<out Any?>");
|
||||
assertSubtype("Tuple1<out Any?>", "Tuple1<in String>");
|
||||
assertSubtype("Base_inT<Int>", "Base_inT<Int>");
|
||||
assertSubtype("Base_inT<in Int>", "Base_inT<in Int>");
|
||||
assertSubtype("Base_inT<in Int>", "Base_inT<Int>");
|
||||
assertSubtype("Base_inT<Int>", "Base_inT<in Int>");
|
||||
assertSubtype("Base_inT<out Int>", "Base_inT<out Any?>");
|
||||
assertSubtype("Base_inT<out Any?>", "Base_inT<out Int>");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void assertSupertypes(String typeStr, String... supertypeStrs) {
|
||||
|
||||
Reference in New Issue
Block a user