diff --git a/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt b/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt index db3dca8a5b6..0aac4708d0b 100644 --- a/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt +++ b/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt @@ -13,4 +13,9 @@ inline class TestNullable(val x: TestNullabl inline class TestRecursionInTypeArguments(val x: List) -inline class TestRecursionInArray(val x: Array) \ No newline at end of file +inline class TestRecursionInArray(val x: Array) + +inline class TestRecursionInUpperBounds>(val x: T) + +inline class Id(val x: T) +inline class TestRecursionThroughId(val x: Id) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.txt b/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.txt index 1640a62bb82..17be4a7b7e5 100644 --- a/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.txt +++ b/compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.txt @@ -1,5 +1,13 @@ package +public final inline class Id { + public constructor Id(/*0*/ x: T) + public final val x: T + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + public final inline class Test1 { public constructor Test1(/*0*/ x: Test1) public final val x: Test1 @@ -71,3 +79,19 @@ public final inline class TestRecursionInTypeArguments { public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String } + +public final inline class TestRecursionInUpperBounds> { + public constructor TestRecursionInUpperBounds>(/*0*/ x: T) + public final val x: T + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +public final inline class TestRecursionThroughId { + public constructor TestRecursionThroughId(/*0*/ x: Id) + public final val x: Id + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index 49b0422440e..e46f41349b8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.resolve -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -37,12 +34,21 @@ fun KotlinType.substitutedUnderlyingType(): KotlinType? { fun KotlinType.isRecursiveInlineClassType() = isRecursiveInlineClassTypeInner(hashSetOf()) -private fun KotlinType.isRecursiveInlineClassTypeInner(visited: HashSet): Boolean { - val descriptor = constructor.declarationDescriptor as? ClassDescriptor ?: return false - if (visited.contains(descriptor)) return true - if (!descriptor.isInlineClass()) return false - visited.add(descriptor) - return unsubstitutedUnderlyingType()?.isRecursiveInlineClassTypeInner(visited) ?: false +private fun KotlinType.isRecursiveInlineClassTypeInner(visited: HashSet): Boolean { + val descriptor = constructor.declarationDescriptor?.original ?: return false + + if (!visited.add(descriptor)) return true + + return when (descriptor) { + is ClassDescriptor -> + descriptor.isInlineClass() && + unsubstitutedUnderlyingType()?.isRecursiveInlineClassTypeInner(visited) == true + + is TypeParameterDescriptor -> + descriptor.upperBounds.any { it.isRecursiveInlineClassTypeInner(visited) } + + else -> false + } } fun KotlinType.isNullableUnderlyingType(): Boolean {