From dc1ce19db9bb2135a3ba58e3cebf442d5f816285 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Mon, 10 May 2021 10:50:01 +0200 Subject: [PATCH] Extract some logic from AbstractTypeConstructor to reuse it later In FE10-binding I would like to re-use equal and hashCode mechanics that was implemented in AbstractTypeConstructor, but I don't need the supertype implementation, because it already there in FIR --- .../kotlin/types/AbstractTypeConstructor.kt | 67 +--------------- .../types/ClassifierBasedTypeConstructor.kt | 80 +++++++++++++++++++ .../types/checker/ClassicTypeSystemContext.kt | 2 +- 3 files changed, 82 insertions(+), 67 deletions(-) create mode 100644 core/descriptors/src/org/jetbrains/kotlin/types/ClassifierBasedTypeConstructor.kt diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt index b77c41f87a0..1d1a82ebf19 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractTypeConstructor.kt @@ -24,13 +24,9 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner import org.jetbrains.kotlin.types.checker.refineTypes import org.jetbrains.kotlin.types.refinement.TypeRefinement -abstract class AbstractTypeConstructor(storageManager: StorageManager) : TypeConstructor { - private var hashCode = 0 - +abstract class AbstractTypeConstructor(storageManager: StorageManager) : ClassifierBasedTypeConstructor() { override fun getSupertypes() = supertypes().supertypesWithoutCycles - abstract override fun getDeclarationDescriptor(): ClassifierDescriptor - @TypeRefinement override fun refine(kotlinTypeRefiner: KotlinTypeRefiner): TypeConstructor = ModuleViewTypeConstructor(kotlinTypeRefiner) @@ -134,65 +130,4 @@ abstract class AbstractTypeConstructor(storageManager: StorageManager) : TypeCon // Only for debugging fun renderAdditionalDebugInformation(): String = "supertypes=${supertypes.renderDebugInformation()}" - override fun hashCode(): Int { - val cachedHashCode = hashCode - if (cachedHashCode != 0) return cachedHashCode - - val descriptor = declarationDescriptor - val computedHashCode = if (hasMeaningfulFqName(descriptor)) { - DescriptorUtils.getFqName(descriptor).hashCode() - } else { - System.identityHashCode(this) - } - - return computedHashCode.also { hashCode = it } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is TypeConstructor) return false - - // performance optimization: getFqName is slow method - // Cast to Any is needed as a workaround for KT-45008. - if ((other as Any).hashCode() != hashCode()) return false - - // Sometimes we can get two classes from different modules with different counts of type parameters. - // To avoid problems in type checker we suppose that it is different type constructors. - if (other.parameters.size != parameters.size) return false - - val myDescriptor = declarationDescriptor - val otherDescriptor = other.declarationDescriptor ?: return false - if (!hasMeaningfulFqName(myDescriptor) || !hasMeaningfulFqName(otherDescriptor)) { - // All error types and local classes have the same descriptor, - // but we've already checked identity equality in the beginning of the method - return false - } - - return isSameClassifier(otherDescriptor) - } - - protected abstract fun isSameClassifier(classifier: ClassifierDescriptor): Boolean - - protected fun areFqNamesEqual(first: ClassifierDescriptor, second: ClassifierDescriptor): Boolean { - if (first.name != second.name) return false - var a: DeclarationDescriptor? = first.containingDeclaration - var b: DeclarationDescriptor? = second.containingDeclaration - while (a != null && b != null) { - when { - a is ModuleDescriptor -> return b is ModuleDescriptor - b is ModuleDescriptor -> return false - a is PackageFragmentDescriptor -> return b is PackageFragmentDescriptor && a.fqName == b.fqName - b is PackageFragmentDescriptor -> return false - a.name != b.name -> return false - else -> { - a = a.containingDeclaration - b = b.containingDeclaration - } - } - } - return true - } - - private fun hasMeaningfulFqName(descriptor: ClassifierDescriptor): Boolean = - !ErrorUtils.isError(descriptor) && !DescriptorUtils.isLocal(descriptor) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ClassifierBasedTypeConstructor.kt b/core/descriptors/src/org/jetbrains/kotlin/types/ClassifierBasedTypeConstructor.kt new file mode 100644 index 00000000000..46d159f21c4 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ClassifierBasedTypeConstructor.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2021 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.types + +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.resolve.DescriptorUtils + +abstract class ClassifierBasedTypeConstructor : TypeConstructor { + private var hashCode = 0 + + abstract override fun getDeclarationDescriptor(): ClassifierDescriptor + + override fun hashCode(): Int { + val cachedHashCode = hashCode + if (cachedHashCode != 0) return cachedHashCode + + val descriptor = declarationDescriptor + val computedHashCode = if (hasMeaningfulFqName(descriptor)) { + DescriptorUtils.getFqName(descriptor).hashCode() + } else { + System.identityHashCode(this) + } + + return computedHashCode.also { hashCode = it } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is TypeConstructor) return false + + // performance optimization: getFqName is slow method + // Cast to Any is needed as a workaround for KT-45008. + if ((other as Any).hashCode() != hashCode()) return false + + // Sometimes we can get two classes from different modules with different counts of type parameters. + // To avoid problems in type checker we suppose that it is different type constructors. + if (other.parameters.size != parameters.size) return false + + val myDescriptor = declarationDescriptor + val otherDescriptor = other.declarationDescriptor ?: return false + if (!hasMeaningfulFqName(myDescriptor) || !hasMeaningfulFqName(otherDescriptor)) { + // All error types and local classes have the same descriptor, + // but we've already checked identity equality in the beginning of the method + return false + } + + return isSameClassifier(otherDescriptor) + } + + protected abstract fun isSameClassifier(classifier: ClassifierDescriptor): Boolean + + protected fun areFqNamesEqual(first: ClassifierDescriptor, second: ClassifierDescriptor): Boolean { + if (first.name != second.name) return false + var a: DeclarationDescriptor? = first.containingDeclaration + var b: DeclarationDescriptor? = second.containingDeclaration + while (a != null && b != null) { + when { + a is ModuleDescriptor -> return b is ModuleDescriptor + b is ModuleDescriptor -> return false + a is PackageFragmentDescriptor -> return b is PackageFragmentDescriptor && a.fqName == b.fqName + b is PackageFragmentDescriptor -> return false + a.name != b.name -> return false + else -> { + a = a.containingDeclaration + b = b.containingDeclaration + } + } + } + return true + } + + private fun hasMeaningfulFqName(descriptor: ClassifierDescriptor): Boolean = + !ErrorUtils.isError(descriptor) && !DescriptorUtils.isLocal(descriptor) +} \ No newline at end of file diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 8b3f1b0f2d5..6e9a2414535 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -610,7 +610,7 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy } override fun TypeConstructorMarker.isTypeParameterTypeConstructor(): Boolean { - return this is AbstractTypeConstructor && this.declarationDescriptor is AbstractTypeParameterDescriptor + return this is ClassifierBasedTypeConstructor && this.declarationDescriptor is AbstractTypeParameterDescriptor } override fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker {