[FIR] Rename isCastPossible to checkCasting, return CastingType instead of boolean
This commit is contained in:
committed by
TeamCityServer
parent
2b5524b18f
commit
1fbccff1bd
+25
-17
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user