[FIR] Make type of safe call always nullable
^KT-46860 In Progress
This commit is contained in:
committed by
teamcityserver
parent
f18e38a49f
commit
09994ee8ea
+1
-1
@@ -3,4 +3,4 @@
|
|||||||
fun test() {
|
fun test() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
foo?.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toString()<!>
|
foo?.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toString()<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val s: String? = ""
|
val s: String? = ""
|
||||||
val empty = s?.<!USELESS_CALL_ON_NOT_NULL!>isNullOrEmpty()<!>
|
val empty = s?.<!USELESS_CALL_ON_NOT_NULL!>isNullOrEmpty()<!>
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val list1: List<Int>? = listOf(1)
|
val list1: List<Int>? = listOf(1)
|
||||||
val list = list1?.<!USELESS_CALL_ON_NOT_NULL!>orEmpty()<!>
|
val list = list1?.<!USELESS_CALL_ON_NOT_NULL!>orEmpty()<!>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
@@ -343,8 +344,11 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
|||||||
) {
|
) {
|
||||||
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
val typeAfterNullCheck = regularQualifiedAccess.expressionTypeOrUnitForAssignment() ?: return
|
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 =
|
val resultingType =
|
||||||
if (isReceiverActuallyNullable)
|
if (isReceiverActuallyNullable)
|
||||||
typeAfterNullCheck.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
typeAfterNullCheck.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
||||||
|
|||||||
+1
-1
@@ -2,5 +2,5 @@ fun Int.gg() = null
|
|||||||
|
|
||||||
fun ff() {
|
fun ff() {
|
||||||
val a: Int = 1
|
val a: Int = 1
|
||||||
val b: Int = <!INITIALIZER_TYPE_MISMATCH!>a<!UNNECESSARY_SAFE_CALL!>?.<!><!TYPE_MISMATCH!>gg()<!><!>
|
val b: Int = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH!>a<!UNNECESSARY_SAFE_CALL!>?.<!>gg()<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ fun main() {
|
|||||||
J <!ARGUMENT_TYPE_MISMATCH!>{ s: String -> s}<!> // should be prohibited, because SAM value parameter has nullable type
|
J <!ARGUMENT_TYPE_MISMATCH!>{ s: String -> s}<!> // should be prohibited, because SAM value parameter has nullable type
|
||||||
J { "" + it<!UNSAFE_CALL!>.<!>length }
|
J { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||||
J { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
J { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
||||||
J { it?.length?.<!ARGUMENT_TYPE_MISMATCH!>toString()<!> }
|
J { <!ARGUMENT_TYPE_MISMATCH!>it?.length?.toString()<!> }
|
||||||
|
|
||||||
J2 <!ARGUMENT_TYPE_MISMATCH!>{ s: String -> s}<!>
|
J2 <!ARGUMENT_TYPE_MISMATCH!>{ s: String -> s}<!>
|
||||||
J2 { "" + it<!UNSAFE_CALL!>.<!>length }
|
J2 { "" + it<!UNSAFE_CALL!>.<!>length }
|
||||||
J2 { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
J2 { <!NULL_FOR_NONNULL_TYPE!>null<!> }
|
||||||
J2 { it?.length?.<!ARGUMENT_TYPE_MISMATCH!>toString()<!> }
|
J2 { <!ARGUMENT_TYPE_MISMATCH!>it?.length?.toString()<!> }
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,5 +8,5 @@ fun foo(i: Int) = i
|
|||||||
|
|
||||||
fun test(a: A?) {
|
fun test(a: A?) {
|
||||||
a?.b(1) //should be no warning
|
a?.b(1) //should be no warning
|
||||||
foo(a?.<!ARGUMENT_TYPE_MISMATCH!>b(1)<!>) //no warning, only error
|
foo(<!ARGUMENT_TYPE_MISMATCH!>a?.b(1)<!>) //no warning, only error
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,5 +6,5 @@
|
|||||||
fun foo(i: Int) {}
|
fun foo(i: Int) {}
|
||||||
|
|
||||||
fun test(s: String?) {
|
fun test(s: String?) {
|
||||||
foo(<!ARGUMENT_TYPE_MISMATCH{PSI}!>s?.<!ARGUMENT_TYPE_MISMATCH{LT}!>length<!><!>)
|
foo(<!ARGUMENT_TYPE_MISMATCH!>s?.length<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -8,13 +8,13 @@ interface A {
|
|||||||
fun takeInt(x: Int) {}
|
fun takeInt(x: Int) {}
|
||||||
|
|
||||||
fun test_1(a: A) {
|
fun test_1(a: A) {
|
||||||
val x = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>a<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!>
|
val x = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>a<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!>
|
||||||
takeInt(x) // should be an error
|
takeInt(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // should be an error
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test_2(a: A?) {
|
fun test_2(a: A?) {
|
||||||
if (a != null) {
|
if (a != null) {
|
||||||
val x = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>a<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!>
|
val x = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>a<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!>
|
||||||
takeInt(x) // should be an error
|
takeInt(<!ARGUMENT_TYPE_MISMATCH!>x<!>) // should be an error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user