FIR: introduce & use various comparators to sort members while de/serialization

#KT-41018 fixed
This commit is contained in:
Jinseong Jeon
2020-08-13 23:17:30 -07:00
committed by Mikhail Zarechenskiy
parent 91c021c699
commit e8157a5488
81 changed files with 1106 additions and 554 deletions
@@ -0,0 +1,67 @@
/*
* 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.declarations
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.FirTypeRefComparator
object FirCallableMemberDeclarationComparator : Comparator<FirCallableMemberDeclaration<*>> {
override fun compare(a: FirCallableMemberDeclaration<*>, b: FirCallableMemberDeclaration<*>): Int {
val typeAndNameDiff = FirMemberDeclarationComparator.TypeAndNameComparator.compare(a, b)
if (typeAndNameDiff != 0) {
return typeAndNameDiff
}
// Compare the receiver type if any.
if (a.receiverTypeRef != null || b.receiverTypeRef != null) {
val aHasReceiverType = if (a.receiverTypeRef != null) 1 else 0
val bHasReceiverType = if (b.receiverTypeRef != null) 1 else 0
val receiverTypePresenceDiff = aHasReceiverType - bHasReceiverType
if (receiverTypePresenceDiff != 0) {
return receiverTypePresenceDiff
}
assert(a.receiverTypeRef != null && b.receiverTypeRef != null)
}
// Compare the return type.
val returnTypeDiff = FirTypeRefComparator.compare(a.returnTypeRef, b.returnTypeRef)
if (returnTypeDiff != 0) {
return returnTypeDiff
}
// Compare the value parameters for functions.
if (a is FirFunction<*>) {
require(b is FirFunction<*>) {
"TypeAndNameComparator is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val valueParameterSizeDiff = a.valueParameters.size - b.valueParameters.size
if (valueParameterSizeDiff != 0) {
return valueParameterSizeDiff
}
for ((aValueParameter, bValueParameter) in a.valueParameters.zip(b.valueParameters)) {
val valueParameterDiff = FirValueParameterComparator.compare(aValueParameter, bValueParameter)
if (valueParameterDiff != 0) {
return valueParameterDiff
}
}
}
// Compare the type parameters.
val typeParameterSizeDiff = a.typeParameters.size - b.typeParameters.size
if (typeParameterSizeDiff != 0) {
return typeParameterSizeDiff
}
for ((aTypeParameter, bTypeParameter) in a.typeParameters.zip(b.typeParameters)) {
val typeParameterDiff = FirTypeParameterRefComparator.compare(aTypeParameter, bTypeParameter)
if (typeParameterDiff != 0) {
return typeParameterDiff
}
}
// Lastly, compare the fully qualified package name.
return a.symbol.callableId.packageName.asString().compareTo(b.symbol.callableId.packageName.asString())
}
}
@@ -0,0 +1,84 @@
/*
* 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.declarations
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.FirTypeRefComparator
import org.jetbrains.kotlin.name.Name
object FirMemberDeclarationComparator : Comparator<FirMemberDeclaration> {
// Comparing different kinds of callable members by assigning distinct priorities to those members.
object TypeAndNameComparator : Comparator<FirMemberDeclaration> {
private val FirMemberDeclaration.priority : Int
get() = when (this) {
is FirEnumEntry -> 7
is FirConstructor -> 6
is FirProperty -> 5
is FirField -> 4
is FirFunction<*> -> 3
is FirClass<*> -> 2
is FirTypeAlias -> 1
else -> 0
}
private val FirMemberDeclaration.name : Name
get() = when (this) {
is FirCallableMemberDeclaration<*> ->
this.symbol.callableId.callableName
is FirClass<*> ->
this.classId.shortClassName
is FirTypeAlias ->
this.name
else ->
error("Unsupported name retrieval for ${render()}")
}
override fun compare(a: FirMemberDeclaration, b: FirMemberDeclaration): Int {
val priorityDiff = a.priority - b.priority
if (priorityDiff != 0) {
return priorityDiff
}
// Never reorder enum entries.
if (a is FirEnumEntry) {
require(b is FirEnumEntry) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return 0
}
return a.name.compareTo(b.name)
}
}
override fun compare(a: FirMemberDeclaration, b: FirMemberDeclaration): Int {
if (a is FirCallableMemberDeclaration<*> && b is FirCallableMemberDeclaration<*>) {
return FirCallableMemberDeclarationComparator.compare(a, b)
}
val typeAndNameDiff = TypeAndNameComparator.compare(a, b)
if (typeAndNameDiff != 0) {
return typeAndNameDiff
}
// Note that names are already compared. Check other details per kind.
when (a) {
is FirClass<*> -> {
require(b is FirClass<*>) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return a.classId.packageFqName.asString().compareTo(b.classId.packageFqName.asString())
}
is FirTypeAlias -> {
require(b is FirTypeAlias) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return FirTypeRefComparator.compare(a.expandedTypeRef, b.expandedTypeRef)
}
else ->
error("Unsupported member declaration comparison: ${a.render()} v.s. ${b.render()}")
}
}
}
@@ -0,0 +1,68 @@
/*
* 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.declarations
import org.jetbrains.kotlin.fir.declarations.impl.FirConstructedClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.FirTypeRefComparator
object FirTypeParameterRefComparator : Comparator<FirTypeParameterRef> {
private val FirTypeParameterRef.priority : Int
get() = when (this) {
is FirConstructedClassTypeParameterRef -> 3
is FirOuterClassTypeParameterRef -> 2
is FirTypeParameter -> 1
else -> 0
}
override fun compare(a: FirTypeParameterRef, b: FirTypeParameterRef): Int {
val priorityDiff = a.priority - b.priority
if (priorityDiff != 0) {
return priorityDiff
}
when (a) {
is FirConstructedClassTypeParameterRef -> {
require(b is FirConstructedClassTypeParameterRef) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return a.symbol.name.compareTo(b.symbol.name)
}
is FirOuterClassTypeParameterRef -> {
require(b is FirOuterClassTypeParameterRef) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return a.symbol.name.compareTo(b.symbol.name)
}
is FirTypeParameter -> {
require(b is FirTypeParameter) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val nameDiff = a.symbol.name.compareTo(b.symbol.name)
if (nameDiff != 0) {
return nameDiff
}
val varianceDiff = a.variance.ordinal - b.variance.ordinal
if (varianceDiff != 0) {
return varianceDiff
}
val boundsSizeDiff = a.bounds.size - b.bounds.size
if (boundsSizeDiff != 0) {
return boundsSizeDiff
}
for ((aBound, bBound) in a.bounds.zip(b.bounds)) {
val boundDiff = FirTypeRefComparator.compare(aBound, bBound)
if (boundDiff != 0) {
return boundDiff
}
}
return 0
}
else ->
error("Unsupported type parameter reference comparison: ${a.render()} v.s. ${b.render()}")
}
}
}
@@ -0,0 +1,33 @@
/*
* 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.declarations
import org.jetbrains.kotlin.fir.types.FirTypeRefComparator
object FirValueParameterComparator : Comparator<FirValueParameter> {
override fun compare(a: FirValueParameter, b: FirValueParameter): Int {
val valueParameterNameDiff = a.name.compareTo(b.name)
if (valueParameterNameDiff != 0) {
return valueParameterNameDiff
}
val valueParameterTypeDiff = FirTypeRefComparator.compare(a.returnTypeRef, b.returnTypeRef)
if (valueParameterTypeDiff != 0) {
return valueParameterTypeDiff
}
val aHasDefaultValue = if (a.defaultValue != null) 1 else 0
val bHasDefaultValue = if (b.defaultValue != null) 1 else 0
val defaultValueDiff = aHasDefaultValue - bHasDefaultValue
if (defaultValueDiff != 0) {
return defaultValueDiff
}
val aIsVararg = if (a.isVararg) 1 else 0
val bIsVararg = if (b.isVararg) 1 else 0
return aIsVararg - bIsVararg
}
}
@@ -0,0 +1,173 @@
/*
* 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
object ConeKotlinTypeComparator : Comparator<ConeKotlinType> {
private val ConeKotlinType.priority : Int
get() = when (this) {
is ConeKotlinErrorType -> 8
is ConeLookupTagBasedType -> 7
is ConeFlexibleType -> 6
is ConeCapturedType -> 5
is ConeDefinitelyNotNullType -> 4
is ConeIntersectionType -> 3
is ConeStubType -> 2
is ConeIntegerLiteralType -> 1
else -> 0
}
private fun compare(a: ConeTypeProjection, b: ConeTypeProjection): Int {
val kindDiff = a.kind.ordinal - b.kind.ordinal
if (kindDiff != 0) {
return kindDiff
}
when (a) {
is ConeStarProjection -> return 0
is ConeKotlinTypeProjectionIn -> {
require(b is ConeKotlinTypeProjectionIn) {
"ordinal is inconsistent: $a v.s. $b"
}
return compare(a.type, b.type)
}
is ConeKotlinTypeProjectionOut -> {
require(b is ConeKotlinTypeProjectionOut) {
"ordinal is inconsistent: $a v.s. $b"
}
return compare(a.type, b.type)
}
else -> {
assert(a is ConeKotlinType && b is ConeKotlinType) {
"Expect INVARIANT: $a v.s. $b"
}
return compare(a as ConeKotlinType, b as ConeKotlinType)
}
}
}
private fun compare(a: Array<out ConeTypeProjection>, b: Array<out ConeTypeProjection>): Int {
val sizeDiff = a.size - b.size
if (sizeDiff != 0) {
return sizeDiff
}
for ((aTypeProjection, bTypeProjection) in a.zip(b)) {
val typeProjectionDiff = compare(aTypeProjection, bTypeProjection)
if (typeProjectionDiff != 0) {
return typeProjectionDiff
}
}
return 0
}
private fun compare(a: ConeNullability, b: ConeNullability): Int {
return a.ordinal - b.ordinal
}
override fun compare(a: ConeKotlinType, b: ConeKotlinType): Int {
val priorityDiff = a.priority - b.priority
if (priorityDiff != 0) {
return priorityDiff
}
when (a) {
is ConeKotlinErrorType -> {
require(b is ConeKotlinErrorType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return a.hashCode() - b.hashCode()
}
is ConeLookupTagBasedType -> {
require(b is ConeLookupTagBasedType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val nameDiff = a.lookupTag.name.compareTo(b.lookupTag.name)
if (nameDiff != 0) {
return nameDiff
}
val nullabilityDiff = compare(a.nullability, b.nullability)
if (nullabilityDiff != 0) {
return nullabilityDiff
}
return compare(a.typeArguments, b.typeArguments)
}
is ConeFlexibleType -> {
require(b is ConeFlexibleType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val lowerBoundDiff = compare(a.lowerBound, b.lowerBound)
if (lowerBoundDiff != 0) {
return lowerBoundDiff
}
return compare(a.upperBound, b.upperBound)
}
is ConeCapturedType -> {
require(b is ConeCapturedType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val aHasLowerType = if (a.lowerType != null) 1 else 0
val bHasLowerType = if (b.lowerType != null) 1 else 0
val hasLowerTypeDiff = aHasLowerType - bHasLowerType
if (hasLowerTypeDiff != 0) {
return hasLowerTypeDiff
}
if (a.lowerType != null && b.lowerType != null) {
val lowerTypeDiff = compare(a.lowerType!!, b.lowerType!!)
if (lowerTypeDiff != 0) {
return lowerTypeDiff
}
}
val nullabilityDiff = compare(a.nullability, b.nullability)
if (nullabilityDiff != 0) {
return nullabilityDiff
}
return a.constructor.hashCode() - b.constructor.hashCode()
}
is ConeDefinitelyNotNullType -> {
require(b is ConeDefinitelyNotNullType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return compare(a.original, b.original)
}
is ConeIntersectionType -> {
require(b is ConeIntersectionType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val sizeDiff = a.intersectedTypes.size - b.intersectedTypes.size
if (sizeDiff != 0) {
return 0
}
// Can't compare individual types from each side, since their orders are not guaranteed.
return a.hashCode() - b.hashCode()
}
is ConeStubType -> {
require(b is ConeStubType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val nameDiff = a.variable.typeConstructor.name.compareTo(b.variable.typeConstructor.name)
if (nameDiff != 0) {
return nameDiff
}
return compare(a.nullability, b.nullability)
}
is ConeIntegerLiteralType -> {
require(b is ConeIntegerLiteralType) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val valueDiff = a.value - b.value
if (valueDiff != 0L) {
return valueDiff.toInt()
}
val nullabilityDiff = compare(a.nullability, b.nullability)
if (nullabilityDiff != 0) {
return nullabilityDiff
}
// Can't compare individual types from each side, since their orders are not guaranteed.
return a.hashCode() - b.hashCode()
}
else ->
error("Unsupported type comparison: ${a.render()} v.s. ${b.render()}")
}
}
}
@@ -0,0 +1,42 @@
/*
* 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.render
object FirTypeProjectionComparator : Comparator<FirTypeProjection> {
private val FirTypeProjection.priority : Int
get() = when (this) {
is FirTypeProjectionWithVariance -> 2
is FirStarProjection -> 1
else -> 0
}
override fun compare(a: FirTypeProjection, b: FirTypeProjection): Int {
val priorityDiff = a.priority - b.priority
if (priorityDiff != 0) {
return priorityDiff
}
when (a) {
is FirTypeProjectionWithVariance -> {
require(b is FirTypeProjectionWithVariance) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val typeRefDiff = FirTypeRefComparator.compare(a.typeRef, b.typeRef)
if (typeRefDiff != 0) {
return typeRefDiff
}
return a.variance.ordinal - b.variance.ordinal
}
is FirStarProjection -> {
return 0
}
else ->
error("Unsupported type projection comparison: ${a.render()} v.s. ${b.render()}")
}
}
}
@@ -0,0 +1,71 @@
/*
* 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.render
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
object FirTypeRefComparator : Comparator<FirTypeRef> {
private val FirTypeRef.priority : Int
get() = when (this) {
is FirUserTypeRef -> 3
is FirImplicitBuiltinTypeRef -> 2
is FirResolvedTypeRef -> 1
else -> 0
}
override fun compare(a: FirTypeRef, b: FirTypeRef): Int {
val priorityDiff = a.priority - b.priority
if (priorityDiff != 0) {
return priorityDiff
}
when (a) {
is FirUserTypeRef -> {
require(b is FirUserTypeRef) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
val qualifierSizeDiff = a.qualifier.size - b.qualifier.size
if (qualifierSizeDiff != 0) {
return qualifierSizeDiff
}
for ((aQualifier, bQualifier) in a.qualifier.zip(b.qualifier)) {
val qualifierNameDiff = aQualifier.name.compareTo(bQualifier.name)
if (qualifierNameDiff != 0) {
return qualifierNameDiff
}
val typeArgumentSizeDiff =
aQualifier.typeArgumentList.typeArguments.size - bQualifier.typeArgumentList.typeArguments.size
if (typeArgumentSizeDiff != 0) {
return typeArgumentSizeDiff
}
val typeArguments = aQualifier.typeArgumentList.typeArguments.zip(bQualifier.typeArgumentList.typeArguments)
for ((aTypeArgument, bTypeArgument) in typeArguments) {
val typeArgumentDiff = FirTypeProjectionComparator.compare(aTypeArgument, bTypeArgument)
if (typeArgumentDiff != 0) {
return typeArgumentDiff
}
}
}
return 0
}
is FirImplicitBuiltinTypeRef -> {
require(b is FirImplicitBuiltinTypeRef) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return a.id.shortClassName.compareTo(b.id.shortClassName)
}
is FirResolvedTypeRef -> {
require(b is FirResolvedTypeRef) {
"priority is inconsistent: ${a.render()} v.s. ${b.render()}"
}
return ConeKotlinTypeComparator.compare(a.type, b.type)
}
else ->
error("Unsupported type reference comparison: ${a.render()} v.s. ${b.render()}")
}
}
}