From 963557f3c8ee131b58ea936e58c4d722fcbeaad4 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 27 Feb 2012 15:34:57 +0400 Subject: [PATCH] KT-1457 Subtyping doesn't work when type parameter is used indirectly in supertype declaration --- .../types/checker/TypeCheckingProcedure.java | 58 ++++++++++++++++++- .../diagnostics/tests/subtyping/kt-1457.jet | 8 +++ .../jet/types/JetTypeCheckerTest.java | 15 +++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/subtyping/kt-1457.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java index 765ac15aee2..c62d901ed96 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java @@ -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 then C and C 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 subArguments = subtype.getArguments(); List superArguments = supertype.getArguments(); List 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); diff --git a/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet b/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet new file mode 100644 index 00000000000..bcbf5ce0407 --- /dev/null +++ b/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet @@ -0,0 +1,8 @@ +// +JDK +import java.util.ArrayList + +class MyListOfPairs : ArrayList<#(T, T)>() { } + +fun test() { + MyListOfPairs : ArrayList<#(Int, Int)> +} diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 89c41a74ca9..68acc9f10f6 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -471,6 +471,21 @@ public class JetTypeCheckerTest extends JetLiteFixture { assertSupertypes("Derived1_inT", "Derived_T", "Base_T", "Any", "Base_inT"); } + public void testEffectiveProjectionKinds() throws Exception { + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void assertSupertypes(String typeStr, String... supertypeStrs) {