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:
compiler/testData/diagnostics/tests/subtyping/invariantArgumentForTypeParameterWithMultipleBounds.kt
Vendored
+18
@@ -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>
|
||||||
|
}
|
||||||
+43
@@ -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");
|
||||||
|
|||||||
+26
-20
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user