Use "Any?" as out-type for type parameters instead of intersection of bounds

Also refactor checkSubtypeForTheSameConstructor to compute everything in the
best order
This commit is contained in:
Alexander Udalov
2015-10-22 23:26:37 +03:00
parent bed75e8af2
commit 12d6b6e7e4
4 changed files with 93 additions and 20 deletions
@@ -0,0 +1,18 @@
import java.io.Serializable
class A<T> where T : Cloneable, T : Serializable
interface CS1 : Cloneable, Serializable
interface CS2 : CS1
interface I1 {
fun foo(): A<in CS2>
}
interface I2 : I1 {
override fun foo(): A<CS1>
}
interface I3 : I1 {
override fun foo(): A<in CS1>
}
@@ -0,0 +1,43 @@
package
public final class A</*0*/ T : kotlin.Cloneable> where T : java.io.Serializable {
public constructor A</*0*/ T : kotlin.Cloneable>() where T : java.io.Serializable
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface CS1 : kotlin.Cloneable, java.io.Serializable {
protected open override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface CS2 : CS1 {
protected open override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface I1 {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(): A<in CS2>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface I2 : I1 {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract override /*1*/ fun foo(): A<CS1>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface I3 : I1 {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract override /*1*/ fun foo(): A<in CS1>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -15657,6 +15657,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("invariantArgumentForTypeParameterWithMultipleBounds.kt")
public void testInvariantArgumentForTypeParameterWithMultipleBounds() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/invariantArgumentForTypeParameterWithMultipleBounds.kt");
doTest(fileName);
}
@TestMetadata("kt2069.kt") @TestMetadata("kt2069.kt")
public void testKt2069() throws Exception { public void testKt2069() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/kt2069.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/subtyping/kt2069.kt");
@@ -20,9 +20,12 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.types.Variance.*; import static org.jetbrains.kotlin.types.Variance.*;
@@ -43,12 +46,14 @@ public class TypeCheckingProcedure {
return UtilsKt.findCorrespondingSupertype(subtype, supertype, typeCheckingProcedureCallbacks); return UtilsKt.findCorrespondingSupertype(subtype, supertype, typeCheckingProcedureCallbacks);
} }
public static KotlinType getOutType(TypeParameterDescriptor parameter, TypeProjection argument) { @NotNull
boolean isOutProjected = argument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE; private static KotlinType getOutType(@NotNull TypeParameterDescriptor parameter, @NotNull TypeProjection argument) {
return isOutProjected ? parameter.getUpperBoundsAsType() : argument.getType(); boolean isInProjected = argument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE;
return isInProjected ? DescriptorUtilsKt.getBuiltIns(parameter).getNullableAnyType() : argument.getType();
} }
public static KotlinType getInType(@NotNull TypeParameterDescriptor parameter, @NotNull TypeProjection argument) { @NotNull
private static KotlinType getInType(@NotNull TypeParameterDescriptor parameter, @NotNull TypeProjection argument) {
boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE; boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE;
return isOutProjected ? DescriptorUtilsKt.getBuiltIns(parameter).getNothingType() : argument.getType(); return isOutProjected ? DescriptorUtilsKt.getBuiltIns(parameter).getNothingType() : argument.getType();
} }
@@ -229,30 +234,31 @@ public class TypeCheckingProcedure {
TypeParameterDescriptor parameter = parameters.get(i); TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection superArgument = superArguments.get(i); TypeProjection superArgument = superArguments.get(i);
if (superArgument.isStarProjection()) continue;
KotlinType superIn = getInType(parameter, superArgument);
KotlinType superOut = getOutType(parameter, superArgument);
TypeProjection subArgument = subArguments.get(i); TypeProjection subArgument = subArguments.get(i);
KotlinType subIn = getInType(parameter, subArgument);
KotlinType subOut = getOutType(parameter, subArgument); if (superArgument.isStarProjection()) continue;
if (capture(subArgument, superArgument, parameter)) continue; if (capture(subArgument, superArgument, parameter)) continue;
boolean argumentIsErrorType = subArgument.getType().isError() || superArgument.getType().isError(); boolean argumentIsErrorType = subArgument.getType().isError() || superArgument.getType().isError();
if (!argumentIsErrorType && parameter.getVariance() == INVARIANT if (!argumentIsErrorType && parameter.getVariance() == INVARIANT &&
&& subArgument.getProjectionKind() == INVARIANT && superArgument.getProjectionKind() == INVARIANT) { subArgument.getProjectionKind() == INVARIANT && superArgument.getProjectionKind() == INVARIANT) {
if (!constraints.assertEqualTypes(subArgument.getType(), superArgument.getType(), this)) return false; if (!constraints.assertEqualTypes(subArgument.getType(), superArgument.getType(), this)) return false;
continue;
}
KotlinType superOut = getOutType(parameter, superArgument);
KotlinType subOut = getOutType(parameter, subArgument);
if (!constraints.assertSubtype(subOut, superOut, this)) return false;
KotlinType superIn = getInType(parameter, superArgument);
KotlinType subIn = getInType(parameter, subArgument);
if (superArgument.getProjectionKind() != Variance.OUT_VARIANCE) {
if (!constraints.assertSubtype(superIn, subIn, this)) return false;
} }
else { else {
if (!constraints.assertSubtype(subOut, superOut, this)) return false; assert KotlinBuiltIns.isNothing(superIn) : "In component must be Nothing for out-projection";
if (superArgument.getProjectionKind() != Variance.OUT_VARIANCE) {
if (!constraints.assertSubtype(superIn, subIn, this)) return false;
}
else {
assert KotlinBuiltIns.isNothing(superIn) : "In component must be Nothing for out-projection";
}
} }
} }
return true; return true;