From 72823657c91f76aba664a7106c74debb355d82fe Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Fri, 24 Feb 2023 16:02:35 +0200 Subject: [PATCH] [FIR] Assume `SafeCallsAreAlwaysNullable` is always on --- .../kotlin/fir/resolve/ResolveUtils.kt | 13 +------ ...rCallCompletionResultsWriterTransformer.kt | 2 +- .../FirExpressionsResolveTransformer.kt | 2 +- .../redundantSafeCall_1_4.kt | 3 ++ .../tests/SafeCallNonNullReceiver.fir.kt | 7 ++++ .../tests/SafeCallNonNullReceiver.kt | 1 - .../controlFlowAnalysis/throwInLambda.fir.kt | 2 +- .../safeCallOnNotNullableType.fir.kt | 34 +++++++++++++++++++ .../safeCallOnNotNullableType.kt | 1 - 9 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.fir.kt create mode 100644 compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.fir.kt 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 e901f7c954f..043af0b2ae4 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 @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind -import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fakeElement @@ -493,25 +492,15 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver( } fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( - nullableReceiverExpression: FirExpression, session: FirSession, file: FirFile, ) { - val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe() val selector = selector val resultingType = when { selector is FirExpression && !selector.isCallToStatementLikeFunction -> { val type = selector.typeRef.coneTypeSafe() ?: return - - val isReceiverActuallyNullable = session.languageVersionSettings.supportsFeature(LanguageFeature.SafeCallsAreAlwaysNullable) - || receiverType != null && session.typeContext.run { receiverType.isNullableType() } - - if (isReceiverActuallyNullable) { - type.withNullability(ConeNullability.NULLABLE, session.typeContext) - } else { - type - } + type.withNullability(ConeNullability.NULLABLE, session.typeContext) } // Branch for things that shouldn't be used as expressions. // They are forced to return not-null `Unit`, regardless of the receiver. diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 2ad630f32f3..5ff0da98482 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -343,7 +343,7 @@ class FirCallCompletionResultsWriterTransformer( )?.toExpectedType() ) - safeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(safeCallExpression.receiver, session, context.file) + safeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(session, context.file) return safeCallExpression } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 0c1232201e8..92681244294 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -357,7 +357,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT safeCallExpression.apply { checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session, components.file) transformSelector(this@FirExpressionsResolveTransformer, data) - propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session, context.file) + propagateTypeFromQualifiedAccessAfterNullCheck(session, context.file) } dataFlowAnalyzer.exitSafeCall(safeCallExpression) diff --git a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt index ff40c8cea9a..ef51f4c5f3e 100644 --- a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt +++ b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall_1_4.kt @@ -1,4 +1,7 @@ // !LANGUAGE: -SafeCallsAreAlwaysNullable +// IGNORE_BACKEND_K2: JVM_IR +// Status: Feature is always on in K2 + fun test(s: String) = s?.length // 0 IFNULL diff --git a/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.fir.kt b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.fir.kt new file mode 100644 index 00000000000..b8df0267ee6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.fir.kt @@ -0,0 +1,7 @@ +// !LANGUAGE: -SafeCallsAreAlwaysNullable +// http://youtrack.jetbrains.net/issue/KT-418 + +fun ff() { + val i: Int = 1 + val a: Int = i?.plus(2) +} diff --git a/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.kt b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.kt index 6d1d4b10516..77fca4eb250 100644 --- a/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.kt +++ b/compiler/testData/diagnostics/tests/SafeCallNonNullReceiver.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: -SafeCallsAreAlwaysNullable // http://youtrack.jetbrains.net/issue/KT-418 diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/throwInLambda.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/throwInLambda.fir.kt index 9ac2a512356..363ef526eda 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/throwInLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/throwInLambda.fir.kt @@ -8,6 +8,6 @@ fun foo(): String { } fun bar(): String { val x = fn() ?: return "" - val y = x?.let { throw Exception() } ?: "unreachable" + val y = x?.let { throw Exception() } ?: "unreachable" return y } diff --git a/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.fir.kt b/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.fir.kt new file mode 100644 index 00000000000..795f7cddd0f --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.fir.kt @@ -0,0 +1,34 @@ +// LANGUAGE: -SafeCallsAreAlwaysNullable +// DIAGNOSTICS: -UNNECESSARY_SAFE_CALL +// ISSUE: KT-46860 + +interface A { + fun id(): A + + fun foo(): String +} + +fun test_1(a: A) { + val s = a.id().id().id().id().id().id().id().id()?.foo().length +} + +fun test_2(a: A) { + val s = a.id() + .id() + .id() + .id() + ?.id() + .id() + .id() + .id() + ?.foo() + ?.length +} + +fun test_3(a: A) { + val s = a.id()?. + id(). + id()?. + foo(). + length +} diff --git a/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt b/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt index 03e40352f7b..d7984e85248 100644 --- a/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt +++ b/compiler/testData/diagnostics/tests/nullableTypes/safeCallOnNotNullableType.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // LANGUAGE: -SafeCallsAreAlwaysNullable // DIAGNOSTICS: -UNNECESSARY_SAFE_CALL // ISSUE: KT-46860