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>) {
symbolTable.enterScope(this)
val typeArguments = typeParameters.map {
@@ -129,9 +130,9 @@ class Fir2IrClassifierStorage(
}
private fun IrClass.declareTypeParameters(klass: FirClass) {
preCacheTypeParameters(klass, symbol)
setTypeParameters(klass)
if (klass is FirRegularClass) {
preCacheTypeParameters(klass, symbol)
setTypeParameters(klass)
val fieldsForContextReceiversOfCurrentClass = createContextReceiverFields(klass)
if (fieldsForContextReceiversOfCurrentClass.isNotEmpty()) {
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? {
return if (klass is FirAnonymousObject || klass is FirRegularClass && klass.visibility == Visibilities.Local) {
localStorage[klass]
@@ -242,14 +237,7 @@ class Fir2IrClassifierStorage(
}
}
}.last()
val result = when (classOrLocalParent) {
is FirAnonymousObject -> createIrAnonymousObject(classOrLocalParent, irParent = temporaryParent).apply {
converter.processAnonymousObjectOnTheFly(classOrLocalParent, this)
}
is FirRegularClass -> {
converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent)
}
}
val result = converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent)
// 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
// 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) {
when (klass) {
is FirRegularClass -> converter.processClassMembers(klass, irClass)
is FirRegularClass -> converter.processRegularClassMembers(klass, irClass)
is FirAnonymousObject -> converter.processAnonymousObjectMembers(klass, irClass, processHeaders = false)
}
}
fun processClassHeader(regularClass: FirRegularClass, irClass: IrClass = getCachedIrClass(regularClass)!!): IrClass {
irClass.declareTypeParameters(regularClass)
irClass.setThisReceiver(regularClass.typeParameters)
irClass.declareSupertypes(regularClass)
irClass.declareValueClassRepresentation(regularClass)
fun processClassHeader(klass: FirClass, irClass: IrClass = getCachedIrClass(klass)!!): IrClass {
irClass.declareTypeParameters(klass)
irClass.setThisReceiver(klass.typeParameters)
irClass.declareSupertypes(klass)
if (klass is FirRegularClass) {
irClass.declareValueClassRepresentation(klass)
}
return irClass
}
@@ -378,7 +368,7 @@ class Fir2IrClassifierStorage(
return irClass
}
fun createIrAnonymousObject(
fun registerIrAnonymousObject(
anonymousObject: FirAnonymousObject,
visibility: Visibility = Visibilities.Local,
name: Name = Name.special("<no name provided>"),
@@ -386,7 +376,7 @@ class Fir2IrClassifierStorage(
): IrClass {
val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL
val result = anonymousObject.convertWithOffsets { startOffset, endOffset ->
val irAnonymousObject = anonymousObject.convertWithOffsets { startOffset, endOffset ->
irFactory.createClass(
startOffset, endOffset, origin, IrClassSymbolImpl(), name,
// NB: for unknown reason, IR uses 'CLASS' kind for simple anonymous objects
@@ -394,19 +384,20 @@ class Fir2IrClassifierStorage(
components.visibilityConverter.convertToDescriptorVisibility(visibility), modality
).apply {
metadata = FirMetadataSource.Class(anonymousObject)
setThisReceiver(anonymousObject.typeParameters)
if (irParent != null) {
this.parent = irParent
}
}
}.declareSupertypesAndTypeParameters(anonymousObject)
localStorage[anonymousObject] = result
return result
}
if (irParent != null) {
irAnonymousObject.parent = irParent
}
localStorage[anonymousObject] = irAnonymousObject
return irAnonymousObject
}
private fun getIrAnonymousObjectForEnumEntry(anonymousObject: FirAnonymousObject, name: Name, irParent: IrClass?): IrClass {
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(
@@ -5,13 +5,11 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -118,21 +116,19 @@ class Fir2IrConverter(
}
}
fun processLocalClassAndNestedClassesOnTheFly(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
val irClass = registerClassAndNestedClasses(regularClass, parent)
processClassAndNestedClassHeaders(regularClass)
fun processLocalClassAndNestedClassesOnTheFly(klass: FirClass, parent: IrDeclarationParent): IrClass {
val irClass = registerClassAndNestedClasses(klass, parent)
processClassAndNestedClassHeaders(klass)
return irClass
}
fun processAnonymousObjectOnTheFly(anonymousObject: FirAnonymousObject, irClass: IrClass) {
registerNestedClasses(anonymousObject, irClass)
processNestedClassHeaders(anonymousObject)
}
fun processLocalClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
val irClass = registerClassAndNestedClasses(regularClass, parent)
processClassAndNestedClassHeaders(regularClass)
processClassMembers(regularClass, irClass)
fun processLocalClassAndNestedClasses(klass: FirClass, parent: IrDeclarationParent): IrClass {
val irClass = registerClassAndNestedClasses(klass, parent)
processClassAndNestedClassHeaders(klass)
when (klass) {
is FirRegularClass -> processRegularClassMembers(klass, irClass)
is FirAnonymousObject -> processAnonymousObjectMembers(klass, irClass, processHeaders = false)
}
bindFakeOverridesInClass(irClass)
return irClass
}
@@ -187,6 +183,7 @@ class Fir2IrConverter(
}
}
// TODO: unite with/extract common part from processRegularClassMembers
fun processAnonymousObjectMembers(
anonymousObject: FirAnonymousObject,
irClass: IrClass,
@@ -211,12 +208,11 @@ class Fir2IrConverter(
with(fakeOverrideGenerator) {
irClass.addFakeOverrides(anonymousObject, realDeclarations)
}
bindFakeOverridesInClass(irClass)
return irClass
}
internal fun processClassMembers(
internal fun processRegularClassMembers(
regularClass: FirRegularClass,
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
): IrClass {
@@ -298,14 +294,17 @@ class Fir2IrConverter(
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)
// So, we only need to set its parent properly
val irClass =
classifierStorage.getCachedIrClass(regularClass)?.apply {
classifierStorage.getCachedIrClass(klass)?.apply {
this.parent = parent
} ?: classifierStorage.registerIrClass(regularClass, parent)
registerNestedClasses(regularClass, irClass)
} ?: when (klass) {
is FirRegularClass -> classifierStorage.registerIrClass(klass, parent)
is FirAnonymousObject -> classifierStorage.registerIrAnonymousObject(klass, irParent = parent)
}
registerNestedClasses(klass, irClass)
return irClass
}
@@ -324,9 +323,9 @@ class Fir2IrConverter(
}
}
private fun processClassAndNestedClassHeaders(regularClass: FirRegularClass) {
classifierStorage.processClassHeader(regularClass)
processNestedClassHeaders(regularClass)
private fun processClassAndNestedClassHeaders(klass: FirClass) {
classifierStorage.processClassHeader(klass)
processNestedClassHeaders(klass)
}
private fun processNestedClassHeaders(klass: FirClass) {
@@ -353,7 +352,7 @@ class Fir2IrConverter(
(containingClass !is FirRegularClass || containingClass.isLocal)
return when (declaration) {
is FirRegularClass -> {
processClassMembers(declaration)
processRegularClassMembers(declaration)
}
is FirScript -> {
assert(parent is IrFile)
@@ -124,6 +124,7 @@ class Fir2IrVisitor(
classifierStorage.putEnumEntryClassInScope(enumEntry, correspondingClass)
val anonymousObject = (enumEntry.initializer as FirAnonymousObjectExpression).anonymousObject
converter.processAnonymousObjectMembers(anonymousObject, correspondingClass, processHeaders = true)
converter.bindFakeOverridesInClass(correspondingClass)
conversionScope.withParent(correspondingClass) {
conversionScope.withContainingFirClass(anonymousObject) {
memberGenerator.convertClassContent(correspondingClass, anonymousObject)
@@ -223,9 +224,8 @@ class Fir2IrVisitor(
val irParent = conversionScope.parentFromStack()
// NB: for implicit types it is possible that anonymous object is already cached
val irAnonymousObject = classifierStorage.getCachedIrClass(anonymousObject)?.apply { this.parent = irParent }
?: classifierStorage.createIrAnonymousObject(anonymousObject, irParent = irParent).also { irClass ->
converter.processAnonymousObjectMembers(anonymousObject, irClass, processHeaders = true)
}
?: converter.processLocalClassAndNestedClasses(anonymousObject, irParent)
conversionScope.withParent(irAnonymousObject) {
conversionScope.withContainingFirClass(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>()
}
}