FIR: handle recursion in super-types correctly
Related to KT-24077
This commit is contained in:
+19
-7
@@ -18,13 +18,16 @@ import org.jetbrains.kotlin.fir.scopes.impl.*
|
|||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.transformSingle
|
import org.jetbrains.kotlin.fir.transformSingle
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedFunctionTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedFunctionTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
|
|
||||||
open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
open class FirTypeResolveTransformer(
|
||||||
|
private val traversedClassifiers: Set<FirMemberDeclaration> = setOf()
|
||||||
|
) : FirTransformer<Nothing?>() {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return (element.transformChildren(this, data) as E).compose()
|
return (element.transformChildren(this, data) as E).compose()
|
||||||
@@ -53,7 +56,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
|
|
||||||
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
|
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
|
||||||
try {
|
try {
|
||||||
element.transformChildren(SuperTypeResolver(), null)
|
element.transformChildren(SuperTypeResolver(traversedClassifiers + listOfNotNull(element)), null)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
class SuperTypeResolveException(cause: Exception) : Exception(element.render(), cause)
|
class SuperTypeResolveException(cause: Exception) : Exception(element.render(), cause)
|
||||||
throw SuperTypeResolveException(e)
|
throw SuperTypeResolveException(e)
|
||||||
@@ -179,14 +182,17 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
return typeProjectionWithVariance.compose()
|
return typeProjectionWithVariance.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SuperTypeResolveTransformer(val elementIterator: Iterator<FirElement>) : FirTypeResolveTransformer() {
|
private class SuperTypeResolveTransformer(
|
||||||
|
val elementIterator: Iterator<FirElement>,
|
||||||
|
traversedClassifiers: Set<FirMemberDeclaration>
|
||||||
|
) : FirTypeResolveTransformer(traversedClassifiers) {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data)
|
if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data)
|
||||||
return element.compose()
|
return element.compose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SuperTypeResolver : FirTransformer<Nothing?>() {
|
private inner class SuperTypeResolver(val traversedClassifiers: Set<FirMemberDeclaration>) : FirTransformer<Nothing?>() {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
return element.compose()
|
return element.compose()
|
||||||
}
|
}
|
||||||
@@ -208,7 +214,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val transformer = SuperTypeResolveTransformer(
|
val transformer = SuperTypeResolveTransformer(
|
||||||
firElementsToVisit.iterator()
|
firElementsToVisit.iterator(), traversedClassifiers
|
||||||
)
|
)
|
||||||
file.transformSingle(transformer, null)
|
file.transformSingle(transformer, null)
|
||||||
|
|
||||||
@@ -227,7 +233,13 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
val symbol = typeResolver.resolveToSymbol(type, scope, position = FirPosition.SUPER_TYPE_OR_EXPANSION)
|
val symbol = typeResolver.resolveToSymbol(type, scope, position = FirPosition.SUPER_TYPE_OR_EXPANSION)
|
||||||
val myTransformer = this@FirTypeResolveTransformer
|
val myTransformer = this@FirTypeResolveTransformer
|
||||||
|
|
||||||
if (symbol != null) walkSymbols(symbol)
|
if (symbol != null) {
|
||||||
|
if (symbol is AbstractFirBasedSymbol<*> && symbol.fir in traversedClassifiers) {
|
||||||
|
return FirErrorTypeImpl(type.session, type.psi, "Recursion detected: ${type.render()}").compose()
|
||||||
|
} else {
|
||||||
|
walkSymbols(symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type !is FirUserType) return type.transform(myTransformer, data)
|
if (type !is FirUserType) return type.transform(myTransformer, data)
|
||||||
|
|
||||||
@@ -245,7 +257,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private tailrec fun ConeClassLikeSymbol.collectSuperTypes(list: MutableList<ConeClassLikeType>) {
|
private tailrec fun ConeClassLikeSymbol.collectSuperTypes(list: MutableList<ConeClassLikeType>) {
|
||||||
return when (this) {
|
when (this) {
|
||||||
is ConeClassSymbol -> {
|
is ConeClassSymbol -> {
|
||||||
val superClassType =
|
val superClassType =
|
||||||
this.superTypes
|
this.superTypes
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import incorrect.directory.My
|
||||||
|
|
||||||
|
class My : My()
|
||||||
|
|
||||||
|
class Your : His()
|
||||||
|
|
||||||
|
class His : Your()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
FILE: fakeRecursiveSupertype.kt
|
||||||
|
public final class My : R|error: Recursion detected: My| {
|
||||||
|
public constructor(): super<R|My|>()
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class Your : R|His| {
|
||||||
|
public constructor(): super<R|His|>()
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class His : R|error: Recursion detected: Your| {
|
||||||
|
public constructor(): super<R|Your|>()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import incorrect.directory.Your
|
||||||
|
|
||||||
|
typealias My = incorrect.directory.My
|
||||||
|
|
||||||
|
typealias Your = Your
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
FILE: fakeRecursiveTypealias.kt
|
||||||
|
public final typealias My = R|error: Symbol not found|
|
||||||
|
public final typealias Your = R|error: Recursion detected: Your|
|
||||||
+10
@@ -49,6 +49,16 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/F.kt");
|
runTest("compiler/fir/resolve/testData/resolve/F.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fakeRecursiveSupertype.kt")
|
||||||
|
public void testFakeRecursiveSupertype() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fakeRecursiveTypealias.kt")
|
||||||
|
public void testFakeRecursiveTypealias() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ft.kt")
|
@TestMetadata("ft.kt")
|
||||||
public void testFt() throws Exception {
|
public void testFt() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/ft.kt");
|
runTest("compiler/fir/resolve/testData/resolve/ft.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user