[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|()
|
^ 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|()
|
^ R|<local>/x|.R|kotlin/Int.plus|(Int(1)).R|kotlin/Any.toString|()
|
||||||
}
|
}
|
||||||
, Int(1))
|
, 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|()
|
^ R|<local>/x|.R|kotlin/Number.toInt|().R|kotlin/Any.toString|()
|
||||||
}
|
}
|
||||||
, Int(2))
|
, Int(2))
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ FILE: main.kt
|
|||||||
}
|
}
|
||||||
|
|
||||||
Q|JavaClass|.R|/JavaClass.foo2|(R|<local>/y|)
|
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|()
|
^ R|<local>/it|.R|kotlin/Int.plus|(Int(4)).R|kotlin/Any.toString|()
|
||||||
}
|
}
|
||||||
, Int(5))
|
, Int(5))
|
||||||
|
|||||||
Generated
+5
@@ -1288,6 +1288,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedLambdas.kt");
|
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")
|
@TestMetadata("receiverWithCapturedType.kt")
|
||||||
public void testReceiverWithCapturedType() throws Exception {
|
public void testReceiverWithCapturedType() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/receiverWithCapturedType.kt");
|
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");
|
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")
|
@TestMetadata("receiverWithCapturedType.kt")
|
||||||
public void testReceiverWithCapturedType() throws Exception {
|
public void testReceiverWithCapturedType() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/receiverWithCapturedType.kt");
|
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)
|
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 possibleTypes: Collection<ConeClassLikeType>
|
||||||
abstract val supertypes: List<ConeClassLikeType>
|
abstract val supertypes: List<ConeClassLikeType>
|
||||||
|
|
||||||
override val typeArguments: Array<out ConeTypeProjection> = emptyArray()
|
override val typeArguments: Array<out ConeTypeProjection> = emptyArray()
|
||||||
override val nullability: ConeNullability = ConeNullability.NOT_NULL
|
|
||||||
|
|
||||||
abstract fun getApproximatedType(expectedType: ConeKotlinType? = null): ConeClassLikeType
|
abstract fun getApproximatedType(expectedType: ConeKotlinType? = null): ConeClassLikeType
|
||||||
|
|
||||||
|
|||||||
@@ -121,34 +121,34 @@ fun <T : ConeKotlinType> T.withNullability(nullability: ConeNullability, typeCon
|
|||||||
|
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeClassErrorType -> this
|
is ConeClassErrorType -> this
|
||||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable) as T
|
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable)
|
||||||
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable) as T
|
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable)
|
||||||
is ConeFlexibleType -> {
|
is ConeFlexibleType -> {
|
||||||
if (nullability == ConeNullability.UNKNOWN) {
|
if (nullability == ConeNullability.UNKNOWN) {
|
||||||
if (lowerBound.nullability != upperBound.nullability || lowerBound.nullability == ConeNullability.UNKNOWN) {
|
if (lowerBound.nullability != upperBound.nullability || lowerBound.nullability == ConeNullability.UNKNOWN) {
|
||||||
return this
|
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 ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag)
|
||||||
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor) as T
|
is ConeCapturedType -> ConeCapturedType(captureStatus, lowerType, nullability, constructor)
|
||||||
is ConeIntersectionType -> when (nullability) {
|
is ConeIntersectionType -> when (nullability) {
|
||||||
ConeNullability.NULLABLE -> this.mapTypes {
|
ConeNullability.NULLABLE -> this.mapTypes {
|
||||||
it.withNullability(nullability)
|
it.withNullability(nullability)
|
||||||
}
|
}
|
||||||
ConeNullability.UNKNOWN -> this // TODO: is that correct?
|
ConeNullability.UNKNOWN -> this // TODO: is that correct?
|
||||||
ConeNullability.NOT_NULL -> this
|
ConeNullability.NOT_NULL -> this
|
||||||
} as T
|
}
|
||||||
is ConeStubType -> ConeStubType(variable, nullability) as T
|
is ConeStubType -> ConeStubType(variable, nullability)
|
||||||
is ConeDefinitelyNotNullType -> when (nullability) {
|
is ConeDefinitelyNotNullType -> when (nullability) {
|
||||||
ConeNullability.NOT_NULL -> this
|
ConeNullability.NOT_NULL -> this
|
||||||
ConeNullability.NULLABLE -> original.withNullability(nullability)
|
ConeNullability.NULLABLE -> original.withNullability(nullability)
|
||||||
ConeNullability.UNKNOWN -> original.withNullability(nullability)
|
ConeNullability.UNKNOWN -> original.withNullability(nullability)
|
||||||
} as T
|
}
|
||||||
is ConeIntegerLiteralType -> this
|
is ConeIntegerLiteralType -> ConeIntegerLiteralTypeImpl(value, nullability)
|
||||||
else -> error("sealed: ${this::class}")
|
else -> error("sealed: ${this::class}")
|
||||||
}
|
} as T
|
||||||
}
|
}
|
||||||
|
|
||||||
fun coneFlexibleOrSimpleType(
|
fun coneFlexibleOrSimpleType(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
|||||||
class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
||||||
override val possibleTypes: Collection<ConeClassLikeType>
|
override val possibleTypes: Collection<ConeClassLikeType>
|
||||||
|
|
||||||
constructor(value: Long) : super(value) {
|
constructor(value: Long, nullability: ConeNullability = ConeNullability.NOT_NULL) : super(value, nullability) {
|
||||||
possibleTypes = mutableListOf()
|
possibleTypes = mutableListOf()
|
||||||
|
|
||||||
fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) {
|
fun checkBoundsAndAddPossibleType(classId: ClassId, range: LongRange) {
|
||||||
@@ -34,7 +34,11 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
|||||||
// TODO: add support of unsigned types
|
// 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
|
this.possibleTypes = possibleTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,10 +50,11 @@ class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getApproximatedType(expectedType: ConeKotlinType?): ConeClassLikeType {
|
override fun getApproximatedType(expectedType: ConeKotlinType?): ConeClassLikeType {
|
||||||
return when (expectedType) {
|
val approximatedType = when (expectedType) {
|
||||||
null, !in possibleTypes -> possibleTypes.first()
|
null, !in possibleTypes -> possibleTypes.first()
|
||||||
else -> expectedType as ConeClassLikeType
|
else -> expectedType as ConeClassLikeType
|
||||||
}
|
}
|
||||||
|
return approximatedType.withNullability(nullability)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -121,4 +126,14 @@ fun ConeKotlinType.approximateIntegerLiteralType(expectedType: ConeKotlinType? =
|
|||||||
(this as? ConeIntegerLiteralType)?.getApproximatedType(expectedType) ?: this
|
(this as? ConeIntegerLiteralType)?.getApproximatedType(expectedType) ?: this
|
||||||
|
|
||||||
fun ConeKotlinType.approximateIntegerLiteralTypeOrNull(expectedType: ConeKotlinType? = null): ConeKotlinType? =
|
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 {
|
fun box() : String {
|
||||||
val s = "notA"
|
val s = "notA"
|
||||||
val id = when (s) {
|
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:b index:0 type:kotlin.Boolean
|
||||||
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
WHEN type=kotlin.Int origin=IF
|
WHEN type=kotlin.Int? origin=IF
|
||||||
BRANCH
|
BRANCH
|
||||||
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
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]
|
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
|
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
|
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
|
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
|
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