FIR: Analyze return statements for implicit lambda with independent context

This commit is contained in:
Denis.Zharkov
2021-01-13 21:13:48 +03:00
parent 5e83e10a72
commit 0e368cc237
5 changed files with 47 additions and 10 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.sure
@@ -56,6 +57,8 @@ class BodyResolveContext(
@set:PrivateForInline
var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT
val anonymousFunctionsAnalyzedInDependentContext: MutableSet<FirFunctionSymbol<*>> = mutableSetOf()
@OptIn(PrivateForInline::class)
inline fun <R> withInferenceSession(inferenceSession: FirInferenceSession, block: () -> R): R {
val oldSession = this.inferenceSession
@@ -125,6 +128,16 @@ class BodyResolveContext(
}
}
@OptIn(PrivateForInline::class)
inline fun <R> withLambdaBeingAnalyzedInDependentContext(lambda: FirAnonymousFunctionSymbol, l: () -> R): R {
anonymousFunctionsAnalyzedInDependentContext.add(lambda)
return try {
l()
} finally {
anonymousFunctionsAnalyzedInDependentContext.remove(lambda)
}
}
@OptIn(PrivateForInline::class)
fun replaceTowerDataContext(newContext: FirTowerDataContext) {
towerDataContext = newContext
@@ -189,5 +202,6 @@ class BodyResolveContext(
towerDataContextForAnonymousFunctions.putAll(this@BodyResolveContext.towerDataContextForAnonymousFunctions)
containers = this@BodyResolveContext.containers
towerDataContext = this@BodyResolveContext.towerDataContext
anonymousFunctionsAnalyzedInDependentContext.addAll(this@BodyResolveContext.anonymousFunctionsAnalyzedInDependentContext)
}
}
@@ -342,6 +342,13 @@ open class FirBodyResolveTransformer(
return controlFlowStatementsTransformer.transformJump(jump, data)
}
override fun transformReturnExpression(
returnExpression: FirReturnExpression,
data: ResolutionMode
): CompositeTransformResult<FirStatement> {
return controlFlowStatementsTransformer.transformReturnExpression(returnExpression, data)
}
override fun transformThrowExpression(
throwExpression: FirThrowExpression,
data: ResolutionMode
@@ -187,18 +187,30 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
// ------------------------------- Jumps -------------------------------
override fun <E : FirTargetElement> transformJump(jump: FirJump<E>, data: ResolutionMode): CompositeTransformResult<FirStatement> {
val expectedTypeRef = (jump as? FirReturnExpression)?.target?.labeledElement?.returnTypeRef
val mode = if (expectedTypeRef != null) {
ResolutionMode.WithExpectedType(expectedTypeRef)
} else {
ResolutionMode.ContextIndependent
}
val result = transformer.transformExpression(jump, mode).single
val result = transformer.transformExpression(jump, data).single
dataFlowAnalyzer.exitJump(jump)
return result.compose()
}
override fun transformReturnExpression(
returnExpression: FirReturnExpression,
data: ResolutionMode
): CompositeTransformResult<FirStatement> {
val labeledElement = returnExpression.target.labeledElement
val expectedTypeRef = labeledElement.returnTypeRef
@Suppress("IntroduceWhenSubject")
val mode = when {
labeledElement.symbol in context.anonymousFunctionsAnalyzedInDependentContext -> {
ResolutionMode.ContextDependent
}
else -> {
ResolutionMode.WithExpectedType(expectedTypeRef)
}
}
return transformJump(returnExpression, mode)
}
override fun transformThrowExpression(
throwExpression: FirThrowExpression,
data: ResolutionMode
@@ -435,7 +435,11 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
fun transform(): FirAnonymousFunction {
val expectedReturnType =
lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef }
val result = transformFunction(anonymousFunction, withExpectedType(expectedReturnType)).single as FirAnonymousFunction
val result = context.withLambdaBeingAnalyzedInDependentContext(anonymousFunction.symbol) {
transformFunction(anonymousFunction, withExpectedType(expectedReturnType)).single as FirAnonymousFunction
}
val body = result.body
if (result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(transformer, withExpectedType(body.resultType))
@@ -3,7 +3,7 @@
fun testLambda() {
val basicTest: (Int) -> Int = myRun {
val x: Any? = null
if (x is String) return@myRun { it -> x.length <!AMBIGUITY!>+<!> it }
if (x is String) return@myRun { it -> x.length + it }
if (x !is Int) return@myRun { it -> it }
{ it -> x + it }