From 8ff4af034a62ef3c718ed38c5e6a09a7fe5c47c4 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 23 Feb 2023 20:19:20 +0200 Subject: [PATCH] [FIR] Don't drop directly inherited functions from origins for intersection overrides in intersection scope ``` open class Base { fun foo(): T = ... } class Derived : Base { override fun foo(): T = ... } ``` In intersection scope of type `Base & Other` we should create intersection override based on `Base.foo(): T` and `Derived.foo(): R` at the same time, despite the fact that `Derived.foo` actually directly overrides `Base.foo` ^KT-56722 Fixed --- ...nosisCompilerFirTestdataTestGenerated.java | 6 ++++ ...TouchedTilContractsPhaseTestGenerated.java | 5 ++++ .../smartcastToStarProjectedSubclass.fir.txt | 19 +++++++++++++ .../smartcastToStarProjectedSubclass.kt | 28 +++++++++++++++++++ .../FirLightTreeDiagnosticsTestGenerated.java | 6 ++++ .../FirPsiDiagnosticTestGenerated.java | 6 ++++ .../impl/FirTypeIntersectionScopeContext.kt | 2 +- 7 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.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 702b16ee41b..ca7ef011213 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 @@ -4623,6 +4623,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis public void testNoSmartcastToNullableNothing() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/noSmartcastToNullableNothing.kt"); } + + @Test + @TestMetadata("smartcastToStarProjectedSubclass.kt") + public void testSmartcastToStarProjectedSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt"); + } } @Nested 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 ec31a923992..a3d5fdf5de6 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 @@ -4088,6 +4088,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract public void testNoSmartcastToNullableNothing() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/noSmartcastToNullableNothing.kt"); } + + @TestMetadata("smartcastToStarProjectedSubclass.kt") + public void testSmartcastToStarProjectedSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt"); + } } @TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers") diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.fir.txt new file mode 100644 index 00000000000..3ce351f110d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.fir.txt @@ -0,0 +1,19 @@ +FILE: test.kt + public final fun test_1(option: R|Option>?|): R|kotlin/Unit| { + when () { + (R|/option| is R|Option.Some<*>|) -> { + lval x: R|kotlin/String| = R|/option|.R|/Option.Some.get|().R|SubstitutionOverride| + R|/x|.R|kotlin/String.length| + } + } + + } + public final fun test_2(option: R|Option>?|): R|kotlin/Unit| { + when () { + (R|/option| is R|Option.Some>|) -> { + lval x: R|kotlin/String| = R|/option|.R|SubstitutionOverride, kotlin/Pair?>|>|().R|SubstitutionOverride| + R|/x|.R|kotlin/String.length| + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt new file mode 100644 index 00000000000..c011ed9dbcf --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt @@ -0,0 +1,28 @@ +// WITH_STDLIB +// ISSUE: KT-56722 +// FILE: Option.java +public interface Option { + T get(); + + public final class Some implements Option { + @Override + public T get() { + return null; + } + } +} + +// FILE: test.kt +fun test_1(option: Option>?) { + if (option is Option.Some<*>) { + val x = ..kotlin.Pair?!")!>option.get().first + x.length + } +} + +fun test_2(option: Option>?) { + if (option is Option.Some) { + val x = ..kotlin.Pair?!")!>option.get().first + x.length + } +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java index 8cf933e6fe6..3e8a9fbf2f9 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java @@ -4623,6 +4623,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi public void testNoSmartcastToNullableNothing() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/noSmartcastToNullableNothing.kt"); } + + @Test + @TestMetadata("smartcastToStarProjectedSubclass.kt") + public void testSmartcastToStarProjectedSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt"); + } } @Nested diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java index 67618dd82ea..a89d87300ad 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java @@ -4623,6 +4623,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest public void testNoSmartcastToNullableNothing() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/noSmartcastToNullableNothing.kt"); } + + @Test + @TestMetadata("smartcastToStarProjectedSubclass.kt") + public void testSmartcastToStarProjectedSubclass() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/problems/smartcastToStarProjectedSubclass.kt"); + } } @Nested diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt index aa5f2372372..6b269e39e4b 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt @@ -152,7 +152,7 @@ class FirTypeIntersectionScopeContext( val groupWithPrivate = overrideService.extractBothWaysOverridable(allMembersWithScope.maxByVisibility(), allMembersWithScope, overrideChecker) val group = groupWithPrivate.filter { !Visibilities.isPrivate(it.member.fir.visibility) }.ifEmpty { groupWithPrivate } - val directOverrides = group.onlyDirectlyInherited() + val directOverrides = if (forClassUseSiteScope) group.onlyDirectlyInherited() else group val mostSpecific = overrideService.selectMostSpecificMembers(directOverrides, ReturnTypeCalculatorForFullBodyResolve) val nonTrivial = if (forClassUseSiteScope) { // Create a non-trivial intersection override when the base methods come from different scopes,