diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/configureInterfacesAndAbstractClasses.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/configureInterfacesAndAbstractClasses.kt index 71c0a54191d..b5ecf386775 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/configureInterfacesAndAbstractClasses.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/configureInterfacesAndAbstractClasses.kt @@ -9,81 +9,19 @@ import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder import org.jetbrains.kotlin.fir.tree.generator.model.* import org.jetbrains.kotlin.generators.tree.ImplementationKindOwner import org.jetbrains.kotlin.generators.tree.ImplementationKind -import org.jetbrains.kotlin.generators.util.Node -import org.jetbrains.kotlin.generators.util.solveGraphForClassVsInterface +import org.jetbrains.kotlin.generators.tree.InterfaceAndAbstractClassConfigurator -private class NodeImpl(val element: ImplementationKindOwner) : Node { - override val parents: List - get() = element.allParents.map(::NodeImpl) +private class FirInterfaceAndAbstractClassConfigurator(builder: AbstractFirTreeBuilder) : InterfaceAndAbstractClassConfigurator() { - override val origin: NodeImpl - get() = if (element.origin == element) this else NodeImpl(element.origin) + override val elements = (builder.elements + builder.elements.flatMap { it.allImplementations }).map { it.origin } - override fun equals(other: Any?): Boolean = - other is NodeImpl && element == other.element + override val ImplementationKindOwner.origin: ImplementationKindOwner + get() = if (this is ImplementationWithArg) implementation else this - override fun hashCode(): Int = - element.hashCode() + override fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set): Boolean = + element is Implementation && element !in allParents } fun configureInterfacesAndAbstractClasses(builder: AbstractFirTreeBuilder) { - val elements = collectElements(builder) - val solution = solveGraphForClassVsInterface( - elements, - elements.filter { it.element.kind?.isInterface == true }, - elements.filter { it.element.kind?.isInterface == false }, - ) - updateKinds(elements, solution) - updateSealedKinds(elements) + FirInterfaceAndAbstractClassConfigurator(builder).configureInterfacesAndAbstractClasses() } - -private fun collectElements(builder: AbstractFirTreeBuilder): List { - return (builder.elements + builder.elements.flatMap { it.allImplementations }).map { NodeImpl(it.origin) } -} - -private fun updateKinds(nodes: List, solution: List) { - val allParents = nodes.flatMapTo(mutableSetOf()) { element -> element.parents.map { it.origin } } - - for (index in solution.indices) { - val isClass = solution[index] - val node = nodes[index].origin - val element = node.element - val existingKind = element.kind - if (isClass) { - if (existingKind == ImplementationKind.Interface) - throw IllegalStateException(element.toString()) - - if (existingKind == null) { - element.kind = when (element) { - is Implementation -> { - if (node in allParents) - ImplementationKind.AbstractClass - else - ImplementationKind.FinalClass - } - is Element -> ImplementationKind.AbstractClass - else -> throw IllegalStateException() - } - } - } else { - element.kind = ImplementationKind.Interface - } - } -} - -private fun updateSealedKinds(nodes: Collection) { - for (node in nodes) { - val element = node.element - if (element is Element) { - if (element.isSealed) { - element.kind = when (element.kind) { - ImplementationKind.AbstractClass -> ImplementationKind.SealedClass - ImplementationKind.Interface -> ImplementationKind.SealedInterface - else -> error("element $element with kind ${element.kind} can not be sealed") - } - } - } - } -} - -private val ImplementationKindOwner.origin: ImplementationKindOwner get() = if (this is ImplementationWithArg) implementation else this diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt index 5987e1e2cc2..bf90138a1af 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt @@ -42,8 +42,13 @@ class Element( var visitorParent: ElementRef? = null var transformerReturnType: Element? = null - val targetKind = config.typeKind - override var kind: ImplementationKind? = null + + override var kind: ImplementationKind? = when (config.typeKind) { + TypeKind.Class -> ImplementationKind.AbstractClass + TypeKind.Interface -> ImplementationKind.Interface + null -> null + } + val typeName get() = elementName2typeName(name) diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/configureInterfacesAndAbstractClasses.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/configureInterfacesAndAbstractClasses.kt index 829ce50092c..490a5743959 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/configureInterfacesAndAbstractClasses.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/configureInterfacesAndAbstractClasses.kt @@ -5,44 +5,12 @@ package org.jetbrains.kotlin.ir.generator.model -import org.jetbrains.kotlin.generators.tree.ImplementationKind -import org.jetbrains.kotlin.generators.tree.TypeKind -import org.jetbrains.kotlin.generators.util.Node -import org.jetbrains.kotlin.generators.util.solveGraphForClassVsInterface - -private class NodeImpl(val element: Element) : Node { - override val parents: List - get() = element.elementParents.map { NodeImpl(it.element) } - - override val origin: Node - get() = this - - override fun equals(other: Any?): Boolean = - other is NodeImpl && element == other.element - - override fun hashCode(): Int = - element.hashCode() -} +import org.jetbrains.kotlin.generators.tree.ImplementationKindOwner +import org.jetbrains.kotlin.generators.tree.InterfaceAndAbstractClassConfigurator fun configureInterfacesAndAbstractClasses(elements: List) { - val nodes = elements.map(::NodeImpl) - val solution = solveGraphForClassVsInterface( - nodes, - nodes.filter { it.element.targetKind == TypeKind.Interface }, - nodes.filter { it.element.targetKind == TypeKind.Class }, - ) - updateKinds(nodes, solution) -} - -private fun updateKinds(nodes: List, solution: List) { - for (index in solution.indices) { - val isClass = solution[index] - val element = nodes[index].element - if (isClass) { - check(element.targetKind != TypeKind.Interface) { element } - element.kind = ImplementationKind.AbstractClass - } else { - element.kind = ImplementationKind.Interface - } - } + object : InterfaceAndAbstractClassConfigurator() { + override val elements: List + get() = elements + }.configureInterfacesAndAbstractClasses() } diff --git a/generators/tree-generator-common/build.gradle.kts b/generators/tree-generator-common/build.gradle.kts index 63df389e132..6f3b480f5ff 100644 --- a/generators/tree-generator-common/build.gradle.kts +++ b/generators/tree-generator-common/build.gradle.kts @@ -5,6 +5,8 @@ plugins { dependencies { api(project(":core:compiler.common")) + + implementation(project(":generators")) } sourceSets { diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt new file mode 100644 index 00000000000..99c77cc934b --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2023 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.generators.tree + +import org.jetbrains.kotlin.generators.util.Node +import org.jetbrains.kotlin.generators.util.solveGraphForClassVsInterface + +/** + * Decides which element in the tree must be an (abstract) class, and which must be an interface. + */ +abstract class InterfaceAndAbstractClassConfigurator { + + private inner class NodeImpl(val element: ImplementationKindOwner) : Node { + override val parents: List + get() = element.allParents.map(::NodeImpl) + + override val origin: NodeImpl + get() = if (element.origin == element) this else NodeImpl(element.origin) + + override fun equals(other: Any?): Boolean = other is NodeImpl && element == other.element + + override fun hashCode(): Int = element.hashCode() + } + + protected open val ImplementationKindOwner.origin: ImplementationKindOwner + get() = this + + /** + * The list of elements of the tree to infer their [ImplementationKind]. + */ + protected abstract val elements: List + + /** + * If [element]'s kind was inferred as abstract class, allows to forcibly make that element a final class instead. + */ + protected open fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set): Boolean = false + + private fun updateKinds(nodes: List, solution: List) { + val allParents = nodes.flatMapTo(mutableSetOf()) { element -> element.parents.map { it.origin.element } } + + for (index in solution.indices) { + val isClass = solution[index] + val node = nodes[index].origin + val element = node.element + val existingKind = element.kind + if (isClass) { + require(existingKind != ImplementationKind.Interface) { + "$element must NOT be an interface" + } + if (existingKind == null) { + element.kind = if (shouldBeFinalClass(element, allParents)) + ImplementationKind.FinalClass + else + ImplementationKind.AbstractClass + } + } else { + element.kind = ImplementationKind.Interface + } + } + } + + private fun updateSealedKinds(nodes: Collection) { + for (node in nodes) { + val element = node.element + if (element is AbstractElement<*, *>) { + if (element.isSealed) { + element.kind = when (element.kind) { + ImplementationKind.AbstractClass -> ImplementationKind.SealedClass + ImplementationKind.Interface -> ImplementationKind.SealedInterface + else -> error("element $element with kind ${element.kind} can not be sealed") + } + } + } + } + } + + fun configureInterfacesAndAbstractClasses() { + val nodes = this.elements.map(::NodeImpl) + val solution = solveGraphForClassVsInterface( + nodes, + nodes.filter { it.element.kind?.typeKind == TypeKind.Interface }, + nodes.filter { it.element.kind?.typeKind == TypeKind.Class }, + ) + updateKinds(nodes, solution) + updateSealedKinds(nodes) + } +} \ No newline at end of file