[FIR] Rename isCastPossible to checkCasting, return CastingType instead of boolean

This commit is contained in:
Ivan Kochurkin
2021-09-16 21:52:12 +03:00
committed by TeamCityServer
parent 2b5524b18f
commit 1fbccff1bd
2 changed files with 27 additions and 19 deletions
@@ -19,12 +19,18 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeChecker.findCorrespondingSupertypes import org.jetbrains.kotlin.types.AbstractTypeChecker.findCorrespondingSupertypes
import org.jetbrains.kotlin.types.model.typeConstructor import org.jetbrains.kotlin.types.model.typeConstructor
fun isCastPossible( enum class CastingType {
Possible,
Impossible,
Always
}
fun checkCasting(
lhsType: ConeKotlinType, lhsType: ConeKotlinType,
rhsType: ConeKotlinType, rhsType: ConeKotlinType,
isSafeCase: Boolean, isSafeCase: Boolean,
context: CheckerContext context: CheckerContext
): Boolean { ): CastingType {
val lhsLowerType = lhsType.lowerBoundIfFlexible() val lhsLowerType = lhsType.lowerBoundIfFlexible()
val rhsLowerType = rhsType.lowerBoundIfFlexible() val rhsLowerType = rhsType.lowerBoundIfFlexible()
val session = context.session val session = context.session
@@ -32,36 +38,38 @@ fun isCastPossible(
if (lhsLowerType is ConeIntersectionType) { if (lhsLowerType is ConeIntersectionType) {
var result = false var result = false
for (intersectedType in lhsLowerType.intersectedTypes) { for (intersectedType in lhsLowerType.intersectedTypes) {
val isIntersectedCastPossible = isCastPossible(intersectedType, rhsLowerType, isSafeCase, context) val isIntersectedCastPossible = checkCasting(intersectedType, rhsLowerType, isSafeCase, context)
val intersectedTypeSymbol = intersectedType.toRegularClassSymbol(context.session) val intersectedTypeSymbol = intersectedType.toRegularClassSymbol(context.session)
if (intersectedTypeSymbol?.isInterface == false && !isIntersectedCastPossible) { if (intersectedTypeSymbol?.isInterface == false && isIntersectedCastPossible == CastingType.Impossible) {
return false // Any class type in intersection type should be subtype of RHS return CastingType.Impossible // Any class type in intersection type should be subtype of RHS
} }
result = result or isIntersectedCastPossible result = result or (isIntersectedCastPossible != CastingType.Impossible)
} }
return result return if (result) CastingType.Possible else CastingType.Impossible
} }
val lhsNullable = lhsLowerType.canBeNull val lhsNullable = lhsLowerType.canBeNull
val rhsNullable = rhsLowerType.canBeNull val rhsNullable = rhsLowerType.canBeNull
if (lhsLowerType.isNothing) return true if (lhsLowerType.isNothing) return CastingType.Possible
if (lhsLowerType.isNullableNothing && !rhsNullable) { if (lhsLowerType.isNullableNothing && !rhsNullable) {
return isSafeCase return if (isSafeCase) CastingType.Always else CastingType.Impossible
} }
if (rhsLowerType.isNothing) return false if (rhsLowerType.isNothing) return CastingType.Impossible
if (rhsLowerType.isNullableNothing) return lhsNullable if (rhsLowerType.isNullableNothing) {
if (lhsNullable && rhsNullable) return true return if (lhsNullable) CastingType.Possible else CastingType.Impossible
}
if (lhsNullable && rhsNullable) return CastingType.Possible
val lhsClassSymbol = lhsLowerType.toRegularClassSymbol(context.session) val lhsClassSymbol = lhsLowerType.toRegularClassSymbol(context.session)
val rhsClassSymbol = rhsLowerType.toRegularClassSymbol(context.session) val rhsClassSymbol = rhsLowerType.toRegularClassSymbol(context.session)
if (isRelated(lhsLowerType, rhsLowerType, lhsClassSymbol, rhsClassSymbol, context)) return true if (isRelated(lhsLowerType, rhsLowerType, lhsClassSymbol, rhsClassSymbol, context)) return CastingType.Possible
// This is an oversimplification (which does not render the method incomplete): // This is an oversimplification (which does not render the method incomplete):
// we consider any type parameter capable of taking any value, which may be made more precise if we considered bounds // we consider any type parameter capable of taking any value, which may be made more precise if we considered bounds
if (lhsLowerType is ConeTypeParameterType || rhsLowerType is ConeTypeParameterType) return true if (lhsLowerType is ConeTypeParameterType || rhsLowerType is ConeTypeParameterType) return CastingType.Possible
if (isFinal(lhsLowerType, session) || isFinal(rhsLowerType, session)) return false if (isFinal(lhsLowerType, session) || isFinal(rhsLowerType, session)) return CastingType.Impossible
if (lhsClassSymbol?.isInterface == true || rhsClassSymbol?.isInterface == true) return true if (lhsClassSymbol?.isInterface == true || rhsClassSymbol?.isInterface == true) return CastingType.Possible
return false return CastingType.Impossible
} }
/** /**
@@ -43,7 +43,7 @@ fun f(a: SomeClass?) {
aa<!UNSAFE_CALL!>.<!>hashCode() aa<!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!> aa.<!UNRESOLVED_REFERENCE!>foo<!>
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo (aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo (aa as SomeSubClass).foo
} }
val b = (aa as? SomeSubClass)?.foo val b = (aa as? SomeSubClass)?.foo
aa = null aa = null
@@ -52,7 +52,7 @@ fun f(a: SomeClass?) {
aa<!UNSAFE_CALL!>.<!>hashCode() aa<!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!> aa.<!UNRESOLVED_REFERENCE!>foo<!>
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo (aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo (aa as SomeSubClass).foo
} }
aa = a aa = a
val c = aa as? SomeSubClass val c = aa as? SomeSubClass