From f7ef551f99c4f87db39041a90a021cffa1fc345f Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Fri, 24 Sep 2021 16:33:07 +0300 Subject: [PATCH] Report warnings on overrides with wrong types nullability ^KT-48899 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 12 +++ ...irOldFrontendDiagnosticsTestGenerated.java | 12 +++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 +++ ...nAnnotationsCompiledJavaTestGenerated.java | 6 ++ ...dJavaWithPsiClassReadingTestGenerated.java | 6 ++ ...ignAnnotationsSourceJavaTestGenerated.java | 6 ++ .../jvm/checkers/JavaNullabilityChecker.kt | 26 +++--- ...rideWithWrongNullabilityOverrideChecker.kt | 59 ++++++++++++++ .../diagnostics/DefaultErrorMessagesJvm.java | 4 + .../resolve/jvm/diagnostics/ErrorsJvm.java | 7 +- .../jvm/platform/JvmPlatformConfigurator.kt | 3 +- .../warnMode/OverrideOfAnnotated.fir.kt | 79 +++++++++++++++++++ .../jspecify/warnMode/OverrideOfAnnotated.kt | 79 +++++++++++++++++++ .../jspecify/warnMode/OverrideOfAnnotated.txt | 57 +++++++++++++ ...otlinOverridesDefinitelyNonNullable.fir.kt | 39 +++++++++ ...ithKotlinOverridesDefinitelyNonNullable.kt | 39 +++++++++ ...thKotlinOverridesDefinitelyNonNullable.txt | 34 ++++++++ ...ParameterWithKotlinOverridesWarning.fir.kt | 38 +++++++++ ...TypeParameterWithKotlinOverridesWarning.kt | 38 +++++++++ ...ypeParameterWithKotlinOverridesWarning.txt | 34 ++++++++ .../test/runners/DiagnosticTestGenerated.java | 12 +++ ...nAnnotationsCompiledJavaTestGenerated.java | 6 ++ ...dJavaWithPsiClassReadingTestGenerated.java | 6 ++ ...ignAnnotationsSourceJavaTestGenerated.java | 6 ++ .../kotlin/types/AbstractTypeChecker.kt | 6 +- .../kotlin/types/model/TypeSystemContext.kt | 8 ++ .../kotlin/resolve/OverridingUtil.java | 41 ++++++---- .../OverridingUtilTypeSystemContext.kt | 36 ++++++--- .../types/checker/ClassicTypeSystemContext.kt | 3 + 29 files changed, 672 insertions(+), 42 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaOverrideWithWrongNullabilityOverrideChecker.kt create mode 100644 compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt create mode 100644 compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt create mode 100644 compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.fir.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.txt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.fir.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.txt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index e6cd70932a1..877892ff7f3 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -17848,6 +17848,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinNullableWarnings.kt"); } + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt") + public void testNotNullTypeParameterWithKotlinOverridesDefinitelyNonNullable() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt"); + } + + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesWarning.kt") + public void testNotNullTypeParameterWithKotlinOverridesWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt"); + } + @Test @TestMetadata("returnCollection.kt") public void testReturnCollection() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 5ed4f76598b..c5034a36d12 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -17848,6 +17848,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinNullableWarnings.kt"); } + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt") + public void testNotNullTypeParameterWithKotlinOverridesDefinitelyNonNullable() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt"); + } + + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesWarning.kt") + public void testNotNullTypeParameterWithKotlinOverridesWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt"); + } + @Test @TestMetadata("returnCollection.kt") public void testReturnCollection() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 0fd4b9d3813..cdfb8a062cb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -17848,6 +17848,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinNullableWarnings.kt"); } + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt") + public void testNotNullTypeParameterWithKotlinOverridesDefinitelyNonNullable() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt"); + } + + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesWarning.kt") + public void testNotNullTypeParameterWithKotlinOverridesWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt"); + } + @Test @TestMetadata("returnCollection.kt") public void testReturnCollection() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaTestGenerated.java index 7fd19eac967..e922370f5a7 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaTestGenerated.java @@ -778,6 +778,12 @@ public class FirOldFrontendForeignAnnotationsCompiledJavaTestGenerated extends A runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java index 431b94d039e..de3dabfd549 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java @@ -778,6 +778,12 @@ public class FirOldFrontendForeignAnnotationsCompiledJavaWithPsiClassReadingTest runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsSourceJavaTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsSourceJavaTestGenerated.java index cad7ce07b29..3ad0ad75951 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsSourceJavaTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendForeignAnnotationsSourceJavaTestGenerated.java @@ -778,6 +778,12 @@ public class FirOldFrontendForeignAnnotationsSourceJavaTestGenerated extends Abs runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt index fea4f638502..2f4913cc14d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt @@ -189,17 +189,6 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio return metWrongNullabilityInsideArguments } - private fun isNullableTypeAgainstNotNullTypeParameter( - subType: KotlinType, - superType: KotlinType - ): Boolean { - if (superType !is NotNullTypeVariable) return false - return !AbstractNullabilityChecker.isSubtypeOfAny( - createClassicTypeCheckerState(isErrorTypeEqualsToAnything = true), - subType - ) - } - override fun checkReceiver( receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, @@ -279,6 +268,10 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio } companion object { + val typePreparatorUnwrappingEnhancement: KotlinTypePreparator = object : KotlinTypePreparator() { + override fun prepareType(type: KotlinTypeMarker): UnwrappedType = + super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap() + } val typeCheckerForEnhancedTypes = NewKotlinTypeCheckerImpl( kotlinTypeRefiner = KotlinTypeRefiner.Default, kotlinTypePreparator = object : KotlinTypePreparator() { @@ -287,6 +280,17 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio } ) val typeCheckerForBaseTypes = NewKotlinTypeCheckerImpl(KotlinTypeRefiner.Default) + + fun isNullableTypeAgainstNotNullTypeParameter( + subType: KotlinType, + superType: KotlinType + ): Boolean { + if (superType !is NotNullTypeVariable || subType is NotNullTypeVariable) return false + return !AbstractNullabilityChecker.isSubtypeOfAny( + createClassicTypeCheckerState(isErrorTypeEqualsToAnything = true), + subType + ) + } } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaOverrideWithWrongNullabilityOverrideChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaOverrideWithWrongNullabilityOverrideChecker.kt new file mode 100644 index 00000000000..8b29f9025fa --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaOverrideWithWrongNullabilityOverrideChecker.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2021 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.resolve.jvm.checkers + +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm +import org.jetbrains.kotlin.types.* + +object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker { + private val overridingUtilWithEnhancementUnwrapped = + OverridingUtil + .createWithTypePreparatorAndCustomSubtype(JavaNullabilityChecker.typePreparatorUnwrappingEnhancement) { subtype, supertype -> + !JavaNullabilityChecker.isNullableTypeAgainstNotNullTypeParameter(subtype, supertype) + } + + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (descriptor !is CallableMemberDescriptor) return + if (descriptor.overriddenDescriptors.isEmpty()) return + + val containingClass = descriptor.containingDeclaration as? ClassDescriptor ?: return + + for (overriddenDescriptor in descriptor.overriddenDescriptors) { + if (overriddenDescriptor !is JavaMethodDescriptor) continue + // Skip, if even with enhancement unwrapped, it's still a valid override + if (overridingUtilWithEnhancementUnwrapped + .isOverridableBy( + overriddenDescriptor, descriptor, containingClass, true + ).result == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) continue + + // Skip if it wasn't an override already before enhancement unwrappement, since errors already have been reported + if (OverridingUtil.DEFAULT + .isOverridableBy( + overriddenDescriptor, descriptor, containingClass, true + ).result != OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) continue + + + val unwrappedOverridden = overriddenDescriptor.substitute(TypeSubstitutor.create(object : TypeSubstitution() { + override fun get(key: KotlinType): TypeProjection? = null + override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = + topLevelType.getEnhancementDeeply() ?: topLevelType + })) ?: overriddenDescriptor + + context.trace.report(ErrorsJvm.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, descriptor, unwrappedOverridden)) + + break + } + + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java index 557b38c6557..0e6201ca4d8 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java @@ -109,6 +109,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS, "Unsafe use of a nullable receiver of type {0}", RENDER_TYPE); + MAP.put(WRONG_NULLABILITY_FOR_JAVA_OVERRIDE, + "Override ''{0}'' has incorrect nullability in its signature comparing with overridden ''{1}''", COMPACT, COMPACT); + + MAP.put(ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR, "An accessor will not be generated for ''{0}'', so the annotation will not be written to the class file", STRING); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java index 8196dd37e2c..eb0f58def8d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java @@ -7,10 +7,7 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics; import com.intellij.psi.PsiElement; import org.jetbrains.kotlin.config.LanguageFeature; -import org.jetbrains.kotlin.descriptors.CallableDescriptor; -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.Named; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.*; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.*; @@ -163,6 +160,8 @@ public interface ErrorsJvm { DiagnosticFactory1 RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS = DiagnosticFactory1.create(WARNING); + DiagnosticFactory2 WRONG_NULLABILITY_FOR_JAVA_OVERRIDE = + DiagnosticFactory2.create(WARNING, OVERRIDE_MODIFIER); DiagnosticFactory1 ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR = DiagnosticFactory1.create(WARNING); DiagnosticFactory1 SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 7667cc426ab..30197800d65 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -41,7 +41,8 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase( JvmMultifileClassStateChecker, DefaultCheckerInTailrec, FunctionDelegateMemberNameClashChecker, - ClassInheritsJavaSealedClassChecker + ClassInheritsJavaSealedClassChecker, + JavaOverrideWithWrongNullabilityOverrideChecker, ), additionalCallCheckers = listOf( diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt new file mode 100644 index 00000000000..47c613ef709 --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.fir.kt @@ -0,0 +1,79 @@ +// JSPECIFY_STATE: warn + +// FILE: Foo.java +public interface Foo {} +// FILE: BaseClass.java + +import org.jspecify.nullness.*; + +@NullMarked +public class BaseClass { + public Foo everythingNotNullable(Foo x) { return null; } + + public @Nullable Foo everythingNullable(@Nullable Foo x) { return null; } + + public @NullnessUnspecified Foo everythingUnknown(@NullnessUnspecified Foo x) { return null; } + + public @Nullable Foo mixed(Foo x) { return null; } + + public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; } +} + + +// FILE: main.kt + +private val FOO = object : Foo {} + +class Correct : BaseClass() { + override fun everythingNotNullable(x: Foo): Foo { + return FOO + } + + override fun everythingNullable(x: Foo?): Foo? { + return null + } + + override fun everythingUnknown(x: Foo?): Foo? { + return null + } + + override fun mixed(x: Foo): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo): Foo { + return FOO + } +} + +class WrongReturnTypes : BaseClass() { + override fun everythingNotNullable(x: Foo): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo): Foo? { + return null + } +} + +class WrongParameter : BaseClass() { + override fun everythingNotNullable(x: Foo?): Foo { + return FOO + } + + override fun everythingNullable(x: Foo): Foo? { + return null + } + + override fun everythingUnknown(x: Foo): Foo? { + return null + } + + override fun mixed(x: Foo?): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo?): Foo { + return FOO + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt new file mode 100644 index 00000000000..7579f0cedaf --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt @@ -0,0 +1,79 @@ +// JSPECIFY_STATE: warn + +// FILE: Foo.java +public interface Foo {} +// FILE: BaseClass.java + +import org.jspecify.nullness.*; + +@NullMarked +public class BaseClass { + public Foo everythingNotNullable(Foo x) { return null; } + + public @Nullable Foo everythingNullable(@Nullable Foo x) { return null; } + + public @NullnessUnspecified Foo everythingUnknown(@NullnessUnspecified Foo x) { return null; } + + public @Nullable Foo mixed(Foo x) { return null; } + + public Foo explicitlyNullnessUnspecified(@NullnessUnspecified Foo x) { return null; } +} + + +// FILE: main.kt + +private val FOO = object : Foo {} + +class Correct : BaseClass() { + override fun everythingNotNullable(x: Foo): Foo { + return FOO + } + + override fun everythingNullable(x: Foo?): Foo? { + return null + } + + override fun everythingUnknown(x: Foo?): Foo? { + return null + } + + override fun mixed(x: Foo): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo): Foo { + return FOO + } +} + +class WrongReturnTypes : BaseClass() { + override fun everythingNotNullable(x: Foo): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo): Foo? { + return null + } +} + +class WrongParameter : BaseClass() { + override fun everythingNotNullable(x: Foo?): Foo { + return FOO + } + + override fun everythingNullable(x: Foo): Foo? { + return null + } + + override fun everythingUnknown(x: Foo): Foo? { + return null + } + + override fun mixed(x: Foo?): Foo? { + return null + } + + override fun explicitlyNullnessUnspecified(x: Foo?): Foo { + return FOO + } +} diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt new file mode 100644 index 00000000000..ba103d20d2b --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.txt @@ -0,0 +1,57 @@ +package + +private val FOO: FOO. + +@org.jspecify.nullness.NullMarked public open class BaseClass { + public constructor BaseClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun everythingNotNullable(/*0*/ x: Foo!): Foo! + @org.jspecify.nullness.Nullable public open fun everythingNullable(/*0*/ @org.jspecify.nullness.Nullable x: @org.jspecify.nullness.Nullable Foo!): @org.jspecify.nullness.Nullable Foo! + @org.jspecify.nullness.NullnessUnspecified public open fun everythingUnknown(/*0*/ @org.jspecify.nullness.NullnessUnspecified x: @org.jspecify.nullness.NullnessUnspecified Foo!): @org.jspecify.nullness.NullnessUnspecified Foo! + public open fun explicitlyNullnessUnspecified(/*0*/ @org.jspecify.nullness.NullnessUnspecified x: @org.jspecify.nullness.NullnessUnspecified Foo!): Foo! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + @org.jspecify.nullness.Nullable public open fun mixed(/*0*/ x: Foo!): @org.jspecify.nullness.Nullable Foo! + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Correct : BaseClass { + public constructor Correct() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo): Foo + public open override /*1*/ fun everythingNullable(/*0*/ x: Foo?): Foo? + public open override /*1*/ fun everythingUnknown(/*0*/ x: Foo?): Foo? + public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo): Foo + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun mixed(/*0*/ x: Foo): Foo? + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Foo { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class WrongParameter : BaseClass { + public constructor WrongParameter() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo?): Foo + public open override /*1*/ fun everythingNullable(/*0*/ x: Foo): Foo? + public open override /*1*/ fun everythingUnknown(/*0*/ x: Foo): Foo? + public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo?): Foo + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun mixed(/*0*/ x: Foo?): Foo? + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class WrongReturnTypes : BaseClass { + public constructor WrongReturnTypes() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun everythingNotNullable(/*0*/ x: Foo): Foo? + @org.jspecify.nullness.Nullable public open override /*1*/ /*fake_override*/ fun everythingNullable(/*0*/ @org.jspecify.nullness.Nullable x: @org.jspecify.nullness.Nullable Foo!): @org.jspecify.nullness.Nullable Foo! + @org.jspecify.nullness.NullnessUnspecified public open override /*1*/ /*fake_override*/ fun everythingUnknown(/*0*/ @org.jspecify.nullness.NullnessUnspecified x: @org.jspecify.nullness.NullnessUnspecified Foo!): @org.jspecify.nullness.NullnessUnspecified Foo! + public open override /*1*/ fun explicitlyNullnessUnspecified(/*0*/ x: Foo): Foo? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + @org.jspecify.nullness.Nullable public open override /*1*/ /*fake_override*/ fun mixed(/*0*/ x: Foo!): @org.jspecify.nullness.Nullable Foo! + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.fir.kt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.fir.kt new file mode 100644 index 00000000000..80884bf6695 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.fir.kt @@ -0,0 +1,39 @@ +// !SKIP_JAVAC +// !LANGUAGE: -ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated +// !LANGUAGE: +DefinitelyNonNullableTypes +// FILE: SLRUMap.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public interface SLRUMap { + void takeV(@NotNull V value); + void takeE(@NotNull E value); + + void takeVList(@NotNull List<@NotNull V> value); + void takeEList(@NotNull List<@NotNull E> value); + + public K id(K value) { return null; } +} + +// FILE: main.kt + +interface Q1 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} + +interface Q2 : SLRUMap { + override fun takeV(x: X & Any) + override fun takeE(e: E1 & Any) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt new file mode 100644 index 00000000000..c0ee8734c64 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt @@ -0,0 +1,39 @@ +// !SKIP_JAVAC +// !LANGUAGE: -ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated +// !LANGUAGE: +DefinitelyNonNullableTypes +// FILE: SLRUMap.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public interface SLRUMap { + void takeV(@NotNull V value); + void takeE(@NotNull E value); + + void takeVList(@NotNull List<@NotNull V> value); + void takeEList(@NotNull List<@NotNull E> value); + + public K id(K value) { return null; } +} + +// FILE: main.kt + +interface Q1 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} + +interface Q2 : SLRUMap { + override fun takeV(x: X & Any) + override fun takeE(e: E1 & Any) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.txt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.txt new file mode 100644 index 00000000000..f765b979f2e --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.txt @@ -0,0 +1,34 @@ +package + +public interface Q1 : SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ fun id(/*0*/ k2: K2): K2 + public abstract override /*1*/ fun takeE(/*0*/ e: E1): kotlin.Unit + public abstract override /*1*/ fun takeEList(/*0*/ l2: kotlin.collections.List): kotlin.Unit + public abstract override /*1*/ fun takeV(/*0*/ x: X): kotlin.Unit + public abstract override /*1*/ fun takeVList(/*0*/ l: kotlin.collections.List): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Q2 : SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ fun id(/*0*/ k2: K2): K2 + public abstract override /*1*/ fun takeE(/*0*/ e: E1 & Any): kotlin.Unit + public abstract override /*1*/ fun takeEList(/*0*/ l2: kotlin.collections.List): kotlin.Unit + public abstract override /*1*/ fun takeV(/*0*/ x: X & Any): kotlin.Unit + public abstract override /*1*/ fun takeVList(/*0*/ l: kotlin.collections.List): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun id(/*0*/ value: K!): K! + public abstract fun takeE(/*0*/ @org.jetbrains.annotations.NotNull value: E): kotlin.Unit + public abstract fun takeEList(/*0*/ @org.jetbrains.annotations.NotNull value: kotlin.collections.(Mutable)List<@org.jetbrains.annotations.NotNull E>): kotlin.Unit + public abstract fun takeV(/*0*/ @org.jetbrains.annotations.NotNull value: V): kotlin.Unit + public abstract fun takeVList(/*0*/ @org.jetbrains.annotations.NotNull value: kotlin.collections.(Mutable)List<@org.jetbrains.annotations.NotNull V>): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.fir.kt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.fir.kt new file mode 100644 index 00000000000..e80bcc4f019 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.fir.kt @@ -0,0 +1,38 @@ +// !SKIP_JAVAC +// !LANGUAGE: -ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated +// FILE: SLRUMap.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public interface SLRUMap { + void takeV(@NotNull V value); + void takeE(@NotNull E value); + + void takeVList(@NotNull List<@NotNull V> value); + void takeEList(@NotNull List<@NotNull E> value); + + public K id(K value) { return null; } +} + +// FILE: main.kt + +interface Q1 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} + +interface Q2 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt new file mode 100644 index 00000000000..92cde3c0d8d --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt @@ -0,0 +1,38 @@ +// !SKIP_JAVAC +// !LANGUAGE: -ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated +// FILE: SLRUMap.java + +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public interface SLRUMap { + void takeV(@NotNull V value); + void takeE(@NotNull E value); + + void takeVList(@NotNull List<@NotNull V> value); + void takeEList(@NotNull List<@NotNull E> value); + + public K id(K value) { return null; } +} + +// FILE: main.kt + +interface Q1 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} + +interface Q2 : SLRUMap { + override fun takeV(x: X) + override fun takeE(e: E1) + + override fun takeVList(l: List) + override fun takeEList(l2: List) + + override fun id(k2: K2): K2 +} diff --git a/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.txt b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.txt new file mode 100644 index 00000000000..d159a874dc2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.txt @@ -0,0 +1,34 @@ +package + +public interface Q1 : SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ fun id(/*0*/ k2: K2): K2 + public abstract override /*1*/ fun takeE(/*0*/ e: E1): kotlin.Unit + public abstract override /*1*/ fun takeEList(/*0*/ l2: kotlin.collections.List): kotlin.Unit + public abstract override /*1*/ fun takeV(/*0*/ x: X): kotlin.Unit + public abstract override /*1*/ fun takeVList(/*0*/ l: kotlin.collections.List): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Q2 : SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ fun id(/*0*/ k2: K2): K2 + public abstract override /*1*/ fun takeE(/*0*/ e: E1): kotlin.Unit + public abstract override /*1*/ fun takeEList(/*0*/ l2: kotlin.collections.List): kotlin.Unit + public abstract override /*1*/ fun takeV(/*0*/ x: X): kotlin.Unit + public abstract override /*1*/ fun takeVList(/*0*/ l: kotlin.collections.List): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface SLRUMap { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun id(/*0*/ value: K!): K! + public abstract fun takeE(/*0*/ @org.jetbrains.annotations.NotNull value: E): kotlin.Unit + public abstract fun takeEList(/*0*/ @org.jetbrains.annotations.NotNull value: kotlin.collections.(Mutable)List<@org.jetbrains.annotations.NotNull E>): kotlin.Unit + public abstract fun takeV(/*0*/ @org.jetbrains.annotations.NotNull value: V): kotlin.Unit + public abstract fun takeVList(/*0*/ @org.jetbrains.annotations.NotNull value: kotlin.collections.(Mutable)List<@org.jetbrains.annotations.NotNull V>): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} 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 7bc73d1028f..8e777ff2ed8 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 @@ -17854,6 +17854,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinNullableWarnings.kt"); } + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt") + public void testNotNullTypeParameterWithKotlinOverridesDefinitelyNonNullable() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesDefinitelyNonNullable.kt"); + } + + @Test + @TestMetadata("notNullTypeParameterWithKotlinOverridesWarning.kt") + public void testNotNullTypeParameterWithKotlinOverridesWarning() throws Exception { + runTest("compiler/testData/diagnostics/tests/j+k/types/notNullTypeParameterWithKotlinOverridesWarning.kt"); + } + @Test @TestMetadata("returnCollection.kt") public void testReturnCollection() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java index 283e43f58e7..b590d91f189 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaTestGenerated.java @@ -778,6 +778,12 @@ public class ForeignAnnotationsCompiledJavaTestGenerated extends AbstractForeign runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java index a28b5e31901..a33834e69ba 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated.java @@ -778,6 +778,12 @@ public class ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated exte runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java index 9a6e23e139b..5ff5ffb51e0 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ForeignAnnotationsSourceJavaTestGenerated.java @@ -778,6 +778,12 @@ public class ForeignAnnotationsSourceJavaTestGenerated extends AbstractForeignAn runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/NullnessUnspecifiedTypeParameter.kt"); } + @Test + @TestMetadata("OverrideOfAnnotated.kt") + public void testOverrideOfAnnotated() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/OverrideOfAnnotated.kt"); + } + @Test @TestMetadata("SelfType.kt") public void testSelfType() throws Exception { diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index 54a41f0b23a..db6566b5d51 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt @@ -445,9 +445,10 @@ object AbstractTypeChecker { return true } + @OptIn(ObsoleteTypeKind::class) private fun TypeSystemContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean = type.typeConstructor().isDenotable() && - !type.isDynamic() && !type.isDefinitelyNotNullType() && + !type.isDynamic() && !type.isDefinitelyNotNullType() && !type.isNotNullTypeVariable() && type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor() fun effectiveVariance(declared: TypeVariance, useSite: TypeVariance): TypeVariance? { @@ -702,7 +703,8 @@ object AbstractNullabilityChecker { if (superType.isMarkedNullable()) return true // i.e. subType is definitely not null - if (subType.isDefinitelyNotNullType()) return true + @OptIn(ObsoleteTypeKind::class) + if (subType.isDefinitelyNotNullType() || subType.isNotNullTypeVariable()) return true // i.e. subType is captured type, projection of which is marked not-null if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 4be9e1dd7cc..3e0314da714 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -377,6 +377,11 @@ interface TypeSystemContext : TypeSystemOptimizationContext { fun KotlinTypeMarker.isDefinitelyNotNullType(): Boolean = asSimpleType()?.asDefinitelyNotNullType() != null + // This kind of types is obsolete (expected to be removed at 1.7) and shouldn't be used further in a new code + // Now, such types are being replaced with definitely non-nullable types + @ObsoleteTypeKind + fun KotlinTypeMarker.isNotNullTypeVariable(): Boolean = false + fun KotlinTypeMarker.hasFlexibleNullability() = lowerBoundIfFlexible().isMarkedNullable() != upperBoundIfFlexible().isMarkedNullable() @@ -495,3 +500,6 @@ fun requireOrDescribe(condition: Boolean, value: Any?) { "Unexpected: value = '$value'$typeInfo" } } + +@RequiresOptIn("This kinds of type is obsolete and should not be used until you really need it") +annotation class ObsoleteTypeKind diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 0cbe834f483..601b8e41f9d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -60,18 +60,23 @@ public class OverridingUtil { }; static { - - DEFAULT = new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE); - } - - @NotNull - public static OverridingUtil createWithEqualityAxioms(@NotNull KotlinTypeChecker.TypeConstructorEquality equalityAxioms) { - return new OverridingUtil(equalityAxioms, KotlinTypeRefiner.Default.INSTANCE); + DEFAULT = new OverridingUtil( + DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE, KotlinTypePreparator.Default.INSTANCE, + null + ); } @NotNull public static OverridingUtil createWithTypeRefiner(@NotNull KotlinTypeRefiner kotlinTypeRefiner) { - return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, kotlinTypeRefiner); + return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, kotlinTypeRefiner, KotlinTypePreparator.Default.INSTANCE, null); + } + + @NotNull + public static OverridingUtil createWithTypePreparatorAndCustomSubtype( + @NotNull KotlinTypePreparator kotlinTypePreparator, + @NotNull Function2 customSubtype + ) { + return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE, kotlinTypePreparator, customSubtype); } @NotNull @@ -79,18 +84,24 @@ public class OverridingUtil { @NotNull KotlinTypeRefiner kotlinTypeRefiner, @NotNull KotlinTypeChecker.TypeConstructorEquality equalityAxioms ) { - return new OverridingUtil(equalityAxioms, kotlinTypeRefiner); + return new OverridingUtil(equalityAxioms, kotlinTypeRefiner, KotlinTypePreparator.Default.INSTANCE, null); } private final KotlinTypeRefiner kotlinTypeRefiner; + private final KotlinTypePreparator kotlinTypePreparator; private final KotlinTypeChecker.TypeConstructorEquality equalityAxioms; + private final Function2 customSubtype; private OverridingUtil( @NotNull KotlinTypeChecker.TypeConstructorEquality axioms, - @NotNull KotlinTypeRefiner kotlinTypeRefiner + @NotNull KotlinTypeRefiner kotlinTypeRefiner, + @NotNull KotlinTypePreparator kotlinTypePreparator, + @Nullable Function2 customSubtype ) { equalityAxioms = axioms; this.kotlinTypeRefiner = kotlinTypeRefiner; + this.kotlinTypePreparator = kotlinTypePreparator; + this.customSubtype = customSubtype; } /** @@ -395,8 +406,9 @@ public class OverridingUtil { "Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters; if (firstParameters.isEmpty()) { - return new OverridingUtilTypeSystemContext(null, equalityAxioms, kotlinTypeRefiner) - .newTypeCheckerState(true, true); + return new OverridingUtilTypeSystemContext( + null, equalityAxioms, kotlinTypeRefiner, kotlinTypePreparator, customSubtype + ).newTypeCheckerState(true, true); } Map matchingTypeConstructors = new HashMap(); @@ -404,8 +416,9 @@ public class OverridingUtil { matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor()); } - return new OverridingUtilTypeSystemContext(matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner) - .newTypeCheckerState(true, true); + return new OverridingUtilTypeSystemContext( + matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner, kotlinTypePreparator, customSubtype + ).newTypeCheckerState(true, true); } @Nullable diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt index 1f66eca5ce4..c820cf81a24 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtilTypeSystemContext.kt @@ -5,18 +5,19 @@ package org.jetbrains.kotlin.resolve +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.TypeConstructor -import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner -import org.jetbrains.kotlin.types.checker.createClassicTypeCheckerState +import org.jetbrains.kotlin.types.checker.* +import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker class OverridingUtilTypeSystemContext( val matchingTypeConstructors: Map?, private val equalityAxioms: KotlinTypeChecker.TypeConstructorEquality, - val kotlinTypeRefiner: KotlinTypeRefiner + private val kotlinTypeRefiner: KotlinTypeRefiner, + private val kotlinTypePreparator: KotlinTypePreparator, + private val customSubtype: ((KotlinType, KotlinType) -> Boolean)? = null, ) : ClassicTypeSystemContext { override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean { @@ -29,12 +30,27 @@ class OverridingUtilTypeSystemContext( errorTypesEqualToAnything: Boolean, stubTypesEqualToAnything: Boolean ): TypeCheckerState { - return createClassicTypeCheckerState( - errorTypesEqualToAnything, - stubTypesEqualToAnything, + if (customSubtype == null) { + return createClassicTypeCheckerState( + errorTypesEqualToAnything, + stubTypesEqualToAnything, + typeSystemContext = this, + kotlinTypeRefiner = kotlinTypeRefiner, + kotlinTypePreparator = kotlinTypePreparator, + ) + } + + return object : TypeCheckerState( + errorTypesEqualToAnything, stubTypesEqualToAnything, allowedTypeVariable = true, typeSystemContext = this, - kotlinTypeRefiner = kotlinTypeRefiner - ) + kotlinTypePreparator, kotlinTypeRefiner, + ) { + override fun customIsSubtypeOf(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean { + require(subType is KotlinType) + require(superType is KotlinType) + return customSubtype.invoke(subType, superType) + } + } } private fun areEqualTypeConstructorsByAxioms(a: TypeConstructor, b: TypeConstructor): Boolean { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index aef68dad16e..13dc77d3f32 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -150,6 +150,9 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this as? DefinitelyNotNullType } + @OptIn(ObsoleteTypeKind::class) + override fun KotlinTypeMarker.isNotNullTypeVariable(): Boolean = this is NotNullTypeVariable + override fun SimpleTypeMarker.isMarkedNullable(): Boolean { require(this is SimpleType, this::errorMessage) return this.isMarkedNullable