diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt new file mode 100644 index 00000000000..fa7354b66de --- /dev/null +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeAttributes.kt @@ -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> { + 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 +} + +class ConeAttributes private constructor(attributes: List>) : AttributeArrayOwner, ConeAttribute<*>>() { + companion object : TypeRegistry, ConeAttribute<*>>() { + inline fun > attributeAccessor(): ReadOnlyProperty { + @Suppress("UNCHECKED_CAST") + return generateNullableAccessor, T>(T::class) as ReadOnlyProperty + } + + val Empty: ConeAttributes = ConeAttributes(emptyList()) + + fun create(attributes: List>): 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>() + 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<*>> + get() = Companion + + private fun isEmpty(): Boolean { + return arrayMap.isEmpty() + } +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index 562565bf628..f2e63c6a50a 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt @@ -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 get() = emptyArray() + + override val attributes: ConeAttributes get() = ConeAttributes.Empty } data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleKotlinType(), DefinitelyNotNullTypeMarker { override val typeArguments: Array 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 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 diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt index 2154769e817..e0bac7ef278 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/impl/Impl.kt @@ -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, - isNullable: Boolean + isNullable: Boolean, + override val attributes: ConeAttributes = ConeAttributes.Empty ) : ConeClassLikeType() { override val nullability: ConeNullability = ConeNullability.create(isNullable) diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt index d1f8ae0fdd0..0a685e62688 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt @@ -12,6 +12,9 @@ sealed class ArrayMap : Iterable { abstract operator fun get(index: Int): T? } +fun ArrayMap<*>.isEmpty(): Boolean = size == 0 +fun ArrayMap<*>.isNotEmpty(): Boolean = size != 0 + internal object EmptyArrayMap : ArrayMap() { override val size: Int get() = 0 diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt index 391a3f8a9d2..5ed03531cf4 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt @@ -59,4 +59,7 @@ abstract class TypeRegistry { fun getId(kClass: KClass): Int { return idPerType.getOrPut(kClass) { idPerType.size } } + + protected val indices: Collection + get() = idPerType.values } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt index ef5e47d1c91..41c854c2e7b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/ConeIntegerLiteralTypeImpl.kt @@ -14,6 +14,9 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker class ConeIntegerLiteralTypeImpl : ConeIntegerLiteralType { override val possibleTypes: Collection + override val attributes: ConeAttributes + get() = ConeAttributes.Empty + constructor(value: Long, isUnsigned: Boolean, nullability: ConeNullability = ConeNullability.NOT_NULL) : super(value, isUnsigned, nullability) { possibleTypes = mutableListOf() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/ConeTypeParameterTypeImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/ConeTypeParameterTypeImpl.kt index 3dfabd49e0b..b30dd116665 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/ConeTypeParameterTypeImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/ConeTypeParameterTypeImpl.kt @@ -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 get() = EMPTY_ARRAY diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt index e92847cd63d..a80d9d4f7f6 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/addToStdlib.kt @@ -163,4 +163,13 @@ inline fun Iterable.same(extractor: (T) -> R): Boolean { return true } -inline fun runIf(condition: Boolean, block: () -> R): R? = if (condition) block() else null \ No newline at end of file +inline fun runIf(condition: Boolean, block: () -> R): R? = if (condition) block() else null + +inline fun Collection.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 +} \ No newline at end of file