[FIR2IR] Generate fake overrides earlier and bind them later

Before this commit, we generated fake overrides at last FIR2IR stage,
after having all functions and classes built. This could lead to a
situation when fake override was called before it was generated.
This commit fixes this situation.
This commit is contained in:
Mikhail Glukhikh
2020-08-21 16:27:50 +03:00
parent ee9c597767
commit 53ad502d2a
6 changed files with 102 additions and 64 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants
import org.jetbrains.kotlin.fir.backend.generators.AnnotationGenerator
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
import org.jetbrains.kotlin.fir.backend.generators.DataClassMembersGenerator
import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
@@ -89,40 +91,90 @@ class Fir2IrConverter(
it, irClass, isLocal = true
)
}
val processedCallableNames = mutableSetOf<Name>()
for (declaration in sortBySynthetic(anonymousObject.declarations)) {
if (declaration is FirRegularClass) {
registerClassAndNestedClasses(declaration, irClass)
processClassAndNestedClassHeaders(declaration)
}
val irDeclaration = processMemberDeclaration(declaration, anonymousObject, irClass) ?: continue
when (declaration) {
is FirSimpleFunction -> processedCallableNames += declaration.name
is FirProperty -> processedCallableNames += declaration.name
}
irClass.declarations += irDeclaration
}
return irClass
}
// Add delegated members *before* fake override generations.
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
processedCallableNames += delegatedMemberNames(irClass)
with(fakeOverrideGenerator) {
irClass.addFakeOverrides(anonymousObject, processedCallableNames)
}
// Sort declarations so that all non-synthetic declarations are before synthetic ones.
// This is needed because converting synthetic fields for implementation delegation needs to know
// existing declarations in the class to avoid adding redundant delegated members.
private fun sortBySynthetic(declarations: List<FirDeclaration>) : Iterable<FirDeclaration> {
return declarations.sortedBy { it.isSynthetic }
return irClass
}
private fun processClassMembers(
regularClass: FirRegularClass,
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
): IrClass {
regularClass.getPrimaryConstructorIfAny()?.let {
irClass.declarations += declarationStorage.createIrConstructor(
it, irClass, isLocal = regularClass.isLocal
)
val irConstructor = regularClass.getPrimaryConstructorIfAny()?.let {
declarationStorage.createIrConstructor(it, irClass, isLocal = regularClass.isLocal)
}
if (irConstructor != null) {
irClass.declarations += irConstructor
}
val processedCallableNames = mutableSetOf<Name>()
for (declaration in sortBySynthetic(regularClass.declarations)) {
val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue
when (declaration) {
is FirSimpleFunction -> processedCallableNames += declaration.name
is FirProperty -> processedCallableNames += declaration.name
}
irClass.declarations += irDeclaration
}
// Add delegated members *before* fake override generations.
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
processedCallableNames += delegatedMemberNames(irClass)
// Add synthetic members *before* fake override generations.
// Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added.
if (irConstructor != null && (irClass.isInline || irClass.isData)) {
declarationStorage.enterScope(irConstructor)
val dataClassMembersGenerator = DataClassMembersGenerator(components)
if (irClass.isInline) {
processedCallableNames += dataClassMembersGenerator.generateInlineClassMembers(regularClass, irClass)
}
if (irClass.isData) {
processedCallableNames += dataClassMembersGenerator.generateDataClassMembers(regularClass, irClass)
}
declarationStorage.leaveScope(irConstructor)
}
with(fakeOverrideGenerator) {
irClass.addFakeOverrides(regularClass, processedCallableNames)
}
return irClass
}
private fun delegatedMemberNames(irClass: IrClass): List<Name> {
return irClass.declarations.filter {
it.origin == IrDeclarationOrigin.DELEGATED_MEMBER
}.mapNotNull {
when (it) {
is IrSimpleFunction -> it.name
is IrProperty -> it.name
else -> null
}
}
}
// Sort declarations so that all non-synthetic declarations are before synthetic ones.
// This is needed because converting synthetic fields for implementation delegation needs to know
// existing declarations in the class to avoid adding redundant delegated members.
private fun sortBySynthetic(declarations: List<FirDeclaration>): Iterable<FirDeclaration> {
return declarations.sortedBy { it.isSynthetic }
}
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
val irClass = classifierStorage.registerIrClass(regularClass, parent)
regularClass.declarations.forEach {
@@ -15,19 +15,13 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.processDirectlyOverriddenProperties
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.unwrapSubstitutionOverrides
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.ir.util.isAnnotationClass
@@ -61,32 +55,7 @@ internal class ClassMemberGenerator(
convertFunctionContent(irPrimaryConstructor, primaryConstructor, containingClass = klass)
}
}
val processedCallableNames = klass.declarations.mapNotNullTo(mutableSetOf()) {
when (it) {
is FirSimpleFunction -> it.name
is FirProperty -> it.name
else -> null
}
}
// Add delegated members *before* fake override generations.
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
irClass.declarations.filter {
it.origin == IrDeclarationOrigin.DELEGATED_MEMBER
}.forEach {
when (it) {
is IrSimpleFunction -> processedCallableNames += it.name
is IrProperty -> processedCallableNames += it.name
}
}
// Add synthetic members *before* fake override generations.
// Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added.
if (irClass.isInline && klass.getPrimaryConstructorIfAny() != null) {
processedCallableNames += DataClassMembersGenerator(components).generateInlineClassMembers(klass, irClass)
}
if (irClass.isData && klass.getPrimaryConstructorIfAny() != null) {
processedCallableNames += DataClassMembersGenerator(components).generateDataClassMembers(klass, irClass)
}
with(fakeOverrideGenerator) { irClass.addFakeOverrides(klass, processedCallableNames) }
fakeOverrideGenerator.bindOverriddenSymbols(irClass.declarations)
klass.declarations.forEach { declaration ->
when {
declaration is FirTypeAlias -> {
@@ -33,6 +33,9 @@ class FakeOverrideGenerator(
private val fakeOverrideMode: FakeOverrideMode
) {
private val baseFunctionSymbols = mutableMapOf<IrFunction, FirNamedFunctionSymbol>()
private val basePropertySymbols = mutableMapOf<IrProperty, FirPropertySymbol>()
private fun IrSimpleFunction.withFunction(f: IrSimpleFunction.() -> Unit): IrSimpleFunction {
return conversionScope.withFunction(this, f)
}
@@ -98,11 +101,9 @@ class FakeOverrideGenerator(
// In fake overrides, parent logic is a bit specific, because
// parent of *original* function (base class) is used for dispatch receiver,
// but fake override itself uses parent from its containing (derived) class
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
irFunction.parent = this
result += irFunction.withFunction {
overriddenSymbols = listOf(overriddenSymbol)
}
baseFunctionSymbols[irFunction] = baseSymbol
result += irFunction
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalFunction.allowsToHaveFakeOverrideIn(klass)) {
// Trivial fake override case
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction(
@@ -123,11 +124,9 @@ class FakeOverrideGenerator(
if (irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() }) {
return@processFunctionsByName
}
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
irFunction.parent = this
result += irFunction.withFunction {
overriddenSymbols = listOf(overriddenSymbol)
}
baseFunctionSymbols[irFunction] = baseSymbol
result += irFunction
}
}
}
@@ -149,10 +148,8 @@ class FakeOverrideGenerator(
isLocal = isLocal
)
irProperty.parent = this
result += irProperty.withProperty {
discardAccessorsAccordingToBaseVisibility(baseSymbol)
setOverriddenSymbolsForAccessors(declarationStorage, originalProperty, firOverriddenSymbol = baseSymbol)
}
basePropertySymbols[irProperty] = baseSymbol
result += irProperty
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) {
// Trivial fake override case
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideProperty(
@@ -175,10 +172,8 @@ class FakeOverrideGenerator(
return@processPropertiesByName
}
irProperty.parent = this
result += irProperty.withProperty {
discardAccessorsAccordingToBaseVisibility(baseSymbol)
setOverriddenSymbolsForAccessors(declarationStorage, fakeOverrideProperty, firOverriddenSymbol = baseSymbol)
}
basePropertySymbols[irProperty] = baseSymbol
result += irProperty
}
}
}
@@ -186,6 +181,28 @@ class FakeOverrideGenerator(
return result
}
fun bindOverriddenSymbols(declarations: List<IrDeclaration>) {
for (declaration in declarations) {
if (declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) continue
when (declaration) {
is IrSimpleFunction -> {
val baseSymbol = baseFunctionSymbols[declaration]!!
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
declaration.withFunction {
overriddenSymbols = listOf(overriddenSymbol)
}
}
is IrProperty -> {
val baseSymbol = basePropertySymbols[declaration]!!
declaration.withProperty {
discardAccessorsAccordingToBaseVisibility(baseSymbol)
setOverriddenSymbolsForAccessors(declarationStorage, declaration.isVar, firOverriddenSymbol = baseSymbol)
}
}
}
}
}
private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbol: FirPropertySymbol) {
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) {
@@ -199,7 +216,7 @@ class FakeOverrideGenerator(
private fun IrProperty.setOverriddenSymbolsForAccessors(
declarationStorage: Fir2IrDeclarationStorage,
property: FirProperty,
isVar: Boolean,
firOverriddenSymbol: FirPropertySymbol
): IrProperty {
val irSymbol = declarationStorage.getIrPropertyOrFieldSymbol(firOverriddenSymbol) as? IrPropertySymbol ?: return this
@@ -207,7 +224,7 @@ class FakeOverrideGenerator(
getter?.apply {
overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) }
}
if (property.isVar) {
if (isVar) {
setter?.apply {
overriddenProperty.setter?.symbol?.let { overriddenSymbols = listOf(it) }
}
@@ -164,7 +164,9 @@ class Fir2IrLazyClass(
}
}
with(fakeOverrideGenerator) {
result += getFakeOverrides(fir, processedNames)
val fakeOverrides = getFakeOverrides(fir, processedNames)
bindOverriddenSymbols(fakeOverrides)
result += fakeOverrides
}
// TODO: remove this check to save time
for (declaration in result) {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box() = Class().printSome()
public abstract class AbstractClass<T> {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// See also kt33054.kt