FIR: Add separate local scopes for blocks

This commit is contained in:
Denis Zharkov
2020-05-14 11:39:18 +03:00
parent b084399b58
commit b691b13d8e
9 changed files with 81 additions and 10 deletions
@@ -0,0 +1,16 @@
class B {
fun append() {}
}
class A {
val message = B()
fun foo(w: Boolean) {
if (w) {
val message = ""
message.toString()
} else {
message.append() // message here should relate to the class-level property
}
}
}
@@ -0,0 +1,32 @@
FILE: blockLocalScopes.kt
public final class B : R|kotlin/Any| {
public constructor(): R|B| {
super<R|kotlin/Any|>()
}
public final fun append(): R|kotlin/Unit| {
}
}
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final val message: R|B| = R|/B.B|()
public get(): R|B|
public final fun foo(w: R|kotlin/Boolean|): R|kotlin/Unit| {
when () {
R|<local>/w| -> {
lval message: R|kotlin/String| = String()
R|<local>/message|.R|kotlin/Any.toString|()
}
else -> {
this@R|/A|.R|/A.message|.R|/B.append|()
}
}
}
}
@@ -909,6 +909,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/baseQualifier.kt");
}
@TestMetadata("blockLocalScopes.kt")
public void testBlockLocalScopes() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt");
}
@TestMetadata("CallBasedInExpressionGenerator.kt")
public void testCallBasedInExpressionGenerator() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/CallBasedInExpressionGenerator.kt");
@@ -909,6 +909,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/baseQualifier.kt");
}
@TestMetadata("blockLocalScopes.kt")
public void testBlockLocalScopes() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt");
}
@TestMetadata("CallBasedInExpressionGenerator.kt")
public void testCallBasedInExpressionGenerator() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/expresssions/CallBasedInExpressionGenerator.kt");
@@ -39,7 +39,7 @@ open class FirBodyResolveTransformer(
final override val components: BodyResolveTransformerComponents =
BodyResolveTransformerComponents(session, scopeSession, this, context)
private val expressionsTransformer = FirExpressionsResolveTransformer(this)
internal val expressionsTransformer = FirExpressionsResolveTransformer(this)
protected open val declarationsTransformer = FirDeclarationsResolveTransformer(this)
private val controlFlowStatementsTransformer = FirControlFlowStatementsResolveTransformer(this)
@@ -40,10 +40,17 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
}
override fun transformDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: ResolutionMode): CompositeTransformResult<FirStatement> {
return doWhileLoop.also(dataFlowAnalyzer::enterDoWhileLoop)
.transformBlock(transformer, data).also(dataFlowAnalyzer::enterDoWhileLoopCondition)
.transformCondition(transformer, data).also(dataFlowAnalyzer::exitDoWhileLoop)
.transformOtherChildren(transformer, data).compose()
// Do-while has a specific scope structure (its block and condition effectively share the scope)
return withNewLocalScope {
doWhileLoop.also(dataFlowAnalyzer::enterDoWhileLoop)
.apply {
transformer.expressionsTransformer.transformBlockInCurrentScope(block, data)
dataFlowAnalyzer
}
.also(dataFlowAnalyzer::enterDoWhileLoopCondition).transformCondition(transformer, data)
.also(dataFlowAnalyzer::exitDoWhileLoop)
.transformOtherChildren(transformer, data).compose()
}
}
// ------------------------------- When expressions -------------------------------
@@ -191,6 +191,14 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
}
override fun transformBlock(block: FirBlock, data: ResolutionMode): CompositeTransformResult<FirStatement> {
withNewLocalScope {
transformBlockInCurrentScope(block, data)
}
return block.compose()
}
internal fun transformBlockInCurrentScope(block: FirBlock, data: ResolutionMode) {
dataFlowAnalyzer.enterBlock(block)
val numberOfStatements = block.statements.size
@@ -220,8 +228,8 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
diagnostic = ConeSimpleDiagnostic("No type for block", DiagnosticKind.InferenceError)
}
}
dataFlowAnalyzer.exitBlock(block)
return block.compose()
}
override fun transformThisReceiverExpression(
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
var result = ""
fun overload() {
@@ -70,8 +70,8 @@ class Your {
val z = if (true) {
val xx: Int
exec {
<!UNRESOLVED_REFERENCE!>xx<!> = 24
xx = 24
}
42
}
else 0
else 0