Implement IrType.equals/hashCode via isEqualTo/toHashCode
This commit is contained in:
+2
-2
@@ -53,8 +53,8 @@ class CheckIrElementVisitor(
|
||||
if (!config.checkTypes)
|
||||
return
|
||||
|
||||
if (!expectedType.isEqualTo(type)) {
|
||||
reportError(this, "unexpected expression.type: expected $expectedType, got ${type.render()}")
|
||||
if (type != expectedType) {
|
||||
reportError(this, "unexpected expression.type: expected ${expectedType.render()}, got ${type.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -20,21 +20,24 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
|
||||
/**
|
||||
* This lowering pass replaces [IrStringConcatenation]s with StringBuilder appends.
|
||||
*/
|
||||
@@ -65,19 +68,17 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower
|
||||
private val toStringFunction = stringBuilder.functions.single {
|
||||
it.valueParameters.size == 0 && it.name == nameToString
|
||||
}
|
||||
|
||||
private val defaultAppendFunction = stringBuilder.functions.single {
|
||||
it.name == nameAppend &&
|
||||
it.valueParameters.size == 1 &&
|
||||
it.valueParameters.single().type.isNullableAny()
|
||||
}
|
||||
|
||||
|
||||
private val appendFunctions: Map<IrType, IrSimpleFunction?> =
|
||||
typesWithSpecialAppendFunction.map { type ->
|
||||
type to stringBuilder.functions.toList().atMostOne {
|
||||
it.name == nameAppend &&
|
||||
it.valueParameters.size == 1 &&
|
||||
it.valueParameters.single().type.isEqualTo(type)
|
||||
it.name == nameAppend && it.valueParameters.singleOrNull()?.type == type
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
|
||||
+1
-2
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.isEqualTo
|
||||
import org.jetbrains.kotlin.ir.util.isInlined
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
@@ -546,7 +545,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
val value = JsIrBuilder.buildGetValue(unboundParamSymbols[i])
|
||||
val parameter = callTarget.valueParameters[j]
|
||||
val argument =
|
||||
if (parameter.varargElementType?.let { closureParam.type.isEqualTo(it) } == true) {
|
||||
if (parameter.varargElementType == closureParam.type) {
|
||||
// fun foo(x: X, vararg y: Y): Z
|
||||
// val r: (X, Y) -> Z = ::foo
|
||||
val tailValues = unboundParamSymbols.drop(i)
|
||||
|
||||
+2
-16
@@ -5,12 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
@@ -58,21 +58,7 @@ internal fun MemberToTransformer.add(type: IrType, name: Name, v: (IrCall) -> Ir
|
||||
put(SimpleMemberKey(type, name), v)
|
||||
}
|
||||
|
||||
internal class SimpleMemberKey(val klass: IrType, val name: Name) {
|
||||
// TODO drop custom equals and hashCode when IrTypes will have right equals
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as SimpleMemberKey
|
||||
|
||||
if (name != other.name) return false
|
||||
|
||||
return klass.isEqualTo(other.klass)
|
||||
}
|
||||
|
||||
override fun hashCode() = 31 * klass.toHashCode() + name.hashCode()
|
||||
}
|
||||
internal data class SimpleMemberKey(val klass: IrType, val name: Name)
|
||||
|
||||
enum class PrimitiveType {
|
||||
FLOATING_POINT_NUMBER,
|
||||
|
||||
+6
@@ -57,6 +57,12 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
//Hack implementation to support CR java types in lower
|
||||
class CrIrType(val type: Type) : IrType {
|
||||
override val annotations = emptyList()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is CrIrType && type == other.type
|
||||
|
||||
override fun hashCode(): Int =
|
||||
type.hashCode()
|
||||
}
|
||||
|
||||
internal val callableReferencePhase = makeIrFilePhase(
|
||||
|
||||
+23
-2
@@ -5,13 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.symbols
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
interface IrClassifierEqualityChecker {
|
||||
fun areEqual(left: IrClassifierSymbol, right: IrClassifierSymbol): Boolean
|
||||
|
||||
fun getHashCode(symbol: IrClassifierSymbol): Int
|
||||
}
|
||||
|
||||
object FqNameEqualityChecker : IrClassifierEqualityChecker {
|
||||
@@ -23,8 +28,24 @@ object FqNameEqualityChecker : IrClassifierEqualityChecker {
|
||||
return checkViaDeclarations(left.owner, right.owner)
|
||||
}
|
||||
|
||||
private val IrDeclarationWithName.fqName
|
||||
get(): FqName? {
|
||||
override fun getHashCode(symbol: IrClassifierSymbol): Int {
|
||||
if (symbol.isBound) {
|
||||
val owner = symbol.owner
|
||||
if (owner is IrClass && !isLocalClass(owner)) {
|
||||
return owner.fqName.hashCode()
|
||||
}
|
||||
return owner.hashCode()
|
||||
}
|
||||
|
||||
val descriptor = symbol.descriptor
|
||||
if (descriptor is ClassDescriptor && !DescriptorUtils.isLocal(descriptor)) {
|
||||
return descriptor.fqNameSafe.hashCode()
|
||||
}
|
||||
return descriptor.hashCode()
|
||||
}
|
||||
|
||||
private val IrDeclarationWithName.fqName: FqName?
|
||||
get() {
|
||||
val parentFqName = when (val parent = parent) {
|
||||
is IrPackageFragment -> parent.fqName
|
||||
is IrDeclarationWithName -> parent.fqName
|
||||
|
||||
@@ -11,6 +11,18 @@ import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
interface IrType {
|
||||
val annotations: List<IrCall>
|
||||
|
||||
/**
|
||||
* @return true if this type is equal to [other] symbolically. Note that this is NOT EQUIVALENT to the full type checking algorithm
|
||||
* used in the compiler frontend. For example, this method will return `false` on the types `List<*>` and `List<Any?>`,
|
||||
* whereas the real type checker from the compiler frontend would return `true`.
|
||||
*
|
||||
* Classes are compared by FQ names, which means that even if two types refer to different symbols of the class with the same FQ name,
|
||||
* such types will be considered equal. Type annotations do not have any effect on the behavior of this method.
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean
|
||||
|
||||
override fun hashCode(): Int
|
||||
}
|
||||
|
||||
interface IrErrorType : IrType
|
||||
@@ -23,11 +35,15 @@ interface IrSimpleType : IrType {
|
||||
val arguments: List<IrTypeArgument>
|
||||
}
|
||||
|
||||
interface IrTypeArgument
|
||||
interface IrTypeArgument {
|
||||
override fun equals(other: Any?): Boolean
|
||||
|
||||
override fun hashCode(): Int
|
||||
}
|
||||
|
||||
interface IrStarProjection : IrTypeArgument
|
||||
|
||||
interface IrTypeProjection : IrTypeArgument {
|
||||
val variance: Variance
|
||||
val type: IrType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.types
|
||||
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
|
||||
fun IrClassifierSymbol.superTypes() = when (this) {
|
||||
is IrClassSymbol -> owner.superTypes
|
||||
is IrTypeParameterSymbol -> owner.superTypes
|
||||
@@ -26,41 +28,6 @@ fun IrType.isSubtypeOfClass(superClass: IrClassSymbol): Boolean {
|
||||
return classifier.isSubtypeOfClass(superClass)
|
||||
}
|
||||
|
||||
fun IrType.isEqualTo(that: IrType): Boolean {
|
||||
if (this is IrDynamicType && that is IrDynamicType) return true
|
||||
if (this is IrErrorType || that is IrErrorType) return false
|
||||
if (this === that) return true
|
||||
if (this is IrSimpleType && that is IrSimpleType) return FqNameEqualityChecker.areEqual(this.classifier, that.classifier) &&
|
||||
this.arguments.zip(that.arguments).all { (ths, tht) ->
|
||||
when (ths) {
|
||||
is IrStarProjection -> tht is IrStarProjection
|
||||
is IrTypeProjection -> tht is IrTypeProjection
|
||||
&& ths.variance == tht.variance
|
||||
&& ths.type.isEqualTo(tht.type)
|
||||
else -> error("Unsupported Type Argument")
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun IrTypeArgument.toHashCode(): Int = when (this) {
|
||||
is IrTypeProjection -> 31 * type.toHashCode() + variance.hashCode()
|
||||
is IrStarProjection -> hashCode()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
fun IrType.toHashCode(): Int {
|
||||
if (this is IrDynamicType) return -1
|
||||
if (this is IrErrorType) return 0
|
||||
|
||||
require(this is IrSimpleType)
|
||||
|
||||
var result = classifier.hashCode()
|
||||
|
||||
result = 31 * result + arguments.fold(0) { a, t -> 31 * a + t.toHashCode() }
|
||||
return 31 * result + if (hasQuestionMark) 1 else 0
|
||||
}
|
||||
|
||||
fun Collection<IrClassifierSymbol>.commonSuperclass(): IrClassifierSymbol {
|
||||
var superClassifiers: MutableSet<IrClassifierSymbol>? = null
|
||||
|
||||
@@ -91,4 +58,4 @@ fun Collection<IrClassifierSymbol>.commonSuperclass(): IrClassifierSymbol {
|
||||
postfix = "]"
|
||||
) { it.owner.render() }}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.types.impl
|
||||
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.symbols.FqNameEqualityChecker
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -45,12 +46,28 @@ class IrSimpleTypeImpl(
|
||||
other.classifier, other.hasQuestionMark, other.arguments, other.annotations, variance
|
||||
)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is IrSimpleTypeImpl &&
|
||||
FqNameEqualityChecker.areEqual(classifier, other.classifier) &&
|
||||
hasQuestionMark == other.hasQuestionMark &&
|
||||
arguments == other.arguments &&
|
||||
variance == other.variance
|
||||
|
||||
override fun hashCode(): Int =
|
||||
((FqNameEqualityChecker.getHashCode(classifier) * 31 + hasQuestionMark.hashCode()) * 31 +
|
||||
arguments.hashCode()) * 31 + variance.hashCode()
|
||||
}
|
||||
|
||||
class IrTypeProjectionImpl internal constructor(
|
||||
override val type: IrType,
|
||||
override val variance: Variance
|
||||
) : IrTypeProjection
|
||||
) : IrTypeProjection {
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is IrTypeProjectionImpl && type == other.type && variance == other.variance
|
||||
|
||||
override fun hashCode(): Int =
|
||||
type.hashCode() * 31 + variance.hashCode()
|
||||
}
|
||||
|
||||
fun makeTypeProjection(type: IrType, variance: Variance): IrTypeProjection =
|
||||
when {
|
||||
@@ -59,4 +76,4 @@ fun makeTypeProjection(type: IrType, variance: Variance): IrTypeProjection =
|
||||
type is IrDynamicType -> IrDynamicTypeImpl(null, type.annotations, variance)
|
||||
type is IrErrorType -> IrErrorTypeImpl(null, type.annotations, variance)
|
||||
else -> IrTypeProjectionImpl(type, variance)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,31 +16,45 @@ abstract class IrTypeBase(
|
||||
override val annotations: List<IrCall>,
|
||||
override val variance: Variance
|
||||
) : IrType, IrTypeProjection {
|
||||
|
||||
override val type: IrType get() = this
|
||||
|
||||
}
|
||||
|
||||
class IrErrorTypeImpl(
|
||||
kotlinType: KotlinType?,
|
||||
annotations: List<IrCall>,
|
||||
variance: Variance
|
||||
) : IrTypeBase(kotlinType, annotations, variance), IrErrorType
|
||||
) : IrTypeBase(kotlinType, annotations, variance), IrErrorType {
|
||||
override fun equals(other: Any?): Boolean = other is IrErrorTypeImpl
|
||||
|
||||
override fun hashCode(): Int = IrErrorTypeImpl::class.java.name.hashCode()
|
||||
}
|
||||
|
||||
class IrDynamicTypeImpl(
|
||||
kotlinType: KotlinType?,
|
||||
annotations: List<IrCall>,
|
||||
variance: Variance
|
||||
) : IrTypeBase(kotlinType, annotations, variance), IrDynamicType, IrTypeProjection
|
||||
) : IrTypeBase(kotlinType, annotations, variance), IrDynamicType, IrTypeProjection {
|
||||
override fun equals(other: Any?): Boolean = other is IrDynamicTypeImpl
|
||||
|
||||
override fun hashCode(): Int = IrDynamicTypeImpl::class.java.name.hashCode()
|
||||
}
|
||||
|
||||
|
||||
val IrType.originalKotlinType: KotlinType?
|
||||
get() = safeAs<IrTypeBase>()?.kotlinType
|
||||
|
||||
|
||||
object IrStarProjectionImpl : IrStarProjection
|
||||
object IrStarProjectionImpl : IrStarProjection {
|
||||
override fun equals(other: Any?): Boolean = this === other
|
||||
|
||||
override fun hashCode(): Int = System.identityHashCode(this)
|
||||
}
|
||||
|
||||
@Deprecated("Hack to temporary cover late type initialization")
|
||||
object IrUninitializedType : IrType {
|
||||
override val annotations: List<IrCall> = emptyList()
|
||||
|
||||
override fun equals(other: Any?): Boolean = this === other
|
||||
|
||||
override fun hashCode(): Int = System.identityHashCode(this)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user