[FIR] Don't smartcast variables to invisible types
#KT-44802 Fixed
This commit is contained in:
@@ -34,7 +34,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
symbol: AbstractFirBasedSymbol<*>,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
candidate: Candidate,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
session: FirSession
|
||||
): Boolean {
|
||||
return true
|
||||
@@ -45,8 +45,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
declaration: T,
|
||||
candidate: Candidate
|
||||
): Boolean where T : FirMemberDeclaration, T : FirSymbolOwner<*> {
|
||||
val symbol = declaration.symbol
|
||||
|
||||
if (declaration is FirCallableDeclaration<*> && (declaration.isIntersectionOverride || declaration.isSubstitutionOverride)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return isVisible(declaration.originalIfFakeOverride() as T, candidate)
|
||||
@@ -56,8 +54,19 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
val useSiteFile = callInfo.containingFile
|
||||
val containingDeclarations = callInfo.containingDeclarations
|
||||
val session = callInfo.session
|
||||
val provider = session.firProvider
|
||||
|
||||
return isVisible(declaration, session, useSiteFile, containingDeclarations, candidate.dispatchReceiverValue)
|
||||
}
|
||||
|
||||
fun <T> isVisible(
|
||||
declaration: T,
|
||||
session: FirSession,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
dispatchReceiver: ReceiverValue?
|
||||
): Boolean where T : FirMemberDeclaration, T : FirSymbolOwner<*> {
|
||||
val provider = session.firProvider
|
||||
val symbol = declaration.symbol
|
||||
return when (declaration.visibility) {
|
||||
Visibilities.Internal -> {
|
||||
declaration.session == session || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
|
||||
@@ -91,7 +100,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
|
||||
Visibilities.Protected -> {
|
||||
val ownerId = symbol.getOwnerId()
|
||||
ownerId != null && canSeeProtectedMemberOf(containingDeclarations, candidate.dispatchReceiverValue, ownerId, session)
|
||||
ownerId != null && canSeeProtectedMemberOf(containingDeclarations, dispatchReceiver, ownerId, session)
|
||||
}
|
||||
|
||||
else -> platformVisibilityCheck(
|
||||
@@ -99,7 +108,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
symbol,
|
||||
useSiteFile,
|
||||
containingDeclarations,
|
||||
candidate,
|
||||
dispatchReceiver,
|
||||
session
|
||||
)
|
||||
}
|
||||
@@ -110,7 +119,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
symbol: AbstractFirBasedSymbol<*>,
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
candidate: Candidate,
|
||||
dispatchReceiver: ReceiverValue?,
|
||||
session: FirSession
|
||||
): Boolean
|
||||
|
||||
|
||||
+26
-2
@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.contracts.buildContractFir
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.contracts.createArgumentsMapping
|
||||
@@ -31,6 +30,7 @@ import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visibilityChecker
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -84,6 +84,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
private val receiverStack: PersistentImplicitReceiverStack
|
||||
get() = components.implicitReceiverStack as PersistentImplicitReceiverStack
|
||||
|
||||
private val symbolProvider = components.session.symbolProvider
|
||||
private val visibilityChecker = components.session.visibilityChecker
|
||||
|
||||
override val logicSystem: PersistentLogicSystem =
|
||||
object : PersistentLogicSystem(components.session.inferenceComponents.ctx) {
|
||||
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
|
||||
@@ -109,6 +112,27 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> {
|
||||
val symbol = fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false
|
||||
val declaration = symbol.fir as? FirRegularClass ?: return true
|
||||
visibilityChecker.isVisible(
|
||||
declaration,
|
||||
components.session,
|
||||
components.context.file,
|
||||
components.context.containers,
|
||||
dispatchReceiver = null
|
||||
)
|
||||
}
|
||||
is ConeTypeParameterType -> true
|
||||
is ConeFlexibleType -> lowerBound.isAcceptableForSmartcast() && upperBound.isAcceptableForSmartcast()
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.isAcceptableForSmartcast() }
|
||||
is ConeDefinitelyNotNullType -> original.isAcceptableForSmartcast()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import org.jetbrains.kotlin.fir.types.ConeInferenceContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.canBeNull
|
||||
import org.jetbrains.kotlin.fir.types.commonSuperTypeOrNull
|
||||
|
||||
abstract class Flow {
|
||||
@@ -59,6 +60,8 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
||||
|
||||
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
|
||||
|
||||
protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean
|
||||
|
||||
// ------------------------------- Callbacks for updating implicit receiver stack -------------------------------
|
||||
|
||||
abstract fun processUpdatedReceiverVariable(flow: FLOW, variable: RealVariable)
|
||||
@@ -150,7 +153,14 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
||||
}
|
||||
}
|
||||
val result = mutableSetOf<ConeKotlinType>()
|
||||
context.commonSuperTypeOrNull(intersectedTypes)?.let { result.add(it) }
|
||||
context.commonSuperTypeOrNull(intersectedTypes)?.let {
|
||||
if (it.isAcceptableForSmartcast()) {
|
||||
result.add(it)
|
||||
} else if (!it.canBeNull) {
|
||||
result.add(context.anyType())
|
||||
}
|
||||
Unit
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -32,19 +32,19 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
|
||||
val symbolProvider: FirSymbolProvider get() = session.symbolProvider
|
||||
|
||||
override fun nullableNothingType(): SimpleTypeMarker {
|
||||
override fun nullableNothingType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nullableNothingType.type
|
||||
}
|
||||
|
||||
override fun nullableAnyType(): SimpleTypeMarker {
|
||||
override fun nullableAnyType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nullableAnyType.type
|
||||
}
|
||||
|
||||
override fun nothingType(): SimpleTypeMarker {
|
||||
override fun nothingType(): ConeClassLikeType {
|
||||
return session.builtinTypes.nothingType.type
|
||||
}
|
||||
|
||||
override fun anyType(): SimpleTypeMarker {
|
||||
override fun anyType(): ConeClassLikeType {
|
||||
return session.builtinTypes.anyType.type
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user