diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt index 4607a6efdf0..b787283bb44 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt @@ -179,27 +179,31 @@ private fun FirTypeParameter.getErasedUpperBound( val firstUpperBound = this.bounds.first().coneTypeUnsafe() - if (firstUpperBound is ConeClassLikeType) { - return firstUpperBound.withArguments(firstUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray()) - } - - val alreadyVisited = mutableSetOf(potentiallyRecursiveTypeParameter, this) - var current = (firstUpperBound as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir - - while (current !in alreadyVisited) { - alreadyVisited += current - - val nextUpperBound = current.bounds.first().coneTypeUnsafe() - if (nextUpperBound is ConeClassLikeType) { - return nextUpperBound.withArguments(nextUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray()) - } - - current = (nextUpperBound as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir - } - - return defaultValue() + return getErasedVersionOfFirstUpperBound(firstUpperBound, mutableSetOf(this, potentiallyRecursiveTypeParameter), defaultValue) } +private tailrec fun getErasedVersionOfFirstUpperBound( + firstUpperBound: ConeKotlinType, + alreadyVisitedParameters: MutableSet, + defaultValue: () -> ConeKotlinType +): ConeKotlinType = + when (firstUpperBound) { + is ConeClassLikeType -> + firstUpperBound.withArguments(firstUpperBound.typeArguments.map { ConeStarProjection }.toTypedArray()) + + is ConeTypeParameterType -> { + val current = firstUpperBound.lookupTag.typeParameterSymbol.fir + + if (alreadyVisitedParameters.add(current)) { + val nextUpperBound = current.bounds.first().coneTypeUnsafe() + getErasedVersionOfFirstUpperBound(nextUpperBound, alreadyVisitedParameters, defaultValue) + } else { + defaultValue() + } + } + else -> error("Unexpected kind of firstUpperBound: $firstUpperBound [${firstUpperBound::class}]") + } + fun computeProjection( session: FirSession,