FIR: Support loading built-in top-level functions

This commit is contained in:
Denis Zharkov
2019-03-25 15:23:03 +03:00
parent 705f97cbae
commit f03c5e0583
12 changed files with 294 additions and 26 deletions
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.deserialization
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.Variance
class FirDeserializationContext(
val nameResolver: NameResolver,
val typeTable: TypeTable,
val versionRequirementTable: VersionRequirementTable,
val session: FirSession,
val packageFqName: FqName,
val relativeClassName: FqName?,
val typeDeserializer: FirTypeDeserializer,
val components: FirDeserializationComponents
) {
fun childContext(
typeParameterProtos: List<ProtoBuf.TypeParameter>
): FirDeserializationContext = FirDeserializationContext(
nameResolver, typeTable, versionRequirementTable, session, packageFqName, relativeClassName,
FirTypeDeserializer(
nameResolver, typeTable, typeParameterProtos, typeDeserializer
),
components
)
val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this)
}
// TODO: Move something here
class FirDeserializationComponents
class FirMemberDeserializer(private val c: FirDeserializationContext) {
private fun loadOldFlags(oldFlags: Int): Int {
val lowSixBits = oldFlags and 0x3f
val rest = (oldFlags shr 8) shl 6
return lowSixBits + rest
}
fun loadFunction(proto: ProtoBuf.Function): FirNamedFunction {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val receiverAnnotations =
// TODO: support annotations
Annotations.EMPTY
val versionRequirementTable =
// TODO: Support case for KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME
c.versionRequirementTable
val callableName = c.nameResolver.getName(proto.name)
val symbol = FirFunctionSymbol(CallableId(c.packageFqName, c.relativeClassName, callableName))
val local = c.childContext(proto.typeParameterList)
// TODO: support contracts
return FirMemberFunctionImpl(
c.session,
null,
symbol,
callableName,
ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
ProtoEnumFlags.modality(Flags.MODALITY.get(flags)),
Flags.IS_EXPECT_FUNCTION.get(flags),
false,
false,
Flags.IS_OPERATOR.get(flags),
Flags.IS_INFIX.get(flags),
Flags.IS_INLINE.get(flags),
Flags.IS_TAILREC.get(flags),
Flags.IS_EXTERNAL_FUNCTION.get(flags),
Flags.IS_SUSPEND.get(flags),
proto.receiverType(c.typeTable)?.let(local.typeDeserializer::type)?.toTypeRef(),
local.typeDeserializer.type(proto.returnType(c.typeTable)).toTypeRef()
).apply {
typeParameters += local.typeDeserializer.ownTypeParameters.map { createTypeParameterSymbol(it.name).fir }
valueParameters += local.memberDeserializer.valueParameters(proto.valueParameterList)
annotations += getAnnotations(proto, flags, AnnotatedCallableKind.FUNCTION)
}
}
private fun createTypeParameterSymbol(name: Name): FirTypeParameterSymbol {
val firSymbol = FirTypeParameterSymbol()
FirTypeParameterImpl(c.session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
return firSymbol
}
private fun valueParameters(
valueParameters: List<ProtoBuf.ValueParameter>
): List<FirValueParameter> {
return valueParameters.mapIndexed { i, proto ->
val flags = if (proto.hasFlags()) proto.flags else 0
FirValueParameterImpl(
c.session, null, c.nameResolver.getName(proto.name),
c.typeDeserializer.type(proto.type(c.typeTable)).toTypeRef(),
null, // TODO: default value
Flags.IS_CROSSINLINE.get(flags),
Flags.IS_NOINLINE.get(flags),
proto.varargElementType(c.typeTable) != null
).apply {
annotations += emptyList() // TODO: parameter annotations
}
}.toList()
}
// TODO: Annotations
private fun getAnnotations(proto: MessageLite, flags: Int, kind: AnnotatedCallableKind) = emptyList<FirAnnotationCall>()
private fun ConeKotlinType.toTypeRef(): FirTypeRef {
// TODO: annotations
return FirResolvedTypeRefImpl(c.session, null, this, nullability.isNullable, emptyList())
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
interface FirSymbolProvider {
@@ -26,6 +27,8 @@ interface FirSymbolProvider {
fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol>
fun getAllCallableNamesInPackage(fqName: FqName): Set<Name> = emptySet()
fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
// TODO: should not retrieve session through the FirElement::session
@@ -11,15 +11,12 @@ import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class FirCompositeSymbolProvider(val providers: List<FirSymbolProvider>) : FirSymbolProvider {
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
for (provider in providers) {
val symbols = provider.getCallableSymbols(callableId)
if (symbols.isNotEmpty()) return symbols
}
return emptyList()
return providers.flatMap { it.getCallableSymbols(callableId) }
}
override fun getPackage(fqName: FqName): FqName? {
@@ -29,4 +26,8 @@ class FirCompositeSymbolProvider(val providers: List<FirSymbolProvider>) : FirSy
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? {
return providers.firstNotNullResult { it.getClassLikeSymbolByFqName(classId) }
}
}
override fun getAllCallableNamesInPackage(fqName: FqName): Set<Name> {
return providers.flatMapTo(mutableSetOf()) { it.getAllCallableNamesInPackage(fqName) }
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider() {
private val dependencyProviders by lazy {
@@ -26,13 +27,8 @@ class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSy
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
return callableCache.lookupCacheOrCalculate(callableId) {
for (provider in dependencyProviders) {
provider.getCallableSymbols(callableId).let {
if (it.isNotEmpty()) return@lookupCacheOrCalculate it
}
}
emptyList()
}.orEmpty()
dependencyProviders.flatMap { provider -> provider.getCallableSymbols(callableId) }
} ?: emptyList()
}
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? {
@@ -56,4 +52,8 @@ class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSy
null
}
}
}
override fun getAllCallableNamesInPackage(fqName: FqName): Set<Name> {
return dependencyProviders.flatMapTo(mutableSetOf()) { it.getAllCallableNamesInPackage(fqName) }
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationComponents
import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext
import org.jetbrains.kotlin.fir.deserialization.FirTypeDeserializer
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.getOrPut
@@ -26,10 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.deserialization.supertypes
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -42,11 +41,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import java.io.InputStream
class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider {
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
// TODO
return emptyList()
}
private class BuiltInsPackageFragment(stream: InputStream, val fqName: FqName, val session: FirSession) {
lateinit var version: BuiltInsBinaryVersion
@@ -70,6 +64,22 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider
val classDataFinder = ProtoBasedClassDataFinder(packageProto, nameResolver, version) { SourceElement.NO_SOURCE }
private val memberDeserializer by lazy {
FirDeserializationContext(
nameResolver, TypeTable(packageProto.`package`.typeTable),
VersionRequirementTable.EMPTY, // TODO:
session,
fqName,
null,
FirTypeDeserializer(
nameResolver,
TypeTable(packageProto.`package`.typeTable),
emptyList(),
null
),
FirDeserializationComponents()
).memberDeserializer
}
val lookup = mutableMapOf<ClassId, ConeClassLikeSymbol>()
@@ -124,6 +134,16 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider
}
}
}
fun getTopLevelCallableSymbols(name: Name): List<ConeCallableSymbol> {
return packageProto.`package`.functionList.filter { nameResolver.getName(it.name) == name }.map {
memberDeserializer.loadFunction(it).symbol
}
}
fun getAllCallableNames(): Set<Name> {
return packageProto.`package`.functionList.mapTo(mutableSetOf()) { nameResolver.getName(it.name) }
}
}
override fun getPackage(fqName: FqName): FqName? {
@@ -176,4 +196,21 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider
}
}
}
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
if (callableId.classId != null) {
// TODO: Support classes
return emptyList()
}
return allPackageFragments[callableId.packageName]?.flatMap {
it.getTopLevelCallableSymbols(callableId.callableName)
} ?: emptyList()
}
override fun getAllCallableNamesInPackage(fqName: FqName): Set<Name> {
return allPackageFragments[fqName]?.flatMapTo(mutableSetOf()) {
it.getAllCallableNames()
} ?: emptySet()
}
}
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+30
View File
@@ -0,0 +1,30 @@
<T> public final inline fun arrayOf(vararg elements: R|kotlin/Array<out T>|): R|kotlin/Array<T>|
<T> public final fun arrayOfNulls(size: R|kotlin/Int|): R|kotlin/Array<T>|
public final fun booleanArrayOf(vararg elements: R|kotlin/BooleanArray|): R|kotlin/BooleanArray|
public final fun byteArrayOf(vararg elements: R|kotlin/ByteArray|): R|kotlin/ByteArray|
public final fun charArrayOf(vararg elements: R|kotlin/CharArray|): R|kotlin/CharArray|
public final fun doubleArrayOf(vararg elements: R|kotlin/DoubleArray|): R|kotlin/DoubleArray|
<T> public final inline fun emptyArray(): R|kotlin/Array<T>|
<T> public final inline fun enumValueOf(name: R|kotlin/String|): R|T|
<T> public final inline fun enumValues(): R|kotlin/Array<T>|
public final fun floatArrayOf(vararg elements: R|kotlin/FloatArray|): R|kotlin/FloatArray|
public final fun intArrayOf(vararg elements: R|kotlin/IntArray|): R|kotlin/IntArray|
public final fun longArrayOf(vararg elements: R|kotlin/LongArray|): R|kotlin/LongArray|
public final fun shortArrayOf(vararg elements: R|kotlin/ShortArray|): R|kotlin/ShortArray|
public final operator fun R|kotlin/String|.plus(other: R|kotlin/Any|): R|kotlin/String|
public final fun R|kotlin/Any|.toString(): R|kotlin/String|
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
private get(): R|kotlin/Int|
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
^foo <Unresolved name: plus>#(<Unresolved name: plus>#(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
^foo R|kotlin/plus|(R|kotlin/plus|(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
}
public final override var bar: R|kotlin/Boolean|
+1 -1
View File
@@ -13,7 +13,7 @@ FILE: simpleClass.kt
private get(): R|kotlin/Int|
public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
^foo <Unresolved name: plus>#(<Unresolved name: plus>#(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
^foo R|kotlin/plus|(R|kotlin/plus|(R|<local>/y|, R|<local>/x|), R|/SomeClass.baz|)
}
public final override var bar: R|kotlin/Boolean|
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
class BuiltInsDeserializationForFirTestCase : AbstractFirResolveWithSessionTestCase() {
override fun createEnvironment(): KotlinCoreEnvironment {
return createEnvironmentWithJdk(ConfigurationKind.ALL, TestJdkKind.FULL_JDK)
}
fun testCallables() {
for (packageFqName in listOf(
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME,
KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME
)) {
checkCallablesInPackage(packageFqName)
}
}
private fun checkCallablesInPackage(packageFqName: FqName) {
val session = createSession(project, GlobalSearchScope.allScope(project))
val provider = session.getService(FirSymbolProvider::class)
val names = provider.getAllCallableNamesInPackage(packageFqName)
val builder = StringBuilder()
val firRenderer = FirRenderer(builder)
for (name in names) {
for (symbol in provider.getCallableSymbols(CallableId(packageFqName, null, name))) {
(symbol as FirCallableSymbol).fir.accept(firRenderer)
builder.appendln()
}
}
KotlinTestUtils.assertEqualsToFile(
File("compiler/fir/resolve/testData/builtIns/" + packageFqName.asString().replace('.', '-') + ".txt"),
builder.toString()
)
}
}
@@ -5,7 +5,7 @@ FILE: jvm.kt
public final fun test(): R|kotlin/Unit| {
lval res1: R|kotlin/Boolean| = R|/Some.foo|(Int(1))
lval res2: R|kotlin/Boolean| = R|/Some.foo|(<Unresolved name: unaryMinus>#(Int(1)))
lval res3: R|kotlin/Array<ft<java/lang/String, java/lang/String?>>| = R|/Some.bar|(<Unresolved name: intArrayOf>#(Int(0), Int(2), <Unresolved name: unaryMinus>#(Int(2))))
lval res3: R|kotlin/Array<ft<java/lang/String, java/lang/String?>>| = R|/Some.bar|(R|kotlin/intArrayOf|(Int(0), Int(2), <Unresolved name: unaryMinus>#(Int(2))))
}
}