diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/Context.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/Context.kt index 5e7abc3c617..b5f2c048de3 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/Context.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/Context.kt @@ -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>() val firFunctionCalls = mutableListOf() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index cc222b94585..988e07c6cc3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -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) + } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt index 4c57c8f7fe5..dcf21ee6cda 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirProvider.kt @@ -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<*>? diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 2fab8f081b7..e71b2952d32 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -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 BodyResolveComponents.typeFromCallee(access: T): FirResolvedTypeRef { val makeNullable: Boolean by lazy { if (access is FirQualifiedAccess && access.safe) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt index b00fb568429..802baa2ee8d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt @@ -52,8 +52,12 @@ val USE_SITE = scopeSessionKey() data class SubstitutionScopeKey(val type: ConeClassLikeType) : ScopeSessionKey() {} 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? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index 023e67d3591..f65783edd41 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -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(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) + } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt index b6aae314f29..b4c05afd31f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirProviderImpl.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 9bb8eafa1f1..4e89f1db57a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -134,6 +134,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) } override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult { + localScopes.lastOrNull()?.storeDeclaration(regularClass) val oldConstructorScope = primaryConstructorParametersScope primaryConstructorParametersScope = null val type = regularClass.defaultType() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt index dc9c79c6b45..227d34d8a77 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirLocalScope.kt @@ -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>() val functions = mutableMapOf>() + val classes = mutableMapOf() 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 } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.kt b/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.kt new file mode 100644 index 00000000000..2844400f9f0 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.kt @@ -0,0 +1,5 @@ +fun test() { + class Local + + val l = Local() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.txt b/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.txt new file mode 100644 index 00000000000..0fb17b39b70 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/expresssions/localConstructor.txt @@ -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() + } + + } + + lval l: R|Local| = R|/Local.Local|() + } diff --git a/compiler/fir/resolve/testData/resolve/stdlib/problems.txt b/compiler/fir/resolve/testData/resolve/stdlib/problems.txt index 112c753373a..97827a4c002 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/problems.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/problems.txt @@ -24,7 +24,7 @@ FILE: problems.kt } - #() + R|/Local.Local|() } public final val R|kotlin/Any|.bar: R|kotlin/String| public get(): R|kotlin/String| { diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index 0d7259c9c31..21376452f7d 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -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"); diff --git a/compiler/testData/ir/irText/declarations/localClassWithOverrides.fir.txt b/compiler/testData/ir/irText/declarations/localClassWithOverrides.fir.txt index 53d6d9d8412..377dca19007 100644 --- a/compiler/testData/ir/irText/declarations/localClassWithOverrides.fir.txt +++ b/compiler/testData/ir/irText/declarations/localClassWithOverrides.fir.txt @@ -3,7 +3,7 @@ FILE fqName: fileName:/localClassWithOverrides.kt BLOCK_BODY CLASS CLASS name:ALocal modality:ABSTRACT visibility:local superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.outer.ALocal - CONSTRUCTOR visibility:public <> () returnType:IrErrorType [primary] + CONSTRUCTOR visibility:public <> () returnType:.outer.ALocal [primary] BLOCK_BODY DELEGATING_CONSTRUCTOR_CALL 'public constructor () [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: fileName:/localClassWithOverrides.kt correspondingProperty: PROPERTY name:avar visibility:public modality:ABSTRACT [var] $this: VALUE_PARAMETER name: type:.outer.ALocal VALUE_PARAMETER name: 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: 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: 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: type:kotlin.Any CLASS CLASS name:Local modality:FINAL visibility:local superTypes:[IrErrorType] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.outer.Local - CONSTRUCTOR visibility:public <> () returnType:IrErrorType [primary] + CONSTRUCTOR visibility:public <> () returnType:.outer.Local [primary] BLOCK_BODY - ERROR_CALL 'Cannot find delegated constructor call' type=IrErrorType + ERROR_CALL 'Cannot find delegated constructor call' type=.outer.Local INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Local modality:FINAL visibility:local superTypes:[IrErrorType]' FUN name:afun visibility:public modality:FINAL <> ($this:.outer.Local) returnType:kotlin.Unit $this: VALUE_PARAMETER name: type:.outer.Local diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/IdeFirProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/IdeFirProvider.kt index de8f783abeb..475e28d654b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/IdeFirProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/IdeFirProvider.kt @@ -33,18 +33,18 @@ class IdeFirProvider( // TODO: invalidation? private val files = mutableMapOf() - 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) } }