FIR2IR: make handling of FirRegularClass & FirAnonymousObject more consistent

#KT-57221 Fixed
This commit is contained in:
Mikhail Glukhikh
2023-03-15 12:13:40 +01:00
committed by Space Team
parent 51cd1b2d6f
commit e1c2dc06f1
5 changed files with 117 additions and 59 deletions
@@ -88,6 +88,7 @@ class Fir2IrClassifierStorage(
} }
} }
// Note: declareTypeParameters should be called before!
private fun IrClass.setThisReceiver(typeParameters: List<FirTypeParameterRef>) { private fun IrClass.setThisReceiver(typeParameters: List<FirTypeParameterRef>) {
symbolTable.enterScope(this) symbolTable.enterScope(this)
val typeArguments = typeParameters.map { val typeArguments = typeParameters.map {
@@ -129,9 +130,9 @@ class Fir2IrClassifierStorage(
} }
private fun IrClass.declareTypeParameters(klass: FirClass) { private fun IrClass.declareTypeParameters(klass: FirClass) {
preCacheTypeParameters(klass, symbol)
setTypeParameters(klass)
if (klass is FirRegularClass) { if (klass is FirRegularClass) {
preCacheTypeParameters(klass, symbol)
setTypeParameters(klass)
val fieldsForContextReceiversOfCurrentClass = createContextReceiverFields(klass) val fieldsForContextReceiversOfCurrentClass = createContextReceiverFields(klass)
if (fieldsForContextReceiversOfCurrentClass.isNotEmpty()) { if (fieldsForContextReceiversOfCurrentClass.isNotEmpty()) {
declarations.addAll(fieldsForContextReceiversOfCurrentClass) declarations.addAll(fieldsForContextReceiversOfCurrentClass)
@@ -175,12 +176,6 @@ class Fir2IrClassifierStorage(
} }
} }
private fun IrClass.declareSupertypesAndTypeParameters(klass: FirClass): IrClass {
declareTypeParameters(klass)
declareSupertypes(klass)
return this
}
fun getCachedIrClass(klass: FirClass): IrClass? { fun getCachedIrClass(klass: FirClass): IrClass? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) { return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) {
localStorage[klass] localStorage[klass]
@@ -242,14 +237,7 @@ class Fir2IrClassifierStorage(
} }
} }
}.last() }.last()
val result = when (classOrLocalParent) { val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent)
is FirAnonymousObject -> createIrAnonymousObject(classOrLocalParent, irParent = temporaryParent).apply {
converter.processAnonymousObjectOnTheFly(classOrLocalParent, this)
}
is FirRegularClass -> {
converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent)
}
}
// Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter // Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter
// If non-local classes are already created (this means we are in body translation) we do everything immediately // If non-local classes are already created (this means we are in body translation) we do everything immediately
// The last variant is possible for local variables like 'val a = object : Any() { ... }' // The last variant is possible for local variables like 'val a = object : Any() { ... }'
@@ -279,16 +267,18 @@ class Fir2IrClassifierStorage(
private fun processMembersOfClassCreatedOnTheFly(klass: FirClass, irClass: IrClass) { private fun processMembersOfClassCreatedOnTheFly(klass: FirClass, irClass: IrClass) {
when (klass) { when (klass) {
is FirRegularClass -> converter.processClassMembers(klass, irClass) is FirRegularClass -> converter.processRegularClassMembers(klass, irClass)
is FirAnonymousObject -> converter.processAnonymousObjectMembers(klass, irClass, processHeaders = false) is FirAnonymousObject -> converter.processAnonymousObjectMembers(klass, irClass, processHeaders = false)
} }
} }
fun processClassHeader(regularClass: FirRegularClass, irClass: IrClass = getCachedIrClass(regularClass)!!): IrClass { fun processClassHeader(klass: FirClass, irClass: IrClass = getCachedIrClass(klass)!!): IrClass {
irClass.declareTypeParameters(regularClass) irClass.declareTypeParameters(klass)
irClass.setThisReceiver(regularClass.typeParameters) irClass.setThisReceiver(klass.typeParameters)
irClass.declareSupertypes(regularClass) irClass.declareSupertypes(klass)
irClass.declareValueClassRepresentation(regularClass) if (klass is FirRegularClass) {
irClass.declareValueClassRepresentation(klass)
}
return irClass return irClass
} }
@@ -378,7 +368,7 @@ class Fir2IrClassifierStorage(
return irClass return irClass
} }
fun createIrAnonymousObject( fun registerIrAnonymousObject(
anonymousObject: FirAnonymousObject, anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.Local, visibility: Visibility = Visibilities.Local,
name: Name = Name.special("<no name provided>"), name: Name = Name.special("<no name provided>"),
@@ -386,7 +376,7 @@ class Fir2IrClassifierStorage(
): IrClass { ): IrClass {
val origin = IrDeclarationOrigin.DEFINED val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL val modality = Modality.FINAL
val result = anonymousObject.convertWithOffsets { startOffset, endOffset -> val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset ->
irFactory.createClass( irFactory.createClass(
startOffset, endOffset, origin, IrClassSymbolImpl(), name, startOffset, endOffset, origin, IrClassSymbolImpl(), name,
// NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects // NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects
@@ -394,19 +384,20 @@ class Fir2IrClassifierStorage(
components.visibilityConverter.convertToDescriptorVisibility(visibility), modality components.visibilityConverter.convertToDescriptorVisibility(visibility), modality
).apply { ).apply {
metadata = FirMetadataSource.Class(anonymousObject) metadata = FirMetadataSource.Class(anonymousObject)
setThisReceiver(anonymousObject.typeParameters)
if (irParent != null) {
this.parent = irParent
}
} }
}.declareSupertypesAndTypeParameters(anonymousObject) }
localStorage[anonymousObject] = result if (irParent != null) {
return result irAnonymousObject.parent = irParent
}
localStorage[anonymousObject] = irAnonymousObject
return irAnonymousObject
} }
private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass { private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
localStorage[anonymousObject]?.let { return it } localStorage[anonymousObject]?.let { return it }
return createIrAnonymousObject(anonymousObject, Visibilities.Private, name, irParent) val irAnonymousObject = registerIrAnonymousObject(anonymousObject, Visibilities.Private, name, irParent)
processClassHeader(anonymousObject, irAnonymousObject)
return irAnonymousObject
} }
private fun createIrTypeParameterWithoutBounds( private fun createIrTypeParameterWithoutBounds(
@@ -5,13 +5,11 @@
package org.jetbrains.kotlin.fir.backend package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -118,21 +116,19 @@ class Fir2IrConverter(
} }
} }
fun processLocalClassAndNestedClassesOnTheFly(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass { fun processLocalClassAndNestedClassesOnTheFly(klass: FirClass, parent: IrDeclarationParent): IrClass {
val irClass = registerClassAndNestedClasses(regularClass, parent) val irClass = registerClassAndNestedClasses(klass, parent)
processClassAndNestedClassHeaders(regularClass) processClassAndNestedClassHeaders(klass)
return irClass return irClass
} }
fun processAnonymousObjectOnTheFly(anonymousObject: FirAnonymousObject, irClass: IrClass) { fun processLocalClassAndNestedClasses(klass: FirClass, parent: IrDeclarationParent): IrClass {
registerNestedClasses(anonymousObject, irClass) val irClass = registerClassAndNestedClasses(klass, parent)
processNestedClassHeaders(anonymousObject) processClassAndNestedClassHeaders(klass)
} when (klass) {
is FirRegularClass -> processRegularClassMembers(klass, irClass)
fun processLocalClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass { is FirAnonymousObject -> processAnonymousObjectMembers(klass, irClass, processHeaders = false)
val irClass = registerClassAndNestedClasses(regularClass, parent) }
processClassAndNestedClassHeaders(regularClass)
processClassMembers(regularClass, irClass)
bindFakeOverridesInClass(irClass) bindFakeOverridesInClass(irClass)
return irClass return irClass
} }
@@ -187,6 +183,7 @@ class Fir2IrConverter(
} }
} }
// TODO: unite with/extract common part from processRegularClassMembers
fun processAnonymousObjectMembers( fun processAnonymousObjectMembers(
anonymousObject: FirAnonymousObject, anonymousObject: FirAnonymousObject,
irClass: IrClass, irClass: IrClass,
@@ -211,12 +208,11 @@ class Fir2IrConverter(
with(fakeOverrideGenerator) { with(fakeOverrideGenerator) {
irClass.addFakeOverrides(anonymousObject, realDeclarations) irClass.addFakeOverrides(anonymousObject, realDeclarations)
} }
bindFakeOverridesInClass(irClass)
return irClass return irClass
} }
internal fun processClassMembers( internal fun processRegularClassMembers(
regularClass: FirRegularClass, regularClass: FirRegularClass,
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!! irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
): IrClass { ): IrClass {
@@ -298,14 +294,17 @@ class Fir2IrConverter(
return declarations.sortedBy { it !is FirField && it.isSynthetic } return declarations.sortedBy { it !is FirField && it.isSynthetic }
} }
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass { private fun registerClassAndNestedClasses(klass: FirClass, parent: IrDeclarationParent): IrClass {
// Local classes might be referenced before they declared (see usages of Fir2IrClassifierStorage.createLocalIrClassOnTheFly) // Local classes might be referenced before they declared (see usages of Fir2IrClassifierStorage.createLocalIrClassOnTheFly)
// So, we only need to set its parent properly // So, we only need to set its parent properly
val irClass = val irClass =
classifierStorage.getCachedIrClass(regularClass)?.apply { classifierStorage.getCachedIrClass(klass)?.apply {
this.parent = parent this.parent = parent
} ?: classifierStorage.registerIrClass(regularClass, parent) } ?: when (klass) {
registerNestedClasses(regularClass, irClass) is FirRegularClass -> classifierStorage.registerIrClass(klass, parent)
is FirAnonymousObject -> classifierStorage.registerIrAnonymousObject(klass, irParent = parent)
}
registerNestedClasses(klass, irClass)
return irClass return irClass
} }
@@ -324,9 +323,9 @@ class Fir2IrConverter(
} }
} }
private fun processClassAndNestedClassHeaders(regularClass: FirRegularClass) { private fun processClassAndNestedClassHeaders(klass: FirClass) {
classifierStorage.processClassHeader(regularClass) classifierStorage.processClassHeader(klass)
processNestedClassHeaders(regularClass) processNestedClassHeaders(klass)
} }
private fun processNestedClassHeaders(klass: FirClass) { private fun processNestedClassHeaders(klass: FirClass) {
@@ -353,7 +352,7 @@ class Fir2IrConverter(
(containingClass !is FirRegularClass || containingClass.isLocal) (containingClass !is FirRegularClass || containingClass.isLocal)
return when (declaration) { return when (declaration) {
is FirRegularClass -> { is FirRegularClass -> {
processClassMembers(declaration) processRegularClassMembers(declaration)
} }
is FirScript -> { is FirScript -> {
assert(parent is IrFile) assert(parent is IrFile)
@@ -124,6 +124,7 @@ class Fir2IrVisitor(
classifierStorage.putEnumEntryClassInScope(enumEntry, correspondingClass) classifierStorage.putEnumEntryClassInScope(enumEntry, correspondingClass)
val anonymousObject = (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject val anonymousObject = (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject
converter.processAnonymousObjectMembers(anonymousObject, correspondingClass, processHeaders = true) converter.processAnonymousObjectMembers(anonymousObject, correspondingClass, processHeaders = true)
converter.bindFakeOverridesInClass(correspondingClass)
conversionScope.withParent(correspondingClass) { conversionScope.withParent(correspondingClass) {
conversionScope.withContainingFirClass(anonymousObject) { conversionScope.withContainingFirClass(anonymousObject) {
memberGenerator.convertClassContent(correspondingClass, anonymousObject) memberGenerator.convertClassContent(correspondingClass, anonymousObject)
@@ -223,9 +224,8 @@ class Fir2IrVisitor(
val irParent = conversionScope.parentFromStack() val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that anonymous object is already cached // NB: for implicit types it is possible that anonymous object is already cached
val irAnonymousObject = classifierStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent } val irAnonymousObject = classifierStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent }
?: classifierStorage.createIrAnonymousObject(anonymousObject, irParent = irParent).also { irClass -> ?: converter.processLocalClassAndNestedClasses(anonymousObject, irParent)
converter.processAnonymousObjectMembers(anonymousObject, irClass, processHeaders = true)
}
conversionScope.withParent(irAnonymousObject) { conversionScope.withParent(irAnonymousObject) {
conversionScope.withContainingFirClass(anonymousObject) { conversionScope.withContainingFirClass(anonymousObject) {
memberGenerator.convertClassContent(irAnonymousObject, anonymousObject) memberGenerator.convertClassContent(irAnonymousObject, anonymousObject)
@@ -0,0 +1,46 @@
FILE fqName:<root> fileName:/AnonymousAsReturnOfGenericFunction.kt
CLASS INTERFACE name:NestedGroupFragment modality:ABSTRACT visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.NestedGroupFragment
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:addMavenOptionsGroupFragment visibility:private modality:FINAL <> () returnType:<root>.addOptionsGroup.<no name provided><kotlin.Int>
BLOCK_BODY
RETURN type=kotlin.Nothing from='private final fun addMavenOptionsGroupFragment (): <root>.addOptionsGroup.<no name provided><kotlin.Int> declared in <root>'
CALL 'private final fun addOptionsGroup <S> (): <root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup> declared in <root>' type=<root>.addOptionsGroup.<no name provided><kotlin.Int> origin=null
<S>: kotlin.Int
FUN name:addOptionsGroup visibility:private modality:FINAL <S> () returnType:<root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup>
TYPE_PARAMETER name:S index:0 variance: superTypes:[kotlin.Any?] reified:false
BLOCK_BODY
RETURN type=kotlin.Nothing from='private final fun addOptionsGroup <S> (): <root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup> declared in <root>'
BLOCK type=<root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup> origin=OBJECT_LITERAL
CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.NestedGroupFragment]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup>
CONSTRUCTOR visibility:private <> () returnType:<root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup> [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:<no name provided> modality:FINAL visibility:local superTypes:[<root>.NestedGroupFragment]'
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.NestedGroupFragment
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.NestedGroupFragment
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String [fake_override] declared in <root>.NestedGroupFragment
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
CONSTRUCTOR_CALL 'private constructor <init> () [primary] declared in <root>.addOptionsGroup.<no name provided>' type=<root>.addOptionsGroup.<no name provided><S of <root>.addOptionsGroup> origin=OBJECT_LITERAL
@@ -0,0 +1,22 @@
interface NestedGroupFragment {
}
private fun addMavenOptionsGroupFragment(): <no name provided><Int> {
return addOptionsGroup<Int>()
}
private fun <S : Any?> addOptionsGroup(): <no name provided><S> {
return { // BLOCK
local class <no name provided> : NestedGroupFragment {
private constructor() /* primary */ {
super/*Any*/()
/* <init>() */
}
}
<no name provided>()
}
}