Use type markers instead of class descriptors in effective visibility

This commit is contained in:
Dmitriy Novozhilov
2020-09-01 10:38:34 +03:00
parent 64ec3fc42b
commit 6346b1b2ab
@@ -20,7 +20,16 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.* import org.jetbrains.kotlin.descriptors.EffectiveVisibility.*
import org.jetbrains.kotlin.descriptors.RelationToType.* import org.jetbrains.kotlin.descriptors.RelationToType.*
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext
import org.jetbrains.kotlin.types.model.TypeSystemContext
import org.jetbrains.kotlin.types.model.typeConstructor
sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = false, val privateApi: Boolean = false) { sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = false, val privateApi: Boolean = false) {
@@ -74,7 +83,7 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
override fun lowerBound(other: EffectiveVisibility) = when (other) { override fun lowerBound(other: EffectiveVisibility) = when (other) {
Public -> this Public -> this
Private, Local, InternalProtectedBound, is InternalOrPackage, is InternalProtected -> other Private, Local, InternalProtectedBound, is InternalOrPackage, is InternalProtected -> other
is Protected -> InternalProtected(other.container) is Protected -> InternalProtected(other.containerType, other.typeContext)
ProtectedBound -> InternalProtectedBound ProtectedBound -> InternalProtectedBound
} }
} }
@@ -87,19 +96,22 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
override fun toVisibility() = Visibilities.PRIVATE override fun toVisibility() = Visibilities.PRIVATE
} }
class Protected(val container: ClassDescriptor?) : EffectiveVisibility("protected", publicApi = true) { class Protected(
val containerType: KotlinTypeMarker?,
val typeContext: AbstractTypeCheckerContext
) : EffectiveVisibility("protected", publicApi = true) {
override fun equals(other: Any?) = (other is Protected && container == other.container) override fun equals(other: Any?) = (other is Protected && containerType == other.containerType)
override fun hashCode() = container?.hashCode() ?: 0 override fun hashCode() = containerType?.hashCode() ?: 0
override fun toString() = "${super.toString()} (in ${container?.name ?: '?'})" override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})"
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility) = when (other) {
Public -> Permissiveness.LESS Public -> Permissiveness.LESS
Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE
is Protected -> containerRelation(container, other.container) is Protected -> containerRelation(containerType, other.containerType, typeContext)
is InternalProtected -> when (containerRelation(container, other.container)) { is InternalProtected -> when (containerRelation(containerType, other.containerType, typeContext)) {
// Protected never can be less permissive than internal & protected // Protected never can be less permissive than internal & protected
Permissiveness.SAME, Permissiveness.MORE -> Permissiveness.MORE Permissiveness.SAME, Permissiveness.MORE -> Permissiveness.MORE
Permissiveness.UNKNOWN, Permissiveness.LESS -> Permissiveness.UNKNOWN Permissiveness.UNKNOWN, Permissiveness.LESS -> Permissiveness.UNKNOWN
@@ -119,7 +131,7 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
Permissiveness.LESS -> other Permissiveness.LESS -> other
else -> InternalProtectedBound else -> InternalProtectedBound
} }
is InternalOrPackage -> InternalProtected(container) is InternalOrPackage -> InternalProtected(containerType, typeContext)
} }
override fun toVisibility() = Visibilities.PROTECTED override fun toVisibility() = Visibilities.PROTECTED
@@ -144,19 +156,22 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
} }
// Lower bound for internal and protected(C) // Lower bound for internal and protected(C)
class InternalProtected(val container: ClassDescriptor?): EffectiveVisibility("internal & protected") { class InternalProtected(
val containerType: KotlinTypeMarker?,
val typeContext: AbstractTypeCheckerContext,
) : EffectiveVisibility("internal & protected") {
override fun equals(other: Any?) = (other is InternalProtected && container == other.container) override fun equals(other: Any?) = (other is InternalProtected && containerType == other.containerType)
override fun hashCode() = container?.hashCode() ?: 0 override fun hashCode() = containerType?.hashCode() ?: 0
override fun toString() = "${super.toString()} (in ${container?.name ?: '?'})" override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})"
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility) = when (other) {
Public, is InternalOrPackage -> Permissiveness.LESS Public, is InternalOrPackage -> Permissiveness.LESS
Private, Local, InternalProtectedBound -> Permissiveness.MORE Private, Local, InternalProtectedBound -> Permissiveness.MORE
is InternalProtected -> containerRelation(container, other.container) is InternalProtected -> containerRelation(containerType, other.containerType, typeContext)
is Protected -> when (containerRelation(container, other.container)) { is Protected -> when (containerRelation(containerType, other.containerType, typeContext)) {
// Internal & protected never can be more permissive than just protected // Internal & protected never can be more permissive than just protected
Permissiveness.SAME, Permissiveness.LESS -> Permissiveness.LESS Permissiveness.SAME, Permissiveness.LESS -> Permissiveness.LESS
Permissiveness.UNKNOWN, Permissiveness.MORE -> Permissiveness.UNKNOWN Permissiveness.UNKNOWN, Permissiveness.MORE -> Permissiveness.UNKNOWN
@@ -207,22 +222,19 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
} }
} }
internal fun containerRelation(first: ClassDescriptor?, second: ClassDescriptor?): Permissiveness = internal fun containerRelation(
if (first == null || second == null) { first: KotlinTypeMarker?,
Permissiveness.UNKNOWN second: KotlinTypeMarker?,
} typeContext: AbstractTypeCheckerContext
else if (first == second) { ): Permissiveness {
Permissiveness.SAME return when {
} first == null || second == null -> Permissiveness.UNKNOWN
else if (DescriptorUtils.isSubclass(first, second)) { first == second -> Permissiveness.SAME
Permissiveness.LESS AbstractTypeChecker.isSubtypeOf(typeContext, first, second) -> Permissiveness.LESS
} AbstractTypeChecker.isSubtypeOf(typeContext, second, first) -> Permissiveness.MORE
else if (DescriptorUtils.isSubclass(second, first)) { else -> Permissiveness.UNKNOWN
Permissiveness.MORE }
} }
else {
Permissiveness.UNKNOWN
}
private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility) = private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility) =
first.lowerBound(second) first.lowerBound(second)
@@ -236,7 +248,7 @@ private fun lowerBound(args: List<EffectiveVisibility>) =
private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility = private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility =
when (this) { when (this) {
Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> Private Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> Private
Visibilities.PROTECTED -> Protected(descriptor.containingDeclaration as? ClassDescriptor) Visibilities.PROTECTED -> Protected((descriptor.containingDeclaration as? ClassDescriptor)?.defaultType, ClassicTypeCheckerContext(errorTypeEqualsToAnything = false))
Visibilities.INTERNAL -> if (!checkPublishedApi || Visibilities.INTERNAL -> if (!checkPublishedApi ||
!descriptor.isPublishedApi()) Internal else Public !descriptor.isPublishedApi()) Internal else Public
Visibilities.PUBLIC -> Public Visibilities.PUBLIC -> Public