FIR: Refactor nested scope, fix super-type resolving jump context

#KT-24017 Fixed
This commit is contained in:
Simon Ogorodnik
2018-03-20 20:55:11 +03:00
committed by Mikhail Glukhikh
parent f82ad6ac20
commit bc9175c4e8
10 changed files with 114 additions and 52 deletions
@@ -12,26 +12,27 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirNestedClassifierScope
import org.jetbrains.kotlin.fir.scopes.impl.FirSelfImportingScope
import org.jetbrains.kotlin.fir.transformInplace
import org.jetbrains.kotlin.fir.types.ConeClassType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedType
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.*
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.FirVisitor
import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return (element.transformChildren(this, data) as E).compose()
return if (superTypesOnly) {
element.compose()
} else {
(element.transformChildren(this, data) as E).compose()
}
}
lateinit var scope: FirCompositeScope
@@ -46,13 +47,21 @@ class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
)
)
packageFqName = file.packageFqName
return file.also { it.transformChildren(this, null) }.compose()
return super.transformFile(file, data)
}
private fun lookupSuperTypes(klass: FirClass): List<ClassId> {
val superTypesBuilder = SuperClassHierarchyBuilder()
klass.superTypes.any { it.accept(superTypesBuilder, null) }
return superTypesBuilder.classes
}
override fun transformClass(klass: FirClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
klass.transformChildren(SuperTypeResolver(), null)
className = className.child(klass.name)
scope.scopes += FirNestedClassifierScope(ClassId(packageFqName, className, false), klass.session)
scope.scopes.addAll(lookupSuperTypes(klass).map { FirNestedClassifierScope(it, klass.session) })
val result = super.transformClass(klass, data)
scope.scopes.also { it.removeAt(it.lastIndex) }
className = className.parent()
@@ -91,10 +100,53 @@ class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
val classId = (transformedType.type as? ConeClassType)?.fqName ?: return transformedType.compose()
val firProvider = FirProvider.getInstance(transformedType.session)
// ???
firProvider.getFirClassifierByFqName(classId)!!.transformChildren(this, data)
val classes = generateSequence(classId) { it.outerClassId }.toList()
val transformer = FirTypeResolveTransformer(superTypesOnly = true)
val file = firProvider.getFirClassifierContainerFile(classes.last())
file.transformSingle(transformer, null)
classes.forEach {
firProvider.getFirClassifierByFqName(it)!!.transformSingle(transformer, data)
}
return transformedType.compose()
}
}
private inner class SuperClassHierarchyBuilder : FirVisitor<Boolean, Nothing?>() {
override fun visitElement(element: FirElement, data: Nothing?): Boolean {
return false
}
private tailrec fun ConeClassType.computePartialExpansion(): ClassId {
return when (this) {
!is ConeAbbreviatedType -> this.fqName
else -> (this.directExpansion as ConeClassType).computePartialExpansion()
}
}
val classes = mutableListOf<ClassId>()
override fun visitResolvedType(resolvedType: FirResolvedType, data: Nothing?): Boolean {
val provider = FirProvider.getInstance(resolvedType.session)
val targetClassId = resolvedType.coneTypeSafe<ConeClassType>()?.computePartialExpansion() ?: return false
val classifier = provider.getFirClassifierByFqName(targetClassId)!!
when (classifier) {
is FirClass -> {
if (classifier.classKind == ClassKind.CLASS) {
classes += targetClassId
classifier.superTypes.any { it.accept(this, data) }
}
}
is FirTypeAlias -> classifier.abbreviatedType.accept(this, data)
}
return true
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
@@ -19,6 +20,7 @@ interface FirProvider {
fun getFirTypeParameterByFqName(fqName: ClassId, parameterName: Name): FirTypeParameter?
fun getFirClassifierContainerFile(fqName: ClassId): FirFile
companion object {
fun getInstance(session: FirSession): FirProvider = session.service()
@@ -15,6 +15,9 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirProviderImpl(val session: FirSession) : FirProvider {
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile {
return classifierContainerFileMap[fqName] ?: error("Couldn't find container for $fqName")
}
fun recordFile(file: FirFile) {
val packageName = file.packageFqName
@@ -27,7 +30,9 @@ class FirProviderImpl(val session: FirSession) : FirProvider {
override fun visitClass(klass: FirClass) {
val fqName = containerFqName.child(klass.name)
classifierMap[ClassId(packageName, fqName, false)] = klass
val classId = ClassId(packageName, fqName, false)
classifierMap[classId] = klass
classifierContainerFileMap[classId] = file
containerFqName = fqName
klass.acceptChildren(this)
@@ -36,13 +41,16 @@ class FirProviderImpl(val session: FirSession) : FirProvider {
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
val fqName = containerFqName.child(typeAlias.name)
classifierMap[ClassId(packageName, fqName, false)] = typeAlias
val classId = ClassId(packageName, fqName, false)
classifierMap[classId] = typeAlias
classifierContainerFileMap[classId] = file
}
})
}
private val fileMap = mutableMapOf<FqName, List<FirFile>>()
private val classifierMap = mutableMapOf<ClassId, FirMemberDeclaration>()
private val classifierContainerFileMap = mutableMapOf<ClassId, FirFile>()
override fun getFirFilesByPackage(fqName: FqName): List<FirFile> {
return fileMap[fqName].orEmpty()
@@ -6,16 +6,9 @@
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.types.ConeAbbreviatedType
import org.jetbrains.kotlin.fir.types.ConeClassType
import org.jetbrains.kotlin.fir.types.FirResolvedType
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -23,40 +16,12 @@ class FirNestedClassifierScope(val classId: ClassId, val session: FirSession) :
private val firProvider = FirProvider.getInstance(session)
fun ClassId.getFir(): FirMemberDeclaration? {
private fun ClassId.getFir(): FirMemberDeclaration? {
return firProvider.getFirClassifierByFqName(this)
}
private tailrec fun ConeClassType.computePartialExpansion(): ClassId {
return when (this) {
!is ConeAbbreviatedType -> this.fqName
else -> (this.directExpansion as ConeClassType).computePartialExpansion()
}
}
private val superScopes by lazy {
val self = classId.getFir()
when (self) {
is FirClass -> {
val superTypes = self.superTypes as List<FirResolvedType>
FirCompositeScope(superTypes.mapTo(ArrayList(superTypes.size)) {
FirNestedClassifierScope(it.coneTypeUnsafe<ConeClassType>().computePartialExpansion(), session)
})
}
is FirTypeAlias -> {
val expansionTarget = self.abbreviatedType.coneTypeUnsafe<ConeClassType>().computePartialExpansion()
FirNestedClassifierScope(expansionTarget, session)
}
else -> error("!")
}
}
override fun processClassifiersByName(name: Name, processor: (ClassId) -> Boolean): Boolean {
val child = ClassId(classId.packageFqName, classId.relativeClassName.child(name), false)
if (child.getFir() != null && !processor(child)) return false
return superScopes.processClassifiersByName(name, processor)
return child.getFir() == null || processor(child)
}
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.types.KotlinType
interface FirResolvedType : FirTypeWithNullability {
val type: ConeKotlinType
@@ -15,4 +14,5 @@ interface FirResolvedType : FirTypeWithNullability {
visitor.visitResolvedType(this, data)
}
inline fun <reified T> FirType.coneTypeUnsafe() = (this as FirResolvedType).type as T
inline fun <reified T : ConeKotlinType> FirType.coneTypeUnsafe() = (this as FirResolvedType).type as T
inline fun <reified T : ConeKotlinType> FirType.coneTypeSafe() = (this as FirResolvedType).type as? T
@@ -0,0 +1,7 @@
package b
import c.C
open class B : C() {
open class NestedInB : NestedInC()
}
@@ -0,0 +1,5 @@
package c
open class C {
open class NestedInC
}
@@ -0,0 +1,8 @@
package a
import b.B
class A : B() {
class NestedInA1 : NestedInB()
class NestedInA2 : NestedInC()
}
@@ -0,0 +1,9 @@
FILE: NestedSuperType.kt
unknown final class A() : R/b.B/ {
unknown final class NestedInA1() : R/b.B.NestedInB/ {
}
unknown final class NestedInA2() : R/c.C.NestedInC/ {
}
}
@@ -69,6 +69,12 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/fir/resolve/multifile"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("NestedSuperType.kt")
public void testNestedSuperType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/fir/resolve/multifile/NestedSuperType.kt");
doTest(fileName);
}
@TestMetadata("simpleAliasedImport.kt")
public void testSimpleAliasedImport() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/fir/resolve/multifile/simpleAliasedImport.kt");