From 384134a0693ecdf1d867f18eca3b2c300fe99b4c Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 28 Oct 2019 16:10:42 +0300 Subject: [PATCH] FIR2IR: fix handling constructors & their symbols (related also to local classes) --- .../fir/backend/Fir2IrDeclarationStorage.kt | 34 +++++++------- .../kotlin/fir/backend/Fir2IrVisitor.kt | 45 +++++++++---------- .../ir/irText/classes/localClasses.fir.txt | 14 ------ .../ir/irText/classes/localClasses.kt | 1 + 4 files changed, 42 insertions(+), 52 deletions(-) delete mode 100644 compiler/testData/ir/irText/classes/localClasses.fir.txt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 004ea58400a..0a589c4c857 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -423,22 +423,26 @@ class Fir2IrDeclarationStorage( irParent: IrDeclarationParent? = null, shouldLeaveScope: Boolean = false ): IrConstructor { - return constructorCache.getOrPut(constructor) { - val descriptor = WrappedClassConstructorDescriptor() - val origin = IrDeclarationOrigin.DEFINED - val isPrimary = constructor.isPrimary - return constructor.convertWithOffsets { startOffset, endOffset -> - irSymbolTable.declareConstructor(startOffset, endOffset, origin, descriptor) { symbol -> - IrConstructorImpl( - startOffset, endOffset, origin, symbol, - constructor.name, constructor.visibility, - constructor.returnTypeRef.toIrType(session, this), - isInline = false, isExternal = false, isPrimary = isPrimary, isExpect = false - ).bindAndDeclareParameters(constructor, descriptor, irParent, isStatic = true, shouldLeaveScope = shouldLeaveScope) - } - } - + val cached = constructorCache[constructor] + if (cached != null) { + return if (shouldLeaveScope) cached else cached.enterLocalScope(constructor) } + + val descriptor = WrappedClassConstructorDescriptor() + val origin = IrDeclarationOrigin.DEFINED + val isPrimary = constructor.isPrimary + val created = constructor.convertWithOffsets { startOffset, endOffset -> + irSymbolTable.declareConstructor(startOffset, endOffset, origin, descriptor) { symbol -> + IrConstructorImpl( + startOffset, endOffset, origin, symbol, + constructor.name, constructor.visibility, + constructor.returnTypeRef.toIrType(session, this), + isInline = false, isExternal = false, isPrimary = isPrimary, isExpect = false + ).bindAndDeclareParameters(constructor, descriptor, irParent, isStatic = true, shouldLeaveScope = shouldLeaveScope) + } + } + constructorCache[constructor] = created + return created } private fun createIrPropertyAccessor( 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 8a6c919eebc..c7840b59403 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 @@ -360,31 +360,17 @@ class Fir2IrVisitor( overriddenSymbols += overriddenSymbol } } - body = firFunction?.body?.convertToIrBlockBody() - if (this !is IrConstructor) { - // Scope for primary constructor should be left after class declaration - // Scope for secondary constructor should be left after delegating call - declarationStorage.leaveScope(descriptor) - } - } - return this - } - - override fun visitConstructor(constructor: FirConstructor, data: Any?): IrElement { - val irConstructor = declarationStorage.getIrConstructor( - constructor, irParent = parentStack.last() as? IrClass - ) - return irConstructor.setParentByParentStack().withFunction { - setFunctionContent(irConstructor.descriptor, constructor) - }.withParent { - if (!parentAsClass.isAnnotationClass) { - val body = this.body as IrBlockBody? ?: IrBlockBodyImpl(startOffset, endOffset) - val delegatedConstructor = constructor.delegatedConstructor + var body = firFunction?.body?.convertToIrBlockBody() + if (firFunction is FirConstructor && this is IrConstructor && !parentAsClass.isAnnotationClass) { + if (body == null) { + body = IrBlockBodyImpl(startOffset, endOffset) + } + val delegatedConstructor = firFunction.delegatedConstructor if (delegatedConstructor != null) { val irDelegatingConstructorCall = delegatedConstructor.toIrDelegatingConstructorCall() body.statements += irDelegatingConstructorCall ?: delegatedConstructor.convertWithOffsets { startOffset, endOffset -> IrErrorCallExpressionImpl( - startOffset, endOffset, irConstructor.returnType, "Cannot find delegated constructor call" + startOffset, endOffset, returnType, "Cannot find delegated constructor call" ) } } @@ -397,11 +383,24 @@ class Fir2IrVisitor( if (body.statements.isNotEmpty()) { this.body = body } + } else if (this !is IrConstructor) { + this.body = body } - if (!constructor.isPrimary) { - declarationStorage.leaveScope(irConstructor.descriptor) + if (this !is IrConstructor || !this.isPrimary) { + // Scope for primary constructor should be left after class declaration + declarationStorage.leaveScope(descriptor) } } + return this + } + + override fun visitConstructor(constructor: FirConstructor, data: Any?): IrElement { + val irConstructor = declarationStorage.getIrConstructor( + constructor, irParent = parentStack.last() as? IrClass + ) + return irConstructor.setParentByParentStack().withFunction { + setFunctionContent(irConstructor.descriptor, constructor) + } } override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Any?): IrElement { diff --git a/compiler/testData/ir/irText/classes/localClasses.fir.txt b/compiler/testData/ir/irText/classes/localClasses.fir.txt deleted file mode 100644 index 2e48e7c1fe3..00000000000 --- a/compiler/testData/ir/irText/classes/localClasses.fir.txt +++ /dev/null @@ -1,14 +0,0 @@ -FILE fqName: fileName:/localClasses.kt - FUN name:outer visibility:public modality:FINAL <> () returnType:kotlin.Unit - BLOCK_BODY - CLASS CLASS name:LocalClass modality:FINAL visibility:local superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.outer.LocalClass - CONSTRUCTOR visibility:public <> () returnType:IrErrorType [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:LocalClass modality:FINAL visibility:local superTypes:[kotlin.Any]' - FUN name:foo visibility:public modality:FINAL <> ($this:.outer.LocalClass) returnType:kotlin.Unit - $this: VALUE_PARAMETER name: type:.outer.LocalClass - BLOCK_BODY - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - diff --git a/compiler/testData/ir/irText/classes/localClasses.kt b/compiler/testData/ir/irText/classes/localClasses.kt index 88a307cb76a..5fe0b5e7793 100644 --- a/compiler/testData/ir/irText/classes/localClasses.kt +++ b/compiler/testData/ir/irText/classes/localClasses.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun outer() { class LocalClass { fun foo() {}