[Core API] Introduce KotlinTypeRefiner component
This commit is contained in:
committed by
Dmitry Savvinov
parent
5c17148146
commit
2fe3a23183
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.config
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.REFINER_CAPABILITY
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@UseExperimental(TypeRefinement::class)
|
||||
class KotlinTypeRefinerImpl(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
storageManager: StorageManager
|
||||
) : KotlinTypeRefiner() {
|
||||
init {
|
||||
moduleDescriptor.getCapability(REFINER_CAPABILITY)?.value = this
|
||||
}
|
||||
|
||||
private val refinedTypeCache = storageManager.createCacheWithNotNullValues<TypeConstructor, KotlinType>()
|
||||
private val isRefinementNeededForTypeConstructorCache = storageManager.createCacheWithNotNullValues<ClassifierDescriptor, Boolean>()
|
||||
private val scopes = storageManager.createCacheWithNotNullValues<ClassDescriptor, MemberScope>()
|
||||
|
||||
/**
|
||||
* IMPORTANT: that function has not obvious contract: it refines only supertypes,
|
||||
* and don't refines type arguments, so return type is "partly refined".
|
||||
*
|
||||
* It's fine for subtyping, because we refine type arguments inside type checker when it needs to
|
||||
* It's fine for scopes, because we refine type of every expression:
|
||||
*
|
||||
* // common module
|
||||
* expect interface A
|
||||
* class Inv<T>(val value: T)
|
||||
* fun getA(): Inv<A> = ...
|
||||
*
|
||||
* // platform module
|
||||
*
|
||||
* actual interface A {
|
||||
* val x: Int
|
||||
* }
|
||||
*
|
||||
* fun foo() {
|
||||
* getA().value.x
|
||||
* }
|
||||
*
|
||||
* Let's call type of `actual interface A` A'
|
||||
*
|
||||
* expression `getA()` has not refined type Inv<A> and same refined type
|
||||
* expression `getA().value` has not refined type A that refines into type A', so there is a
|
||||
* field `x` in it's member scope
|
||||
*/
|
||||
@TypeRefinement
|
||||
override fun refineType(type: KotlinType): KotlinType {
|
||||
return when {
|
||||
!type.needsRefinement() -> type
|
||||
type.canBeCached() -> {
|
||||
val cached = refinedTypeCache.computeIfAbsent(type.constructor) {
|
||||
type.constructor.declarationDescriptor!!.defaultType.refine(this)
|
||||
}
|
||||
cached.replace(type.arguments)
|
||||
}
|
||||
else -> type.refine(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.needsRefinement(): Boolean = isRefinementNeededForTypeConstructor(constructor)
|
||||
|
||||
private fun KotlinType.canBeCached(): Boolean = hasNotTrivialRefinementFactory && constructor.declarationDescriptor != null
|
||||
|
||||
@TypeRefinement
|
||||
override fun refineSupertypes(classDescriptor: ClassDescriptor): Collection<KotlinType> {
|
||||
// Note that we can't omit refinement even if classDescriptor.module == moduleDescriptor,
|
||||
// because such class may have supertypes which need refinement
|
||||
return classDescriptor.typeConstructor.supertypes.map { refineType(it) }
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun refineDescriptor(descriptor: DeclarationDescriptor): ClassifierDescriptor? {
|
||||
if (descriptor !is ClassifierDescriptorWithTypeParameters) return null
|
||||
val classId = descriptor.classId ?: return null
|
||||
return moduleDescriptor.findClassifierAcrossModuleDependencies(classId)
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun findClassAcrossModuleDependencies(classId: ClassId): ClassDescriptor? {
|
||||
return moduleDescriptor.findClassAcrossModuleDependencies(classId)
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun isRefinementNeededForModule(moduleDescriptor: ModuleDescriptor): Boolean {
|
||||
return this.moduleDescriptor !== moduleDescriptor
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun isRefinementNeededForTypeConstructor(typeConstructor: TypeConstructor): Boolean {
|
||||
val owner = typeConstructor.declarationDescriptor ?: return typeConstructor.areThereExpectSupertypes()
|
||||
return isRefinementNeededForTypeConstructorCache.computeIfAbsent(owner) { typeConstructor.areThereExpectSupertypes() }
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun <S : MemberScope> getOrPutScopeForClass(classDescriptor: ClassDescriptor, compute: () -> S): S {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return scopes.computeIfAbsent(classDescriptor, compute) as S
|
||||
}
|
||||
|
||||
private fun TypeConstructor.areThereExpectSupertypes(): Boolean {
|
||||
var result = false
|
||||
DFS.dfs(
|
||||
listOf(this),
|
||||
DFS.Neighbors(TypeConstructor::allDependentTypeConstructors),
|
||||
DFS.VisitedWithSet(),
|
||||
object : DFS.AbstractNodeHandler<TypeConstructor, Unit>() {
|
||||
override fun beforeChildren(current: TypeConstructor): Boolean {
|
||||
if (current.isExpectClass() && current.declarationDescriptor?.module != moduleDescriptor) {
|
||||
result = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun result() = Unit
|
||||
}
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private val TypeConstructor.allDependentTypeConstructors: Collection<TypeConstructor>
|
||||
get() = when (this) {
|
||||
is NewCapturedTypeConstructor -> {
|
||||
supertypes.map { it.constructor } + projection.type.constructor
|
||||
}
|
||||
else -> supertypes.map { it.constructor }
|
||||
}
|
||||
|
||||
private fun TypeConstructor.isExpectClass() =
|
||||
declarationDescriptor?.safeAs<ClassDescriptor>()?.isExpect == true
|
||||
@@ -26,8 +26,10 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.checker.REFINER_CAPABILITY
|
||||
import org.jetbrains.kotlin.types.checker.Ref
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
moduleName: Name,
|
||||
@@ -35,13 +37,18 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
override val builtIns: KotlinBuiltIns,
|
||||
// May be null in compiler context, should be not-null in IDE context
|
||||
override val platform: TargetPlatform? = null,
|
||||
private val capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap(),
|
||||
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap(),
|
||||
override val stableName: Name? = null
|
||||
) : DeclarationDescriptorImpl(Annotations.EMPTY, moduleName), ModuleDescriptor {
|
||||
private val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||
|
||||
init {
|
||||
if (!moduleName.isSpecial) {
|
||||
throw IllegalArgumentException("Module name must be special: $moduleName")
|
||||
}
|
||||
this.capabilities = capabilities.toMutableMap()
|
||||
@UseExperimental(TypeRefinement::class)
|
||||
this.capabilities[REFINER_CAPABILITY] = Ref(null)
|
||||
}
|
||||
|
||||
private var dependencies: ModuleDependencies? = null
|
||||
|
||||
@@ -17,9 +17,9 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.getContainingClass
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
@@ -29,6 +29,9 @@ import org.jetbrains.kotlin.types.TypeProjection
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.types.checker.REFINER_CAPABILITY
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
@@ -441,3 +444,6 @@ fun DeclarationDescriptor.isAnnotationConstructor(): Boolean =
|
||||
|
||||
fun DeclarationDescriptor.isPrimaryConstructorOfInlineClass(): Boolean =
|
||||
this is ConstructorDescriptor && this.isPrimary && this.constructedClass.isInline
|
||||
|
||||
@TypeRefinement
|
||||
fun ModuleDescriptor.getKotlinTypeRefiner(): KotlinTypeRefiner = getCapability(REFINER_CAPABILITY)?.value ?: KotlinTypeRefiner.Default
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.types.checker
|
||||
|
||||
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
|
||||
@DefaultImplementation(impl = KotlinTypeRefiner.Default::class)
|
||||
abstract class KotlinTypeRefiner {
|
||||
@TypeRefinement
|
||||
abstract fun refineType(type: KotlinType): KotlinType
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun refineSupertypes(classDescriptor: ClassDescriptor): Collection<KotlinType>
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun refineDescriptor(descriptor: DeclarationDescriptor): ClassifierDescriptor?
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun findClassAcrossModuleDependencies(classId: ClassId): ClassDescriptor?
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun isRefinementNeededForModule(moduleDescriptor: ModuleDescriptor): Boolean
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun isRefinementNeededForTypeConstructor(typeConstructor: TypeConstructor): Boolean
|
||||
|
||||
@TypeRefinement
|
||||
abstract fun <S : MemberScope> getOrPutScopeForClass(classDescriptor: ClassDescriptor, compute: () -> S): S
|
||||
|
||||
object Default : KotlinTypeRefiner() {
|
||||
@TypeRefinement
|
||||
override fun refineType(type: KotlinType): KotlinType = type
|
||||
|
||||
@TypeRefinement
|
||||
override fun refineSupertypes(classDescriptor: ClassDescriptor): Collection<KotlinType> {
|
||||
return classDescriptor.typeConstructor.supertypes
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun refineDescriptor(descriptor: DeclarationDescriptor): ClassDescriptor? {
|
||||
return null
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun findClassAcrossModuleDependencies(classId: ClassId): ClassDescriptor? {
|
||||
return null
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun isRefinementNeededForModule(moduleDescriptor: ModuleDescriptor): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun isRefinementNeededForTypeConstructor(typeConstructor: TypeConstructor): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
override fun <S : MemberScope> getOrPutScopeForClass(classDescriptor: ClassDescriptor, compute: () -> S): S {
|
||||
return compute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
fun KotlinTypeRefiner.refineTypes(types: Iterable<KotlinType>): List<KotlinType> = types.map { refineType(it) }
|
||||
|
||||
class Ref<T : Any>(var value: T?)
|
||||
|
||||
@TypeRefinement
|
||||
val REFINER_CAPABILITY = ModuleDescriptor.Capability<Ref<KotlinTypeRefiner>>("KotlinTypeRefiner")
|
||||
Reference in New Issue
Block a user