Cleanup code in EffectiveVisibility.kt and extract descriptors related part to separate file

This commit is contained in:
Dmitriy Novozhilov
2020-09-01 11:12:28 +03:00
parent 6346b1b2ab
commit 7d9b7df3b4
3 changed files with 152 additions and 134 deletions
@@ -160,6 +160,22 @@ object AbstractTypeChecker {
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true, stubTypesEqualToAnything), subType, superType) return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true, stubTypesEqualToAnything), subType, superType)
} }
fun isSubtypeOfClass(
context: AbstractTypeCheckerContext,
typeConstructor: TypeConstructorMarker,
superConstructor: TypeConstructorMarker
): Boolean {
if (typeConstructor == superConstructor) return true
with(context) {
for (superType in typeConstructor.supertypes()) {
if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) {
return true
}
}
}
return false
}
fun equalTypes( fun equalTypes(
context: TypeCheckerProviderContext, context: TypeCheckerProviderContext,
a: KotlinTypeMarker, a: KotlinTypeMarker,
@@ -16,23 +16,12 @@
package org.jetbrains.kotlin.descriptors package org.jetbrains.kotlin.descriptors
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.*
import org.jetbrains.kotlin.descriptors.RelationToType.*
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext import org.jetbrains.kotlin.types.model.TypeConstructorMarker
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) {
override fun toString() = name override fun toString() = name
// Public // Public
@@ -49,31 +38,31 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
object Private : EffectiveVisibility("private", privateApi = true) { object Private : EffectiveVisibility("private", privateApi = true) {
override fun relation(other: EffectiveVisibility) = override fun relation(other: EffectiveVisibility): Permissiveness =
if (this == other || Local == other) Permissiveness.SAME else Permissiveness.LESS if (this == other || Local == other) Permissiveness.SAME else Permissiveness.LESS
override fun toVisibility() = Visibilities.PRIVATE override fun toVisibility(): Visibility = Visibilities.PRIVATE
} }
// Effectively same as Private // Effectively same as Private
object Local : EffectiveVisibility("local") { object Local : EffectiveVisibility("local") {
override fun relation(other: EffectiveVisibility) = override fun relation(other: EffectiveVisibility): Permissiveness =
if (this == other || Private == other) Permissiveness.SAME else Permissiveness.LESS if (this == other || Private == other) Permissiveness.SAME else Permissiveness.LESS
override fun toVisibility() = Visibilities.LOCAL override fun toVisibility(): Visibility = Visibilities.LOCAL
} }
object Public : EffectiveVisibility("public", publicApi = true) { object Public : EffectiveVisibility("public", publicApi = true) {
override fun relation(other: EffectiveVisibility) = override fun relation(other: EffectiveVisibility): Permissiveness =
if (this == other) Permissiveness.SAME else Permissiveness.MORE if (this == other) Permissiveness.SAME else Permissiveness.MORE
override fun toVisibility() = Visibilities.PUBLIC override fun toVisibility(): Visibility = Visibilities.PUBLIC
} }
abstract class InternalOrPackage protected constructor(internal: Boolean) : EffectiveVisibility( abstract class InternalOrPackage protected constructor(internal: Boolean) : EffectiveVisibility(
if (internal) "internal" else "public/*package*/" if (internal) "internal" else "public/*package*/"
) { ) {
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
Public -> Permissiveness.LESS Public -> Permissiveness.LESS
Private, Local, InternalProtectedBound, is InternalProtected -> Permissiveness.MORE Private, Local, InternalProtectedBound, is InternalProtected -> Permissiveness.MORE
is InternalOrPackage -> Permissiveness.SAME is InternalOrPackage -> Permissiveness.SAME
@@ -83,35 +72,35 @@ 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.containerType, other.typeContext) is Protected -> InternalProtected(other.containerTypeConstructor, other.typeContext)
ProtectedBound -> InternalProtectedBound ProtectedBound -> InternalProtectedBound
} }
} }
object Internal : InternalOrPackage(true) { object Internal : InternalOrPackage(true) {
override fun toVisibility() = Visibilities.INTERNAL override fun toVisibility(): Visibility = Visibilities.INTERNAL
} }
object PackagePrivate : InternalOrPackage(false) { object PackagePrivate : InternalOrPackage(false) {
override fun toVisibility() = Visibilities.PRIVATE override fun toVisibility(): Visibility = Visibilities.PRIVATE
} }
class Protected( class Protected(
val containerType: KotlinTypeMarker?, val containerTypeConstructor: TypeConstructorMarker?,
val typeContext: AbstractTypeCheckerContext val typeContext: AbstractTypeCheckerContext
) : EffectiveVisibility("protected", publicApi = true) { ) : EffectiveVisibility("protected", publicApi = true) {
override fun equals(other: Any?) = (other is Protected && containerType == other.containerType) override fun equals(other: Any?) = (other is Protected && containerTypeConstructor == other.containerTypeConstructor)
override fun hashCode() = containerType?.hashCode() ?: 0 override fun hashCode() = containerTypeConstructor?.hashCode() ?: 0
override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})" override fun toString() = "${super.toString()} (in ${containerTypeConstructor ?: '?'})"
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
Public -> Permissiveness.LESS Public -> Permissiveness.LESS
Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE
is Protected -> containerRelation(containerType, other.containerType, typeContext) is Protected -> containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)
is InternalProtected -> when (containerRelation(containerType, other.containerType, typeContext)) { is InternalProtected -> when (containerRelation(containerTypeConstructor, other.containerTypeConstructor, 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
@@ -131,15 +120,15 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
Permissiveness.LESS -> other Permissiveness.LESS -> other
else -> InternalProtectedBound else -> InternalProtectedBound
} }
is InternalOrPackage -> InternalProtected(containerType, typeContext) is InternalOrPackage -> InternalProtected(containerTypeConstructor, typeContext)
} }
override fun toVisibility() = Visibilities.PROTECTED override fun toVisibility(): Visibility = Visibilities.PROTECTED
} }
// Lower bound for all protected visibilities // Lower bound for all protected visibilities
object ProtectedBound : EffectiveVisibility("protected (in different classes)", publicApi = true) { object ProtectedBound : EffectiveVisibility("protected (in different classes)", publicApi = true) {
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
Public, is Protected -> Permissiveness.LESS Public, is Protected -> Permissiveness.LESS
Private, Local, InternalProtectedBound -> Permissiveness.MORE Private, Local, InternalProtectedBound -> Permissiveness.MORE
ProtectedBound -> Permissiveness.SAME ProtectedBound -> Permissiveness.SAME
@@ -152,26 +141,26 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
is InternalOrPackage, is InternalProtected -> InternalProtectedBound is InternalOrPackage, is InternalProtected -> InternalProtectedBound
} }
override fun toVisibility() = Visibilities.PROTECTED override fun toVisibility(): Visibility = Visibilities.PROTECTED
} }
// Lower bound for internal and protected(C) // Lower bound for internal and protected(C)
class InternalProtected( class InternalProtected(
val containerType: KotlinTypeMarker?, val containerTypeConstructor: TypeConstructorMarker?,
val typeContext: AbstractTypeCheckerContext, val typeContext: AbstractTypeCheckerContext,
) : EffectiveVisibility("internal & protected") { ) : EffectiveVisibility("internal & protected") {
override fun equals(other: Any?) = (other is InternalProtected && containerType == other.containerType) override fun equals(other: Any?) = (other is InternalProtected && containerTypeConstructor == other.containerTypeConstructor)
override fun hashCode() = containerType?.hashCode() ?: 0 override fun hashCode() = containerTypeConstructor?.hashCode() ?: 0
override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})" override fun toString() = "${super.toString()} (in ${containerTypeConstructor ?: '?'})"
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility): Permissiveness = 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(containerType, other.containerType, typeContext) is InternalProtected -> containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)
is Protected -> when (containerRelation(containerType, other.containerType, typeContext)) { is Protected -> when (containerRelation(containerTypeConstructor, other.containerTypeConstructor, 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
@@ -190,18 +179,18 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
ProtectedBound -> InternalProtectedBound ProtectedBound -> InternalProtectedBound
} }
override fun toVisibility() = Visibilities.PRIVATE override fun toVisibility(): Visibility = Visibilities.PRIVATE
} }
// Lower bound for internal and protected lower bound // Lower bound for internal and protected lower bound
object InternalProtectedBound : EffectiveVisibility("internal & protected (in different classes)") { object InternalProtectedBound : EffectiveVisibility("internal & protected (in different classes)") {
override fun relation(other: EffectiveVisibility) = when (other) { override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
Public, is Protected, is InternalProtected, ProtectedBound, is InternalOrPackage -> Permissiveness.LESS Public, is Protected, is InternalProtected, ProtectedBound, is InternalOrPackage -> Permissiveness.LESS
Private, Local -> Permissiveness.MORE Private, Local -> Permissiveness.MORE
InternalProtectedBound -> Permissiveness.SAME InternalProtectedBound -> Permissiveness.SAME
} }
override fun toVisibility() = Visibilities.PRIVATE override fun toVisibility(): Visibility = Visibilities.PRIVATE
} }
enum class Permissiveness { enum class Permissiveness {
@@ -215,51 +204,13 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
abstract fun toVisibility(): Visibility abstract fun toVisibility(): Visibility
open internal fun lowerBound(other: EffectiveVisibility) = when (relation(other)) { internal open fun lowerBound(other: EffectiveVisibility) = when (relation(other)) {
Permissiveness.SAME, Permissiveness.LESS -> this Permissiveness.SAME, Permissiveness.LESS -> this
Permissiveness.MORE -> other Permissiveness.MORE -> other
Permissiveness.UNKNOWN -> Private Permissiveness.UNKNOWN -> Private
} }
} }
internal fun containerRelation(
first: KotlinTypeMarker?,
second: KotlinTypeMarker?,
typeContext: AbstractTypeCheckerContext
): Permissiveness {
return when {
first == null || second == null -> Permissiveness.UNKNOWN
first == second -> Permissiveness.SAME
AbstractTypeChecker.isSubtypeOf(typeContext, first, second) -> Permissiveness.LESS
AbstractTypeChecker.isSubtypeOf(typeContext, second, first) -> Permissiveness.MORE
else -> Permissiveness.UNKNOWN
}
}
private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility) =
first.lowerBound(second)
private fun lowerBound(first: EffectiveVisibility, args: List<EffectiveVisibility>) =
args.fold(first, { x, y -> x.lowerBound(y) })
private fun lowerBound(args: List<EffectiveVisibility>) =
if (args.isEmpty()) Public else lowerBound(args.first(), args.subList(1, args.size))
private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility =
when (this) {
Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> Private
Visibilities.PROTECTED -> Protected((descriptor.containingDeclaration as? ClassDescriptor)?.defaultType, ClassicTypeCheckerContext(errorTypeEqualsToAnything = false))
Visibilities.INTERNAL -> if (!checkPublishedApi ||
!descriptor.isPublishedApi()) Internal else Public
Visibilities.PUBLIC -> Public
Visibilities.LOCAL -> Local
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
else -> throw AssertionError("Visibility $name is not allowed in forVisibility")
}
fun effectiveVisibility(visibility: Visibility, descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false) =
visibility.forVisibility(descriptor, checkPublishedApi)
enum class RelationToType(val description: String) { enum class RelationToType(val description: String) {
CONSTRUCTOR(""), CONSTRUCTOR(""),
CONTAINER(" containing declaration"), CONTAINER(" containing declaration"),
@@ -274,53 +225,17 @@ enum class RelationToType(val description: String) {
override fun toString() = description override fun toString() = description
} }
data class DescriptorWithRelation(val descriptor: ClassifierDescriptor, private val relation: RelationToType) { internal fun containerRelation(
fun effectiveVisibility() = first: TypeConstructorMarker?,
(descriptor as? ClassDescriptor)?.visibility?.effectiveVisibility(descriptor, false) ?: Public second: TypeConstructorMarker?,
typeContext: AbstractTypeCheckerContext
override fun toString() = "$relation ${descriptor.name}" ): Permissiveness {
} return when {
first == null || second == null -> Permissiveness.UNKNOWN
private fun ClassifierDescriptor.dependentDescriptors(ownRelation: RelationToType): Set<DescriptorWithRelation> = first == second -> Permissiveness.SAME
setOf(DescriptorWithRelation(this, ownRelation)) + AbstractTypeChecker.isSubtypeOfClass(typeContext, first, second) -> Permissiveness.LESS
((this.containingDeclaration as? ClassifierDescriptor)?.dependentDescriptors(ownRelation.containerRelation()) ?: emptySet()) AbstractTypeChecker.isSubtypeOfClass(typeContext, second, first) -> Permissiveness.MORE
else -> Permissiveness.UNKNOWN
fun ClassDescriptor.effectiveVisibility(checkPublishedApi: Boolean = false) = effectiveVisibility(emptySet(), checkPublishedApi)
private fun ClassDescriptor.effectiveVisibility(classes: Set<ClassDescriptor>, checkPublishedApi: Boolean): EffectiveVisibility =
if (this in classes) Public
else with(this.containingDeclaration as? ClassDescriptor) {
lowerBound(visibility.effectiveVisibility(this@effectiveVisibility, checkPublishedApi), this?.effectiveVisibility(classes + this@effectiveVisibility, checkPublishedApi) ?: Public)
}
// Should collect all dependent classifier descriptors, to get verbose diagnostic
private fun KotlinType.dependentDescriptors() = dependentDescriptors(emptySet(), CONSTRUCTOR)
private fun KotlinType.dependentDescriptors(types: Set<KotlinType>, ownRelation: RelationToType): Set<DescriptorWithRelation> {
if (this in types) return emptySet()
val ownDependent = constructor.declarationDescriptor?.dependentDescriptors(ownRelation) ?: emptySet()
val argumentDependent = arguments.map { it.type.dependentDescriptors(types + this, ARGUMENT) }.flatten()
return ownDependent + argumentDependent
}
private fun Set<DescriptorWithRelation>.leastPermissive(base: EffectiveVisibility): DescriptorWithRelation? {
for (descriptorWithRelation in this) {
val currentVisibility = descriptorWithRelation.effectiveVisibility()
when (currentVisibility.relation(base)) {
Permissiveness.LESS, Permissiveness.UNKNOWN -> {
return descriptorWithRelation
}
else -> {}
}
} }
return null
} }
fun KotlinType.leastPermissiveDescriptor(base: EffectiveVisibility) = dependentDescriptors().leastPermissive(base)
fun DeclarationDescriptorWithVisibility.effectiveVisibility(
visibility: Visibility = this.visibility, checkPublishedApi: Boolean = false
): EffectiveVisibility =
lowerBound(visibility.effectiveVisibility(this, checkPublishedApi),
(this.containingDeclaration as? ClassDescriptor)?.effectiveVisibility(checkPublishedApi) ?: Public)
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
fun effectiveVisibility(visibility: Visibility, descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false) =
visibility.forVisibility(descriptor, checkPublishedApi)
private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility =
when (this) {
Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> EffectiveVisibility.Private
Visibilities.PROTECTED -> EffectiveVisibility.Protected(
(descriptor.containingDeclaration as? ClassDescriptor)?.defaultType?.constructor,
ClassicTypeCheckerContext(errorTypeEqualsToAnything = false)
)
Visibilities.INTERNAL -> if (!checkPublishedApi ||
!descriptor.isPublishedApi()
) EffectiveVisibility.Internal else EffectiveVisibility.Public
Visibilities.PUBLIC -> EffectiveVisibility.Public
Visibilities.LOCAL -> EffectiveVisibility.Local
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
else -> throw AssertionError("Visibility $name is not allowed in forVisibility")
}
data class DescriptorWithRelation(val descriptor: ClassifierDescriptor, private val relation: RelationToType) {
fun effectiveVisibility() =
(descriptor as? ClassDescriptor)?.visibility?.effectiveVisibility(descriptor, false) ?: EffectiveVisibility.Public
override fun toString() = "$relation ${descriptor.name}"
}
private fun ClassifierDescriptor.dependentDescriptors(ownRelation: RelationToType): Set<DescriptorWithRelation> =
setOf(DescriptorWithRelation(this, ownRelation)) +
((this.containingDeclaration as? ClassifierDescriptor)?.dependentDescriptors(ownRelation.containerRelation()) ?: emptySet())
fun ClassDescriptor.effectiveVisibility(checkPublishedApi: Boolean = false) = effectiveVisibility(emptySet(), checkPublishedApi)
private fun ClassDescriptor.effectiveVisibility(classes: Set<ClassDescriptor>, checkPublishedApi: Boolean): EffectiveVisibility =
if (this in classes) EffectiveVisibility.Public
else with(this.containingDeclaration as? ClassDescriptor) {
lowerBound(
visibility.effectiveVisibility(this@effectiveVisibility, checkPublishedApi),
this?.effectiveVisibility(classes + this@effectiveVisibility, checkPublishedApi) ?: EffectiveVisibility.Public
)
}
// Should collect all dependent classifier descriptors, to get verbose diagnostic
private fun KotlinType.dependentDescriptors() = dependentDescriptors(emptySet(), RelationToType.CONSTRUCTOR)
private fun KotlinType.dependentDescriptors(types: Set<KotlinType>, ownRelation: RelationToType): Set<DescriptorWithRelation> {
if (this in types) return emptySet()
val ownDependent = constructor.declarationDescriptor?.dependentDescriptors(ownRelation) ?: emptySet()
val argumentDependent = arguments.map { it.type.dependentDescriptors(types + this, RelationToType.ARGUMENT) }.flatten()
return ownDependent + argumentDependent
}
private fun Set<DescriptorWithRelation>.leastPermissive(base: EffectiveVisibility): DescriptorWithRelation? {
for (descriptorWithRelation in this) {
val currentVisibility = descriptorWithRelation.effectiveVisibility()
when (currentVisibility.relation(base)) {
EffectiveVisibility.Permissiveness.LESS, EffectiveVisibility.Permissiveness.UNKNOWN -> {
return descriptorWithRelation
}
else -> {
}
}
}
return null
}
fun KotlinType.leastPermissiveDescriptor(base: EffectiveVisibility) = dependentDescriptors().leastPermissive(base)
fun DeclarationDescriptorWithVisibility.effectiveVisibility(
visibility: Visibility = this.visibility, checkPublishedApi: Boolean = false
): EffectiveVisibility =
lowerBound(
visibility.effectiveVisibility(this, checkPublishedApi),
(this.containingDeclaration as? ClassDescriptor)?.effectiveVisibility(checkPublishedApi) ?: EffectiveVisibility.Public
)
private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility): EffectiveVisibility = first.lowerBound(second)