From e6fcf20cf22b64a9d0875b3d2ba51620b547eeec Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Mon, 21 Nov 2016 14:35:56 +0300 Subject: [PATCH] No variance elision in type alias substitution. Add test with cyclic inheritance via type alias. --- .../kotlin/resolve/DescriptorResolver.java | 3 + .../kotlin/resolve/TypeAliasExpander.kt | 7 +- .../cyclicInheritanceViaTypeAlias.kt | 7 ++ .../cyclicInheritanceViaTypeAlias.txt | 17 ++++ .../tests/typealias/substitutionVariance.txt | 16 ++-- ...typeAliasForProjectionInSuperInterfaces.kt | 40 ++++++-- ...ypeAliasForProjectionInSuperInterfaces.txt | 94 +++++++++++++++++-- .../compiledKotlin/typealias/Generic.txt | 12 +-- .../checkers/DiagnosticsTestGenerated.java | 6 ++ ...eVarianceConflictInTypeAliasExpansion1.txt | 2 +- 10 files changed, 167 insertions(+), 37 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 450991fc98e..53b383ea98b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -238,7 +238,10 @@ public class DescriptorResolver { } } + // If we have an abbreviated type (written with a type alias), it still can contain type projections in top-level arguments. if (!type.isError() && SpecialTypesKt.getAbbreviatedType(type) != null && !hasProjectionsInWrittenArguments) { + // Only interface inheritance should be checked here. + // Corresponding check for classes is performed for type alias constructor calls in CandidateResolver. if (TypeUtilsKt.isInterface(type) && TypeUtilsKt.containsTypeProjectionsInTopLevelArguments(type)) { trace.report(EXPANDED_TYPE_CANNOT_BE_INHERITED.on(typeElement, type)); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt index 5c9fcdd048d..ba4fb3019f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpander.kt @@ -59,6 +59,8 @@ class TypeAliasExpander( } private fun SimpleType.combineAnnotations(annotations: Annotations): SimpleType { + if (isError) return this + val existingAnnotationTypes = this.annotations.getAllAnnotations().mapTo(hashSetOf()) { it.annotation.type } for (annotation in annotations) { @@ -101,7 +103,8 @@ class TypeAliasExpander( val argumentVariance = argument.projectionKind val underlyingVariance = underlyingProjection.projectionKind - val argumentType = argument.type as? SimpleType ?: throw AssertionError("Non-simple type in type alias argument: $argument") + val argumentType = argument.type.unwrap() as? SimpleType ?: + throw AssertionError("Non-simple type in type alias argument: $argument") val substitutionVariance = when { @@ -117,7 +120,7 @@ class TypeAliasExpander( val parameterVariance = typeParameterDescriptor?.variance ?: Variance.INVARIANT val resultingVariance = when { - parameterVariance == substitutionVariance -> Variance.INVARIANT + parameterVariance == substitutionVariance -> substitutionVariance parameterVariance == Variance.INVARIANT -> substitutionVariance substitutionVariance == Variance.INVARIANT -> Variance.INVARIANT else -> { diff --git a/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.kt b/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.kt new file mode 100644 index 00000000000..4441fc64540 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.kt @@ -0,0 +1,7 @@ +class A : B() { + open class Nested +} + +typealias ANested = A.Nested + +open class B : ANested() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.txt b/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.txt new file mode 100644 index 00000000000..e004c471509 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.txt @@ -0,0 +1,17 @@ +package + +public final class A { + public constructor A() + + public open class Nested { + public constructor Nested() + 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 open class B { + public constructor B() +} +public typealias ANested = A.Nested diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt index a764a2aaf82..c03bf29c425 100644 --- a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt @@ -1,15 +1,15 @@ package public val inv1: Inv1 /* = Inv */ -public fun inIn_In(/*0*/ x: In2 /* = In */): In2 /* = In */ -public fun inIn_Inv(/*0*/ x: In2 /* = In */): In2 /* = In */ +public fun inIn_In(/*0*/ x: In2 /* = In */): In2 /* = In */ +public fun inIn_Inv(/*0*/ x: In2 /* = In */): In2 /* = In */ public fun inIn_Out(/*0*/ x: In2 /* = In */): In2 /* = In */ public fun inIn_Star(/*0*/ x: In2<*> /* = In<*> */): In2<*> /* = In<*> */ -public fun inInv_In(/*0*/ x: In1 /* = In */): In1 /* = In */ +public fun inInv_In(/*0*/ x: In1 /* = In */): In1 /* = In */ public fun inInv_Inv(/*0*/ x: In1 /* = In */): In1 /* = In */ public fun inInv_Out(/*0*/ x: In1 /* = In */): In1 /* = In */ public fun inInv_Star(/*0*/ x: In1<*> /* = In<*> */): In1<*> /* = In<*> */ -public fun inOut_In(/*0*/ x: In3 /* = In */): In3 /* = In */ +public fun inOut_In(/*0*/ x: In3 /* = In */): In3 /* = In */ public fun inOut_Inv(/*0*/ x: In3 /* = In */): In3 /* = In */ public fun inOut_Out(/*0*/ x: In3 /* = In */): In3 /* = In */ public fun inOut_Star(/*0*/ x: In3<*> /* = In<*> */): In3<*> /* = In<*> */ @@ -27,15 +27,15 @@ public fun invOut_Out(/*0*/ x: Inv3 /* = Inv */) public fun invOut_Star(/*0*/ x: Inv3<*> /* = Inv<*> */): Inv3<*> /* = Inv<*> */ public fun outIn_In(/*0*/ x: Out2 /* = Out */): Out2 /* = Out */ public fun outIn_Inv(/*0*/ x: Out2 /* = Out */): Out2 /* = Out */ -public fun outIn_Out(/*0*/ x: Out2 /* = Out */): Out2 /* = Out */ +public fun outIn_Out(/*0*/ x: Out2 /* = Out */): Out2 /* = Out */ public fun outIn_Star(/*0*/ x: Out2<*> /* = Out<*> */): Out2<*> /* = Out<*> */ public fun outInv_In(/*0*/ x: Out1 /* = Out */): Out1 /* = Out */ public fun outInv_Inv(/*0*/ x: Out1 /* = Out */): Out1 /* = Out */ -public fun outInv_Out(/*0*/ x: Out1 /* = Out */): Out1 /* = Out */ +public fun outInv_Out(/*0*/ x: Out1 /* = Out */): Out1 /* = Out */ public fun outInv_Star(/*0*/ x: Out1<*> /* = Out<*> */): Out1<*> /* = Out<*> */ public fun outOut_In(/*0*/ x: Out3 /* = Out */): Out3 /* = Out */ -public fun outOut_Inv(/*0*/ x: Out3 /* = Out */): Out3 /* = Out */ -public fun outOut_Out(/*0*/ x: Out3 /* = Out */): Out3 /* = Out */ +public fun outOut_Inv(/*0*/ x: Out3 /* = Out */): Out3 /* = Out */ +public fun outOut_Out(/*0*/ x: Out3 /* = Out */): Out3 /* = Out */ public fun outOut_Star(/*0*/ x: Out3<*> /* = Out<*> */): Out3<*> /* = Out<*> */ public final class In { diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.kt index ad3fbc07221..774a529a36e 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.kt @@ -1,12 +1,32 @@ -interface I +interface Inv +interface Out +interface In -typealias IStar = I<*> -typealias IIn = I -typealias IOut = I -typealias IT = I +typealias InvStar = Inv<*> +typealias InvIn = Inv +typealias InvOut = Inv +typealias InvT = Inv -class Test1 : IStar -class Test2 : IIn -class Test3 : IOut -class Test4 : IT<*> -class Test5 : IT> \ No newline at end of file +typealias OutStar = Out<*> +typealias OutOut = Out<out Int> +typealias OutT = Out + +typealias InStar = In<*> +typealias InIn = In<in Int> +typealias InT = In + +class Test1 : InvStar +class Test2 : InvIn +class Test3 : InvOut +class Test4 : InvT<*> +class Test5 : InvT> + +class Test6 : OutStar +class Test7 : OutOut +class Test8 : OutT +class Test9 : OutT<out Int> + +class Test10 : InStar +class Test11 : InIn +class Test12 : InT +class Test13 : InT<in Int> \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.txt index 1eac1138f61..fdcb305aaa5 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.txt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.txt @@ -1,46 +1,120 @@ package -public interface I { +public interface In { 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 final class Test1 : IStar /* = I<*> */ { +public interface Inv { + 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 Out { + 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 final class Test1 : InvStar /* = Inv<*> */ { public constructor Test1() 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 final class Test2 : IIn /* = I */ { +public final class Test10 : InStar /* = In<*> */ { + public constructor Test10() + 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 final class Test11 : InIn /* = In */ { + public constructor Test11() + 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 final class Test12 : InT /* = In */ { + public constructor Test12() + 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 final class Test13 : InT /* = In */ { + public constructor Test13() + 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 final class Test2 : InvIn /* = Inv */ { public constructor Test2() 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 final class Test3 : IOut /* = I */ { +public final class Test3 : InvOut /* = Inv */ { public constructor Test3() 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 final class Test4 : IT<*> /* = I<*> */ { +public final class Test4 : InvT<*> /* = Inv<*> */ { public constructor Test4() 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 final class Test5 : IT /* = I<*> */> /* = I> */ { +public final class Test5 : InvT /* = Inv<*> */> /* = Inv> */ { public constructor Test5() 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 typealias IIn = I -public typealias IOut = I -public typealias IStar = I<*> -public typealias IT = I + +public final class Test6 : OutStar /* = Out<*> */ { + public constructor Test6() + 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 final class Test7 : OutOut /* = Out */ { + public constructor Test7() + 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 final class Test8 : OutT /* = Out */ { + public constructor Test8() + 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 final class Test9 : OutT /* = Out */ { + public constructor Test9() + 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 typealias InIn = In +public typealias InStar = In<*> +public typealias InT = In +public typealias InvIn = Inv +public typealias InvOut = Inv +public typealias InvStar = Inv<*> +public typealias InvT = Inv +public typealias OutOut = Out +public typealias OutStar = Out<*> +public typealias OutT = Out diff --git a/compiler/testData/loadJava/compiledKotlin/typealias/Generic.txt b/compiler/testData/loadJava/compiledKotlin/typealias/Generic.txt index f4562542f26..9c457751e32 100644 --- a/compiler/testData/loadJava/compiledKotlin/typealias/Generic.txt +++ b/compiler/testData/loadJava/compiledKotlin/typealias/Generic.txt @@ -1,11 +1,11 @@ package test -public fun test1(/*0*/ x: test.L /* = kotlin.collections.List */): kotlin.Unit -public fun test2(/*0*/ x: test.LL /* = kotlin.collections.List */): kotlin.Unit -public fun test3(/*0*/ x: test.LLL /* = kotlin.collections.List */): kotlin.Unit -public fun test4(/*0*/ x: test.L /* = kotlin.collections.List */> /* = kotlin.collections.List /* = kotlin.collections.List */> */): kotlin.Unit -public fun test5(/*0*/ x: test.LL /* = kotlin.collections.List */> /* = kotlin.collections.List /* = kotlin.collections.List */> */): kotlin.Unit -public fun test6(/*0*/ x: test.LLL /* = kotlin.collections.List */> /* = kotlin.collections.List /* = kotlin.collections.List */> */): kotlin.Unit +public fun test1(/*0*/ x: test.L /* = kotlin.collections.List */): kotlin.Unit +public fun test2(/*0*/ x: test.LL /* = kotlin.collections.List */): kotlin.Unit +public fun test3(/*0*/ x: test.LLL /* = kotlin.collections.List */): kotlin.Unit +public fun test4(/*0*/ x: test.L /* = kotlin.collections.List */> /* = kotlin.collections.List> */): kotlin.Unit +public fun test5(/*0*/ x: test.LL /* = kotlin.collections.List */> /* = kotlin.collections.List> */): kotlin.Unit +public fun test6(/*0*/ x: test.LLL /* = kotlin.collections.List */> /* = kotlin.collections.List> */): kotlin.Unit public typealias L = kotlin.collections.List public typealias LL = test.L public typealias LLL = test.LL diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5e7383eff38..9ce90279065 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -20866,6 +20866,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("cyclicInheritanceViaTypeAlias.kt") + public void testCyclicInheritanceViaTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/cyclicInheritanceViaTypeAlias.kt"); + doTest(fileName); + } + @TestMetadata("exposedExpandedType.kt") public void testExposedExpandedType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/exposedExpandedType.kt"); diff --git a/idea/testData/diagnosticMessage/typeVarianceConflictInTypeAliasExpansion1.txt b/idea/testData/diagnosticMessage/typeVarianceConflictInTypeAliasExpansion1.txt index 68c574288a4..2ad229b08c1 100644 --- a/idea/testData/diagnosticMessage/typeVarianceConflictInTypeAliasExpansion1.txt +++ b/idea/testData/diagnosticMessage/typeVarianceConflictInTypeAliasExpansion1.txt @@ -1,2 +1,2 @@ -Type parameter S is declared as 'out' but occurs in 'invariant' position in abbreviated type AInvOutTT /* = InvOut */ \ No newline at end of file +Type parameter S is declared as 'out' but occurs in 'invariant' position in abbreviated type AInvOutTT /* = InvOut */ \ No newline at end of file