From 981f8b1871abe7da2187e13178b59d5679d40085 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 17 Feb 2022 14:13:14 +0300 Subject: [PATCH] FIR: implement resolve of unqualified enum references in when See KT-16768 --- ...nosisCompilerFirTestdataTestGenerated.java | 52 +++++++++++++ ...TouchedTilContractsPhaseTestGenerated.java | 48 ++++++++++++ .../unqualifiedEnum/correctJava.fir.txt | 12 +++ .../resolve/unqualifiedEnum/correctJava.kt | 13 ++++ .../unqualifiedEnum/incorrectJava.fir.txt | 12 +++ .../resolve/unqualifiedEnum/incorrectJava.kt | 19 +++++ .../resolve/unqualifiedEnum/nested.fir.txt | 71 +++++++++++++++++ .../resolve/unqualifiedEnum/nested.kt | 32 ++++++++ .../unqualifiedEnum/notInsideBranches.fir.txt | 26 +++++++ .../unqualifiedEnum/notInsideBranches.kt | 9 +++ .../resolve/unqualifiedEnum/priority.fir.txt | 60 +++++++++++++++ .../resolve/unqualifiedEnum/priority.kt | 33 ++++++++ .../resolve/unqualifiedEnum/typeAlias.fir.txt | 27 +++++++ .../resolve/unqualifiedEnum/typeAlias.kt | 11 +++ .../unqualifiedEnum/unqualifiedEnum.fir.txt | 77 +++++++++++++++++++ .../unqualifiedEnum/unqualifiedEnum.kt | 37 +++++++++ .../runners/FirDiagnosticTestGenerated.java | 52 +++++++++++++ ...DiagnosticsWithLightTreeTestGenerated.java | 52 +++++++++++++ .../FirBlackBoxCodegenTestGenerated.java | 6 ++ .../impl/FirExplicitStarImportingScope.kt | 2 +- .../impl/FirWhenSubjectImportingScope.kt | 52 +++++++++++++ .../calls/tower/FirTowerResolveTask.kt | 10 ++- .../fir/resolve/calls/tower/TowerGroup.kt | 4 + .../body/resolve/BodyResolveContext.kt | 37 ++++++++- ...ControlFlowStatementsResolveTransformer.kt | 60 ++++++++------- .../fir/declarations/ImplicitReceiverUtils.kt | 2 +- .../codegen/box/fir/unqualifiedEnum.kt | 32 ++++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ 28 files changed, 820 insertions(+), 34 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt create mode 100644 compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirWhenSubjectImportingScope.kt create mode 100644 compiler/testData/codegen/box/fir/unqualifiedEnum.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 736b86bd126..127aad04b29 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 @@ -4122,6 +4122,58 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum") + @TestDataPath("$PROJECT_ROOT") + public class UnqualifiedEnum { + @Test + public void testAllFilesPresentInUnqualifiedEnum() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("correctJava.kt") + public void testCorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt"); + } + + @Test + @TestMetadata("incorrectJava.kt") + public void testIncorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt"); + } + + @Test + @TestMetadata("nested.kt") + public void testNested() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt"); + } + + @Test + @TestMetadata("notInsideBranches.kt") + public void testNotInsideBranches() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt"); + } + + @Test + @TestMetadata("priority.kt") + public void testPriority() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt"); + } + + @Test + @TestMetadata("typeAlias.kt") + public void testTypeAlias() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt"); + } + + @Test + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") @TestDataPath("$PROJECT_ROOT") 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 8cc69277367..ed1ee85cbba 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 @@ -3685,6 +3685,54 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract } } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class UnqualifiedEnum extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInUnqualifiedEnum() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("correctJava.kt") + public void testCorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt"); + } + + @TestMetadata("incorrectJava.kt") + public void testIncorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt"); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt"); + } + + @TestMetadata("notInsideBranches.kt") + public void testNotInsideBranches() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt"); + } + + @TestMetadata("priority.kt") + public void testPriority() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt"); + } + + @TestMetadata("typeAlias.kt") + public void testTypeAlias() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt"); + } + + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.fir.txt new file mode 100644 index 00000000000..04333f3e154 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.fir.txt @@ -0,0 +1,12 @@ +FILE: test.kt + public final fun foo(javaEnum: R|JavaEnum|): R|kotlin/Int| { + ^foo when (R|/javaEnum|) { + ==($subj$, R|/JavaEnum.FIRST|) -> { + Int(1) + } + ==($subj$, R|/JavaEnum.SECOND|) -> { + Int(2) + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt new file mode 100644 index 00000000000..778335b94d3 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt @@ -0,0 +1,13 @@ +// FILE: JavaEnum.java + +public enum JavaEnum { + FIRST, + SECOND; +} + +// FILE: test.kt + +fun foo(javaEnum: JavaEnum) = when (javaEnum) { + FIRST -> 1 + SECOND -> 2 +} diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.fir.txt new file mode 100644 index 00000000000..119d6cfb215 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.fir.txt @@ -0,0 +1,12 @@ +FILE: test.kt + public final fun foo(javaEnum: R|JavaEnum|): R|kotlin/Unit| { + ^foo when (R|/javaEnum|) { + ==($subj$, #()) -> { + Int(1) + } + ==($subj$, #) -> { + Int(2) + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt new file mode 100644 index 00000000000..1acb68f38f0 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt @@ -0,0 +1,19 @@ +// FILE: JavaEnum.java + +public enum JavaEnum { + FIRST, + SECOND; + + public static JavaEnum first() { + return FIRST; + } + + public static JavaEnum second = SECOND; +} + +// FILE: test.kt + +fun foo(javaEnum: JavaEnum) = when (javaEnum) { + first() -> 1 + second -> 2 +} diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.fir.txt new file mode 100644 index 00000000000..5221488cf05 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.fir.txt @@ -0,0 +1,71 @@ +FILE: nested.kt + public final enum class Outer : R|kotlin/Enum| { + private constructor(): R|Outer| { + super|>() + } + + public final static enum entry FIRST: R|Outer| + public final static enum entry SECOND: R|Outer| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|Outer| { + } + + } + public final enum class Inner : R|kotlin/Enum| { + private constructor(): R|Inner| { + super|>() + } + + public final static enum entry SECOND: R|Inner| + public final static enum entry THIRD: R|Inner| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|Inner| { + } + + } + public final fun foo(o: R|Outer|, i: R|Inner|): R|kotlin/Int| { + ^foo when (R|/o|) { + ==($subj$, R|/Outer.FIRST|) -> { + Int(1) + } + ==($subj$, R|/Outer.SECOND|) -> { + when (R|/i|) { + ==($subj$, R|/Inner.SECOND|) -> { + Int(2) + } + ==($subj$, R|/Inner.THIRD|) -> { + Int(3) + } + } + + } + } + + } + public final fun bar(o: R|Outer|, i: R|Inner|): R|kotlin/Int| { + ^bar when (R|/o|) { + ==($subj$, R|/Outer.FIRST|) -> { + Int(1) + } + ==($subj$, R|/Outer.SECOND|) -> { + local final fun baz(): R|kotlin/Int| { + ^baz when (R|/i|) { + ==($subj$, R|/Inner.SECOND|) -> { + Int(2) + } + ==($subj$, R|/Inner.THIRD|) -> { + Int(3) + } + } + + } + + R|/baz|() + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt new file mode 100644 index 00000000000..fa1fda3d059 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt @@ -0,0 +1,32 @@ +enum class Outer { + FIRST, SECOND; +} + +enum class Inner { + SECOND, THIRD; +} + +fun foo(o: Outer, i: Inner): Int { + return when (o) { + FIRST -> 1 + SECOND -> when (i) { + SECOND -> 2 + THIRD -> 3 + } + } +} + +fun bar(o: Outer, i: Inner): Int { + return when (o) { + FIRST -> 1 + SECOND -> { + fun baz(): Int { + return when (i) { + SECOND -> 2 + THIRD -> 3 + } + } + baz() + } + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.fir.txt new file mode 100644 index 00000000000..57955901898 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.fir.txt @@ -0,0 +1,26 @@ +FILE: notInsideBranches.kt + public final enum class Some : R|kotlin/Enum| { + private constructor(): R|Some| { + super|>() + } + + public final static enum entry FIRST: R|Some| + public final static enum entry SECOND: R|Some| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|Some| { + } + + } + public final fun foo(s: R|Some|): { + ^foo when (R|/s|) { + ==($subj$, R|/Some.FIRST|) -> { + # + } + ==($subj$, R|/Some.SECOND|) -> { + # + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt new file mode 100644 index 00000000000..dc1bc6ffcfe --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt @@ -0,0 +1,9 @@ +enum class Some { + FIRST, + SECOND; +} + +fun foo(s: Some) = when (s) { + FIRST -> SECOND + SECOND -> FIRST +} diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.fir.txt new file mode 100644 index 00000000000..498d173110f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.fir.txt @@ -0,0 +1,60 @@ +FILE: first.kt + package first + + public final enum class First : R|kotlin/Enum| { + private constructor(): R|first/First| { + super|>() + } + + public final static enum entry ONE: R|first/First| + public final static enum entry TWO: R|first/First| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|first/First| { + } + + } + public final val THREE: R|first/First| = Q|first/First|.R|first/First.ONE| + public get(): R|first/First| +FILE: second.kt + package second + + public final enum class Second : R|kotlin/Enum| { + private constructor(): R|second/Second| { + super|>() + } + + public final static enum entry THREE: R|second/Second| + public final static enum entry FOUR: R|second/Second| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|second/Second| { + } + + } + public final val ONE: R|second/Second| = Q|second/Second|.R|second/Second.THREE| + public get(): R|second/Second| + public final fun foo(f: R|first/First|): R|kotlin/Unit| { + ^foo when (R|/f|) { + ==($subj$, R|second/ONE|) -> { + Int(1) + } + ==($subj$, R|first/First.TWO|) -> { + Int(2) + } + } + + } + public final fun bar(s: R|second/Second|): R|kotlin/Unit| { + ^bar when (R|/s|) { + ==($subj$, R|first/THREE|) -> { + Int(3) + } + ==($subj$, R|second/Second.FOUR|) -> { + Int(4) + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt new file mode 100644 index 00000000000..7ac70884479 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt @@ -0,0 +1,33 @@ +// FILE: first.kt + +package first + +enum class First { + ONE, TWO; +} + +val THREE = First.ONE + +// FILE: second.kt + +package second + +import first.First +import first.THREE + +enum class Second { + THREE, FOUR; +} + +val ONE = Second.THREE + +fun foo(f: First) = when (f) { + ONE -> 1 + TWO -> 2 +} + +fun bar(s: Second) = when (s) { + THREE -> 3 + FOUR -> 4 +} + diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.fir.txt new file mode 100644 index 00000000000..42f8c4c0e7f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.fir.txt @@ -0,0 +1,27 @@ +FILE: typeAlias.kt + public final enum class Some : R|kotlin/Enum| { + private constructor(): R|Some| { + super|>() + } + + public final static enum entry FIRST: R|Some| + public final static enum entry SECOND: R|Some| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|Some| { + } + + } + public final typealias Other = R|Some| + public final fun foo(o: R|Other|): R|kotlin/Int| { + ^foo when (R|/o|) { + ==($subj$, R|/Some.FIRST|) -> { + Int(1) + } + ==($subj$, R|/Some.SECOND|) -> { + Int(2) + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt new file mode 100644 index 00000000000..a0c1e1eb63c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt @@ -0,0 +1,11 @@ +enum class Some { + FIRST, + SECOND; +} + +typealias Other = Some + +fun foo(o: Other) = when (o) { + FIRST -> 1 + SECOND -> 2 +} diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.fir.txt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.fir.txt new file mode 100644 index 00000000000..4c742baadbb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.fir.txt @@ -0,0 +1,77 @@ +FILE: unqualifiedEnum.kt + package test + + public final enum class Sample : R|kotlin/Enum| { + private constructor(): R|test/Sample| { + super|>() + } + + public final static enum entry FIRST: R|test/Sample| + public final static enum entry SECOND: R|test/Sample| + public final static enum entry THIRD: R|test/Sample| + public final static fun values(): R|kotlin/Array| { + } + + public final static fun valueOf(value: R|kotlin/String|): R|test/Sample| { + } + + } + public final fun trivial(s: R|test/Sample|): R|kotlin/Int| { + ^trivial when (R|/s|) { + ==($subj$, R|test/Sample.FIRST|) -> { + Int(1) + } + ==($subj$, R|test/Sample.SECOND|) -> { + Int(2) + } + ==($subj$, R|test/Sample.THIRD|) -> { + Int(3) + } + } + + } + public final fun shouldNotWork(s: R|test/Sample|): R|kotlin/Int| { + ^shouldNotWork when () { + ==(R|/s|, #) -> { + Int(1) + } + ==(R|/s|, #) -> { + Int(2) + } + ==(R|/s|, #) -> { + Int(3) + } + else -> { + Int(0) + } + } + + } + public final class Container : R|kotlin/Any| { + public constructor(): R|test/Container| { + super() + } + + public final val SECOND: R|test/Sample| = Q|test/Sample|.R|test/Sample.SECOND| + public get(): R|test/Sample| + + public final fun priority(s: R|test/Sample|): R|kotlin/Int| { + lval FIRST: R|test/Sample| = Q|test/Sample|.R|test/Sample.THIRD| + ^priority when (R|/s|) { + ==($subj$, R|/FIRST|) -> { + Int(3) + } + ==($subj$, this@R|test/Container|.R|test/Container.SECOND|) -> { + Int(2) + } + ==($subj$, Q|test/Sample|.R|test/Sample.FIRST|) -> { + Int(1) + } + else -> { + Int(0) + } + } + + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt new file mode 100644 index 00000000000..f8d284c421d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt @@ -0,0 +1,37 @@ +package test + +enum class Sample { + FIRST, SECOND, THIRD; +} + +fun trivial(s: Sample): Int { + return when (s) { + FIRST -> 1 + SECOND -> 2 + THIRD -> 3 + } +} + +fun shouldNotWork(s: Sample): Int { + return when { + s == FIRST -> 1 + s == SECOND -> 2 + s == THIRD -> 3 + else -> 0 + } +} + +class Container { + val SECOND = test.Sample.SECOND + + fun priority(s: Sample): Int { + val FIRST = test.Sample.THIRD + return when (s) { + FIRST -> 3 + SECOND -> 2 + test.Sample.FIRST -> 1 + else -> 0 + } + } +} + 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 42c1f8b8c62..1771d428579 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 @@ -4122,6 +4122,58 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum") + @TestDataPath("$PROJECT_ROOT") + public class UnqualifiedEnum { + @Test + public void testAllFilesPresentInUnqualifiedEnum() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("correctJava.kt") + public void testCorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt"); + } + + @Test + @TestMetadata("incorrectJava.kt") + public void testIncorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt"); + } + + @Test + @TestMetadata("nested.kt") + public void testNested() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt"); + } + + @Test + @TestMetadata("notInsideBranches.kt") + public void testNotInsideBranches() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt"); + } + + @Test + @TestMetadata("priority.kt") + public void testPriority() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt"); + } + + @Test + @TestMetadata("typeAlias.kt") + public void testTypeAlias() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt"); + } + + @Test + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") @TestDataPath("$PROJECT_ROOT") 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 5ab38c83cac..460ed779361 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 @@ -4122,6 +4122,58 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum") + @TestDataPath("$PROJECT_ROOT") + public class UnqualifiedEnum { + @Test + public void testAllFilesPresentInUnqualifiedEnum() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("correctJava.kt") + public void testCorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/correctJava.kt"); + } + + @Test + @TestMetadata("incorrectJava.kt") + public void testIncorrectJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/incorrectJava.kt"); + } + + @Test + @TestMetadata("nested.kt") + public void testNested() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/nested.kt"); + } + + @Test + @TestMetadata("notInsideBranches.kt") + public void testNotInsideBranches() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/notInsideBranches.kt"); + } + + @Test + @TestMetadata("priority.kt") + public void testPriority() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/priority.kt"); + } + + @Test + @TestMetadata("typeAlias.kt") + public void testTypeAlias() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/typeAlias.kt"); + } + + @Test + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/unqualifiedEnum/unqualifiedEnum.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index f8c4e428add..4888ecd68a5 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -17236,6 +17236,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testSuspendExtension() throws Exception { runTest("compiler/testData/codegen/box/fir/SuspendExtension.kt"); } + + @Test + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/testData/codegen/box/fir/unqualifiedEnum.kt"); + } } @Nested diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt index ec03a2178b1..05e51d2ca90 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirImport import org.jetbrains.kotlin.fir.declarations.FirResolvedImport import org.jetbrains.kotlin.fir.resolve.ScopeSession -class FirExplicitStarImportingScope( +open class FirExplicitStarImportingScope( imports: List, session: FirSession, scopeSession: ScopeSession, diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirWhenSubjectImportingScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirWhenSubjectImportingScope.kt new file mode 100644 index 00000000000..568d3b65f59 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirWhenSubjectImportingScope.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.scopes.impl + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.builder.buildImport +import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name + +// Note: at this moment we create this scope for enum classes only, +// and only enum entry symbols are allowed to be processed +class FirWhenSubjectImportingScope( + classId: ClassId, session: FirSession, scopeSession: ScopeSession +) : FirExplicitStarImportingScope( + listOf(buildResolvedImportByClassId(classId)), + session, scopeSession, FirImportingScopeFilter.ALL +) { + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + super.processPropertiesByName(name) { + if (it is FirEnumEntrySymbol) { + processor(it) + } + } + } + + override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { + } + + override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { + } + + companion object { + private fun buildResolvedImportByClassId(classId: ClassId) = buildResolvedImport { + delegate = buildImport { + importedFqName = classId.asSingleFqName() + isAllUnder = true + } + packageFqName = classId.packageFqName + relativeParentClassName = classId.relativeClassName + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt index 48acb9d2928..6776631a81a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.impl.FirWhenSubjectImportingScope import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.name.Name @@ -104,8 +105,13 @@ internal abstract class FirBaseTowerResolveTask( } for ((depth, lexical) in towerDataElementsForName.nonLocalTowerDataElements.withIndex()) { - if (!lexical.isLocal && lexical.scope != null) { - onScope(lexical.scope!!, parentGroup.NonLocal(depth)) + val scope = lexical.scope + if (!lexical.isLocal && scope != null) { + onScope( + scope, + if (scope is FirWhenSubjectImportingScope) TowerGroup.UnqualifiedEnum(depth) + else parentGroup.NonLocal(depth) + ) } val receiver = lexical.implicitReceiver diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt index 85ff7e75d36..ebe5dfbbaf3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt @@ -44,6 +44,8 @@ sealed class TowerGroupKind(val index: Byte) : Comparable { object QualifierValue : TowerGroupKind(8) + class UnqualifiedEnum(depth: Int) : WithDepth(9, depth) + object Last : TowerGroupKind(0b1111) override fun compareTo(other: TowerGroupKind): Int { @@ -157,6 +159,8 @@ private constructor( val Member = kindOf(TowerGroupKind.Member) + fun UnqualifiedEnum(depth: Int) = kindOf(TowerGroupKind.UnqualifiedEnum(depth)) + fun Local(depth: Int) = kindOf(TowerGroupKind.Local(depth)) fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth)) 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 1ee91a60879..7650daef461 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 @@ -33,9 +33,11 @@ import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope +import org.jetbrains.kotlin.fir.scopes.impl.FirWhenSubjectImportingScope 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.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.coneType @@ -77,6 +79,9 @@ class BodyResolveContext( @set:PrivateForInline var containers: ArrayDeque = ArrayDeque() + @PrivateForInline + val whenSubjectImportingScopes: ArrayDeque = ArrayDeque() + @set:PrivateForInline var containingClass: FirRegularClass? = null @@ -94,7 +99,7 @@ class BodyResolveContext( get() = containingClassDeclarations.lastOrNull() @OptIn(PrivateForInline::class) - private inline fun withNewTowerDataForClass(newContexts: FirRegularTowerDataContexts, f: () -> T): T { + inline fun withNewTowerDataForClass(newContexts: FirRegularTowerDataContexts, f: () -> T): T { val old = regularTowerDataContexts regularTowerDataContexts = newContexts return try { @@ -490,6 +495,36 @@ class BodyResolveContext( } } + @OptIn(PrivateForInline::class) + inline fun withWhenSubjectType( + subjectType: ConeKotlinType?, + sessionHolder: SessionHolder, + f: () -> T + ): T { + val session = sessionHolder.session + val subjectClassSymbol = (subjectType as? ConeClassLikeType) + ?.lookupTag?.toFirRegularClassSymbol(session)?.takeIf { it.fir.classKind == ClassKind.ENUM_CLASS } + val whenSubjectImportingScope = subjectClassSymbol?.let { + FirWhenSubjectImportingScope(it.classId, session, sessionHolder.scopeSession) + } + whenSubjectImportingScopes.add(whenSubjectImportingScope) + return try { + f() + } finally { + whenSubjectImportingScopes.removeLast() + } + } + + @OptIn(PrivateForInline::class) + inline fun withWhenSubjectImportingScope(f: () -> T): T { + val whenSubjectImportingScope = whenSubjectImportingScopes.lastOrNull() ?: return f() + val newTowerDataContext = towerDataContext.addNonLocalScope(whenSubjectImportingScope) + val newContexts = FirRegularTowerDataContexts(newTowerDataContext) + return withNewTowerDataForClass(newContexts) { + f() + } + } + private fun FirConstructor.scopesWithPrimaryConstructorParameters( ownerClass: FirClass, session: FirSession 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 87402d1c6ba..475b8694743 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 @@ -12,12 +12,10 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.resolve.ResolutionMode +import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.isUnitOrFlexibleUnit -import org.jetbrains.kotlin.fir.resolve.transformWhenSubjectExpressionUsingSmartcastInfo import org.jetbrains.kotlin.fir.resolve.transformers.FirSyntheticCallGenerator import org.jetbrains.kotlin.fir.resolve.transformers.FirWhenExhaustivenessTransformer -import org.jetbrains.kotlin.fir.resolve.withExpectedType import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef @@ -65,33 +63,35 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran return context.withWhenExpression(whenExpression, session) with@{ @Suppress("NAME_SHADOWING") var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent) - - when { - whenExpression.branches.isEmpty() -> {} - whenExpression.isOneBranch() -> { - whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextIndependent) - whenExpression.resultType = whenExpression.branches.first().result.resultType - } - else -> { - whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextDependent) - - whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression, resolutionContext) ?: run { - whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) - dataFlowAnalyzer.exitWhenExpression(whenExpression) - whenExpression.resultType = buildErrorTypeRef { - diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError) - } - return@with whenExpression + val subjectType = whenExpression.subject?.typeRef?.coneType?.fullyExpandedType(session) + context.withWhenSubjectType(subjectType, components) { + when { + whenExpression.branches.isEmpty() -> {} + whenExpression.isOneBranch() -> { + whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextIndependent) + whenExpression.resultType = whenExpression.branches.first().result.resultType } + else -> { + whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextDependent) - val completionResult = callCompleter.completeCall(whenExpression, data) - whenExpression = completionResult.result + whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression, resolutionContext) ?: run { + whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) + dataFlowAnalyzer.exitWhenExpression(whenExpression) + whenExpression.resultType = buildErrorTypeRef { + diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError) + } + return@withWhenSubjectType whenExpression + } + + val completionResult = callCompleter.completeCall(whenExpression, data) + whenExpression = completionResult.result + } } + whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) + dataFlowAnalyzer.exitWhenExpression(whenExpression) + whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive() + whenExpression } - whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null) - dataFlowAnalyzer.exitWhenExpression(whenExpression) - whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive() - whenExpression } } @@ -110,9 +110,10 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran } override fun transformWhenBranch(whenBranch: FirWhenBranch, data: ResolutionMode): FirWhenBranch { - return whenBranch.also { dataFlowAnalyzer.enterWhenBranchCondition(whenBranch) } - .transformCondition(transformer, withExpectedType(session.builtinTypes.booleanType)) - .also { dataFlowAnalyzer.exitWhenBranchCondition(it) } + dataFlowAnalyzer.enterWhenBranchCondition(whenBranch) + return context.withWhenSubjectImportingScope { + whenBranch.transformCondition(transformer, withExpectedType(session.builtinTypes.booleanType)) + }.also { dataFlowAnalyzer.exitWhenBranchCondition(it) } .transformResult(transformer, data) .also { dataFlowAnalyzer.exitWhenBranchResult(it) } @@ -186,6 +187,7 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran ): FirStatement { val labeledElement = returnExpression.target.labeledElement val expectedTypeRef = labeledElement.returnTypeRef + @Suppress("IntroduceWhenSubject") val mode = when { labeledElement.symbol in context.anonymousFunctionsAnalyzedInDependentContext -> { diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt index 2e6d58835f8..f61c7c62227 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt @@ -167,7 +167,7 @@ class FirTowerDataContext private constructor( return addNonLocalScope(scope) } - private fun addNonLocalScope(scope: FirScope): FirTowerDataContext { + fun addNonLocalScope(scope: FirScope): FirTowerDataContext { val element = scope.asTowerDataElement(isLocal = false) return FirTowerDataContext( towerDataElements.add(element), diff --git a/compiler/testData/codegen/box/fir/unqualifiedEnum.kt b/compiler/testData/codegen/box/fir/unqualifiedEnum.kt new file mode 100644 index 00000000000..c7dffd2af82 --- /dev/null +++ b/compiler/testData/codegen/box/fir/unqualifiedEnum.kt @@ -0,0 +1,32 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND: JVM_IR +// WITH_STDLIB + +enum class Rainbow { + RED, + ORANGE, + YELLOW, + GREEN, + CYAN, + BLUE, + VIOLET +} + +fun sym(r: Rainbow) = when (r) { + RED -> 'r' + ORANGE -> 'o' + YELLOW -> 'y' + GREEN -> 'g' + CYAN -> 'c' + BLUE -> 'b' + VIOLET -> 'v' +} + +fun box(): String { + val s = buildString { + for (value in Rainbow.values()) { + append(sym(value)) + } + } + return if (s == "roygcbv") "OK" else s +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index f333ac2adde..8a8f17f0e46 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -17236,6 +17236,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testSuspendExtension() throws Exception { runTest("compiler/testData/codegen/box/fir/SuspendExtension.kt"); } + + @Test + @TestMetadata("unqualifiedEnum.kt") + public void testUnqualifiedEnum() throws Exception { + runTest("compiler/testData/codegen/box/fir/unqualifiedEnum.kt"); + } } @Nested