[FIR] Add ConeAttributes to ConeKotlinType

This commit is contained in:
Dmitriy Novozhilov
2020-06-04 12:38:06 +03:00
parent 407d1365bd
commit f76befa84e
8 changed files with 131 additions and 9 deletions

View File

@@ -0,0 +1,76 @@
/*
* 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.fir.types
import org.jetbrains.kotlin.fir.utils.AttributeArrayOwner
import org.jetbrains.kotlin.fir.utils.TypeRegistry
import org.jetbrains.kotlin.fir.utils.isEmpty
import org.jetbrains.kotlin.utils.addIfNotNull
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
abstract class ConeAttribute<T : ConeAttribute<T>> {
abstract fun union(other: @UnsafeVariance T?): T?
abstract fun intersect(other: @UnsafeVariance T?): T?
abstract fun isSubtypeOf(other: @UnsafeVariance T?): Boolean
abstract val key: KClass<out T>
}
class ConeAttributes private constructor(attributes: List<ConeAttribute<*>>) : AttributeArrayOwner<ConeAttribute<*>, ConeAttribute<*>>() {
companion object : TypeRegistry<ConeAttribute<*>, ConeAttribute<*>>() {
inline fun <reified T : ConeAttribute<T>> attributeAccessor(): ReadOnlyProperty<ConeAttributes, T?> {
@Suppress("UNCHECKED_CAST")
return generateNullableAccessor<ConeAttribute<*>, T>(T::class) as ReadOnlyProperty<ConeAttributes, T?>
}
val Empty: ConeAttributes = ConeAttributes(emptyList())
fun create(attributes: List<ConeAttribute<*>>): ConeAttributes {
return if (attributes.isEmpty()) {
Empty
} else {
ConeAttributes(attributes)
}
}
}
init {
for (attribute in attributes) {
registerComponent(attribute.key, attribute)
}
}
fun union(other: ConeAttributes): ConeAttributes {
return perform(other) { this.union(it) }
}
fun intersect(other: ConeAttributes): ConeAttributes {
return perform(other) { this.intersect(it) }
}
private inline fun perform(other: ConeAttributes, op: ConeAttribute<*>.(ConeAttribute<*>?) -> ConeAttribute<*>?): ConeAttributes {
if (this.isEmpty() && other.isEmpty()) return this
val attributes = mutableListOf<ConeAttribute<*>>()
for (index in indices) {
val a = arrayMap[index]
val b = other.arrayMap[index]
val res = when {
a == null -> b?.op(a)
else -> a.op(b)
}
attributes.addIfNotNull(res)
}
return create(attributes)
}
override val typeRegistry: TypeRegistry<ConeAttribute<*>, ConeAttribute<*>>
get() = Companion
private fun isEmpty(): Boolean {
return arrayMap.isEmpty()
}
}

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.utils.addToStdlib.foldMap
enum class ProjectionKind {
STAR, IN, OUT, INVARIANT;
@@ -50,9 +51,7 @@ data class ConeKotlinTypeProjectionOut(override val type: ConeKotlinType) : Cone
// We assume type IS an invariant type projection to prevent additional wrapper here
// (more exactly, invariant type projection contains type)
sealed class ConeKotlinType : ConeKotlinTypeProjection(),
KotlinTypeMarker,
TypeArgumentListMarker {
sealed class ConeKotlinType : ConeKotlinTypeProjection(), KotlinTypeMarker, TypeArgumentListMarker {
override val kind: ProjectionKind
get() = ProjectionKind.INVARIANT
@@ -63,6 +62,8 @@ sealed class ConeKotlinType : ConeKotlinTypeProjection(),
abstract val nullability: ConeNullability
abstract val attributes: ConeAttributes
final override fun toString(): String {
return render()
}
@@ -91,6 +92,9 @@ class ConeClassErrorType(val reason: String) : ConeClassLikeType() {
override val nullability: ConeNullability
get() = ConeNullability.UNKNOWN
override val attributes: ConeAttributes
get() = ConeAttributes.Empty
override fun equals(other: Any?) = this === other
override fun hashCode(): Int = System.identityHashCode(this)
}
@@ -103,8 +107,10 @@ abstract class ConeClassLikeType : ConeLookupTagBasedType() {
abstract override val lookupTag: ConeClassLikeLookupTag
}
open class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: ConeKotlinType) : ConeKotlinType(),
FlexibleTypeMarker {
open class ConeFlexibleType(
val lowerBound: ConeKotlinType,
val upperBound: ConeKotlinType
) : ConeKotlinType(), FlexibleTypeMarker {
init {
val message = { "Bounds violation: $lowerBound, $upperBound" }
@@ -118,6 +124,9 @@ open class ConeFlexibleType(val lowerBound: ConeKotlinType, val upperBound: Cone
override val nullability: ConeNullability
get() = lowerBound.nullability.takeIf { it == upperBound.nullability } ?: ConeNullability.UNKNOWN
override val attributes: ConeAttributes
get() = lowerBound.attributes
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -151,7 +160,8 @@ data class ConeCapturedType(
val captureStatus: CaptureStatus,
val lowerType: ConeKotlinType?,
override val nullability: ConeNullability = ConeNullability.NOT_NULL,
val constructor: ConeCapturedTypeConstructor
val constructor: ConeCapturedTypeConstructor,
override val attributes: ConeAttributes = ConeAttributes.Empty
) : ConeSimpleKotlinType(), CapturedTypeMarker {
constructor(
captureStatus: CaptureStatus, lowerType: ConeKotlinType?, projection: ConeTypeProjection,
@@ -197,14 +207,20 @@ data class ConeTypeVariableType(
override val lookupTag: ConeClassifierLookupTag
) : ConeLookupTagBasedType() {
override val typeArguments: Array<out ConeTypeProjection> get() = emptyArray()
override val attributes: ConeAttributes get() = ConeAttributes.Empty
}
data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleKotlinType(), DefinitelyNotNullTypeMarker {
override val typeArguments: Array<out ConeTypeProjection>
get() = original.typeArguments
override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL
override val attributes: ConeAttributes
get() = ConeAttributes.Empty
companion object
}
@@ -225,6 +241,11 @@ class ConeIntersectionType(
override val nullability: ConeNullability
get() = ConeNullability.NOT_NULL
override val attributes: ConeAttributes = intersectedTypes.foldMap(
{ it.attributes },
{ a, b -> a.union(b) }
)
private var hashCode = 0
override fun equals(other: Any?): Boolean {
@@ -253,6 +274,9 @@ class ConeStubType(val variable: ConeTypeVariable, override val nullability: Con
override val typeArguments: Array<out ConeTypeProjection>
get() = emptyArray()
override val attributes: ConeAttributes
get() = ConeAttributes.Empty
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.types.impl
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
import org.jetbrains.kotlin.fir.types.ConeNullability
@@ -13,7 +14,8 @@ import org.jetbrains.kotlin.fir.types.ConeNullability
class ConeClassLikeTypeImpl(
override val lookupTag: ConeClassLikeLookupTag,
override val typeArguments: Array<out ConeTypeProjection>,
isNullable: Boolean
isNullable: Boolean,
override val attributes: ConeAttributes = ConeAttributes.Empty
) : ConeClassLikeType() {
override val nullability: ConeNullability = ConeNullability.create(isNullable)

View File

@@ -12,6 +12,9 @@ sealed class ArrayMap<T : Any> : Iterable<T> {
abstract operator fun get(index: Int): T?
}
fun ArrayMap<*>.isEmpty(): Boolean = size == 0
fun ArrayMap<*>.isNotEmpty(): Boolean = size != 0
internal object EmptyArrayMap : ArrayMap<Nothing>() {
override val size: Int
get() = 0

View File

@@ -59,4 +59,7 @@ abstract class TypeRegistry<K : Any, V : Any> {
fun <T : K> getId(kClass: KClass<T>): Int {
return idPerType.getOrPut(kClass) { idPerType.size }
}
protected val indices: Collection<Int>
get() = idPerType.values
}

View File

@@ -14,6 +14,9 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker
class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType {
override val possibleTypes: Collection<ConeClassLikeType>
override val attributes: ConeAttributes
get() = ConeAttributes.Empty
constructor(value: Long, isUnsigned: Boolean, nullability: ConeNullability = ConeNullability.NOT_NULL) : super(value, isUnsigned, nullability) {
possibleTypes = mutableListOf()

View File

@@ -6,13 +6,15 @@
package org.jetbrains.kotlin.fir.types.impl
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.types.ConeAttributes
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
class ConeTypeParameterTypeImpl(
override val lookupTag: ConeTypeParameterLookupTag,
isNullable: Boolean
isNullable: Boolean,
override val attributes: ConeAttributes = ConeAttributes.Empty
) : ConeTypeParameterType() {
override val typeArguments: Array<out ConeTypeProjection>
get() = EMPTY_ARRAY

View File

@@ -163,4 +163,13 @@ inline fun <T, R> Iterable<T>.same(extractor: (T) -> R): Boolean {
return true
}
inline fun <R> runIf(condition: Boolean, block: () -> R): R? = if (condition) block() else null
inline fun <R> runIf(condition: Boolean, block: () -> R): R? = if (condition) block() else null
inline fun <T, R> Collection<T>.foldMap(transform: (T) -> R, operation: (R, R) -> R): R {
val iterator = iterator()
var result = transform(iterator.next())
while (iterator.hasNext()) {
result = operation(result, transform(iterator.next()))
}
return result
}