FIR: add classifiers to local scopes, process local class symbols correctly

This commit is contained in:
Mikhail Glukhikh
2019-09-05 16:11:50 +03:00
parent aa2765bab8
commit a13ae08b52
15 changed files with 114 additions and 46 deletions
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.name.FqName
class Context {
lateinit var packageFqName: FqName
var className: FqName = FqName.ROOT
val currentClassId get() = ClassId(packageFqName, className, false)
val currentClassId get() = ClassId(packageFqName, className, firFunctions.isNotEmpty())
val firFunctions = mutableListOf<FirFunction<*>>()
val firFunctionCalls = mutableListOf<FirFunctionCall>()
@@ -27,7 +27,9 @@ import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.invoke
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
@@ -204,7 +206,14 @@ class FirCallResolver(
if (referencedSymbol is FirClassLikeSymbol<*>) {
val classId = referencedSymbol.classId
return FirResolvedQualifierImpl(nameReference.source, classId.packageFqName, classId.relativeClassName).apply {
resultType = typeForQualifier(this)
resultType = if (classId.isLocal) {
typeForQualifierByDeclaration(referencedSymbol.fir, resultType)
?: resultType.resolvedTypeFromPrototype(
StandardClassIds.Unit(symbolProvider).constructType(emptyArray(), isNullable = false)
)
} else {
typeForQualifier(this)
}
}
}
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
abstract class FirProvider : FirSymbolProvider() {
abstract fun getFirClassifierByFqName(fqName: ClassId): FirClassLikeDeclaration<*>?
abstract fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>?
abstract override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>?
@@ -242,26 +242,12 @@ fun BodyResolveComponents.typeForQualifier(resolvedQualifier: FirResolvedQualifi
if (classId != null) {
val classSymbol = symbolProvider.getClassLikeSymbolByFqName(classId)!!
val declaration = classSymbol.phasedFir
if (declaration is FirClass) {
if (declaration.classKind == ClassKind.OBJECT) {
return resultType.resolvedTypeFromPrototype(
classSymbol.constructType(emptyArray(), false)
)
} else if (declaration.classKind == ClassKind.ENUM_ENTRY) {
val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!!
return resultType.resolvedTypeFromPrototype(
enumClassSymbol.constructType(emptyArray(), false)
)
} else {
if (declaration is FirRegularClass) {
val companionObject = declaration.companionObject
if (companionObject != null) {
return resultType.resolvedTypeFromPrototype(
companionObject.symbol.constructType(emptyArray(), false)
)
}
}
}
typeForQualifierByDeclaration(declaration, resultType)?.let { return it }
if (declaration is FirRegularClass && declaration.classKind == ClassKind.ENUM_ENTRY) {
val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!!
return resultType.resolvedTypeFromPrototype(
enumClassSymbol.constructType(emptyArray(), false)
)
}
}
// TODO: Handle no value type here
@@ -270,6 +256,24 @@ fun BodyResolveComponents.typeForQualifier(resolvedQualifier: FirResolvedQualifi
)
}
internal fun typeForQualifierByDeclaration(declaration: FirDeclaration, resultType: FirTypeRef): FirTypeRef? {
if (declaration is FirRegularClass) {
if (declaration.classKind == ClassKind.OBJECT) {
return resultType.resolvedTypeFromPrototype(
declaration.symbol.constructType(emptyArray(), false)
)
} else {
val companionObject = declaration.companionObject
if (companionObject != null) {
return resultType.resolvedTypeFromPrototype(
companionObject.symbol.constructType(emptyArray(), false)
)
}
}
}
return null
}
fun <T : FirResolvable> BodyResolveComponents.typeFromCallee(access: T): FirResolvedTypeRef {
val makeNullable: Boolean by lazy {
if (access is FirQualifiedAccess && access.safe) {
@@ -52,8 +52,12 @@ val USE_SITE = scopeSessionKey<FirScope>()
data class SubstitutionScopeKey(val type: ConeClassLikeType) : ScopeSessionKey<FirClassSubstitutionScope>() {}
fun FirRegularClass.buildUseSiteMemberScope(useSiteSession: FirSession, builder: ScopeSession): FirScope? {
if (classId.isLocal) {
// It's not possible to find local class by symbol
return buildDefaultUseSiteMemberScope(useSiteSession, builder)
}
val symbolProvider = useSiteSession.firSymbolProvider
return symbolProvider.getClassUseSiteMemberScope(this.classId, useSiteSession, builder)
return symbolProvider.getClassUseSiteMemberScope(classId, useSiteSession, builder)
}
fun FirTypeAlias.buildUseSiteMemberScope(useSiteSession: FirSession, builder: ScopeSession): FirScope? {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirImplicitThisReference
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.buildDefaultUseSiteMemberScope
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
@@ -92,7 +93,12 @@ class ImplicitDispatchReceiverValue(
scopeSession: ScopeSession
) : ImplicitReceiverValue<FirClassSymbol>(boundSymbol, type, useSiteSession, scopeSession) {
val implicitCompanionScope: FirScope? = boundSymbol.fir.companionObject?.let { companionObject ->
symbolProvider.getClassUseSiteMemberScope(companionObject.classId, useSiteSession, scopeSession)
val companionId = companionObject.classId
if (companionId.isLocal) {
companionObject.buildDefaultUseSiteMemberScope(useSiteSession, scopeSession)
} else {
symbolProvider.getClassUseSiteMemberScope(companionId, useSiteSession, scopeSession)
}
}
}
@@ -136,8 +136,11 @@ class FirProviderImpl(val session: FirSession) : FirProvider() {
return state.fileMap[fqName].orEmpty()
}
override fun getFirClassifierByFqName(fqName: ClassId): FirClassLikeDeclaration<*>? {
return state.classifierMap[fqName]
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? {
require(!classId.isLocal) {
"Local $classId should never be used to find its corresponding classifier"
}
return state.classifierMap[classId]
}
@TestOnly
@@ -134,6 +134,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult<FirStatement> {
localScopes.lastOrNull()?.storeDeclaration(regularClass)
val oldConstructorScope = primaryConstructorParametersScope
primaryConstructorParametersScope = null
val type = regularClass.defaultType()
@@ -9,21 +9,20 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.NAME_FOR_BACKING_FIELD
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.Name
class FirLocalScope : FirScope() {
val properties = mutableMapOf<Name, FirVariableSymbol<*>>()
val functions = mutableMapOf<Name, FirFunctionSymbol<*>>()
val classes = mutableMapOf<Name, FirClassSymbol>()
fun storeDeclaration(declaration: FirNamedDeclaration) {
when (declaration) {
is FirVariable<*> -> properties[declaration.name] = declaration.symbol
is FirSimpleFunction -> functions[declaration.name] = declaration.symbol as FirNamedFunctionSymbol
is FirRegularClass -> classes[declaration.name] = declaration.symbol
}
}
@@ -32,17 +31,25 @@ class FirLocalScope : FirScope() {
}
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
val prop = functions[name]
if (prop != null) {
return processor(prop)
val function = functions[name]
if (function != null) {
return processor(function)
}
return ProcessorAction.NONE
}
override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction {
val prop = properties[name]
if (prop != null) {
return processor(prop)
val property = properties[name]
if (property != null) {
return processor(property)
}
return ProcessorAction.NONE
}
override fun processClassifiersByName(name: Name, processor: (FirClassifierSymbol<*>) -> ProcessorAction): ProcessorAction {
val klass = classes[name]
if (klass != null) {
return processor(klass)
}
return ProcessorAction.NONE
}
@@ -0,0 +1,5 @@
fun test() {
class Local
val l = Local()
}
@@ -0,0 +1,11 @@
FILE: localConstructor.kt
public final fun test(): R|kotlin/Unit| {
local final class Local : R|kotlin/Any| {
public constructor(): R|Local| {
super<R|kotlin/Any|>()
}
}
lval l: R|Local| = R|/Local.Local|()
}
+1 -1
View File
@@ -24,7 +24,7 @@ FILE: problems.kt
}
<Unresolved name: Local>#()
R|/Local.Local|()
}
public final val R|kotlin/Any|.bar: R|kotlin/String|
public get(): R|kotlin/String| {
@@ -326,6 +326,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
runTest("compiler/fir/resolve/testData/resolve/expresssions/lambda.kt");
}
@TestMetadata("localConstructor.kt")
public void testLocalConstructor() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/localConstructor.kt");
}
@TestMetadata("localExtension.kt")
public void testLocalExtension() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/expresssions/localExtension.kt");
@@ -3,7 +3,7 @@ FILE fqName:<root> fileName:/localClassWithOverrides.kt
BLOCK_BODY
CLASS CLASS name:ALocal modality:ABSTRACT visibility:local superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.outer.ALocal
CONSTRUCTOR visibility:public <> () returnType:IrErrorType [primary]
CONSTRUCTOR visibility:public <> () returnType:<root>.outer.ALocal [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:ALocal modality:ABSTRACT visibility:local superTypes:[kotlin.Any]'
@@ -21,11 +21,24 @@ FILE fqName:<root> fileName:/localClassWithOverrides.kt
correspondingProperty: PROPERTY name:avar visibility:public modality:ABSTRACT [var]
$this: VALUE_PARAMETER name:<this> type:<root>.outer.ALocal
VALUE_PARAMETER name:<set-?> index:0 type:kotlin.Int
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CLASS CLASS name:Local modality:FINAL visibility:local superTypes:[IrErrorType]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.outer.Local
CONSTRUCTOR visibility:public <> () returnType:IrErrorType [primary]
CONSTRUCTOR visibility:public <> () returnType:<root>.outer.Local [primary]
BLOCK_BODY
ERROR_CALL 'Cannot find delegated constructor call' type=IrErrorType
ERROR_CALL 'Cannot find delegated constructor call' type=<root>.outer.Local
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Local modality:FINAL visibility:local superTypes:[IrErrorType]'
FUN name:afun visibility:public modality:FINAL <> ($this:<root>.outer.Local) returnType:kotlin.Unit
$this: VALUE_PARAMETER name:<this> type:<root>.outer.Local
@@ -33,18 +33,18 @@ class IdeFirProvider(
// TODO: invalidation?
private val files = mutableMapOf<KtFile, FirFile>()
override fun getFirClassifierByFqName(fqName: ClassId): FirClassLikeDeclaration<*>? {
return cacheProvider.getFirClassifierByFqName(fqName) ?: run {
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? {
return cacheProvider.getFirClassifierByFqName(classId) ?: run {
val classes = KotlinFullClassNameIndex.getInstance().get(fqName.asSingleFqName().asString(), project, scope)
val classes = KotlinFullClassNameIndex.getInstance().get(classId.asSingleFqName().asString(), project, scope)
val ktClass = classes.firstOrNull {
fqName.packageFqName == it.containingKtFile.packageFqName
classId.packageFqName == it.containingKtFile.packageFqName
} ?: return null // TODO: what if two of them?
val ktFile = ktClass.containingKtFile
getOrBuildFile(ktFile)
cacheProvider.getFirClassifierByFqName(fqName)
cacheProvider.getFirClassifierByFqName(classId)
}
}