From e1c2dc06f1c0f7ca887eede160dc80f902d03bf2 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 15 Mar 2023 12:13:40 +0100 Subject: [PATCH] FIR2IR: make handling of FirRegularClass & FirAnonymousObject more consistent #KT-57221 Fixed --- .../fir/backend/Fir2IrClassifierStorage.kt | 55 ++++++++----------- .../kotlin/fir/backend/Fir2IrConverter.kt | 47 ++++++++-------- .../kotlin/fir/backend/Fir2IrVisitor.kt | 6 +- ...nymousAsReturnOfGenericFunction.fir.ir.txt | 46 ++++++++++++++++ ...nymousAsReturnOfGenericFunction.fir.kt.txt | 22 ++++++++ 5 files changed, 117 insertions(+), 59 deletions(-) create mode 100644 compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.ir.txt create mode 100644 compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.kt.txt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index 9b1d6f70c9d..cd9396283fd 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -88,6 +88,7 @@ class Fir2IrClassifierStorage( } } + // Note: declareTypeParameters should be called before! private fun IrClass.setThisReceiver(typeParameters: List) { 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(""), @@ -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( diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index e6774e4eaef..060e6a87328 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -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) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 7aa415d1502..363fcf0aece 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -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) diff --git a/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.ir.txt b/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.ir.txt new file mode 100644 index 00000000000..02cd9b32628 --- /dev/null +++ b/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.ir.txt @@ -0,0 +1,46 @@ +FILE fqName: fileName:/AnonymousAsReturnOfGenericFunction.kt + CLASS INTERFACE name:NestedGroupFragment modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.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: 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: 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: type:kotlin.Any + FUN name:addMavenOptionsGroupFragment visibility:private modality:FINAL <> () returnType:.addOptionsGroup. + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun addMavenOptionsGroupFragment (): .addOptionsGroup. declared in ' + CALL 'private final fun addOptionsGroup (): .addOptionsGroup..addOptionsGroup> declared in ' type=.addOptionsGroup. origin=null + : kotlin.Int + FUN name:addOptionsGroup visibility:private modality:FINAL () returnType:.addOptionsGroup..addOptionsGroup> + TYPE_PARAMETER name:S index:0 variance: superTypes:[kotlin.Any?] reified:false + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun addOptionsGroup (): .addOptionsGroup..addOptionsGroup> declared in ' + BLOCK type=.addOptionsGroup..addOptionsGroup> origin=OBJECT_LITERAL + CLASS CLASS name: modality:FINAL visibility:local superTypes:[.NestedGroupFragment] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.addOptionsGroup..addOptionsGroup> + CONSTRUCTOR visibility:private <> () returnType:.addOptionsGroup..addOptionsGroup> [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name: modality:FINAL visibility:local superTypes:[.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 .NestedGroupFragment + $this: VALUE_PARAMETER name: 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 .NestedGroupFragment + $this: VALUE_PARAMETER name: 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 .NestedGroupFragment + $this: VALUE_PARAMETER name: type:kotlin.Any + CONSTRUCTOR_CALL 'private constructor () [primary] declared in .addOptionsGroup.' type=.addOptionsGroup..addOptionsGroup> origin=OBJECT_LITERAL diff --git a/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.kt.txt b/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.kt.txt new file mode 100644 index 00000000000..30b3a835ef8 --- /dev/null +++ b/compiler/testData/ir/irText/firProblems/AnonymousAsReturnOfGenericFunction.fir.kt.txt @@ -0,0 +1,22 @@ +interface NestedGroupFragment { + +} + +private fun addMavenOptionsGroupFragment(): { + return addOptionsGroup() +} + +private fun addOptionsGroup(): { + return { // BLOCK + local class : NestedGroupFragment { + private constructor() /* primary */ { + super/*Any*/() + /* () */ + + } + + } + + () + } +}