FIR initializer: don't report type mismatch in SomeInt = Int case

This commit is contained in:
Mikhail Glukhikh
2021-04-09 15:42:28 +03:00
parent 57d2eb5da2
commit fa4d664a18
7 changed files with 44 additions and 32 deletions
@@ -12,9 +12,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -26,6 +27,14 @@ object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
val typeContext = context.session.typeContext
if (!isSubtypeForTypeMismatch(typeContext, subtype = expressionType, supertype = propertyType)) {
if (expressionType is ConeClassLikeType &&
expressionType.lookupTag.classId == StandardClassIds.Int &&
propertyType.fullyExpandedType(context.session).isIntegerTypeOrNullableIntegerTypeOfAnySize &&
expressionType.nullability == ConeNullability.NOT_NULL
) {
// val p: Byte = 42 or similar situation
return
}
val source = declaration.source ?: return
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
}
@@ -76,6 +76,9 @@ val ConeKotlinType.isNonPrimitiveArray: Boolean
private val builtinUnsignedTypes = setOf(StandardClassIds.UInt, StandardClassIds.UByte, StandardClassIds.ULong, StandardClassIds.UShort)
val ConeKotlinType.isUnsignedTypeOrNullableUnsignedType: Boolean get() = isAnyOfBuiltinType(builtinUnsignedTypes)
private val builtinIntegerTypes = setOf(StandardClassIds.Int, StandardClassIds.Byte, StandardClassIds.Long, StandardClassIds.Short)
val ConeKotlinType.isIntegerTypeOrNullableIntegerTypeOfAnySize: Boolean get() = isAnyOfBuiltinType(builtinIntegerTypes)
private fun ConeKotlinType.isBuiltinType(classId: ClassId, isNullable: Boolean): Boolean {
if (this !is ConeClassLikeType) return false
return lookupTag.classId == classId && type.isNullable == isNullable
@@ -1,24 +1,24 @@
val p1: Int = 1 - 1
val p2: Long = <!INITIALIZER_TYPE_MISMATCH!>1 - 1<!>
val p3: Byte = <!INITIALIZER_TYPE_MISMATCH!>1 - 1<!>
val p4: Short = <!INITIALIZER_TYPE_MISMATCH!>1 - 1<!>
val p2: Long = 1 - 1
val p3: Byte = 1 - 1
val p4: Short = 1 - 1
val l1: Long = 1 - 1.toLong()
val l2: Byte = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toLong()<!>
val l3: Int = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toLong()<!>
val l4: Short = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toLong()<!>
val b1: Byte = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toByte()<!>
val b1: Byte = 1 - 1.toByte()
val b2: Int = 1 - 1.toByte()
val b3: Long = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toByte()<!>
val b4: Short = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toByte()<!>
val b3: Long = 1 - 1.toByte()
val b4: Short = 1 - 1.toByte()
val i1: Byte = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toInt()<!>
val i1: Byte = 1 - 1.toInt()
val i2: Int = 1 - 1.toInt()
val i3: Long = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toInt()<!>
val i4: Short = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toInt()<!>
val i3: Long = 1 - 1.toInt()
val i4: Short = 1 - 1.toInt()
val s1: Byte = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toShort()<!>
val s1: Byte = 1 - 1.toShort()
val s2: Int = 1 - 1.toShort()
val s3: Long = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toShort()<!>
val s4: Short = <!INITIALIZER_TYPE_MISMATCH!>1 - 1.toShort()<!>
val s3: Long = 1 - 1.toShort()
val s4: Short = 1 - 1.toShort()
@@ -1,10 +1,10 @@
val p1: Byte = <!INITIALIZER_TYPE_MISMATCH!>(1 + 2) * 2<!>
val p2: Short = <!INITIALIZER_TYPE_MISMATCH!>(1 + 2) * 2<!>
val p1: Byte = (1 + 2) * 2
val p2: Short = (1 + 2) * 2
val p3: Int = (1 + 2) * 2
val p4: Long = <!INITIALIZER_TYPE_MISMATCH!>(1 + 2) * 2<!>
val p4: Long = (1 + 2) * 2
val b1: Byte = <!INITIALIZER_TYPE_MISMATCH!>(1.toByte() + 2) * 2<!>
val b2: Short = <!INITIALIZER_TYPE_MISMATCH!>(1.toShort() + 2) * 2<!>
val b1: Byte = (1.toByte() + 2) * 2
val b2: Short = (1.toShort() + 2) * 2
val b3: Int = (1.toInt() + 2) * 2
val b4: Long = (1.toLong() + 2) * 2
@@ -13,17 +13,17 @@ val l2: Byte = <!INITIALIZER_TYPE_MISMATCH!>-1.toLong()<!>
val l3: Int = <!INITIALIZER_TYPE_MISMATCH!>-1.toLong()<!>
val l4: Short = <!INITIALIZER_TYPE_MISMATCH!>-1.toLong()<!>
val b1: Byte = <!INITIALIZER_TYPE_MISMATCH!>-1.toByte()<!>
val b1: Byte = -1.toByte()
val b2: Int = -1.toByte()
val b3: Long = <!INITIALIZER_TYPE_MISMATCH!>-1.toByte()<!>
val b4: Short = <!INITIALIZER_TYPE_MISMATCH!>-1.toByte()<!>
val b3: Long = -1.toByte()
val b4: Short = -1.toByte()
val i1: Byte = <!INITIALIZER_TYPE_MISMATCH!>-1.toInt()<!>
val i1: Byte = -1.toInt()
val i2: Int = -1.toInt()
val i3: Long = <!INITIALIZER_TYPE_MISMATCH!>-1.toInt()<!>
val i4: Short = <!INITIALIZER_TYPE_MISMATCH!>-1.toInt()<!>
val i3: Long = -1.toInt()
val i4: Short = -1.toInt()
val s1: Byte = <!INITIALIZER_TYPE_MISMATCH!>-1.toShort()<!>
val s1: Byte = -1.toShort()
val s2: Int = -1.toShort()
val s3: Long = <!INITIALIZER_TYPE_MISMATCH!>-1.toShort()<!>
val s4: Short = <!INITIALIZER_TYPE_MISMATCH!>-1.toShort()<!>
val s3: Long = -1.toShort()
val s4: Short = -1.toShort()
@@ -17,7 +17,7 @@ fun <T> otherGeneric(l: List<T>) {}
fun test() {
val a: Byte = id(1)
val b: Byte = <!INITIALIZER_TYPE_MISMATCH!>id(300)<!>
val b: Byte = id(300)
val c: Int = <!INITIALIZER_TYPE_MISMATCH!>id(9223372036854775807)<!>
@@ -29,7 +29,7 @@ fun test() {
val f: Byte = either(1, 2)
val g: Byte = <!INITIALIZER_TYPE_MISMATCH!>either(1, 300)<!>
val g: Byte = either(1, 300)
other(<!ARGUMENT_TYPE_MISMATCH!>11<!>)
@@ -6,13 +6,13 @@ fun main() {
val bytePos = 128.toByte() // Byte.MAX_VALUE + 1
assertEquals(-128, bytePos.toInt()) // correct, wrapped to Byte.MIN_VALUE
val byteNeg: Byte = <!INITIALIZER_TYPE_MISMATCH!>-bytePos<!> // should not compile, byteNeg should be Int
val byteNeg: Byte = -bytePos // should not compile, byteNeg should be Int
assertEquals(128, byteNeg.toInt()) // passes, should not be possible
val shortPos = 32768.toShort() // Short.MAX_VALUE + 1
assertEquals(-32768, shortPos.toInt()) // correct, wrapped to Short.MIN_VALUE
val shortNeg: Short = <!INITIALIZER_TYPE_MISMATCH!>-shortPos<!> // should not compile, shortNeg should be Int
val shortNeg: Short = -shortPos // should not compile, shortNeg should be Int
assertEquals(32768, shortNeg.toInt()) // passes, should not be possible
(-128).toByte()