From 2796d21ec6859b8f4ebcef8329f67bbf3121b1ab Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 9 May 2022 14:08:50 +0300 Subject: [PATCH] [FIR] Create snapshot of tower data context for postponed callable referneces This fixes an issue if type of some implicit receiver was changed because of changed smartcast in outer scope ^KT-51228 Fixed --- ...nosisCompilerFirTestdataTestGenerated.java | 6 +++ ...TouchedTilContractsPhaseTestGenerated.java | 5 +++ ...mplicitReceiverOfCallableReference.fir.txt | 39 +++++++++++++++++++ ...stOnImplicitReceiverOfCallableReference.kt | 31 +++++++++++++++ .../runners/FirDiagnosticTestGenerated.java | 6 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 +++ .../kotlin/fir/resolve/calls/FirReceivers.kt | 2 +- .../body/resolve/BodyResolveContext.kt | 2 +- 8 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index 182e5877db6..609bcea3c55 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -3741,6 +3741,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastInByClause.kt"); } + @Test + @TestMetadata("smartcastOnImplicitReceiverOfCallableReference.kt") + public void testSmartcastOnImplicitReceiverOfCallableReference() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt"); + } + @Test @TestMetadata("smartcastToNothing.kt") public void testSmartcastToNothing() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 0be5b64181b..74b2fbf6855 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -3302,6 +3302,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastInByClause.kt"); } + @TestMetadata("smartcastOnImplicitReceiverOfCallableReference.kt") + public void testSmartcastOnImplicitReceiverOfCallableReference() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt"); + } + @TestMetadata("smartcastToNothing.kt") public void testSmartcastToNothing() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToNothing.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.fir.txt new file mode 100644 index 00000000000..637497b811e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.fir.txt @@ -0,0 +1,39 @@ +FILE: smartcastOnImplicitReceiverOfCallableReference.kt + public abstract interface A : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public final fun R|kotlin/Any|.test_1(): R|kotlin/Unit| { + when (this@R|/test_1|) { + ($subj$ is R|A|) -> { + this@R|/test_1|.R|/A.foo|() + ::R|/A.foo| + } + else -> { + throw R|java/lang/Exception.Exception|() + } + } + + } + public final fun R|kotlin/Any|.test_2(): R|kotlin/Unit| { + when (this@R|/test_2|) { + ($subj$ is R|A|) -> { + this@R|/test_2|.R|/A.foo|() + fun (): R|kotlin/Unit| { + this@R|/test_2|.R|/A.foo|() + } + + } + else -> { + } + } + + } + public final fun R|kotlin/Any|.test_3(): R|kotlin/Unit| { + when () { + (this@R|/test_3| is R|A|) -> { + lval f: R|kotlin/reflect/KFunction0| = ::R|/A.foo| + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt new file mode 100644 index 00000000000..cfee20387d2 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt @@ -0,0 +1,31 @@ +// ISSUE: KT-51228 + +interface A { + fun foo() +} + +fun Any.test_1() { + when(this) { + is A -> { + foo() // ok + ::foo // UNRESOLVED_REFERENCE, should be ok + } + else -> throw Exception() + } +} + +fun Any.test_2() { + when(this) { + is A -> { + foo(); // ok + { foo() } + } + else -> {} + } +} + +fun Any.test_3() { + if (this is A) { + val f = ::foo // ok + } +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index ea08e5fe15b..b495dffac4c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -3741,6 +3741,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastInByClause.kt"); } + @Test + @TestMetadata("smartcastOnImplicitReceiverOfCallableReference.kt") + public void testSmartcastOnImplicitReceiverOfCallableReference() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt"); + } + @Test @TestMetadata("smartcastToNothing.kt") public void testSmartcastToNothing() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 80da6e8d3fd..99c50cf8831 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -3741,6 +3741,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastInByClause.kt"); } + @Test + @TestMetadata("smartcastOnImplicitReceiverOfCallableReference.kt") + public void testSmartcastOnImplicitReceiverOfCallableReference() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastOnImplicitReceiverOfCallableReference.kt"); + } + @Test @TestMetadata("smartcastToNothing.kt") public void testSmartcastToNothing() throws Exception { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index 1651779394f..96ecf695386 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -101,8 +101,8 @@ sealed class ImplicitReceiverValue>( * Should be called only in ImplicitReceiverStack */ fun replaceType(type: ConeKotlinType) { - if (!mutable) throw IllegalStateException("Cannot mutate an immutable ImplicitReceiverValue") if (type == this.type) return + if (!mutable) throw IllegalStateException("Cannot mutate an immutable ImplicitReceiverValue") this.type = type receiverExpression = if (type == originalReceiverExpression.typeRef.coneType) { originalReceiverExpression diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt index 08dd6f12c80..e202dfb1ee0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt @@ -806,7 +806,7 @@ class BodyResolveContext( @OptIn(PrivateForInline::class) fun storeCallableReferenceContext(callableReferenceAccess: FirCallableReferenceAccess) { - specialTowerDataContexts.storeCallableReferenceContext(callableReferenceAccess, towerDataContext) + specialTowerDataContexts.storeCallableReferenceContext(callableReferenceAccess, towerDataContext.createSnapshot()) } @OptIn(PrivateForInline::class)