[FIR] Don't smartcast variables to invisible types

#KT-44802 Fixed
This commit is contained in:
Dmitriy Novozhilov
2021-02-18 11:19:08 +03:00
parent 026efca49f
commit 1c0d862e40
24 changed files with 521 additions and 17 deletions
@@ -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
@@ -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
}