[FIR] Add nullability to ILT. #KT-37639 Fixed

This commit is contained in:
Dmitriy Novozhilov
2020-03-20 15:32:33 +03:00
parent 006e1f6528
commit 6ce8d661ad
11 changed files with 89 additions and 23 deletions
@@ -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)
}
@@ -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))
@@ -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))
@@ -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");
@@ -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