From 619bddfdbc444476627554bf1b41b201b51a4475 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 10 Jan 2019 11:50:17 +0300 Subject: [PATCH] FIR: handle recursion in super-types correctly Related to KT-24077 --- .../transformers/FirTypeResolveTransformer.kt | 26 ++++++++++++++----- .../resolve/fakeRecursiveSupertype.kt | 7 +++++ .../resolve/fakeRecursiveSupertype.txt | 13 ++++++++++ .../resolve/fakeRecursiveTypealias.kt | 5 ++++ .../resolve/fakeRecursiveTypealias.txt | 3 +++ .../fir/FirResolveTestCaseGenerated.java | 10 +++++++ 6 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.kt create mode 100644 compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt create mode 100644 compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.kt create mode 100644 compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 78a782c8169..67b1fe4e0b4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -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() { +open class FirTypeResolveTransformer( + private val traversedClassifiers: Set = setOf() +) : FirTransformer() { override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { @Suppress("UNCHECKED_CAST") return (element.transformChildren(this, data) as E).compose() @@ -53,7 +56,7 @@ open class FirTypeResolveTransformer : FirTransformer() { 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() { return typeProjectionWithVariance.compose() } - private class SuperTypeResolveTransformer(val elementIterator: Iterator) : FirTypeResolveTransformer() { + private class SuperTypeResolveTransformer( + val elementIterator: Iterator, + traversedClassifiers: Set + ) : FirTypeResolveTransformer(traversedClassifiers) { override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data) return element.compose() } } - private inner class SuperTypeResolver : FirTransformer() { + private inner class SuperTypeResolver(val traversedClassifiers: Set) : FirTransformer() { override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { return element.compose() } @@ -208,7 +214,7 @@ open class FirTypeResolveTransformer : FirTransformer() { } val transformer = SuperTypeResolveTransformer( - firElementsToVisit.iterator() + firElementsToVisit.iterator(), traversedClassifiers ) file.transformSingle(transformer, null) @@ -227,7 +233,13 @@ open class FirTypeResolveTransformer : FirTransformer() { 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() { } private tailrec fun ConeClassLikeSymbol.collectSuperTypes(list: MutableList) { - return when (this) { + when (this) { is ConeClassSymbol -> { val superClassType = this.superTypes diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.kt b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.kt new file mode 100644 index 00000000000..1d9882832c0 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.kt @@ -0,0 +1,7 @@ +import incorrect.directory.My + +class My : My() + +class Your : His() + +class His : Your() \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt new file mode 100644 index 00000000000..147c65dd506 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt @@ -0,0 +1,13 @@ +FILE: fakeRecursiveSupertype.kt + public final class My : R|error: Recursion detected: My| { + public constructor(): super() + + } + public final class Your : R|His| { + public constructor(): super() + + } + public final class His : R|error: Recursion detected: Your| { + public constructor(): super() + + } diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.kt b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.kt new file mode 100644 index 00000000000..cf2f35a87e1 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.kt @@ -0,0 +1,5 @@ +import incorrect.directory.Your + +typealias My = incorrect.directory.My + +typealias Your = Your \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt new file mode 100644 index 00000000000..65e1055ee62 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt @@ -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| diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index b20da977cb5..5570a3be3df 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -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");