[FIR] Assume SafeCallsAreAlwaysNullable is always on
This commit is contained in:
committed by
Space Team
parent
be5850112a
commit
72823657c9
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve
|
|||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind
|
import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.fakeElement
|
import org.jetbrains.kotlin.fakeElement
|
||||||
@@ -493,25 +492,15 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
||||||
nullableReceiverExpression: FirExpression,
|
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
file: FirFile,
|
file: FirFile,
|
||||||
) {
|
) {
|
||||||
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
|
||||||
val selector = selector
|
val selector = selector
|
||||||
|
|
||||||
val resultingType = when {
|
val resultingType = when {
|
||||||
selector is FirExpression && !selector.isCallToStatementLikeFunction -> {
|
selector is FirExpression && !selector.isCallToStatementLikeFunction -> {
|
||||||
val type = selector.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
val type = selector.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
type.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
||||||
val isReceiverActuallyNullable = session.languageVersionSettings.supportsFeature(LanguageFeature.SafeCallsAreAlwaysNullable)
|
|
||||||
|| receiverType != null && session.typeContext.run { receiverType.isNullableType() }
|
|
||||||
|
|
||||||
if (isReceiverActuallyNullable) {
|
|
||||||
type.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
|
||||||
} else {
|
|
||||||
type
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Branch for things that shouldn't be used as expressions.
|
// Branch for things that shouldn't be used as expressions.
|
||||||
// They are forced to return not-null `Unit`, regardless of the receiver.
|
// They are forced to return not-null `Unit`, regardless of the receiver.
|
||||||
|
|||||||
+1
-1
@@ -343,7 +343,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
)?.toExpectedType()
|
)?.toExpectedType()
|
||||||
)
|
)
|
||||||
|
|
||||||
safeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(safeCallExpression.receiver, session, context.file)
|
safeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(session, context.file)
|
||||||
|
|
||||||
return safeCallExpression
|
return safeCallExpression
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -357,7 +357,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
|||||||
safeCallExpression.apply {
|
safeCallExpression.apply {
|
||||||
checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session, components.file)
|
checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session, components.file)
|
||||||
transformSelector(this@FirExpressionsResolveTransformer, data)
|
transformSelector(this@FirExpressionsResolveTransformer, data)
|
||||||
propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session, context.file)
|
propagateTypeFromQualifiedAccessAfterNullCheck(session, context.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataFlowAnalyzer.exitSafeCall(safeCallExpression)
|
dataFlowAnalyzer.exitSafeCall(safeCallExpression)
|
||||||
|
|||||||
+3
@@ -1,4 +1,7 @@
|
|||||||
// !LANGUAGE: -SafeCallsAreAlwaysNullable
|
// !LANGUAGE: -SafeCallsAreAlwaysNullable
|
||||||
|
// IGNORE_BACKEND_K2: JVM_IR
|
||||||
|
// Status: Feature is always on in K2
|
||||||
|
|
||||||
fun test(s: String) = s?.length
|
fun test(s: String) = s?.length
|
||||||
|
|
||||||
// 0 IFNULL
|
// 0 IFNULL
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// !LANGUAGE: -SafeCallsAreAlwaysNullable
|
||||||
|
// http://youtrack.jetbrains.net/issue/KT-418
|
||||||
|
|
||||||
|
fun ff() {
|
||||||
|
val i: Int = 1
|
||||||
|
val a: Int = <!INITIALIZER_TYPE_MISMATCH!>i<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>plus(2)<!><!>
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
// !LANGUAGE: -SafeCallsAreAlwaysNullable
|
// !LANGUAGE: -SafeCallsAreAlwaysNullable
|
||||||
// http://youtrack.jetbrains.net/issue/KT-418
|
// http://youtrack.jetbrains.net/issue/KT-418
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,6 +8,6 @@ fun foo(): String {
|
|||||||
}
|
}
|
||||||
fun bar(): String {
|
fun bar(): String {
|
||||||
val x = fn() ?: return ""
|
val x = fn() ?: return ""
|
||||||
val y = x<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> <!USELESS_ELVIS!>?: "unreachable"<!>
|
val y = x<!SAFE_CALL_WILL_CHANGE_NULLABILITY!><!UNNECESSARY_SAFE_CALL!>?.<!>let { throw Exception() }<!> ?: "unreachable"
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
|||||||
+34
@@ -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()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.foo()<!><!UNSAFE_CALL!>.<!>length
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2(a: A) {
|
||||||
|
val s = a.id()
|
||||||
|
.id()
|
||||||
|
.id()
|
||||||
|
.id()
|
||||||
|
<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.id()<!>
|
||||||
|
<!UNSAFE_CALL!>.<!>id()
|
||||||
|
.id()
|
||||||
|
.id()
|
||||||
|
<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.foo()<!>
|
||||||
|
?.length
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_3(a: A) {
|
||||||
|
val s = a.id()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.
|
||||||
|
id()<!><!UNSAFE_CALL!>.<!>
|
||||||
|
id()<!SAFE_CALL_WILL_CHANGE_NULLABILITY!>?.
|
||||||
|
foo()<!><!UNSAFE_CALL!>.<!>
|
||||||
|
length
|
||||||
|
}
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
// LANGUAGE: -SafeCallsAreAlwaysNullable
|
// LANGUAGE: -SafeCallsAreAlwaysNullable
|
||||||
// DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
// DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||||
// ISSUE: KT-46860
|
// ISSUE: KT-46860
|
||||||
|
|||||||
Reference in New Issue
Block a user