From 3bfb0866cb8919939f15cbd8c643189f35e9b126 Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Fri, 28 Apr 2023 16:44:24 +0200 Subject: [PATCH] [FIR] Report CANNOT_CHECK_FOR_ERASED independent of reified parameters This changes the logic so that Foo is reported no matter if T is reified or not. Even for Array to align K2 with K1 logic. #KT-55903 Fixed --- .../checkers/FirCastDiagnosticsHelpers.kt | 20 +++++++------------ .../cast/IsErasedUpcastToNonReified.fir.kt | 17 +++++++++++++++- .../tests/cast/IsErasedUpcastToNonReified.kt | 19 ++++++++++++++++-- .../tests/cast/IsErasedUpcastToNonReified.txt | 10 +++++++++- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt index 001ca732637..f410c7762e3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt @@ -141,12 +141,11 @@ fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: Ch // downcasting to a non-reified type parameter is always erased if (isNonReifiedTypeParameter) return true + // downcasting to a reified type parameter is never erased + else if (subtype is ConeTypeParameterType) return false - // Check that we are actually casting to a generic type - // NOTE: this does not account for 'as Array>' - if (subtype.allParameterReified()) return false - - val staticallyKnownSubtype = findStaticallyKnownSubtype(supertype, subtype, context) + val regularClassSymbol = subtype.toRegularClassSymbol(context.session) ?: return true + val staticallyKnownSubtype = findStaticallyKnownSubtype(supertype, regularClassSymbol, context) // If the substitution failed, it means that the result is an impossible type, e.g. something like Out // In this case, we can't guarantee anything, so the cast is considered to be erased @@ -156,10 +155,6 @@ fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: Ch return !AbstractTypeChecker.isSubtypeOf(context.session.typeContext, staticallyKnownSubtype, subtype, stubTypesEqualToAnything = false) } -private fun ConeKotlinType.allParameterReified(): Boolean { - return typeArguments.all { (it.type as? ConeTypeParameterType)?.lookupTag?.typeParameterSymbol?.isReified == true } -} - /** * Remember that we are trying to cast something of type `supertype` to `subtype`. @@ -178,7 +173,7 @@ private fun ConeKotlinType.allParameterReified(): Boolean { */ fun findStaticallyKnownSubtype( supertype: ConeKotlinType, - subtype: ConeKotlinType, + subTypeClassSymbol: FirRegularClassSymbol, context: CheckerContext ): ConeKotlinType { assert(!supertype.isMarkedNullable) { "This method only makes sense for non-nullable types" } @@ -188,8 +183,7 @@ fun findStaticallyKnownSubtype( // Assume we are casting an expression of type Collection to List // First, let's make List, where T is a type variable - val subtypeWithVariables = subtype.toRegularClassSymbol(session)!! - val subtypeWithVariablesType = subtypeWithVariables.defaultType() + val subtypeWithVariablesType = subTypeClassSymbol.defaultType() // Now, let's find a supertype of List that is a Collection of something, // in this case it will be Collection @@ -214,7 +208,7 @@ fun findStaticallyKnownSubtype( normalizedType.typeConstructor(typeContext) ).firstOrNull() - val variables: List = subtypeWithVariables.typeParameterSymbols + val variables: List = subTypeClassSymbol.typeParameterSymbols val substitution = if (supertypeWithVariables != null) { // Now, let's try to unify Collection and Collection solution is a map from T to Foo diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.fir.kt b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.fir.kt index fafd8aea8c4..bbdf67e835c 100644 --- a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.fir.kt @@ -15,10 +15,25 @@ fun test(x: T?, y: S, z: T) { null as S } -inline fun test(x: T?) { +class Box + +inline fun test(x: T?, a: Any) { x is T null as T null as T? + + a is T + a as T + + a is Box + a is Array + a as Box + a as Array + + a is Box> + a is Array> + a as Box> + a as Array> } fun foo(x: List, y: List?) { diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.kt b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.kt index 9ab75201fcd..a561ed046cf 100644 --- a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.kt +++ b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.kt @@ -15,13 +15,28 @@ fun test(x: T?, y: S, z: T) { null as S } -inline fun test(x: T?) { +class Box + +inline fun test(x: T?, a: Any) { x is T null as T null as T? + + a is T + a as T + + a is Box + a is Array + a as Box + a as Array + + a is Box> + a is Array> + a as Box> + a as Array> } fun foo(x: List, y: List?) { x is List y is List -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.txt b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.txt index ea8ecb5ab9e..0fbf010ccd6 100644 --- a/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.txt +++ b/compiler/testData/diagnostics/tests/cast/IsErasedUpcastToNonReified.txt @@ -1,5 +1,13 @@ package public fun foo(/*0*/ x: kotlin.collections.List, /*1*/ y: kotlin.collections.List?): kotlin.Unit -public inline fun test(/*0*/ x: T?): kotlin.Unit public fun test(/*0*/ x: T?, /*1*/ y: S, /*2*/ z: T): kotlin.Unit +public inline fun test(/*0*/ x: T?, /*1*/ a: kotlin.Any): kotlin.Unit + +public final class Box { + public constructor Box() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} +