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 afd6f5d71f4..3159c9c5551 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 @@ -35,11 +35,9 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.expressions.SenselessComparisonChecker import org.jetbrains.kotlin.types.model.KotlinTypeMarker -import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.makeNotNullable class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : AdditionalTypeChecker { @@ -233,31 +231,21 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio ) { if (TypeUtils.noExpectedType(expectedType)) return - val doesExpectedTypeContainsEnhancement = expectedType.contains { it is TypeWithEnhancement } - val doesExpressionTypeContainsEnhancement = expressionType.contains { it is TypeWithEnhancement } + @Suppress("NAME_SHADOWING") + val expressionType = exactedExpressionTypeByDataFlowNullability(expressionType, expressionTypeDataFlowValue, dataFlowInfo) - if (!doesExpectedTypeContainsEnhancement && !doesExpressionTypeContainsEnhancement) return - - val enhancedExpectedType = if (doesExpectedTypeContainsEnhancement) expectedType.unwrapEnhancementDeeply() else expectedType - val enhancedExpressionType = enhanceExpressionTypeByDataFlowNullability( - if (doesExpressionTypeContainsEnhancement) expressionType.unwrapEnhancementDeeply() else expressionType, - expressionTypeDataFlowValue, - dataFlowInfo - ) - - val isEnhancedExpectedTypeSubtypeOfExpressionType = - KotlinTypeChecker.DEFAULT.isSubtypeOf(enhancedExpressionType, enhancedExpectedType) + val isEnhancedExpectedTypeSubtypeOfExpressionType = typeCheckerForEnhancedTypes.isSubtypeOf(expressionType, expectedType) if (isEnhancedExpectedTypeSubtypeOfExpressionType) return - val isExpectedTypeSubtypeOfExpressionType = KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType) + val isExpectedTypeSubtypeOfExpressionType = typeCheckerForBaseTypes.isSubtypeOf(expressionType, expectedType) if (!isEnhancedExpectedTypeSubtypeOfExpressionType && isExpectedTypeSubtypeOfExpressionType) { - reportWarning(enhancedExpectedType, enhancedExpressionType) + reportWarning(expectedType.unwrapEnhancementDeeply(), expressionType.unwrapEnhancementDeeply()) } } - private fun enhanceExpressionTypeByDataFlowNullability( + private fun exactedExpressionTypeByDataFlowNullability( expressionType: KotlinType, expressionTypeDataFlowValue: () -> DataFlowValue, dataFlowInfo: DataFlowInfo, @@ -276,6 +264,17 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio } else { null } + + companion object { + val typeCheckerForEnhancedTypes = NewKotlinTypeCheckerImpl( + kotlinTypeRefiner = KotlinTypeRefiner.Default, + kotlinTypePreparator = object : KotlinTypePreparator() { + override fun prepareType(type: KotlinTypeMarker): UnwrappedType = + super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap() + } + ) + val typeCheckerForBaseTypes = NewKotlinTypeCheckerImpl(KotlinTypeRefiner.Default) + } } class EnhancedNullabilityInfo(val enhancedType: KotlinType, val isFromJava: Boolean) { diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.fir.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.fir.kt index dec96252bd2..a5bb0e961ba 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.fir.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.fir.kt @@ -42,8 +42,7 @@ fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit { // jspecify_nullness_mismatch ak.foo(null) - // jspecify_nullness_mismatch - akn.foo(null) + akn.foo(null) bk.foo(bk) // jspecify_nullness_mismatch @@ -53,6 +52,5 @@ fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit { // jspecify_nullness_mismatch ck.foo(null) - // jspecify_nullness_mismatch - ckn.foo(null) + ckn.foo(null) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.kt index dec96252bd2..65e558acf99 100644 --- a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.kt +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/warnMode/SelfType.kt @@ -42,8 +42,7 @@ fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit { // jspecify_nullness_mismatch ak.foo(null) - // jspecify_nullness_mismatch - akn.foo(null) + akn.foo(null) // the corresponding warning/error is present on the Java side bk.foo(bk) // jspecify_nullness_mismatch @@ -53,6 +52,5 @@ fun main(ak: AK, akn: AKN, bk: BK, ck: CK, ckn: CKN): Unit { // jspecify_nullness_mismatch ck.foo(null) - // jspecify_nullness_mismatch - ckn.foo(null) + ckn.foo(null) // the corresponding warning/error is present on the Java side } \ No newline at end of file diff --git a/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt new file mode 100644 index 00000000000..07f858de200 --- /dev/null +++ b/compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt @@ -0,0 +1,22 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// SKIP_TXT +// MUTE_FOR_PSI_CLASS_FILES_READING + +// We've already had errors in source mode, so it's relevant only for binaries for now + +// FILE: Base.java +// INCLUDE_JAVA_AS_BINARY +public class Base {} + +// FILE: Test.java +// INCLUDE_JAVA_AS_BINARY +import org.jetbrains.annotations.Nullable; + +class Test extends Base<@Nullable String> {} + +// FILE: main.kt +fun takeBaseOfNotNullStrings(x: Base) {} + +fun main() { + val x = takeBaseOfNotNullStrings(Test()) +} \ No newline at end of file diff --git a/compiler/testData/loadJava8/sourceJava/typeUseAnnotations/Basic_DisabledImprovements.txt b/compiler/testData/loadJava8/sourceJava/typeUseAnnotations/Basic_DisabledImprovements.txt index 9b6ffd2351f..63bf24cbfcb 100644 --- a/compiler/testData/loadJava8/sourceJava/typeUseAnnotations/Basic_DisabledImprovements.txt +++ b/compiler/testData/loadJava8/sourceJava/typeUseAnnotations/Basic_DisabledImprovements.txt @@ -11,7 +11,7 @@ public open class Basic_DisabledImprovements : test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.NotNull T!, @org.jetbrains.annotations.NotNull kotlin.String!> { + public/*package*/ interface G : test.Basic_DisabledImprovements.G2<@org.jetbrains.annotations.NotNull T, @org.jetbrains.annotations.NotNull kotlin.String> { } public/*package*/ interface G2 { 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 190d5574b2d..ef57f8b1239 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 @@ -1044,6 +1044,12 @@ public class ForeignAnnotationsCompiledJavaTestGenerated extends AbstractForeign public void testValueParameter_fir() throws Exception { runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/valueParameter.fir.kt"); } + + @Test + @TestMetadata("warningsBasedOnEnhancedBasedType.kt") + public void testWarningsBasedOnEnhancedBasedType() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt"); + } } } 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 d809fac90f9..3d4a9985fb0 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 @@ -1044,6 +1044,12 @@ public class ForeignAnnotationsCompiledJavaWithPsiClassReadingTestGenerated exte public void testValueParameter_fir() throws Exception { runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/valueParameter.fir.kt"); } + + @Test + @TestMetadata("warningsBasedOnEnhancedBasedType.kt") + public void testWarningsBasedOnEnhancedBasedType() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt"); + } } } 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 0db30fbb436..b9b0403ebe0 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 @@ -1044,6 +1044,12 @@ public class ForeignAnnotationsSourceJavaTestGenerated extends AbstractForeignAn public void testValueParameter_fir() throws Exception { runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/valueParameter.fir.kt"); } + + @Test + @TestMetadata("warningsBasedOnEnhancedBasedType.kt") + public void testWarningsBasedOnEnhancedBasedType() throws Exception { + runTest("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/misc/warningsBasedOnEnhancedBasedType.kt"); + } } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt index 638ecea589c..3db48713d96 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -215,10 +215,7 @@ class LazyJavaClassDescriptor( for (javaType in javaTypes) { val kotlinType = c.typeResolver.transformJavaType(javaType, TypeUsage.SUPERTYPE.toAttributes()) - val areImprovementsInStrictMode = c.components.settings.typeEnhancementImprovementsInStrictMode - val enhancedKotlinType = if (areImprovementsInStrictMode) { - c.components.signatureEnhancement.enhanceSuperType(kotlinType, c) - } else kotlinType + val enhancedKotlinType = c.components.signatureEnhancement.enhanceSuperType(kotlinType, c) if (enhancedKotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor) { incomplete.add(javaType) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index 78737803f4f..393252ef7fe 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -188,7 +188,10 @@ public class TypeSubstitutor implements TypeSubstitutorMarker { ); KotlinType substitutedEnhancement = substitute(enhancement, originalProjection.getProjectionKind()); - KotlinType resultingType = TypeWithEnhancementKt.wrapEnhancement(substitution.getType().unwrap(), substitutedEnhancement); + KotlinType resultingType = TypeWithEnhancementKt.wrapEnhancement( + substitution.getType().unwrap(), + substitutedEnhancement instanceof TypeWithEnhancement ? ((TypeWithEnhancement) substitutedEnhancement).getEnhancement() : substitutedEnhancement + ); return new TypeProjectionImpl(substitution.getProjectionKind(), resultingType); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 8a30f3af523..49c1abea55f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -77,11 +77,14 @@ class NewKotlinTypeCheckerImpl( override val overridingUtil: OverridingUtil = OverridingUtil.createWithTypeRefiner(kotlinTypeRefiner) override fun isSubtypeOf(subtype: KotlinType, supertype: KotlinType): Boolean = - ClassicTypeCheckerContext(true, kotlinTypeRefiner = kotlinTypeRefiner) - .isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything + ClassicTypeCheckerContext( + true, kotlinTypeRefiner = kotlinTypeRefiner, kotlinTypePreparator = kotlinTypePreparator + ).isSubtypeOf(subtype.unwrap(), supertype.unwrap()) // todo fix flag errorTypeEqualsToAnything override fun equalTypes(a: KotlinType, b: KotlinType): Boolean = - ClassicTypeCheckerContext(false, kotlinTypeRefiner = kotlinTypeRefiner).equalTypes(a.unwrap(), b.unwrap()) + ClassicTypeCheckerContext( + false, kotlinTypeRefiner = kotlinTypeRefiner, kotlinTypePreparator = kotlinTypePreparator + ).equalTypes(a.unwrap(), b.unwrap()) fun ClassicTypeCheckerContext.equalTypes(a: UnwrappedType, b: UnwrappedType): Boolean { return AbstractTypeChecker.equalTypes(this as AbstractTypeCheckerContext, a, b) diff --git a/nj2k/testData/inference/nullability/callExternallyAnnotatedJavaFunction.kt b/nj2k/testData/inference/nullability/callExternallyAnnotatedJavaFunction.kt index 7bc793a4861..b7484f11f83 100644 --- a/nj2k/testData/inference/nullability/callExternallyAnnotatedJavaFunction.kt +++ b/nj2k/testData/inference/nullability/callExternallyAnnotatedJavaFunction.kt @@ -1,10 +1,11 @@ import java.util.Arrays.asList fun test() { - val x: /*T2@*/List = asList(1/*LIT*/)/*MutableList*/ + val x: /*T2@*/List = asList(1/*LIT*/)/*MutableList!!L*/ val i: /*T3@*/Int = Integer/*LIT*/.valueOf(""/*LIT*/)/*Int!!L*/ } //LOWER <: T0 due to 'PARAMETER' //T1 := T0 due to 'INITIALIZER' +//LOWER <: T2 due to 'INITIALIZER' //LOWER <: T3 due to 'INITIALIZER'