diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index e8de7662044..cbd97ba5526 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -21142,6 +21142,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt"); } + @Test + @TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt") + public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt"); + } + + @Test + @TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt") + public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt"); + } + @Test @TestMetadata("errorType.kt") public void testErrorType() throws Exception { @@ -21232,6 +21244,30 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt"); } + @Test + @TestMetadata("substituteAnotherErasedTypeArgument.kt") + public void testSubstituteAnotherErasedTypeArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt"); + } + + @Test + @TestMetadata("substituteOtherErasedDeepTypeArguments.kt") + public void testSubstituteOtherErasedDeepTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt"); + } + + @Test + @TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt") + public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt"); + } + + @Test + @TestMetadata("substituteSeveralOtherErasedTypeArguments.kt") + public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt"); + } + @Test @TestMetadata("typeEnhancement.kt") public void testTypeEnhancement() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 9a357cf3dbc..383568ff183 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -285,7 +285,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty return this } - override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean { + override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean { require(this is ConeTypeParameterLookupTag) return this.typeParameterSymbol.fir.bounds.any { typeRef -> typeRef.coneType.contains { it.typeConstructor() == this.getTypeConstructor() } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 6a699a8e8e5..1329c8d1400 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -183,7 +183,7 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon return false } - override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean { + override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean { for (i in 0 until this.upperBoundCount()) { val upperBound = this.getUpperBound(i) if (upperBound.containsTypeConstructor(selfConstructor) && upperBound.typeConstructor() == selfConstructor) { diff --git a/compiler/testData/diagnostics/tests/inference/constraints/constraintFromVariantTypeWithNestedProjection.kt b/compiler/testData/diagnostics/tests/inference/constraints/constraintFromVariantTypeWithNestedProjection.kt index 74bc67a8203..977e6d5af5b 100644 --- a/compiler/testData/diagnostics/tests/inference/constraints/constraintFromVariantTypeWithNestedProjection.kt +++ b/compiler/testData/diagnostics/tests/inference/constraints/constraintFromVariantTypeWithNestedProjection.kt @@ -12,5 +12,5 @@ fun choose3(c: Inv>) {} fun f(o: Out>, i: In>, inv: Inv>) { choose1(o) choose2(i) - choose3(inv) + choose3(inv) } diff --git a/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.kt b/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.kt index 4d40c9a77eb..d19f12d2a13 100644 --- a/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.kt +++ b/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.kt @@ -28,5 +28,5 @@ abstract class MySettingsListener {} fun test() { val a = MySettings.getSettings() a.getLinkedProjectsSettings() - a.linkedProjectsSettings + a.linkedProjectsSettings } diff --git a/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.txt b/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.txt index 63b05890938..babfe4e89f8 100644 --- a/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.txt +++ b/compiler/testData/diagnostics/tests/inference/constraints/manyConstraintsDueToFlexibleRawTypes.txt @@ -10,5 +10,5 @@ public open class MySettings!, /*1*/ PS : My public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String // Static members - public open fun getSettings(): MySettings<(raw) MySettings<*, *, *>!, (raw) MyComparableSettings!, (raw) MySettingsListener<*>!>! + public open fun getSettings(): (MySettings<(raw) *, (raw) MyComparableSettings!, (raw) MySettingsListener!>..MySettings<*, *, out MySettingsListener<*>!>?) } diff --git a/compiler/testData/diagnostics/tests/j+k/kt1431.txt b/compiler/testData/diagnostics/tests/j+k/kt1431.txt index c3054d1ab26..1a660d30ada 100644 --- a/compiler/testData/diagnostics/tests/j+k/kt1431.txt +++ b/compiler/testData/diagnostics/tests/j+k/kt1431.txt @@ -5,7 +5,7 @@ package a { public open class C!> { public constructor C!>() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open fun foo(): a.C<(raw) a.C<*>!>! + public open fun foo(): a.C<(raw) *>! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.fir.kt new file mode 100644 index 00000000000..17f89b06a6e --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.fir.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I {} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt new file mode 100644 index 00000000000..9fbe2c5b137 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I {} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..X<*, *>?)")!>t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.txt new file mode 100644 index 00000000000..ef8ac4d3443 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!, /*1*/ P : kotlin.Any!> { + public/*package*/ constructor X!, /*1*/ P : kotlin.Any!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E!>! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.fir.kt new file mode 100644 index 00000000000..0bc39e05135 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.fir.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt new file mode 100644 index 00000000000..07f1973de18 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..X<*>?)")!>t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.txt new file mode 100644 index 00000000000..537039a51be --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!> { + public/*package*/ constructor X!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E!>! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.fir.kt new file mode 100644 index 00000000000..06bf7d09d0e --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.fir.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt new file mode 100644 index 00000000000..8ad2675e928 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?)>..X..I<*>?), *>?)")!>t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.txt new file mode 100644 index 00000000000..82b76d2a427 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!, /*1*/ P : kotlin.Any!> { + public/*package*/ constructor X!, /*1*/ P : kotlin.Any!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E<(X<(raw) I!, (raw) kotlin.Any!>..X!, *>?)>! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.fir.kt new file mode 100644 index 00000000000..cf5a6a0296c --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.fir.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I1, B, I1, P>>> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I1 {} +interface I2 {} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // error before +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt new file mode 100644 index 00000000000..107e5a35083 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I1, B, I1, P>>> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I1 {} +interface I2 {} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I1<*, (I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), *>..I1<*, (I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>..I1<(kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?), (kotlin.Any..kotlin.Any?)>?), *>?)>..X..I1<*, *, *>?), *, out (I1<*, out (I1<*, *, *>..I1<*, *, *>?), *>..I1<*, out (I1<*, *, *>..I1<*, *, *>?), *>?)>?)")!>t + t.id // error before +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.txt new file mode 100644 index 00000000000..73dc0666326 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!, /*1*/ P : kotlin.Any!, /*2*/ A : I1!, B!, I1!, P!>!>!> { + public/*package*/ constructor X!, /*1*/ P : kotlin.Any!, /*2*/ A : I1!, B!, I1!, P!>!>!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E<(X<(raw) I1!, (raw) kotlin.Any!, (raw) I1<*, I1!, *>!>..X!, *, out I1<*, out I1<*, *, *>!, *>!>?)>! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.fir.kt new file mode 100644 index 00000000000..99d560600eb --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.fir.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt new file mode 100644 index 00000000000..a750670d2e6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>..I<(I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>?)>..X..I<*>?), *, out (I..I<*>?)>..I..I<*>?)>?)>?)")!>t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.txt new file mode 100644 index 00000000000..6f6afa643c6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!, /*1*/ P : kotlin.Any!, /*2*/ A : I!> { + public/*package*/ constructor X!, /*1*/ P : kotlin.Any!, /*2*/ A : I!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E<(X<(raw) I!, (raw) kotlin.Any!, (raw) I!>!>..X!, *, out I!>!>?)>! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.fir.kt new file mode 100644 index 00000000000..1f949aec856 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.fir.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I

> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt new file mode 100644 index 00000000000..5e7857a9bc7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FULL_JDK + +// FILE: X.java +class X, P, A extends I

> { + static final E E = new E<>(); + + String getId() { + return null; + } +} + +class E { + T getT() { + return null; + } +} + +interface I

{} + +// FILE: test.kt +fun test() { + val t = X.E.t + ..I<(kotlin.Any..kotlin.Any?)>?), (kotlin.Any..kotlin.Any?), (I<(kotlin.Any..kotlin.Any?)>..I<(kotlin.Any..kotlin.Any?)>?)>..X..I<*>?), *, out (I<*>..I<*>?)>?)")!>t + t.id // should be OK +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.txt new file mode 100644 index 00000000000..10fb27fb8d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public/*package*/ open class X!, /*1*/ P : kotlin.Any!, /*2*/ A : I!> { + public/*package*/ constructor X!, /*1*/ P : kotlin.Any!, /*2*/ A : I!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getId(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ final val E: E<(X<(raw) I!, (raw) kotlin.Any!, (raw) I!>..X!, *, out I<*>!>?)>! +} diff --git a/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBound.txt b/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBound.txt index 71b8e985eaa..3f2722c4648 100644 --- a/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBound.txt +++ b/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBound.txt @@ -3,11 +3,11 @@ package test public open class RawSuperTypeWithRecursiveBound { public constructor RawSuperTypeWithRecursiveBound() - public open inner class Derived : test.RawSuperTypeWithRecursiveBound.Super<(raw) test.RawSuperTypeWithRecursiveBound.Super<*>!> { + public open inner class Derived : test.RawSuperTypeWithRecursiveBound.Super<(raw) *> { public constructor Derived() public open override /*1*/ fun dummy(): kotlin.Unit public open fun foo(/*0*/ p0: kotlin.Any!): kotlin.Unit - public open override /*1*/ fun foo(/*0*/ p0: test.RawSuperTypeWithRecursiveBound.Super<(raw) test.RawSuperTypeWithRecursiveBound.Super<*>!>!): kotlin.Unit + public open override /*1*/ fun foo(/*0*/ p0: test.RawSuperTypeWithRecursiveBound.Super<(raw) *>!): kotlin.Unit } public interface Super!> { diff --git a/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBoundMultipleParameters.txt b/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBoundMultipleParameters.txt index 01f328fa4fa..9123ed9580b 100644 --- a/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBoundMultipleParameters.txt +++ b/compiler/testData/loadJava/compiledJava/signaturePropagation/RawSuperTypeWithRecursiveBoundMultipleParameters.txt @@ -3,11 +3,11 @@ package test public open class RawSuperTypeWithRecursiveBoundMultipleParameters { public constructor RawSuperTypeWithRecursiveBoundMultipleParameters() - public open inner class Derived : test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<*, *>!> { + public open inner class Derived : test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) *> { public constructor Derived() public open override /*1*/ fun dummy(): kotlin.Unit public open fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: kotlin.Any!): kotlin.Unit - public open override /*1*/ fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<*, *>!>!): kotlin.Unit + public open override /*1*/ fun foo(/*0*/ p0: kotlin.Any!, /*1*/ p1: test.RawSuperTypeWithRecursiveBoundMultipleParameters.Super<(raw) kotlin.Any!, (raw) *>!): kotlin.Unit } public interface Super!> { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index bf1d1644fb3..4cac783a240 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -21148,6 +21148,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt"); } + @Test + @TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt") + public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt"); + } + + @Test + @TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt") + public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt"); + } + @Test @TestMetadata("errorType.kt") public void testErrorType() throws Exception { @@ -21238,6 +21250,30 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt"); } + @Test + @TestMetadata("substituteAnotherErasedTypeArgument.kt") + public void testSubstituteAnotherErasedTypeArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt"); + } + + @Test + @TestMetadata("substituteOtherErasedDeepTypeArguments.kt") + public void testSubstituteOtherErasedDeepTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt"); + } + + @Test + @TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt") + public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt"); + } + + @Test + @TestMetadata("substituteSeveralOtherErasedTypeArguments.kt") + public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt"); + } + @Test @TestMetadata("typeEnhancement.kt") public void testTypeEnhancement() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index 18edeb9aa18..f70965cc6b1 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -375,7 +375,7 @@ object AbstractTypeChecker { val typeVariableConstructor = superArgumentType.typeConstructor() as? TypeVariableTypeConstructorMarker ?: return false - return typeVariableConstructor.typeParameter?.doesFormSelfType(selfConstructor) == true + return typeVariableConstructor.typeParameter?.hasRecursiveBounds(selfConstructor) == true } fun AbstractTypeCheckerContext.isSubtypeForSameConstructor( @@ -506,7 +506,7 @@ object AbstractTypeChecker { if (subType is CapturedTypeMarker) { val typeParameter = context.typeSystemContext.getTypeParameterForArgumentInBaseIfItEqualToTarget(baseType = superType, targetType = subType) - if (typeParameter != null && typeParameter.doesFormSelfType(superType.typeConstructor())) { + if (typeParameter != null && typeParameter.hasRecursiveBounds(superType.typeConstructor())) { return true } } diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index b2219dc6b2f..02dd1473c96 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -313,7 +313,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext { fun TypeParameterMarker.upperBoundCount(): Int fun TypeParameterMarker.getUpperBound(index: Int): KotlinTypeMarker fun TypeParameterMarker.getTypeConstructor(): TypeConstructorMarker - fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean + fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt index d7c2e039958..a505681b30b 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt @@ -32,8 +32,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.Variance.* -import org.jetbrains.kotlin.types.typeUtil.createProjection -import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections +import org.jetbrains.kotlin.types.typeUtil.* import org.jetbrains.kotlin.utils.sure private val JAVA_LANG_CLASS_FQ_NAME: FqName = FqName("java.lang.Class") @@ -210,6 +209,15 @@ class JavaTypeResolver( val typeParameters = constructor.parameters if (eraseTypeParameters) { return typeParameters.map { parameter -> + /* + * We shouldn't erase recursive type parameters to avoid creating types unsatisfying upper bounds. + * E.g. if we got erased raw type of `class Foo> {}` we'd create Foo<(raw) Foo<*>!>!, + * but it's wrong because Foo<*> isn't subtype of Foo> in accordance with declared upper bound of Foo. + * So we should create Foo<*> in this case (CapturedType(*) is really subtype of Foo). + */ + if (hasTypeParameterRecursiveBounds(parameter, selfConstructor = null, attr.upperBoundOfTypeParameter)) + return@map StarProjectionImpl(parameter) + // Some activity for preventing recursion in cases like `class A` // // When calculating upper bound of some parameter (attr.upperBoundOfTypeParameter), @@ -222,12 +230,11 @@ class JavaTypeResolver( // - Calculating second argument for raw upper bound of T. It depends on F, that again depends on upper bound of T, // so we get A<*, *>. // Summary result for upper bound of T is `A, A<*, *>>..A, out A<*, *>>` - val erasedUpperBound = - LazyWrappedType(c.storageManager) { - parameter.getErasedUpperBound(attr.upperBoundOfTypeParameter) { - constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections() - } + val erasedUpperBound = LazyWrappedType(c.storageManager) { + parameter.getErasedUpperBound(isRaw, attr) { + constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections() } + } RawSubstitution.computeProjection( parameter, @@ -333,24 +340,51 @@ internal fun TypeParameterDescriptor.getErasedUpperBound( // Calculation of `potentiallyRecursiveTypeParameter.upperBounds` may recursively depend on `this.getErasedUpperBound` // E.g. `class A` // To prevent recursive calls return defaultValue() instead - potentiallyRecursiveTypeParameter: TypeParameterDescriptor? = null, + isRaw: Boolean, + typeAttr: JavaTypeAttributes, defaultValue: (() -> KotlinType) = { ErrorUtils.createErrorType("Can't compute erased upper bound of type parameter `$this`") } ): KotlinType { - if (this === potentiallyRecursiveTypeParameter) return defaultValue() + if (this === typeAttr.upperBoundOfTypeParameter) return defaultValue() + + /* + * We should do erasure of containing type parameters with their erasure to avoid creating inconsistent types. + * E.g. for `class Foo, B>`, we'd have erasure for lower bound: Foo, Any>, + * but it's wrong type: projection(*) != projection(Any). + * So we should substitute erasure of the corresponding type parameter: `Foo, Any>` or `Foo, *>`. + */ + val erasedUpperBounds = defaultType.extractTypeParametersFromUpperBounds(typeAttr.upperBoundOfTypeParameter).associate { + it.typeConstructor to RawSubstitution.computeProjection( + this, + // if erasure happens due to invalid arguments number, use star projections instead + if (isRaw) typeAttr else typeAttr.withFlexibility(INFLEXIBLE), + it.getErasedUpperBound(isRaw, typeAttr) + ) + } + val erasedUpperBoundsSubstitutor = TypeSubstitutor.create(TypeConstructorSubstitution.createByConstructorsMap(erasedUpperBounds)) val firstUpperBound = upperBounds.first() if (firstUpperBound.constructor.declarationDescriptor is ClassDescriptor) { - return firstUpperBound.replaceArgumentsWithStarProjections() + return firstUpperBound.replaceArgumentsWithStarProjectionOrMapped( + erasedUpperBoundsSubstitutor, + erasedUpperBounds, + OUT_VARIANCE, + typeAttr.upperBoundOfTypeParameter + ) } - val stopAt = potentiallyRecursiveTypeParameter ?: this + val stopAt = typeAttr.upperBoundOfTypeParameter ?: this var current = firstUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor while (current != stopAt) { val nextUpperBound = current.upperBounds.first() if (nextUpperBound.constructor.declarationDescriptor is ClassDescriptor) { - return nextUpperBound.replaceArgumentsWithStarProjections() + return nextUpperBound.replaceArgumentsWithStarProjectionOrMapped( + erasedUpperBoundsSubstitutor, + erasedUpperBounds, + OUT_VARIANCE, + typeAttr.upperBoundOfTypeParameter + ) } current = nextUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/RawType.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/RawType.kt index fd181f20209..de50a691b49 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/RawType.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/types/RawType.kt @@ -107,10 +107,9 @@ internal object RawSubstitution : TypeSubstitution() { private val lowerTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_LOWER_BOUND) private val upperTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND) - private fun eraseType(type: KotlinType): KotlinType { - val declaration = type.constructor.declarationDescriptor - return when (declaration) { - is TypeParameterDescriptor -> eraseType(declaration.getErasedUpperBound()) + private fun eraseType(type: KotlinType, attr: JavaTypeAttributes = JavaTypeAttributes(TypeUsage.COMMON)): KotlinType { + return when (val declaration = type.constructor.declarationDescriptor) { + is TypeParameterDescriptor -> eraseType(declaration.getErasedUpperBound(isRaw = true, attr), attr) is ClassDescriptor -> { val declarationForUpper = type.upperIfFlexible().constructor.declarationDescriptor @@ -142,7 +141,7 @@ internal object RawSubstitution : TypeSubstitution() { if (KotlinBuiltIns.isArray(type)) { val componentTypeProjection = type.arguments[0] val arguments = listOf( - TypeProjectionImpl(componentTypeProjection.projectionKind, eraseType(componentTypeProjection.type)) + TypeProjectionImpl(componentTypeProjection.projectionKind, eraseType(componentTypeProjection.type, attr)) ) return KotlinTypeFactory.simpleType( type.annotations, type.constructor, arguments, type.isMarkedNullable @@ -171,7 +170,7 @@ internal object RawSubstitution : TypeSubstitution() { fun computeProjection( parameter: TypeParameterDescriptor, attr: JavaTypeAttributes, - erasedUpperBound: KotlinType = parameter.getErasedUpperBound() + erasedUpperBound: KotlinType = parameter.getErasedUpperBound(isRaw = true, attr) ) = when (attr.flexibility) { // Raw(List) => (List..List<*>) // Raw(Enum) => (Enum>..Enum>) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 8990cc01e61..ed0127acce3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -185,7 +185,74 @@ fun KotlinType.contains(predicate: (UnwrappedType) -> Boolean) = TypeUtils.conta fun KotlinType.replaceArgumentsWithStarProjections() = replaceArgumentsWith(::StarProjectionImpl) fun KotlinType.replaceArgumentsWithNothing() = replaceArgumentsWith { it.builtIns.nothingType.asTypeProjection() } -private inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): KotlinType { +fun KotlinType.extractTypeParametersFromUpperBounds(upperBoundOfTypeParameter: TypeParameterDescriptor?): Set = + mutableSetOf().also { extractTypeParametersFromUpperBounds(this, it, upperBoundOfTypeParameter) } + +private fun KotlinType.extractTypeParametersFromUpperBounds( + baseType: KotlinType, + to: MutableSet, + upperBoundOfTypeParameter: TypeParameterDescriptor? +) { + val declarationDescriptor = constructor.declarationDescriptor + + if (declarationDescriptor is TypeParameterDescriptor) { + if (constructor != baseType.constructor) { + to += declarationDescriptor + } else { + for (upperBound in declarationDescriptor.upperBounds) { + upperBound.extractTypeParametersFromUpperBounds(baseType, to, upperBoundOfTypeParameter) + } + } + } else { + val typeParameters = (constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters)?.declaredTypeParameters + for ((i, argument) in arguments.withIndex()) { + val typeParameter = typeParameters?.get(i) + if (argument.isStarProjection || (typeParameter != null && typeParameter == upperBoundOfTypeParameter)) continue + if (argument.type.constructor.declarationDescriptor in to || argument.type.constructor == baseType.constructor) continue + argument.type.extractTypeParametersFromUpperBounds(baseType, to, upperBoundOfTypeParameter) + } + } +} + +fun hasTypeParameterRecursiveBounds( + typeParameter: TypeParameterDescriptor, + selfConstructor: TypeConstructor? = null, + upperBoundOfTypeParameter: TypeParameterDescriptor? = null +): Boolean = + typeParameter.upperBounds.any { upperBound -> + upperBound.containsSelfTypeParameter(typeParameter.defaultType.constructor, upperBoundOfTypeParameter) + && (selfConstructor == null || upperBound.constructor == selfConstructor) + } + +private fun KotlinType.containsSelfTypeParameter( + baseConstructor: TypeConstructor, + upperBoundOfTypeParameter: TypeParameterDescriptor? +): Boolean { + if (this.constructor == baseConstructor) return true + + val typeParameters = (constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters)?.declaredTypeParameters + return arguments.withIndex().any { (i, argument) -> + val typeParameter = typeParameters?.get(i) + if ((typeParameter != null && typeParameter == upperBoundOfTypeParameter) || argument.isStarProjection) return@any false + argument.type.containsSelfTypeParameter(baseConstructor, upperBoundOfTypeParameter) + } +} + +fun KotlinType.replaceArgumentsWithStarProjectionOrMapped( + substitutor: TypeSubstitutor, + substitutionMap: Map, + variance: Variance, + upperBoundOfTypeParameter: TypeParameterDescriptor? +) = + replaceArgumentsWith { typeParameterDescriptor -> + val argument = arguments.getOrNull(typeParameterDescriptor.index) + if (typeParameterDescriptor != upperBoundOfTypeParameter && argument != null && argument.type.constructor in substitutionMap) { + argument + } else StarProjectionImpl(typeParameterDescriptor) + }.let { substitutor.safeSubstitute(it, variance) } + + +inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): KotlinType { val unwrapped = unwrap() return when (unwrapped) { is FlexibleType -> KotlinTypeFactory.flexibleType( @@ -196,7 +263,7 @@ private inline fun KotlinType.replaceArgumentsWith(replacement: (TypeParameterDe }.inheritEnhancement(unwrapped) } -private inline fun SimpleType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): SimpleType { +inline fun SimpleType.replaceArgumentsWith(replacement: (TypeParameterDescriptor) -> TypeProjection): SimpleType { if (constructor.parameters.isEmpty() || constructor.declarationDescriptor == null) return this val newArguments = constructor.parameters.map(replacement) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 3caaef7c6f3..8b3f1b0f2d5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.contains +import org.jetbrains.kotlin.types.typeUtil.hasTypeParameterRecursiveBounds import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType as classicIsSignedOrUnsignedNumberType @@ -220,11 +221,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this.typeConstructor } - override fun TypeParameterMarker.doesFormSelfType(selfConstructor: TypeConstructorMarker): Boolean { + override fun TypeParameterMarker.hasRecursiveBounds(selfConstructor: TypeConstructorMarker): Boolean { require(this is TypeParameterDescriptor, this::errorMessage) require(selfConstructor is TypeConstructor, this::errorMessage) - return doesTypeParameterFormSelfType(this, selfConstructor) + return hasTypeParameterRecursiveBounds(this, selfConstructor) } override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt index 40c4cc7d627..c4a120adeb6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes import java.util.* @@ -106,8 +105,3 @@ private fun TypeConstructor.debugInfo() = buildString { interface NewTypeVariableConstructor { val originalTypeParameter: TypeParameterDescriptor? } - -fun doesTypeParameterFormSelfType(typeParameter: TypeParameterDescriptor, selfConstructor: TypeConstructor) = - typeParameter.upperBounds.any { upperBound -> - upperBound.contains { it.constructor == typeParameter.typeConstructor } && upperBound.constructor == selfConstructor - }