From cdd7e418919d4b704103f6397af62c0ba23ca64b Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 20 Mar 2020 16:43:16 +0300 Subject: [PATCH] FIR: Support proper implicit return type computation for local classes --- .../expresssions/localImplicitBodies.txt | 12 +- .../expresssions/outerMemberAccesses.txt | 2 +- .../localClasses/implicitInAnonymous.kt | 16 +++ .../localClasses/implicitInAnonymous.txt | 35 +++++ .../localClasses/implicitInLocalClasses.kt | 37 +++++ .../localClasses/implicitInLocalClasses.txt | 75 ++++++++++ .../fir/FirDiagnosticsTestGenerated.java | 23 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 23 +++ .../FirAbstractBodyResolveTransformer.kt | 21 ++- .../FirDeclarationsResolveTransformer.kt | 27 +++- .../body/resolve/FirImplicitBodyResolve.kt | 136 +++++++++++++++--- ...localReturnInsidePropertyAccessor.fir.fail | 2 - .../testData/ir/irText/classes/enum.fir.txt | 3 +- .../multipleThisReferences.fir.txt | 3 +- 14 files changed, 377 insertions(+), 38 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt delete mode 100644 compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.fir.fail diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/localImplicitBodies.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/localImplicitBodies.txt index 234040302f6..c157f059d60 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/localImplicitBodies.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/localImplicitBodies.txt @@ -5,11 +5,8 @@ FILE: localImplicitBodies.kt super() } - public final fun sss(): { - ^abc IntegerLiteral(1) -} -> { - ^sss R?C|/anonymous.abc|() + public final fun sss(): R|kotlin/Int| { + ^sss this@R|/anonymous|.R|/anonymous.abc|() } public final fun abc(): R|kotlin/Int| { @@ -18,8 +15,5 @@ FILE: localImplicitBodies.kt } - lval g: { - ^abc IntegerLiteral(1) -} -> = R|/x|.R?C|/anonymous.sss|() + lval g: R|kotlin/Int| = R|/x|.R|/anonymous.sss|() } diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/outerMemberAccesses.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/outerMemberAccesses.txt index bbb604d4e3d..39eafdaf70d 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/outerMemberAccesses.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/outerMemberAccesses.txt @@ -45,7 +45,7 @@ FILE: O.kt super() } - public final val zz: R|kotlin/Boolean| = R|/z| + public final val zz: R|kotlin/Boolean| = this@R|/O.Derived.Some|.R|/O.Derived.Some.z| public get(): R|kotlin/Boolean| } diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt new file mode 100644 index 00000000000..aff8a65f696 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt @@ -0,0 +1,16 @@ +private val x = object { + fun foo(x: Int) = /* here we have not computed return type for "bar" */bar(x) + fun bar(y: Int) = this.hashCode() + y > 0 + + val w get() = z + val z get() = this.hashCode() == 0 +} + +fun useBoolean(b: Boolean) {} + +fun main() { + useBoolean(x.foo(1)) + useBoolean(x.bar(2)) + useBoolean(x.w) + useBoolean(x.z) +} diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.txt b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.txt new file mode 100644 index 00000000000..10e344bc8fc --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.txt @@ -0,0 +1,35 @@ +FILE: implicitInAnonymous.kt + private final val x: R|anonymous| = object : R|kotlin/Any| { + private constructor(): R|anonymous| { + super() + } + + public final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| { + ^foo this@R|/anonymous|.R|/anonymous.bar|(R|/x|) + } + + public final fun bar(y: R|kotlin/Int|): R|kotlin/Boolean| { + ^bar CMP(>, this@R|/anonymous|.R|kotlin/Any.hashCode|().R|kotlin/Int.plus|(R|/y|).R|kotlin/Int.compareTo|(Int(0))) + } + + public final val w: R|kotlin/Boolean| + public get(): R|kotlin/Boolean| { + ^ this@R|/anonymous|.R|/anonymous.z| + } + + public final val z: R|kotlin/Boolean| + public get(): R|kotlin/Boolean| { + ^ ==(this@R|/anonymous|.R|kotlin/Any.hashCode|(), Int(0)) + } + + } + + private get(): R|anonymous| + public final fun useBoolean(b: R|kotlin/Boolean|): R|kotlin/Unit| { + } + public final fun main(): R|kotlin/Unit| { + R|/useBoolean|(R|/x|.R|/anonymous.foo|(Int(1))) + R|/useBoolean|(R|/x|.R|/anonymous.bar|(Int(2))) + R|/useBoolean|(R|/x|.R|/anonymous.w|) + R|/useBoolean|(R|/x|.R|/anonymous.z|) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt new file mode 100644 index 00000000000..b26a2ffd4ad --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt @@ -0,0 +1,37 @@ +fun useBoolean(b: Boolean) {} + +fun main() { + class A { + fun foo(x: Int) = bar(x) + fun bar(y: Int) = this.hashCode() + y > 0 + + val w get() = z + val z get() = this.hashCode() == 0 + } + + val a = A() + + useBoolean(a.foo(1)) + useBoolean(a.bar(1)) + useBoolean(a.w) + useBoolean(a.z) + + class B { + fun foo(x: Int) = inner.w + fun bar(y: Int) = this.hashCode() + y > 0 + + val inner = Inner() + + inner class Inner { + val w get() = z + val z get() = bar(1) + } + } + + val b = B() + + useBoolean(b.foo(1)) + useBoolean(b.bar(1)) + useBoolean(b.inner.w) + useBoolean(b.inner.z) +} diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt new file mode 100644 index 00000000000..fc2b082a662 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.txt @@ -0,0 +1,75 @@ +FILE: implicitInLocalClasses.kt + public final fun useBoolean(b: R|kotlin/Boolean|): R|kotlin/Unit| { + } + public final fun main(): R|kotlin/Unit| { + local final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public 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| { + ^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 get(): R|kotlin/Boolean| { + ^ this@R|/A|.R|/A.z| + } + + public final val z: R|kotlin/Boolean| + public get(): R|kotlin/Boolean| { + ^ ==(this@R|/A|.R|kotlin/Any.hashCode|(), Int(0)) + } + + } + + lval a: R|A| = R|/A.A|() + R|/useBoolean|(R|/a|.R|/A.foo|(Int(1))) + R|/useBoolean|(R|/a|.R|/A.bar|(Int(1))) + 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| { + super() + } + + public 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| { + ^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 get(): R|B.Inner| + + local final inner class Inner : R|kotlin/Any| { + public constructor(): R|B.Inner| { + super() + } + + public 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 get(): R|kotlin/Boolean| { + ^ this@R|/B|.R|/B.bar|(Int(1)) + } + + } + + } + + lval b: R|B| = R|/B.B|() + R|/useBoolean|(R|/b|.R|/B.foo|(Int(1))) + R|/useBoolean|(R|/b|.R|/B.bar|(Int(1))) + R|/useBoolean|(R|/b|.R|/B.inner|.R|/B.Inner.w|) + R|/useBoolean|(R|/b|.R|/B.inner|.R|/B.Inner.z|) + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 98643e10dc8..6217844f5a5 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -1314,6 +1314,29 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { } } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/localClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalClasses extends AbstractFirDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInLocalClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("implicitInAnonymous.kt") + public void testImplicitInAnonymous() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt"); + } + + @TestMetadata("implicitInLocalClasses.kt") + public void testImplicitInLocalClasses() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/multifile") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index b542ccdd78b..ae55327956c 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1314,6 +1314,29 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos } } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/localClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalClasses extends AbstractFirDiagnosticsWithLightTreeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInLocalClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("implicitInAnonymous.kt") + public void testImplicitInAnonymous() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt"); + } + + @TestMetadata("implicitInLocalClasses.kt") + public void testImplicitInLocalClasses() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInLocalClasses.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/multifile") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt index 8c3d6e92e88..2d79e068d71 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt @@ -99,7 +99,10 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb else -> null } - class BodyResolveContext(val returnTypeCalculator: ReturnTypeCalculator) { + class BodyResolveContext( + val returnTypeCalculator: ReturnTypeCalculator, + val targetedLocalClasses: Set> = emptySet() + ) { val fileImportsScope: MutableList = mutableListOf() @set:PrivateForInline @@ -189,13 +192,27 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb val lastScope = localScopes.lastOrNull() ?: return localScopes = localScopes.set(localScopes.size - 1, lastScope.transform()) } + + @OptIn(PrivateForInline::class) + fun createSnapshotForLocalClasses( + returnTypeCalculator: ReturnTypeCalculator, + targetedLocalClasses: Set> + ) = BodyResolveContext(returnTypeCalculator, targetedLocalClasses).apply { + fileImportsScope.addAll(this@BodyResolveContext.fileImportsScope) + typeParametersScopes = this@BodyResolveContext.typeParametersScopes + localScopes = this@BodyResolveContext.localScopes + file = this@BodyResolveContext.file + implicitReceiverStack = this@BodyResolveContext.implicitReceiverStack + localContextForAnonymousFunctions.putAll(this@BodyResolveContext.localContextForAnonymousFunctions) + containerIfAny = this@BodyResolveContext.containerIfAny + } } class BodyResolveTransformerComponents( override val session: FirSession, override val scopeSession: ScopeSession, val transformer: FirBodyResolveTransformer, - private val context: BodyResolveContext + val context: BodyResolveContext ) : BodyResolveComponents { override val fileImportsScope: List get() = context.fileImportsScope override val typeParametersScopes: List get() = context.typeParametersScopes 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 6eaf893b5b5..e4cf8846006 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 @@ -309,6 +309,14 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) } override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): CompositeTransformResult { + if (regularClass.symbol.classId.isLocal && regularClass !in context.targetedLocalClasses) { + return FirImplicitTypeBodyResolveTransformerAdapterForLocalClasses( + components, data + ).transformRegularClass(regularClass, null).also { + context.storeClass(regularClass) + } + } + context.storeClass(regularClass) return withTypeParametersOf(regularClass) { if (regularClass.symbol.classId.isLocal) { @@ -338,7 +346,16 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) } } - override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: ResolutionMode): CompositeTransformResult { + override fun transformAnonymousObject( + anonymousObject: FirAnonymousObject, + data: ResolutionMode + ): CompositeTransformResult { + if (anonymousObject !in context.targetedLocalClasses) { + return FirImplicitTypeBodyResolveTransformerAdapterForLocalClasses( + components, data + ).transformAnonymousObject(anonymousObject, null) + } + prepareLocalClassForBodyResolve(anonymousObject) val type = anonymousObject.defaultType() anonymousObject.resultType = buildResolvedTypeRef { @@ -640,17 +657,17 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) ): T { val (implicitReceiverValue, implicitCompanionValues) = components.collectImplicitReceivers(type, owner) implicitCompanionValues.forEach { value -> - implicitReceiverStack.add(null, value) + context.implicitReceiverStack.add(null, value) } - implicitReceiverValue?.let { implicitReceiverStack.add(labelName, it) } + implicitReceiverValue?.let { context.implicitReceiverStack.add(labelName, it) } try { return block() } finally { if (type != null) { - implicitReceiverStack.pop(labelName) + context.implicitReceiverStack.pop(labelName) for (i in implicitCompanionValues.indices) - implicitReceiverStack.pop(null) + context.implicitReceiverStack.pop(null) } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt index ae1d1b4253e..152b4394513 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt @@ -7,12 +7,14 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve +import kotlinx.collections.immutable.persistentListOf import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind +import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ScopeSession @@ -25,6 +27,7 @@ import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult +import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.compose @@ -51,6 +54,95 @@ class FirImplicitTypeBodyResolveTransformerAdapter(private val scopeSession: Sco } } +class FirImplicitTypeBodyResolveTransformerAdapterForLocalClasses( + private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, + private val resolutionMode: ResolutionMode, +) : FirTransformer() { + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + return element.compose() + } + + override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult { + return transformClass(regularClass, data) + } + + override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Nothing?): CompositeTransformResult { + return transformClass(anonymousObject, data) + } + + override fun > transformClass(klass: FirClass, data: Nothing?): CompositeTransformResult { + val (designationMap, targetedClasses) = CollectingVisitor().run { + visitClass(klass) + resultingMap to targetedClasses + } + + val implicitBodyResolveComputationSession = + ((components.returnTypeCalculator as? ReturnTypeCalculatorWithJump)?.implicitBodyResolveComputationSession + ?: ImplicitBodyResolveComputationSession()) + val returnTypeCalculator = ReturnTypeCalculatorWithJump( + components.session, + components.scopeSession, + implicitBodyResolveComputationSession, + designationMap, + ) + + val newContext = components.context.createSnapshotForLocalClasses(returnTypeCalculator, targetedClasses) + returnTypeCalculator.outerBodyResolveContext = newContext + + val transformer = FirImplicitAwareBodyResolveTransformer( + components.session, components.scopeSession, + implicitBodyResolveComputationSession, + FirResolvePhase.BODY_RESOLVE, + outerBodyResolveContext = newContext, + implicitTypeOnly = false, + returnTypeCalculator + ) + + return klass.transform(transformer, resolutionMode) + } +} + +private class CollectingVisitor : FirDefaultVisitorVoid() { + val resultingMap = mutableMapOf, List>>() + val targetedClasses = mutableSetOf>() + private var currentPath = persistentListOf>() + + override fun visitElement(element: FirElement) {} + + override fun visitRegularClass(regularClass: FirRegularClass) { + visitClass(regularClass) + } + + override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) { + visitClass(anonymousObject) + } + + override fun > visitClass(klass: FirClass) { + targetedClasses.add(klass) + val prev = currentPath + currentPath = currentPath.add(klass) + + klass.acceptChildren(this) + + currentPath = prev + } + + override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) { + visitCallableMemberDeclaration(simpleFunction) + } + + override fun visitProperty(property: FirProperty) { + visitCallableMemberDeclaration(property) + } + + override fun > visitCallableMemberDeclaration( + callableMemberDeclaration: FirCallableMemberDeclaration + ) { + if (callableMemberDeclaration.returnTypeRef !is FirImplicitTypeRef) return + resultingMap[callableMemberDeclaration] = currentPath + } +} + fun createReturnTypeCalculatorForIDE(session: FirSession, scopeSession: ScopeSession): ReturnTypeCalculator = ReturnTypeCalculatorWithJump(session, scopeSession, ImplicitBodyResolveComputationSession()) @@ -105,7 +197,7 @@ private open class FirImplicitAwareBodyResolveTransformer( require(status is ImplicitBodyResolveComputationStatus.NotComputed) { "Unexpected status in transformCallableMember ($status) for ${member.render()}" } - + implicitBodyResolveComputationSession.startComputing(symbol) val result = transform() implicitBodyResolveComputationSession.storeResult(symbol, result.single) @@ -117,9 +209,12 @@ private open class FirImplicitAwareBodyResolveTransformer( private class ReturnTypeCalculatorWithJump( private val session: FirSession, private val scopeSession: ScopeSession, - private val implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession + val implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession, + val designationMapForLocalClasses: Map, List>> = mapOf() ) : ReturnTypeCalculator { + var outerBodyResolveContext: FirAbstractBodyResolveTransformer.BodyResolveContext? = null + override fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef { if (declaration is FirValueParameter && declaration.returnTypeRef is FirImplicitTypeRef) { // TODO? @@ -150,29 +245,36 @@ private class ReturnTypeCalculatorWithJump( val provider = session.firProvider - val file = provider.getFirCallableContainerFile(symbol) + val (designation, outerBodyResolveContext) = if (declaration in designationMapForLocalClasses) { + designationMapForLocalClasses.getValue(declaration) to outerBodyResolveContext + } else { + val file = provider.getFirCallableContainerFile(symbol) - val outerClasses = generateSequence(id.classId) { classId -> - classId.outerClassId - }.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) } + val outerClasses = generateSequence(id.classId) { classId -> + classId.outerClassId + }.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) } - if (file == null || outerClasses.any { it == null }) { - return buildErrorTypeRef { - diagnostic = ConeSimpleDiagnostic( - "Cannot calculate return type (local class/object?)", - DiagnosticKind.InferenceError - ) + if (file == null || outerClasses.any { it == null }) { + return buildErrorTypeRef { + diagnostic = ConeSimpleDiagnostic( + "Cannot calculate return type (local class/object?)", + DiagnosticKind.InferenceError + ) + } } + (listOf(file) + outerClasses.filterNotNull().asReversed()) to null } - val designation = (listOf(file) + outerClasses.filterNotNull().asReversed() + listOf(declaration)) + val transformer = FirDesignatedBodyResolveTransformerForReturnTypeCalculator( - designation.iterator(), - file.session, + (designation.drop(1) + declaration).iterator(), + session, scopeSession, - implicitBodyResolveComputationSession + implicitBodyResolveComputationSession, + this, + outerBodyResolveContext ) - file.transform(transformer, ResolutionMode.ContextDependent) + designation.first().transform(transformer, ResolutionMode.ContextDependent) val transformedDeclaration = transformer.lastResult as? FirCallableMemberDeclaration<*> ?: error("Unexpected lastResult: ${transformer.lastResult?.render()}") diff --git a/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.fir.fail b/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.fir.fail deleted file mode 100644 index 08fa1008153..00000000000 --- a/compiler/testData/diagnostics/tests/controlStructures/localReturnInsidePropertyAccessor.fir.fail +++ /dev/null @@ -1,2 +0,0 @@ -Failures detected in FirImplicitTypeBodyResolveTransformerAdapter, file: /localReturnInsidePropertyAccessor.fir.kt -Cause: java.lang.NullPointerException diff --git a/compiler/testData/ir/irText/classes/enum.fir.txt b/compiler/testData/ir/irText/classes/enum.fir.txt index caf33d7ae9a..e4f4e7d7af2 100644 --- a/compiler/testData/ir/irText/classes/enum.fir.txt +++ b/compiler/testData/ir/irText/classes/enum.fir.txt @@ -258,7 +258,8 @@ FILE fqName: fileName:/enum.kt BLOCK_BODY SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:z type:kotlin.Int visibility:private [final]' type=kotlin.Unit origin=null receiver: GET_VAR ': .TestEnum4.TEST2 declared in .TestEnum4.TEST2' type=.TestEnum4.TEST2 origin=null - value: GET_VAR 'x: kotlin.Int declared in .TestEnum4.' type=kotlin.Int origin=null + value: CALL 'public final fun (): kotlin.Int declared in .TestEnum4' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR ': .TestEnum4.TEST2 declared in .TestEnum4.TEST2' type=.TestEnum4.TEST2 origin=null FUN name:foo visibility:public modality:FINAL <> ($this:.TestEnum4.TEST2) returnType:kotlin.Unit $this: VALUE_PARAMETER name: type:.TestEnum4.TEST2 BLOCK_BODY diff --git a/compiler/testData/ir/irText/expressions/multipleThisReferences.fir.txt b/compiler/testData/ir/irText/expressions/multipleThisReferences.fir.txt index d9ee6b7df31..de0355b4fa0 100644 --- a/compiler/testData/ir/irText/expressions/multipleThisReferences.fir.txt +++ b/compiler/testData/ir/irText/expressions/multipleThisReferences.fir.txt @@ -87,7 +87,8 @@ FILE fqName: fileName:/multipleThisReferences.kt CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS $this: CALL 'public final fun (): kotlin.Int declared in .Outer.Inner' type=kotlin.Int origin=GET_PROPERTY $this: GET_VAR ': .Host.test. declared in .Host.test.' type=.Host.test. origin=null - other: GET_VAR 'y: kotlin.Int declared in .Host.' type=kotlin.Int origin=null + other: CALL 'public final fun (): kotlin.Int declared in .Host' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR ': .Host declared in .Host.test' type=.Host origin=null FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.Host.test.) returnType:kotlin.Int correspondingProperty: PROPERTY name:xx visibility:public modality:FINAL [val] $this: VALUE_PARAMETER name: type:.Host.test.