From 172df04c9b45e88766b8aff204de1ee5176ef3a3 Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Mon, 4 Mar 2024 11:11:40 +0100 Subject: [PATCH] [FIR] Fix raw type nullability computation Consider the nullability of the type arguments, not of the type. This fixes a false positive ARGUMENT_TYPE_MISMATCH. #KT-66294 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 6 ++++ ...sticCompilerFE10TestDataTestGenerated.java | 6 ++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 6 ++++ ...siOldFrontendDiagnosticsTestGenerated.java | 6 ++++ .../kotlin/fir/java/JavaTypeConversion.kt | 2 +- .../fir/resolve/substitution/Substitutors.kt | 7 +++-- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 25 ++++++++++++--- .../nullableRawTypeWithFlexibleArguments.kt | 31 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++++ 9 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index d2f466698e7..c5881202a91 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -22432,6 +22432,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOrElse.kt"); } + @Test + @TestMetadata("nullableRawTypeWithFlexibleArguments.kt") + public void testNullableRawTypeWithFlexibleArguments() { + runTest("compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt"); + } + @Test @TestMetadata("orderOfSupertypesAndFakeOverrides_1.kt") public void testOrderOfSupertypesAndFakeOverrides_1() { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index a7a7a332475..40ef863f9d3 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -22432,6 +22432,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOrElse.kt"); } + @Test + @TestMetadata("nullableRawTypeWithFlexibleArguments.kt") + public void testNullableRawTypeWithFlexibleArguments() { + runTest("compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt"); + } + @Test @TestMetadata("orderOfSupertypesAndFakeOverrides_1.kt") public void testOrderOfSupertypesAndFakeOverrides_1() { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index e92e62a43d2..d2c3f46e539 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -22426,6 +22426,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOrElse.kt"); } + @Test + @TestMetadata("nullableRawTypeWithFlexibleArguments.kt") + public void testNullableRawTypeWithFlexibleArguments() { + runTest("compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt"); + } + @Test @TestMetadata("orderOfSupertypesAndFakeOverrides_1.kt") public void testOrderOfSupertypesAndFakeOverrides_1() { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 4750bbb9895..c7e12261542 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -22432,6 +22432,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOrElse.kt"); } + @Test + @TestMetadata("nullableRawTypeWithFlexibleArguments.kt") + public void testNullableRawTypeWithFlexibleArguments() { + runTest("compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt"); + } + @Test @TestMetadata("orderOfSupertypesAndFakeOverrides_1.kt") public void testOrderOfSupertypesAndFakeOverrides_1() { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt index 2a02dfe4fd1..53ac05730ff 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaTypeConversion.kt @@ -200,7 +200,7 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound( // Given `C`, `C` -> `C..C<*>?`. when { mode.insideAnnotation -> Array(classifier.allTypeParametersNumber()) { ConeStarProjection } - else -> typeParameterSymbols?.getProjectionsForRawType(session, makeNullable = false) + else -> typeParameterSymbols?.getProjectionsForRawType(session, nullabilities = null) ?: Array(classifier.allTypeParametersNumber()) { ConeStarProjection } } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index c2384084a89..2ef357b8f19 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -281,7 +281,7 @@ class ConeRawScopeSubstitutor( return when { type is ConeTypeParameterType -> { substituteOrSelf( - listOf(type.lookupTag.symbol).getProjectionsForRawType(useSiteSession, makeNullable = type.isNullable)[0] + type.lookupTag.symbol.getProjectionForRawType(useSiteSession, makeNullable = type.isMarkedNullable) ) } type is ConeClassLikeType && type.typeArguments.isNotEmpty() -> { @@ -295,8 +295,11 @@ class ConeRawScopeSubstitutor( } val firClass = type.fullyExpandedType(useSiteSession).lookupTag.toFirRegularClassSymbol(useSiteSession) ?: return null + val nullabilities = BooleanArray(type.typeArguments.size) { type.typeArguments[it].type?.isMarkedNullable == true } ConeRawType.create( - type.withArguments(firClass.typeParameterSymbols.getProjectionsForRawType(useSiteSession, makeNullable = type.isNullable)), + type.withArguments( + firClass.typeParameterSymbols.getProjectionsForRawType(useSiteSession, nullabilities = nullabilities) + ), type.replaceArgumentsWithStarProjections() ) } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 974c24333bd..1104d3a19fb 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -689,15 +689,32 @@ fun List.eraseToUpperBoundsAssociated( } } -fun List.getProjectionsForRawType(session: FirSession, makeNullable: Boolean): Array { +fun List.getProjectionsForRawType(session: FirSession, nullabilities: BooleanArray?): Array { val cache = mutableMapOf() return Array(size) { index -> - this[index].fir.eraseToUpperBound( - session, cache, mode = EraseUpperBoundMode.FOR_RAW_TYPE_ERASURE - ).applyIf(makeNullable) { withNullability(ConeNullability.NULLABLE, session.typeContext) } + this[index].getProjectionForRawType(session, cache, nullabilities?.get(index) == true) } } +fun FirTypeParameterSymbol.getProjectionForRawType( + session: FirSession, + makeNullable: Boolean, +): ConeKotlinType { + return getProjectionForRawType(session, mutableMapOf(), makeNullable) +} + +private fun FirTypeParameterSymbol.getProjectionForRawType( + session: FirSession, + cache: MutableMap, + makeNullable: Boolean, +): ConeKotlinType { + return fir.eraseToUpperBound(session, cache, mode = EraseUpperBoundMode.FOR_RAW_TYPE_ERASURE) + .applyIf(makeNullable) { + withNullability(ConeNullability.NULLABLE, session.typeContext) + } +} + + private enum class EraseUpperBoundMode { FOR_RAW_TYPE_ERASURE, FOR_EMPTY_INTERSECTION_CHECK diff --git a/compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt b/compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt new file mode 100644 index 00000000000..c9e0d514db3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt @@ -0,0 +1,31 @@ +// FIR_IDENTICAL +// FILE: J.java +package test; + +import org.jetbrains.annotations.Nullable; + +class Editor> { + public void onTargetSelected(@Nullable TARGET target) {} +} + +interface BuildConfiguration {} +interface BuildTarget {} + +class Helper extends AbstractHelper {} + +abstract class AbstractHelper> { + @Nullable + public TARGET findRunTarget() { + return null; + } +} + +// FILE: test.kt +package test + +private fun test( + editor: Editor>, + helper: Helper, +) { + editor.onTargetSelected(helper.findRunTarget()) +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index efd420fa867..c7fbaa85f6a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -22432,6 +22432,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/j+k/nullForOptionalOrElse.kt"); } + @Test + @TestMetadata("nullableRawTypeWithFlexibleArguments.kt") + public void testNullableRawTypeWithFlexibleArguments() { + runTest("compiler/testData/diagnostics/tests/j+k/nullableRawTypeWithFlexibleArguments.kt"); + } + @Test @TestMetadata("orderOfSupertypesAndFakeOverrides_1.kt") public void testOrderOfSupertypesAndFakeOverrides_1() {