Skip to content

Commit

Permalink
Optimize signature equals.
Browse files Browse the repository at this point in the history
  • Loading branch information
FilipDolnik committed Apr 12, 2024
1 parent 6ec4df4 commit 29596b9
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ sealed class Signature {
if (this === other) return true
if (other !is Signature) return false

if (this is EnumCase && other is Function || this is Function && other is EnumCase) return false

if (receiver != other.receiver) return false
if (identifier != other.identifier) return false
if (valueParameters != other.valueParameters) return false
if (returnType != other.returnType) return false
if (valueParameters != other.valueParameters) return false
if (scope != other.scope) return false

if (this is EnumCase && other is Function || this is Function && other is EnumCase) return false
if (identifier != other.identifier) return false

return true
}
Expand Down Expand Up @@ -213,11 +213,11 @@ sealed class Signature {

other as Class

if (typeArguments != other.typeArguments) return false

return with(sirHierarchyCache) {
sirClass.sharesDirectInheritanceHierarchy(other.sirClass)
with(sirHierarchyCache) {
if (!sirClass.sharesDirectInheritanceHierarchy(other.sirClass)) return false
}

return typeArguments == other.typeArguments
}

override fun hashCode(): Int = typeArguments.hashCode()
Expand Down Expand Up @@ -284,22 +284,22 @@ sealed class Signature {

companion object {

operator fun invoke(enumCase: SirEnumCase, sirHierarchyCache: SirHierarchyCache): Signature =
operator fun invoke(enumCase: SirEnumCase, sirHierarchyCache: SirHierarchyCache = SirHierarchyCache()): Signature =
with(sirHierarchyCache) {
EnumCase(
receiver = Receiver.Simple(enumCase.parent.asReceiverType, emptySet()),
identifier = enumCase.simpleName,
)
}

operator fun invoke(callableDeclaration: SirCallableDeclaration, sirHierarchyCache: SirHierarchyCache): Signature =
operator fun invoke(callableDeclaration: SirCallableDeclaration, sirHierarchyCache: SirHierarchyCache = SirHierarchyCache()): Signature =
when (callableDeclaration) {
is SirSimpleFunction -> Signature(callableDeclaration, sirHierarchyCache)
is SirConstructor -> Signature(callableDeclaration, sirHierarchyCache)
is SirProperty -> Signature(callableDeclaration, sirHierarchyCache)
}

operator fun invoke(function: SirSimpleFunction, sirHierarchyCache: SirHierarchyCache): Signature =
operator fun invoke(function: SirSimpleFunction, sirHierarchyCache: SirHierarchyCache = SirHierarchyCache()): Signature =
with(sirHierarchyCache) {
SimpleFunction(
receiver = function.receiver,
Expand All @@ -310,7 +310,7 @@ sealed class Signature {
)
}

operator fun invoke(constructor: SirConstructor, sirHierarchyCache: SirHierarchyCache): Signature {
operator fun invoke(constructor: SirConstructor, sirHierarchyCache: SirHierarchyCache = SirHierarchyCache()): Signature {
val receiver = with(sirHierarchyCache) {
constructor.receiver
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,18 @@ import co.touchlab.skie.sir.element.resolveAsSirClass

class SirHierarchyCache {

private val primaryCache = mutableMapOf<SirClass, MutableMap<SirClass, Boolean>>()
private val allSuperTypesAndSelfCache = mutableMapOf<SirClass, Set<SirClass>>()

private val inheritanceCache = mutableMapOf<SirClass, MutableMap<SirClass, Boolean>>()
fun SirClass.sharesDirectInheritanceHierarchy(other: SirClass): Boolean =
this.isSelfOrInheritsFrom(other) || other.isSelfOrInheritsFrom(this)

fun SirClass.sharesDirectInheritanceHierarchy(other: SirClass): Boolean {
if (this == other) {
return true
}

if (!this.canTheoreticallyShareDirectInheritanceHierarchy(other)) {
return false
}

primaryCache[this]?.get(other)?.let { return it }

val result = this.inheritsFrom(other) || other.inheritsFrom(this)

primaryCache.getOrPut(this) { mutableMapOf() }[other] = result
primaryCache.getOrPut(other) { mutableMapOf() }[this] = result

return result
}

private fun SirClass.inheritsFrom(other: SirClass): Boolean {
if (!this.canTheoreticallyInheritFrom(other)) {
return false
}

inheritanceCache[this]?.get(other)?.let { return it }
private fun SirClass.isSelfOrInheritsFrom(other: SirClass): Boolean =
other in this.getAllSuperTypesAndSelf()

val superClasses = superTypes.mapNotNull { it.resolveAsSirClass() }
private fun SirClass.getAllSuperTypesAndSelf(): Set<SirClass> =
allSuperTypesAndSelfCache.getOrPut(this) {
val superTypes = superTypes.mapNotNull { it.resolveAsSirClass() }.toSet()

val inheritsFrom = other in superClasses || superClasses.any { it.inheritsFrom(other) }

inheritanceCache.getOrPut(this) { mutableMapOf() }[other] = inheritsFrom
if (inheritsFrom) {
inheritanceCache.getOrPut(other) { mutableMapOf() }[this] = false
superTypes + superTypes.flatMap { it.getAllSuperTypesAndSelf() } + this
}

return inheritsFrom
}

private fun SirClass.canTheoreticallyShareDirectInheritanceHierarchy(other: SirClass): Boolean {
// TODO Implement based on open/close if added to SirClass
if ((this.kind.isStruct || this.kind.isEnum) && !other.kind.isProtocol) return false
if ((other.kind.isStruct || other.kind.isEnum) && !this.kind.isProtocol) return false

return true
}

private fun SirClass.canTheoreticallyInheritFrom(other: SirClass): Boolean {
// TODO Implement based on open/close if added to SirClass
if (other.kind.isStruct) return false
if (other.kind.isEnum) return false
if (other.kind.isClass && !this.kind.isClass) return false

return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ class UniqueSignatureSet {
private val alreadyAddedDeclarations = mutableSetOf<SirCallableDeclaration>()
private val alreadyAddedEnumCase = mutableSetOf<SirEnumCase>()

// Map so that we can get the signatures for conflicts
// Map so that we can get the signatures for conflicts by identifier (for performance reasons)
// Map of signature to signature instead of set because we need to know which declaration is conflicting
// The algorithm utilises custom equality which checks if the signature is the same from the overload resolution perspective.
private val existingSignaturesMap = mutableMapOf<Signature, Signature>()

private val sirHierarchyCache = SirHierarchyCache()
Expand All @@ -30,8 +32,10 @@ class UniqueSignatureSet {
group.resolveCollisionWithWarning {
val signature = signature

if (signature in existingSignaturesMap) {
"an another declaration '${existingSignaturesMap[signature]}'"
val conflictingSignature = findConflictingSignature(signature)

if (conflictingSignature != null) {
"an another declaration '$conflictingSignature'"
} else {
null
}
Expand All @@ -49,18 +53,27 @@ class UniqueSignatureSet {
enumCase.resolveCollisionWithWarning {
val signature = signature

if (signature in existingSignaturesMap) {
"an another declaration '${existingSignaturesMap[signature]}'"
val conflictingSignature = findConflictingSignature(signature)

if (conflictingSignature != null) {
"an another declaration '${conflictingSignature}'"
} else {
null
}
}

val signature = enumCase.signature
existingSignaturesMap.putIfAbsent(signature, signature)
addSignature(enumCase.signature)

alreadyAddedEnumCase.add(enumCase)
}

private fun findConflictingSignature(signature: Signature): Signature? =
existingSignaturesMap[signature]

private fun addSignature(signature: Signature) {
existingSignaturesMap[signature] = signature
}

private inner class Group(
private val representative: SirCallableDeclaration,
) {
Expand All @@ -72,11 +85,14 @@ class UniqueSignatureSet {
do {
var changed = false

callableDeclarations.forEach {
// Avoid short-circuiting
changed = it.resolveCollisionWithWarning(collisionReasonProvider) || changed
for (callableDeclaration in callableDeclarations) {
changed = callableDeclaration.resolveCollisionWithWarning(collisionReasonProvider)

if (changed) {
unifyNames(callableDeclaration)

unifyNames(it)
break
}
}
} while (changed)
}
Expand All @@ -94,14 +110,12 @@ class UniqueSignatureSet {
}

fun addToCaches() {
val representativeSignature = representative.signature
existingSignaturesMap.putIfAbsent(representativeSignature, representativeSignature)
addSignature(representative.signature)

alreadyAddedDeclarations.addAll(callableDeclarations)
callableDeclarations.forEach {
val signature = it.signature

existingSignaturesMap.putIfAbsent(signature, signature)
callableDeclarations.forEach {
addSignature(it.signature)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ sealed interface SirCallableDeclaration : SirDeclaration, SirElementWithModifier
val deprecationLevel: DeprecationLevel

fun toReadableString(): String =
Signature(this, SirHierarchyCache()).toString()
Signature(this).toString()
}

val SirCallableDeclaration.receiverDeclaration: SirClass?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ sealed class SirFunction(
protected abstract val identifierForReference: String

override fun toString(): String =
Signature(this, SirHierarchyCache()).toString()
Signature(this).toString()
}

fun SirFunction.call(arguments: List<SirValueParameter>): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class SirProperty(
}

override fun toString(): String =
Signature(this, SirHierarchyCache()).toString()
Signature(this).toString()

companion object {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class SirSimpleFunction(
}

override fun toString(): String =
Signature(this, SirHierarchyCache()).toString()
Signature(this).toString()

companion object {

Expand Down

0 comments on commit 29596b9

Please sign in to comment.