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.FirBasedSymbol
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.structure.JavaClass
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.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class KotlinDeserializedJvmSymbolsProvider(
val session: FirSession,
@@ -44,13 +46,18 @@ class KotlinDeserializedJvmSymbolsProvider(
) : AbstractFirSymbolProvider() {
private val classesCache = mutableMapOf<ClassId, FirClassSymbol>()
private val typeAliasCache = mutableMapOf<ClassId, FirTypeAliasSymbol?>()
private val packagePartsCache = mutableMapOf<FqName, Collection<PackagePartsCacheData>>()
private class PackagePartsCacheData(val proto: ProtoBuf.Package, val context: FirDeserializationContext) {
val topLevelNameIndex by lazy {
val topLevelFunctionNameIndex by lazy {
proto.functionList.withIndex()
.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>?>()
@@ -91,9 +98,24 @@ class KotlinDeserializedJvmSymbolsProvider(
}
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(
classId: ClassId,
parentContext: FirDeserializationContext? = null
@@ -119,7 +141,7 @@ class KotlinDeserializedJvmSymbolsProvider(
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<ConeCallableSymbol> {
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) }
.map {
part.context.memberDeserializer.loadFunction(it).symbol
@@ -122,6 +122,27 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
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 {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
@@ -156,10 +156,13 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer() {
sessionForSupertype
.getService(FirSymbolProvider::class)
.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)
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 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");
}
@TestMetadata("typeAliasDeserialization.kt")
public void testTypeAliasDeserialization() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/typeAliasDeserialization.kt");
}
@TestMetadata("unaryOperators.kt")
public void testUnaryOperators() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/unaryOperators.kt");