diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 7db77b8fd78..e6c8b36c008 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -619,6 +619,8 @@ public interface Errors { DiagnosticFactory1> AMBIGUOUS_ANONYMOUS_TYPE_INFERRED = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE); + DiagnosticFactory1 APPROXIMATED_LOCAL_TYPE_WILL_BECOME_NULLABLE = + DiagnosticFactory1.create(WARNING, DECLARATION_SIGNATURE); DiagnosticFactory1 KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE = DiagnosticFactory1.create(ERROR, PositioningStrategies.DECLARATION_NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 20aa1409583..56591abea99 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1067,6 +1067,8 @@ public class DefaultErrorMessages { MAP.put(CATCH_PARAMETER_WITH_DEFAULT_VALUE, "Catch clause parameter may not have a default value"); MAP.put(AMBIGUOUS_ANONYMOUS_TYPE_INFERRED, "Right-hand side has anonymous type. Please specify type explicitly", TO_STRING); + MAP.put(APPROXIMATED_LOCAL_TYPE_WILL_BECOME_NULLABLE, + "Declaration return type inferred as ''{0}'' instead of ''{0}?''. This will be fixed in Kotlin 1.9. Please specify the type explicitly to avoid future errors or unexpected changes in behavior. See https://youtrack.jetbrains.com/issue/KT-53982 for details.", TO_STRING); MAP.put(KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE, "Declaration has an inconsistent return type. Please add upper bound Any for type parameter ''{0}'' or specify return type explicitly", NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 76e08ed6d0b..bdd58fbd489 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -1094,6 +1094,11 @@ public class DescriptorResolver { substitutedSuperType = approximatingSuperType; } + if (languageVersionSettings.supportsFeature(LanguageFeature.KeepNullabilityWhenApproximatingLocalType)) { + return TypeUtils.makeNullableIfNeeded(substitutedSuperType, type.isMarkedNullable()); + } else if (type.isMarkedNullable()) { + trace.report(APPROXIMATED_LOCAL_TYPE_WILL_BECOME_NULLABLE.on(declaration, substitutedSuperType)); + } return substitutedSuperType; } else { diff --git a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.kt b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.kt index 2e4e5e03f3a..ea668fa02d8 100644 --- a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.kt +++ b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.kt @@ -1,4 +1,6 @@ // ISSUE: KT-30054 +// FIR_IDENTICAL +// !LANGUAGE: +KeepNullabilityWhenApproximatingLocalType interface I { fun foo(): String } @@ -13,6 +15,6 @@ fun bar(condition: Boolean) /*: I? */ = fun main() { bar(false).baz() - bar(false).foo() - bar(false)?.foo() + bar(false).foo() + bar(false)?.foo() } diff --git a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.txt b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.txt index e619714080d..cc60679abe1 100644 --- a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.txt +++ b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.txt @@ -1,6 +1,6 @@ package -public fun bar(/*0*/ condition: kotlin.Boolean): I +public fun bar(/*0*/ condition: kotlin.Boolean): I? public fun main(): kotlin.Unit public interface I { diff --git a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.fir.kt b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.fir.kt similarity index 100% rename from compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition.fir.kt rename to compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.fir.kt diff --git a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.kt b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.kt new file mode 100644 index 00000000000..66022c12587 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.kt @@ -0,0 +1,18 @@ +// ISSUE: KT-30054 +interface I { + fun foo(): String +} + +fun bar(condition: Boolean) /*: I? */ = + if (condition) + object : I { + override fun foo() = "should check for null first" + fun baz() = "invisible" + } + else null + +fun main() { + bar(false).baz() + bar(false).foo() + bar(false)?.foo() +} diff --git a/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.txt b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.txt new file mode 100644 index 00000000000..e619714080d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/substitutions/hideNullableLocalTypeInPublicPosition_before.txt @@ -0,0 +1,11 @@ +package + +public fun bar(/*0*/ condition: kotlin.Boolean): I +public fun main(): kotlin.Unit + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 46cfd364a9d..15338044908 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -278,6 +278,7 @@ enum class LanguageFeature( ForbidInferringTypeVariablesIntoEmptyIntersection(KOTLIN_1_9, kind = BUG_FIX), // KT-51221 ForbidExtensionCallsOnInlineFunctionalParameters(KOTLIN_1_9, kind = BUG_FIX), // KT-52502 ForbidInferringPostponedTypeVariableIntoDeclaredUpperBound(KOTLIN_1_9, kind = BUG_FIX), // KT-47986 + KeepNullabilityWhenApproximatingLocalType(KOTLIN_1_9, kind = BUG_FIX), // KT-53982 SkipStandaloneScriptsInSourceRoots(KOTLIN_1_9, kind = OTHER), // KT-52525 ModifierNonBuiltinSuspendFunError(KOTLIN_1_9), BreakContinueInInlineLambdas(KOTLIN_1_9, defaultState = State.ENABLED), // KT-1436