FIR: Support proper implicit return type computation for local classes
This commit is contained in:
+3
-9
@@ -5,11 +5,8 @@ FILE: localImplicitBodies.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun sss(): <ERROR TYPE REF: Cannot calculate return type during full-body resolution (local class/object?): public final fun abc(): <implicit> {
|
||||
^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: <ERROR TYPE REF: Cannot calculate return type during full-body resolution (local class/object?): public final fun abc(): <implicit> {
|
||||
^abc IntegerLiteral(1)
|
||||
}
|
||||
> = R|<local>/x|.R?C|/anonymous.sss|()
|
||||
lval g: R|kotlin/Int| = R|<local>/x|.R|/anonymous.sss|()
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ FILE: O.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val zz: R|kotlin/Boolean| = R|<local>/z|
|
||||
public final val zz: R|kotlin/Boolean| = this@R|/O.Derived.Some|.R|/O.Derived.Some.z|
|
||||
public get(): R|kotlin/Boolean|
|
||||
|
||||
}
|
||||
|
||||
+16
@@ -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)
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
FILE: implicitInAnonymous.kt
|
||||
private final val x: R|anonymous| = object : R|kotlin/Any| {
|
||||
private constructor(): R|anonymous| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| {
|
||||
^foo this@R|/anonymous|.R|/anonymous.bar|(R|<local>/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|<local>/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|)
|
||||
}
|
||||
+37
@@ -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)
|
||||
}
|
||||
+75
@@ -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<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun foo(x: R|kotlin/Int|): R|kotlin/Boolean| {
|
||||
^foo this@R|/A|.R|/A.bar|(R|<local>/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|<local>/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|<local>/a|.R|/A.foo|(Int(1)))
|
||||
R|/useBoolean|(R|<local>/a|.R|/A.bar|(Int(1)))
|
||||
R|/useBoolean|(R|<local>/a|.R|/A.w|)
|
||||
R|/useBoolean|(R|<local>/a|.R|/A.z|)
|
||||
local final class B : R|kotlin/Any| {
|
||||
public constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
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|<local>/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<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
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|<local>/b|.R|/B.foo|(Int(1)))
|
||||
R|/useBoolean|(R|<local>/b|.R|/B.bar|(Int(1)))
|
||||
R|/useBoolean|(R|<local>/b|.R|/B.inner|.R|/B.Inner.w|)
|
||||
R|/useBoolean|(R|<local>/b|.R|/B.inner|.R|/B.Inner.z|)
|
||||
}
|
||||
Generated
+23
@@ -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)
|
||||
|
||||
+23
@@ -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)
|
||||
|
||||
+19
-2
@@ -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<FirClass<*>> = emptySet()
|
||||
) {
|
||||
val fileImportsScope: MutableList<FirScope> = 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<FirClass<*>>
|
||||
) = 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<FirScope> get() = context.fileImportsScope
|
||||
override val typeParametersScopes: List<FirScope> get() = context.typeParametersScopes
|
||||
|
||||
+22
-5
@@ -309,6 +309,14 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
|
||||
}
|
||||
|
||||
override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): CompositeTransformResult<FirStatement> {
|
||||
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<FirStatement> {
|
||||
override fun transformAnonymousObject(
|
||||
anonymousObject: FirAnonymousObject,
|
||||
data: ResolutionMode
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+119
-17
@@ -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<Nothing?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
return element.compose()
|
||||
}
|
||||
|
||||
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||
return transformClass(regularClass, data)
|
||||
}
|
||||
|
||||
override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||
return transformClass(anonymousObject, data)
|
||||
}
|
||||
|
||||
override fun <F : FirClass<F>> transformClass(klass: FirClass<F>, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||
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<FirCallableMemberDeclaration<*>, List<FirClass<*>>>()
|
||||
val targetedClasses = mutableSetOf<FirClass<*>>()
|
||||
private var currentPath = persistentListOf<FirClass<*>>()
|
||||
|
||||
override fun visitElement(element: FirElement) {}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass) {
|
||||
visitClass(regularClass)
|
||||
}
|
||||
|
||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) {
|
||||
visitClass(anonymousObject)
|
||||
}
|
||||
|
||||
override fun <F : FirClass<F>> visitClass(klass: FirClass<F>) {
|
||||
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 <F : FirCallableMemberDeclaration<F>> visitCallableMemberDeclaration(
|
||||
callableMemberDeclaration: FirCallableMemberDeclaration<F>
|
||||
) {
|
||||
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<FirCallableMemberDeclaration<*>, List<FirClass<*>>> = 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<FirElement, ResolutionMode>(transformer, ResolutionMode.ContextDependent)
|
||||
designation.first().transform<FirElement, ResolutionMode>(transformer, ResolutionMode.ContextDependent)
|
||||
|
||||
val transformedDeclaration = transformer.lastResult as? FirCallableMemberDeclaration<*>
|
||||
?: error("Unexpected lastResult: ${transformer.lastResult?.render()}")
|
||||
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
Failures detected in FirImplicitTypeBodyResolveTransformerAdapter, file: /localReturnInsidePropertyAccessor.fir.kt
|
||||
Cause: java.lang.NullPointerException
|
||||
+2
-1
@@ -258,7 +258,8 @@ FILE fqName:<root> 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 '<this>: <root>.TestEnum4.TEST2 declared in <root>.TestEnum4.TEST2' type=<root>.TestEnum4.TEST2 origin=null
|
||||
value: GET_VAR 'x: kotlin.Int declared in <root>.TestEnum4.<init>' type=kotlin.Int origin=null
|
||||
value: CALL 'public final fun <get-x> (): kotlin.Int declared in <root>.TestEnum4' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: GET_VAR '<this>: <root>.TestEnum4.TEST2 declared in <root>.TestEnum4.TEST2' type=<root>.TestEnum4.TEST2 origin=null
|
||||
FUN name:foo visibility:public modality:FINAL <> ($this:<root>.TestEnum4.TEST2) returnType:kotlin.Unit
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.TestEnum4.TEST2
|
||||
BLOCK_BODY
|
||||
|
||||
@@ -87,7 +87,8 @@ FILE fqName:<root> 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 <get-x> (): kotlin.Int declared in <root>.Outer.Inner' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: GET_VAR '<this>: <root>.Host.test.<no name provided> declared in <root>.Host.test.<no name provided>' type=<root>.Host.test.<no name provided> origin=null
|
||||
other: GET_VAR 'y: kotlin.Int declared in <root>.Host.<init>' type=kotlin.Int origin=null
|
||||
other: CALL 'public final fun <get-y> (): kotlin.Int declared in <root>.Host' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: GET_VAR '<this>: <root>.Host declared in <root>.Host.test' type=<root>.Host origin=null
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-xx> visibility:public modality:FINAL <> ($this:<root>.Host.test.<no name provided>) returnType:kotlin.Int
|
||||
correspondingProperty: PROPERTY name:xx visibility:public modality:FINAL [val]
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.Host.test.<no name provided>
|
||||
|
||||
Reference in New Issue
Block a user