From b691b13d8e3e9a448ef6bddda3da7ba618ee1daf Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 14 May 2020 11:39:18 +0300 Subject: [PATCH] FIR: Add separate local scopes for blocks --- .../resolve/expresssions/blockLocalScopes.kt | 16 ++++++++++ .../resolve/expresssions/blockLocalScopes.txt | 32 +++++++++++++++++++ .../fir/FirDiagnosticsTestGenerated.java | 5 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 5 +++ .../body/resolve/FirBodyResolveTransformer.kt | 2 +- ...ControlFlowStatementsResolveTransformer.kt | 15 ++++++--- .../FirExpressionsResolveTransformer.kt | 10 +++++- .../nameClashAcrossDifferentContainers.kt | 2 -- .../initializationInLambda.fir.kt | 4 +-- 9 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.txt diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt new file mode 100644 index 00000000000..e08901b5a9f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.kt @@ -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 + } + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.txt new file mode 100644 index 00000000000..43fc1a966cc --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/blockLocalScopes.txt @@ -0,0 +1,32 @@ +FILE: blockLocalScopes.kt + public final class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + public final fun append(): R|kotlin/Unit| { + } + + } + public final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + 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|/w| -> { + lval message: R|kotlin/String| = String() + R|/message|.R|kotlin/Any.toString|() + } + else -> { + this@R|/A|.R|/A.message|.R|/B.append|() + } + } + + } + + } 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 13484d42b52..15852866e1c 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 @@ -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"); 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 f0cf45eb59d..b2394bce511 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 @@ -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"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 968009df9cc..0942616d0f1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt index 47613b4a126..1ee42e89384 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirControlFlowStatementsResolveTransformer.kt @@ -40,10 +40,17 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran } override fun transformDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: ResolutionMode): CompositeTransformResult { - 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 ------------------------------- diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 0a322e0b375..b057f06750a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -191,6 +191,14 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : } override fun transformBlock(block: FirBlock, data: ResolutionMode): CompositeTransformResult { + 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( diff --git a/compiler/testData/codegen/box/functions/localFunctions/nameClashAcrossDifferentContainers.kt b/compiler/testData/codegen/box/functions/localFunctions/nameClashAcrossDifferentContainers.kt index 9033dbb2c9e..20e8ec52a1f 100644 --- a/compiler/testData/codegen/box/functions/localFunctions/nameClashAcrossDifferentContainers.kt +++ b/compiler/testData/codegen/box/functions/localFunctions/nameClashAcrossDifferentContainers.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR - var result = "" fun overload() { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLambda.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLambda.fir.kt index 5af20bee534..d08d21af1f0 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/initializationInLambda.fir.kt @@ -70,8 +70,8 @@ class Your { val z = if (true) { val xx: Int exec { - xx = 24 + xx = 24 } 42 } -else 0 \ No newline at end of file +else 0