diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt index fc2b082a662..1824902e2e6 100644 --- a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt @@ -3,24 +3,24 @@ FILE: implicitInLocalClasses.kt } public final fun main(): R|kotlin/Unit| { local final class A : R|kotlin/Any| { - public constructor(): R|A| { + public[local] constructor(): R|A| { super() } - public final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| { + public[local] final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| { ^foo this@R|/A|.R|/A.bar|(R|/x|) } - public final fun bar(y: R|kotlin/Int|): R|kotlin/Boolean| { + public[local] final fun bar(y: R|kotlin/Int|): R|kotlin/Boolean| { ^bar CMP(>, this@R|/A|.R|kotlin/Any.hashCode|().R|kotlin/Int.plus|(R|/y|).R|kotlin/Int.compareTo|(Int(0))) } - public final val w: R|kotlin/Boolean| + public[local] final val w: R|kotlin/Boolean| public get(): R|kotlin/Boolean| { ^ this@R|/A|.R|/A.z| } - public final val z: R|kotlin/Boolean| + public[local] final val z: R|kotlin/Boolean| public get(): R|kotlin/Boolean| { ^ ==(this@R|/A|.R|kotlin/Any.hashCode|(), Int(0)) } @@ -33,32 +33,32 @@ FILE: implicitInLocalClasses.kt R|/useBoolean|(R|/a|.R|/A.w|) R|/useBoolean|(R|/a|.R|/A.z|) local final class B : R|kotlin/Any| { - public constructor(): R|B| { + public[local] constructor(): R|B| { super() } - public final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| { + public[local] final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| { ^foo this@R|/B|.R|/B.inner|.R|/B.Inner.w| } - public final fun bar(y: R|kotlin/Int|): R|kotlin/Boolean| { + public[local] final fun bar(y: R|kotlin/Int|): R|kotlin/Boolean| { ^bar CMP(>, this@R|/B|.R|kotlin/Any.hashCode|().R|kotlin/Int.plus|(R|/y|).R|kotlin/Int.compareTo|(Int(0))) } - public final val inner: R|B.Inner| = this@R|/B|.R|/B.Inner.Inner|() + public[local] final val inner: R|B.Inner| = this@R|/B|.R|/B.Inner.Inner|() public get(): R|B.Inner| local final inner class Inner : R|kotlin/Any| { - public constructor(): R|B.Inner| { + public[local] constructor(): R|B.Inner| { super() } - public final val w: R|kotlin/Boolean| + public[local] final val w: R|kotlin/Boolean| public get(): R|kotlin/Boolean| { ^ this@R|/B.Inner|.R|/B.Inner.z| } - public final val z: R|kotlin/Boolean| + public[local] final val z: R|kotlin/Boolean| public get(): R|kotlin/Boolean| { ^ this@R|/B|.R|/B.bar|(Int(1)) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 7f675dad7d1..030a7690310 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -33,7 +33,13 @@ class FirStatusResolveTransformerAdapter : FirTransformer() { } } -class FirStatusResolveTransformer(override val session: FirSession) : +fun > F.runStatusResolveForLocalClass(session: FirSession): F { + val transformer = FirStatusResolveTransformer(session) + + return this.transform(transformer, null).single +} + +private class FirStatusResolveTransformer(override val session: FirSession) : FirAbstractTreeTransformer(phase = FirResolvePhase.STATUS) { private val classes = mutableListOf>() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index 74464b0c33f..4c0582c9492 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo import org.jetbrains.kotlin.fir.scopes.FirIterableScope import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes @@ -42,6 +43,26 @@ class FirSupertypeResolverTransformer( } } +fun > F.runSupertypeResolvePhaseForLocalClass( + session: FirSession, + scopeSession: ScopeSession, + currentScopeList: List, + localClassesNavigationInfo: LocalClassesNavigationInfo, +): F { + val supertypeComputationSession = SupertypeComputationSession() + val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession) + val supertypeResolverVisitor = FirSupertypeResolverVisitor( + session, supertypeComputationSession, scopeSession, + FirImmutableCompositeScope(ImmutableList.ofAll(currentScopeList)), + localClassesNavigationInfo + ) + + this.accept(supertypeResolverVisitor) + supertypeComputationSession.breakLoops(session) + + return this.transform(applySupertypesTransformer, null).single +} + private class FirApplySupertypesTransformer( private val supertypeComputationSession: SupertypeComputationSession ) : FirDefaultTransformer() { @@ -125,7 +146,9 @@ fun FirRegularClass.resolveSupertypesInTheAir(session: FirSession): List): FirImmutableCompositeScope { val classId = classLikeDeclaration.symbol.classId - val outerClassFir = classId.outerClassId?.let(session.firProvider::getFirClassifierByFqName) as? FirRegularClass - val result = if (outerClassFir == null) { - prepareFileScope(session.firProvider.getFirClassifierContainerFile(classId)) - } else { - prepareScopeForNestedClasses(outerClassFir) + val result = when { + classId.isLocal -> { + // Local type aliases are not supported + if (classLikeDeclaration !is FirClass<*>) return FirImmutableCompositeScope.EMPTY + + // Local classes should be treated specially and supplied with localClassesNavigationInfo, normally + // But it seems to be too strict to add an assertion here + val navigationInfo = localClassesNavigationInfo ?: return FirImmutableCompositeScope.EMPTY + + val parent = localClassesNavigationInfo.parentForClass[classLikeDeclaration] + + when { + parent != null -> prepareScopeForNestedClasses(parent) + else -> scopeForLocalClass ?: return FirImmutableCompositeScope.EMPTY + } + } + classId.isNestedClass -> { + val outerClassFir = classId.outerClassId?.let(session.firProvider::getFirClassifierByFqName) as? FirRegularClass + prepareScopeForNestedClasses(outerClassFir ?: return FirImmutableCompositeScope.EMPTY) + } + else -> prepareFileScope(session.firProvider.getFirClassifierContainerFile(classId)) } return result.childScope(classLikeDeclaration.typeParametersScope()) @@ -369,7 +408,7 @@ private class SupertypeComputationSession { fun FirTypeRef.firClassLike(session: FirSession): FirClassLikeDeclaration<*>? { val type = coneTypeSafe() ?: return null - return session.firProvider.getFirClassifierByFqName(type.lookupTag.classId) + return type.lookupTag.toSymbol(session)?.fir } sealed class SupertypeComputationStatus { @@ -384,6 +423,11 @@ private typealias ImmutableList = javaslang.collection.List private class FirImmutableCompositeScope( override val scopes: ImmutableList ) : FirIterableScope() { + + companion object { + val EMPTY = FirImmutableCompositeScope(ImmutableList.empty()) + } + fun childScope(newScope: FirScope?) = newScope?.let { FirImmutableCompositeScope(scopes.push(newScope)) } ?: this fun childScope(newScopes: Collection) = FirImmutableCompositeScope(scopes.pushAll(newScopes)) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 59059677c25..c6f6d188570 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef @@ -33,14 +34,29 @@ class FirTypeResolveTransformerAdapter( } } -class FirTypeResolveTransformer( +fun > F.runTypeResolvePhaseForLocalClass( + session: FirSession, + scopeSession: ScopeSession, + currentScopeList: List, +): F { + val transformer = FirTypeResolveTransformer(scopeSession, session, currentScopeList) + + return this.transform(transformer, null).single +} + +private class FirTypeResolveTransformer( private val scopeSession: ScopeSession, override val session: FirSession, + initialScopes: List = emptyList() ) : FirAbstractTreeTransformerWithSuperTypes( phase = FirResolvePhase.TYPES, reversedScopePriority = true ) { + init { + towerScope.addScopes(initialScopes.asReversed()) + } + private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(towerScope, session) override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { 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 000573ea81a..16ee44aa641 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 @@ -270,43 +270,6 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) ) } - private fun prepareLocalClassForBodyResolve(klass: FirClass<*>) { - if (klass.superTypeRefs.any { it !is FirResolvedTypeRef }) { - klass.replaceSuperTypeRefs( - klass.superTypeRefs.map { superTypeRef -> - this.transformer.transformTypeRef(superTypeRef, ResolutionMode.ContextIndependent).single - } - ) - } - if (klass is FirRegularClass) { - klass.transformStatus(transformer, klass.resolveStatus(klass.status).mode()) - } - // This is necessary because of possible jumps from implicit bodies inside - for (declaration in klass.declarations) { - when (declaration) { - is FirRegularClass -> { - prepareLocalClassForBodyResolve(declaration) - } - is FirCallableMemberDeclaration<*> -> { - withTypeParametersOf(declaration) { - prepareSignatureForBodyResolve(declaration) - declaration.transformStatus(transformer, declaration.resolveStatus(declaration.status, klass).mode()) - if (declaration is FirProperty) { - declaration.getter?.let { it.transformStatus(this, it.resolveStatus(it.status, klass).mode()) } - declaration.setter?.let { it.transformStatus(this, it.resolveStatus(it.status, klass).mode()) } - } - } - } - } - declaration.replaceResolvePhase(FirResolvePhase.STATUS) - } - if (klass is FirRegularClass) { - for (typeParameter in klass.typeParameters) { - typeParameter.replaceResolvePhase(FirResolvePhase.STATUS) - } - } - } - override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): CompositeTransformResult { if (regularClass.symbol.classId.isLocal && regularClass !in context.targetedLocalClasses) { return regularClass.runAllPhasesForLocalClass(components, data).also { @@ -316,10 +279,6 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) context.storeClass(regularClass) return withTypeParametersOf(regularClass) { - if (regularClass.symbol.classId.isLocal) { - prepareLocalClassForBodyResolve(regularClass) - } - val oldConstructorScope = primaryConstructorParametersScope val oldContainingClass = containingClass primaryConstructorParametersScope = null @@ -351,7 +310,6 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) return anonymousObject.runAllPhasesForLocalClass(components, data).compose() } - prepareLocalClassForBodyResolve(anonymousObject) val type = anonymousObject.defaultType() anonymousObject.resultType = buildResolvedTypeRef { source = anonymousObject.source diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt index 7885d4ac48e..b02db3b9202 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt @@ -7,12 +7,28 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.resolve.ResolutionMode +import org.jetbrains.kotlin.fir.resolve.transformers.runStatusResolveForLocalClass +import org.jetbrains.kotlin.fir.resolve.transformers.runSupertypeResolvePhaseForLocalClass +import org.jetbrains.kotlin.fir.resolve.transformers.runTypeResolvePhaseForLocalClass +import org.jetbrains.kotlin.fir.scopes.impl.createCurrentScopeList fun > F.runAllPhasesForLocalClass( components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, resolutionMode: ResolutionMode ): F { val localClassesNavigationInfo = collectLocalClassesNavigationInfo() + runSupertypeResolvePhaseForLocalClass( + components.session, + components.scopeSession, + components.createCurrentScopeList(), + localClassesNavigationInfo + ) + runTypeResolvePhaseForLocalClass( + components.session, + components.scopeSession, + components.createCurrentScopeList() + ) + runStatusResolveForLocalClass(components.session) runBodiesResolutionForLocalClass(components, resolutionMode, localClassesNavigationInfo) return this } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeResolveScopeForBodyResolve.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeResolveScopeForBodyResolve.kt index 945141b1ccf..1d4502cf2b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeResolveScopeForBodyResolve.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeResolveScopeForBodyResolve.kt @@ -14,13 +14,16 @@ class FirTypeResolveScopeForBodyResolve( private val components: BodyResolveComponents ) : FirIterableScope() { override val scopes: Iterable - get() = mutableListOf().apply { - addAll(components.localScopes.asReversed()) - components.implicitReceiverStack.receiversAsReversed().mapNotNullTo(this) { - (it as? ImplicitDispatchReceiverValue)?.implicitScope - } - - addAll(components.typeParametersScopes.asReversed()) - addAll(components.fileImportsScope.asReversed()) - } + get() = components.createCurrentScopeList() } + +fun BodyResolveComponents.createCurrentScopeList(): List = + mutableListOf().apply { + addAll(localScopes.asReversed()) + implicitReceiverStack.receiversAsReversed().mapNotNullTo(this) { + (it as? ImplicitDispatchReceiverValue)?.implicitScope + } + + addAll(typeParametersScopes.asReversed()) + addAll(fileImportsScope.asReversed()) + } diff --git a/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInMemberOfLocalClass.fir.kt b/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInMemberOfLocalClass.fir.kt index aecbf5dd376..c04d7e863a6 100644 --- a/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInMemberOfLocalClass.fir.kt +++ b/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInMemberOfLocalClass.fir.kt @@ -6,8 +6,8 @@ fun test(x: Any) { if (y !is String) return class Local { init { - x.length - y.length + x.length + y.length } } } diff --git a/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInitializer.fir.kt b/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInitializer.fir.kt index 361ec612108..e5654e7c87a 100644 --- a/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInitializer.fir.kt +++ b/compiler/testData/diagnostics/tests/dataFlow/local/LocalClassInitializer.fir.kt @@ -4,7 +4,7 @@ fun f(a: Any?) { if (a is B) { class C : X(a) { init { - a.foo() + a.foo() } } } @@ -13,4 +13,4 @@ fun f(a: Any?) { interface B { fun foo() {} } -open class X(b: B) \ No newline at end of file +open class X(b: B) diff --git a/compiler/testData/diagnostics/tests/dataFlow/local/NestedLocalClass.fir.kt b/compiler/testData/diagnostics/tests/dataFlow/local/NestedLocalClass.fir.kt index c94b2140ba6..3bc44509615 100644 --- a/compiler/testData/diagnostics/tests/dataFlow/local/NestedLocalClass.fir.kt +++ b/compiler/testData/diagnostics/tests/dataFlow/local/NestedLocalClass.fir.kt @@ -4,7 +4,7 @@ fun test(x: Any) { class LocalOuter { inner class Local { init { - x.length + x.length } } } diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.fir.kt index e3a2e94fcd8..abfb4754be7 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundLocal.fir.kt @@ -1,5 +1,5 @@ // !WITH_NEW_INFERENCE fun bar() { fun foo() {} - foo() + foo() }