K2 resolve: prefer derived class property to base class field

#KT-50082 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-11-16 17:14:56 +01:00
committed by teamcity
parent 642bbd38ba
commit 59bafedd8a
15 changed files with 407 additions and 41 deletions
@@ -194,7 +194,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
if (isStatic && containingClass != null) {
containingUseSiteDeclarations.firstNotNullOfOrNull {
if (it !is FirClass) return@firstNotNullOfOrNull null
it.takeIf { it.isSubClass(containingLookupTag, session, supertypeSupplier) }
it.takeIf { it.isSubclassOf(containingLookupTag, session, isStrict = false, supertypeSupplier) }
}?.let { return it }
}
@@ -380,10 +380,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
return false
}
// 'local' isn't taken into account here
private fun ClassId.isSame(other: ClassId): Boolean =
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
private fun ConeClassLikeLookupTag.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? {
if (classId.isLocal) return null
val outerClassId = classId.outerClassId ?: return null
@@ -405,11 +401,11 @@ abstract class FirVisibilityChecker : FirSessionComponent {
supertypeSupplier: SupertypeSupplier
): Boolean {
dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
if (containingUseSiteClass.isSubClass(companionOwnerLookupTag, session, supertypeSupplier)) return true
if (containingUseSiteClass.isSubclassOf(companionOwnerLookupTag, session, isStrict = false, supertypeSupplier)) return true
}
return when {
!containingUseSiteClass.isSubClass(ownerLookupTag, session, supertypeSupplier) -> false
!containingUseSiteClass.isSubclassOf(ownerLookupTag, session, isStrict = false, supertypeSupplier) -> false
isVariableOrNamedFunction -> doesReceiverFitForProtectedVisibility(
dispatchReceiver,
containingUseSiteClass,
@@ -460,26 +456,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
return false
}
private fun FirClass.isSubClass(
ownerLookupTag: ConeClassLikeLookupTag,
session: FirSession,
supertypeSupplier: SupertypeSupplier
): Boolean {
if (classId.isSame(ownerLookupTag.classId)) return true
return lookupSuperTypes(
this,
lookupInterfaces = true,
deep = true,
session,
substituteTypes = false,
supertypeSupplier
).any { superType ->
// Note: We check just classId here, so type substitution isn't needed ^ (we aren't interested in type arguments)
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerLookupTag.classId) == true
}
}
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
(this?.type as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.SmartSet
@@ -90,6 +92,33 @@ fun lookupSuperTypes(
}
}
fun FirClass.isSubclassOf(
ownerLookupTag: ConeClassLikeLookupTag,
session: FirSession,
isStrict: Boolean,
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default
): Boolean {
if (classId.isSame(ownerLookupTag.classId)) {
return !isStrict
}
return lookupSuperTypes(
this,
lookupInterfaces = true,
deep = true,
session,
substituteTypes = false,
supertypeSupplier
).any { superType ->
// Note: We check just classId here, so type substitution isn't needed
superType.lookupTag.classId.isSame(ownerLookupTag.classId)
}
}
// 'local' isn't taken into account here
fun ClassId.isSame(other: ClassId): Boolean =
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
fun FirClass.isThereLoopInSupertypes(session: FirSession): Boolean {
val visitedSymbols: MutableSet<FirClassifierSymbol<*>> = SmartSet.create()
val inProcess: MutableSet<FirClassifierSymbol<*>> = mutableSetOf()