[FIR] Add nullability to ILT. #KT-37639 Fixed
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
// ISSUE: KT-37639
|
||||
|
||||
fun takeInt(x: Int) {}
|
||||
|
||||
fun test_1(b: Boolean) {
|
||||
val x = if (b) 1 else null
|
||||
<!INAPPLICABLE_CANDIDATE!>takeInt<!>(x)
|
||||
}
|
||||
|
||||
fun test_2(b: Boolean, y: Int) {
|
||||
val x = if (b) y else null
|
||||
<!INAPPLICABLE_CANDIDATE!>takeInt<!>(x)
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
FILE: nullableIntegerLiteralType.kt
|
||||
public final fun takeInt(x: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test_1(b: R|kotlin/Boolean|): R|kotlin/Unit| {
|
||||
lval x: R|kotlin/Int?| = when () {
|
||||
R|<local>/b| -> {
|
||||
Int(1)
|
||||
}
|
||||
else -> {
|
||||
Null(null)
|
||||
}
|
||||
}
|
||||
|
||||
<Inapplicable(INAPPLICABLE): [/takeInt]>#(R|<local>/x|)
|
||||
}
|
||||
public final fun test_2(b: R|kotlin/Boolean|, y: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
lval x: R|kotlin/Int?| = when () {
|
||||
R|<local>/b| -> {
|
||||
R|<local>/y|
|
||||
}
|
||||
else -> {
|
||||
Null(null)
|
||||
}
|
||||
}
|
||||
|
||||
<Inapplicable(INAPPLICABLE): [/takeInt]>#(R|<local>/x|)
|
||||
}
|
||||
@@ -12,11 +12,11 @@ FILE: main.kt
|
||||
^ R|<local>/x|.R|kotlin/Any.toString|()
|
||||
}
|
||||
)
|
||||
Q|JavaUsage|.R|/JavaUsage.foo3|<R|kotlin/Int|, R|ft<kotlin/String, kotlin/String?>!|>(foo3@fun <anonymous>(x: R|ft<kotlin/Int, kotlin/Int?>!|): R|kotlin/String| {
|
||||
Q|JavaUsage|.R|/JavaUsage.foo3|<R|ft<kotlin/Int, kotlin/Int?>!|, R|ft<kotlin/String, kotlin/String?>!|>(foo3@fun <anonymous>(x: R|ft<kotlin/Int, kotlin/Int?>!|): R|kotlin/String| {
|
||||
^ R|<local>/x|.R|kotlin/Int.plus|(Int(1)).R|kotlin/Any.toString|()
|
||||
}
|
||||
, Int(1))
|
||||
Q|JavaUsage|.R|/JavaUsage.foo3|<R|kotlin/Int|, R|ft<kotlin/String, kotlin/String?>!|>(foo3@fun <anonymous>(x: R|kotlin/Number|): R|kotlin/String| {
|
||||
Q|JavaUsage|.R|/JavaUsage.foo3|<R|ft<kotlin/Int, kotlin/Int?>!|, R|ft<kotlin/String, kotlin/String?>!|>(foo3@fun <anonymous>(x: R|kotlin/Number|): R|kotlin/String| {
|
||||
^ R|<local>/x|.R|kotlin/Number.toInt|().R|kotlin/Any.toString|()
|
||||
}
|
||||
, Int(2))
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ FILE: main.kt
|
||||
}
|
||||
|
||||
Q|JavaClass|.R|/JavaClass.foo2|(R|<local>/y|)
|
||||
Q|JavaClass|.R|/JavaClass.foo3|<R|kotlin/Int|>(foo3@fun <anonymous>(it: R|ft<kotlin/Int, kotlin/Int?>!|): R|ft<kotlin/String, kotlin/String?>!| {
|
||||
Q|JavaClass|.R|/JavaClass.foo3|<R|ft<kotlin/Int, kotlin/Int?>!|>(foo3@fun <anonymous>(it: R|ft<kotlin/Int, kotlin/Int?>!|): R|ft<kotlin/String, kotlin/String?>!| {
|
||||
^ R|<local>/it|.R|kotlin/Int.plus|(Int(4)).R|kotlin/Any.toString|()
|
||||
}
|
||||
, Int(5))
|
||||
|
||||
Generated
+5
@@ -1288,6 +1288,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedLambdas.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableIntegerLiteralType.kt")
|
||||
public void testNullableIntegerLiteralType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nullableIntegerLiteralType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("receiverWithCapturedType.kt")
|
||||
public void testReceiverWithCapturedType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/receiverWithCapturedType.kt");
|
||||
|
||||
+5
@@ -1288,6 +1288,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedLambdas.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableIntegerLiteralType.kt")
|
||||
public void testNullableIntegerLiteralType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nullableIntegerLiteralType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("receiverWithCapturedType.kt")
|
||||
public void testReceiverWithCapturedType() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/receiverWithCapturedType.kt");
|
||||
|
||||
@@ -219,12 +219,14 @@ class ConeTypeVariableTypeConstructor(val debugName: String) : ConeClassifierLoo
|
||||
override val name: Name get() = Name.identifier(debugName)
|
||||
}
|
||||
|
||||
abstract class ConeIntegerLiteralType(val value: Long) : ConeSimpleKotlinType(), TypeConstructorMarker {
|
||||
abstract class ConeIntegerLiteralType(
|
||||
val value: Long,
|
||||
override val nullability: ConeNullability
|
||||
) : ConeSimpleKotlinType(), TypeConstructorMarker {
|
||||
abstract val possibleTypes: Collection<ConeClassLikeType>
|
||||
abstract val supertypes: List<ConeClassLikeType>
|
||||
|
||||
override val typeArguments: Array<out ConeTypeProjection> = emptyArray()
|
||||
override val nullability: ConeNullability = ConeNullability.NOT_NULL
|
||||
|
||||
abstract fun getApproximatedType(expectedType: ConeKotlinType? = null): ConeClassLikeType
|
||||
|
||||
|
||||
@@ -121,34 +121,34 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability, typeCon
|
||||
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> this
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable) as T
|
||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable)
|
||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable)
|
||||
is ConeFlexibleType -> {
|
||||
if (nullability == ConeNullability.UNKNOWN) {
|
||||
if (lowerBound.nullability != upperBound.nullability || lowerBound.nullability == ConeNullability.UNKNOWN) {
|
||||
return this
|
||||
}
|
||||
}
|
||||
coneFlexibleOrSimpleType(typeContext, lowerBound.withNullability(nullability), upperBound.withNullability(nullability)) as T
|
||||
coneFlexibleOrSimpleType(typeContext, lowerBound.withNullability(nullability), upperBound.withNullability(nullability))
|
||||
}
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag) as T
|
||||
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag)
|
||||
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor)
|
||||
is ConeIntersectionType -> when (nullability) {
|
||||
ConeNullability.NULLABLE -> this.mapTypes {
|
||||
it.withNullability(nullability)
|
||||
}
|
||||
ConeNullability.UNKNOWN -> this // TODO: is that correct?
|
||||
ConeNullability.NOT_NULL -> this
|
||||
} as T
|
||||
is ConeStubType -> ConeStubType(variable, nullability) as T
|
||||
}
|
||||
is ConeStubType -> ConeStubType(variable, nullability)
|
||||
is ConeDefinitelyNotNullType -> when (nullability) {
|
||||
ConeNullability.NOT_NULL -> this
|
||||
ConeNullability.NULLABLE -> original.withNullability(nullability)
|
||||
ConeNullability.UNKNOWN -> original.withNullability(nullability)
|
||||
} as T
|
||||
is ConeIntegerLiteralType -> this
|
||||
}
|
||||
is ConeIntegerLiteralType -> ConeIntegerLiteralTypeImpl(value, nullability)
|
||||
else -> error("sealed: ${this::class}")
|
||||
}
|
||||
} as T
|
||||
}
|
||||
|
||||
fun coneFlexibleOrSimpleType(
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
||||
override val possibleTypes: Collection<ConeClassLikeType>
|
||||
|
||||
constructor(value: Long) : super(value) {
|
||||
constructor(value: Long, nullability: ConeNullability = ConeNullability.NOT_NULL) : super(value, nullability) {
|
||||
possibleTypes = mutableListOf()
|
||||
|
||||
fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) {
|
||||
@@ -34,7 +34,11 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
||||
// TODO: add support of unsigned types
|
||||
}
|
||||
|
||||
private constructor(value: Long, possibleTypes: Collection<ConeClassLikeType>) : super(value) {
|
||||
private constructor(
|
||||
value: Long,
|
||||
possibleTypes: Collection<ConeClassLikeType>,
|
||||
nullability: ConeNullability = ConeNullability.NOT_NULL
|
||||
) : super(value, nullability) {
|
||||
this.possibleTypes = possibleTypes
|
||||
}
|
||||
|
||||
@@ -46,10 +50,11 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
||||
}
|
||||
|
||||
override fun getApproximatedType(expectedType: ConeKotlinType?): ConeClassLikeType {
|
||||
return when (expectedType) {
|
||||
val approximatedType = when (expectedType) {
|
||||
null, !in possibleTypes -> possibleTypes.first()
|
||||
else -> expectedType as ConeClassLikeType
|
||||
}
|
||||
return approximatedType.withNullability(nullability)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -121,4 +126,14 @@ fun ConeKotlinType.approximateIntegerLiteralType(expectedType: ConeKotlinType? =
|
||||
(this as? ConeIntegerLiteralType)?.getApproximatedType(expectedType) ?: this
|
||||
|
||||
fun ConeKotlinType.approximateIntegerLiteralTypeOrNull(expectedType: ConeKotlinType? = null): ConeKotlinType? =
|
||||
(this as? ConeIntegerLiteralType)?.getApproximatedType(expectedType)
|
||||
(this as? ConeIntegerLiteralType)?.getApproximatedType(expectedType)
|
||||
|
||||
private fun ConeClassLikeType.withNullability(nullability: ConeNullability): ConeClassLikeType {
|
||||
if (nullability == this.nullability) return this
|
||||
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> this
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable)
|
||||
else -> error("sealed")
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
fun box() : String {
|
||||
val s = "notA"
|
||||
val id = when (s) {
|
||||
|
||||
@@ -3,13 +3,13 @@ FILE fqName:<root> fileName:/whenUnusedExpression.kt
|
||||
VALUE_PARAMETER name:b index:0 type:kotlin.Boolean
|
||||
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
||||
BLOCK_BODY
|
||||
WHEN type=kotlin.Int origin=IF
|
||||
WHEN type=kotlin.Int? origin=IF
|
||||
BRANCH
|
||||
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
||||
then: BLOCK type=kotlin.Int origin=WHEN
|
||||
then: BLOCK type=kotlin.Int? origin=WHEN
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
|
||||
GET_VAR 'i: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
|
||||
WHEN type=kotlin.Int origin=WHEN
|
||||
WHEN type=kotlin.Int? origin=WHEN
|
||||
BRANCH
|
||||
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.test' type=kotlin.Int origin=null
|
||||
|
||||
Reference in New Issue
Block a user