FIR: handle recursion in super-types correctly

Related to KT-24077
This commit is contained in:
Mikhail Glukhikh
2019-01-10 11:50:17 +03:00
parent a2f4efbc2a
commit 619bddfdbc
6 changed files with 57 additions and 7 deletions
@@ -18,13 +18,16 @@ import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.transformSingle
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.FirResolvedTypeImpl
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirTransformer
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> {
@Suppress("UNCHECKED_CAST")
return (element.transformChildren(this, data) as E).compose()
@@ -53,7 +56,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
try {
element.transformChildren(SuperTypeResolver(), null)
element.transformChildren(SuperTypeResolver(traversedClassifiers + listOfNotNull(element)), null)
} catch (e: Exception) {
class SuperTypeResolveException(cause: Exception) : Exception(element.render(), cause)
throw SuperTypeResolveException(e)
@@ -179,14 +182,17 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
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> {
if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data)
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> {
return element.compose()
}
@@ -208,7 +214,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
}
val transformer = SuperTypeResolveTransformer(
firElementsToVisit.iterator()
firElementsToVisit.iterator(), traversedClassifiers
)
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 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)
@@ -245,7 +257,7 @@ open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
}
private tailrec fun ConeClassLikeSymbol.collectSuperTypes(list: MutableList<ConeClassLikeType>) {
return when (this) {
when (this) {
is ConeClassSymbol -> {
val superClassType =
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|
@@ -49,6 +49,16 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
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")
public void testFt() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/ft.kt");