From 09994ee8ea9c3194abd89a6bb49705a1d05cabbd Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 21 Jun 2021 17:34:21 +0300 Subject: [PATCH] [FIR] Make type of safe call always nullable ^KT-46860 In Progress --- .../RedundantCallOfConversionMethod/safeString.kt | 2 +- .../UselessCallOnNotNullChecker/NullOrEmptySafe.kt | 2 +- .../UselessCallOnNotNullChecker/SafeCall.kt | 2 +- .../src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt | 8 ++++++-- .../tests/SafeCallNonNullReceiverReturnNull.fir.kt | 2 +- .../tests/j+k/sam/enhancedSamConstructor.fir.kt | 4 ++-- .../tests/nullableTypes/safeCallWithInvoke.fir.kt | 2 +- .../tests/resolve/nestedCalls/kt5971NestedSafeCall.fir.kt | 2 +- .../smartCasts/safecalls/safeCallIsAlwaysNullable.fir.kt | 8 ++++---- 9 files changed, 18 insertions(+), 14 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt index 117eefbbe6a..e479da51b0f 100644 --- a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt +++ b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt @@ -3,4 +3,4 @@ fun test() { val foo: String? = null foo?.toString() -} \ No newline at end of file +} diff --git a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptySafe.kt b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptySafe.kt index 15e458bc332..7ed493f1427 100644 --- a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptySafe.kt +++ b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptySafe.kt @@ -1,4 +1,4 @@ // WITH_RUNTIME val s: String? = "" -val empty = s?.isNullOrEmpty() \ No newline at end of file +val empty = s?.isNullOrEmpty() diff --git a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/SafeCall.kt b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/SafeCall.kt index 688b7c51722..d553f4ed464 100644 --- a/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/SafeCall.kt +++ b/compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/SafeCall.kt @@ -1,4 +1,4 @@ // WITH_RUNTIME val list1: List? = listOf(1) -val list = list1?.orEmpty() \ No newline at end of file +val list = list1?.orEmpty() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 61421dd7140..e2d990200b5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.functions.FunctionClassKind +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* @@ -343,8 +344,11 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( ) { val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe() val typeAfterNullCheck = regularQualifiedAccess.expressionTypeOrUnitForAssignment() ?: return - val isReceiverActuallyNullable = receiverType != null && session.typeContext.run { receiverType.isNullableType() } - + val isReceiverActuallyNullable = if (session.languageVersionSettings.supportsFeature(LanguageFeature.SafeCallsAreAlwaysNullable)) { + true + } else { + receiverType != null && session.typeContext.run { receiverType.isNullableType() } + } val resultingType = if (isReceiverActuallyNullable) typeAfterNullCheck.withNullability(ConeNullability.NULLABLE, session.typeContext) diff --git a/compiler/testData/diagnostics/tests/SafeCallNonNullReceiverReturnNull.fir.kt b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiverReturnNull.fir.kt index 55512d0cfd5..095029e7c7b 100644 --- a/compiler/testData/diagnostics/tests/SafeCallNonNullReceiverReturnNull.fir.kt +++ b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiverReturnNull.fir.kt @@ -2,5 +2,5 @@ fun Int.gg() = null fun ff() { val a: Int = 1 - val b: Int = a?.gg() + val b: Int = a?.gg() } diff --git a/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.fir.kt b/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.fir.kt index cd09789325d..24ab93247c7 100644 --- a/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/sam/enhancedSamConstructor.fir.kt @@ -18,10 +18,10 @@ fun main() { J { s: String -> s} // should be prohibited, because SAM value parameter has nullable type J { "" + it.length } J { null } - J { it?.length?.toString() } + J { it?.length?.toString() } J2 { s: String -> s} J2 { "" + it.length } J2 { null } - J2 { it?.length?.toString() } + J2 { it?.length?.toString() } } diff --git a/compiler/testData/diagnostics/tests/nullableTypes/safeCallWithInvoke.fir.kt b/compiler/testData/diagnostics/tests/nullableTypes/safeCallWithInvoke.fir.kt index 4394ffb1230..d2c0aa98deb 100644 --- a/compiler/testData/diagnostics/tests/nullableTypes/safeCallWithInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/nullableTypes/safeCallWithInvoke.fir.kt @@ -8,5 +8,5 @@ fun foo(i: Int) = i fun test(a: A?) { a?.b(1) //should be no warning - foo(a?.b(1)) //no warning, only error + foo(a?.b(1)) //no warning, only error } diff --git a/compiler/testData/diagnostics/tests/resolve/nestedCalls/kt5971NestedSafeCall.fir.kt b/compiler/testData/diagnostics/tests/resolve/nestedCalls/kt5971NestedSafeCall.fir.kt index 8e8a35fc8fb..852b21a2e30 100644 --- a/compiler/testData/diagnostics/tests/resolve/nestedCalls/kt5971NestedSafeCall.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/nestedCalls/kt5971NestedSafeCall.fir.kt @@ -6,5 +6,5 @@ fun foo(i: Int) {} fun test(s: String?) { - foo(s?.length) + foo(s?.length) } diff --git a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeCallIsAlwaysNullable.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeCallIsAlwaysNullable.fir.kt index c29d2d705a5..8442161aeeb 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeCallIsAlwaysNullable.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/safecalls/safeCallIsAlwaysNullable.fir.kt @@ -8,13 +8,13 @@ interface A { fun takeInt(x: Int) {} fun test_1(a: A) { - val x = a?.foo() - takeInt(x) // should be an error + val x = a?.foo() + takeInt(x) // should be an error } fun test_2(a: A?) { if (a != null) { - val x = a?.foo() - takeInt(x) // should be an error + val x = a?.foo() + takeInt(x) // should be an error } }