FIR deserializer: support type-aliases

This commit is contained in:
Simon Ogorodnik
2019-04-18 18:18:53 +03:00
committed by Mikhail Glukhikh
parent e6ab38a583
commit 8324ee7272
6 changed files with 65 additions and 5 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.getName import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class KotlinDeserializedJvmSymbolsProvider( class KotlinDeserializedJvmSymbolsProvider(
val session: FirSession, val session: FirSession,
@@ -44,13 +46,18 @@ class KotlinDeserializedJvmSymbolsProvider(
) : AbstractFirSymbolProvider() { ) : AbstractFirSymbolProvider() {
private val classesCache = mutableMapOf<ClassId, FirClassSymbol>() private val classesCache = mutableMapOf<ClassId, FirClassSymbol>()
private val typeAliasCache = mutableMapOf<ClassId, FirTypeAliasSymbol?>()
private val packagePartsCache = mutableMapOf<FqName, Collection<PackagePartsCacheData>>() private val packagePartsCache = mutableMapOf<FqName, Collection<PackagePartsCacheData>>()
private class PackagePartsCacheData(val proto: ProtoBuf.Package, val context: FirDeserializationContext) { private class PackagePartsCacheData(val proto: ProtoBuf.Package, val context: FirDeserializationContext) {
val topLevelNameIndex by lazy { val topLevelFunctionNameIndex by lazy {
proto.functionList.withIndex() proto.functionList.withIndex()
.groupBy({ context.nameResolver.getName(it.value.name) }) { (index) -> index } .groupBy({ context.nameResolver.getName(it.value.name) }) { (index) -> index }
} }
val typeAliasNameIndex by lazy {
proto.typeAliasList.withIndex()
.groupBy({ context.nameResolver.getName(it.value.name) }) { (index) -> index }
}
} }
private val knownClassNamesInPackage = mutableMapOf<FqName, Set<String>?>() private val knownClassNamesInPackage = mutableMapOf<FqName, Set<String>?>()
@@ -91,9 +98,24 @@ class KotlinDeserializedJvmSymbolsProvider(
} }
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? { override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? {
return findAndDeserializeClass(classId) return findAndDeserializeClass(classId) ?: findAndDeserializeTypeAlias(classId)
} }
private fun findAndDeserializeTypeAlias(
classId: ClassId
): FirTypeAliasSymbol? {
return typeAliasCache.getOrPut(classId) {
getPackageParts(classId.packageFqName).firstNotNullResult { part ->
val ids = part.typeAliasNameIndex[classId.shortClassName]
if (ids == null || ids.isEmpty()) return@firstNotNullResult null
val aliasProto = ids.map { part.proto.getTypeAlias(it) }.single()
part.context.memberDeserializer.loadTypeAlias(aliasProto).symbol
}
}
}
private fun findAndDeserializeClass( private fun findAndDeserializeClass(
classId: ClassId, classId: ClassId,
parentContext: FirDeserializationContext? = null parentContext: FirDeserializationContext? = null
@@ -119,7 +141,7 @@ class KotlinDeserializedJvmSymbolsProvider(
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<ConeCallableSymbol> { override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<ConeCallableSymbol> {
return getPackageParts(packageFqName).flatMap { part -> return getPackageParts(packageFqName).flatMap { part ->
val functionIds = part.topLevelNameIndex[name] ?: return@flatMap emptyList() val functionIds = part.topLevelFunctionNameIndex[name] ?: return@flatMap emptyList()
functionIds.map { part.proto.getFunction(it) } functionIds.map { part.proto.getFunction(it) }
.map { .map {
part.context.memberDeserializer.loadFunction(it).symbol part.context.memberDeserializer.loadFunction(it).symbol
@@ -122,6 +122,27 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
return lowSixBits + rest return lowSixBits + rest
} }
fun loadTypeAlias(proto: ProtoBuf.TypeAlias): FirTypeAlias {
val flags = proto.flags
val name = c.nameResolver.getName(proto.name)
return FirTypeAliasImpl(
c.session,
null,
FirTypeAliasSymbol(ClassId(c.packageFqName, name)),
name,
ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
Flags.IS_EXPECT_CLASS.get(flags),
false,
FirResolvedTypeRefImpl(
c.session,
null,
c.typeDeserializer.type(proto.underlyingType(c.typeTable)),
false,
emptyList() /* TODO */
)
)
}
fun loadFunction(proto: ProtoBuf.Function): FirNamedFunction { fun loadFunction(proto: ProtoBuf.Function): FirNamedFunction {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags) val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
@@ -156,10 +156,13 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer() {
sessionForSupertype sessionForSupertype
.getService(FirSymbolProvider::class) .getService(FirSymbolProvider::class)
.getClassLikeSymbolByFqName(superTypeClassId) .getClassLikeSymbolByFqName(superTypeClassId)
?.toFirClassLike() as? FirClass ?.toFirClassLike()
// TODO: this if is a temporary hack for built-in types (because we can't load file for them) // TODO: this if is a temporary hack for built-in types (because we can't load file for them)
if (firClassForSupertype == null || firClassForSupertype.superTypeRefs.any { it !is FirResolvedTypeRef }) { if (firClassForSupertype == null ||
(firClassForSupertype is FirClass &&
firClassForSupertype.superTypeRefs.any { it !is FirResolvedTypeRef })
) {
val provider = sessionForSupertype.getService(FirProvider::class) val provider = sessionForSupertype.getService(FirProvider::class)
val firForSuperClassFile = provider.getFirClassifierContainerFile(superTypeClassId) val firForSuperClassFile = provider.getFirClassifierContainerFile(superTypeClassId)
@@ -0,0 +1,4 @@
fun main() {
val a = LinkedHashSet<String>()
a.add("")
}
@@ -0,0 +1,5 @@
FILE: typeAliasDeserialization.kt
public final fun main(): R|kotlin/Unit| {
lval a: R|java/util/LinkedHashSet| = R|java/util/LinkedHashSet.LinkedHashSet|()
R|<local>/a|.<Inapplicable(INAPPLICABLE): [java/util/HashSet.add, java/util/AbstractCollection.add, java/util/Collection.add, java/util/Set.add]>#(String())
}
@@ -59,6 +59,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt"); runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
} }
@TestMetadata("typeAliasDeserialization.kt")
public void testTypeAliasDeserialization() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/typeAliasDeserialization.kt");
}
@TestMetadata("unaryOperators.kt") @TestMetadata("unaryOperators.kt")
public void testUnaryOperators() throws Exception { public void testUnaryOperators() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/unaryOperators.kt"); runTest("compiler/fir/resolve/testData/resolve/stdlib/unaryOperators.kt");