From 5357e7b3abc8d866ce457c2d2b0645f63a772a58 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 16 Mar 2020 13:35:56 +0300 Subject: [PATCH] [FIR2IR] Extract ClassMemberGenerator from the main visitor --- .../kotlin/fir/backend/Fir2IrVisitor.kt | 351 +++--------------- .../generators/ClassMemberGenerator.kt | 289 ++++++++++++++ 2 files changed, 345 insertions(+), 295 deletions(-) create mode 100644 compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt 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 b90fc26ce59..3010ef473de 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 @@ -7,10 +7,8 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.fir.* -import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator +import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter -import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression @@ -33,14 +31,12 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import java.util.* @@ -59,7 +55,7 @@ class Fir2IrVisitor( private val conversionScope = Fir2IrConversionScope() - private val fakeOverrideGenerator = FakeOverrideGenerator(session, declarationStorage, conversionScope, fakeOverrideMode) + private val memberGenerator = ClassMemberGenerator(components, this, conversionScope, fakeOverrideMode) private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() } @@ -97,7 +93,7 @@ class Fir2IrVisitor( classifierStorage.putEnumEntryClassInScope(enumEntry, correspondingClass) converter.processAnonymousObjectMembers(enumEntry.initializer as FirAnonymousObject, correspondingClass) conversionScope.withParent(correspondingClass) { - setClassContent(enumEntry.initializer as FirAnonymousObject) + memberGenerator.convertClassContent(correspondingClass, enumEntry.initializer as FirAnonymousObject) irEnumEntry.initializerExpression = IrExpressionBodyImpl( IrEnumConstructorCallImpl( startOffset, endOffset, enumEntry.returnTypeRef.toIrType(), @@ -109,40 +105,6 @@ class Fir2IrVisitor( return irEnumEntry } - private fun IrClass.setClassContent(klass: FirClass<*>) { - declarationStorage.enterScope(descriptor) - conversionScope.withClass(this) { - val primaryConstructor = klass.getPrimaryConstructorIfAny() - val irPrimaryConstructor = primaryConstructor?.let { declarationStorage.getCachedIrConstructor(it)!! } - if (irPrimaryConstructor != null) { - with(declarationStorage) { - enterScope(irPrimaryConstructor.descriptor) - irPrimaryConstructor.valueParameters.forEach { symbolTable.introduceValueParameter(it) } - irPrimaryConstructor.putParametersInScope(primaryConstructor) - irPrimaryConstructor.setFunctionContent(irPrimaryConstructor.descriptor, primaryConstructor) - } - } - val processedCallableNames = mutableListOf() - klass.declarations.forEach { - if (it !is FirConstructor || !it.isPrimary) { - it.toIrDeclaration() ?: return@forEach - when (it) { - is FirSimpleFunction -> processedCallableNames += it.name - is FirProperty -> processedCallableNames += it.name - } - } - } - with(fakeOverrideGenerator) { addFakeOverrides(klass, processedCallableNames) } - annotations = klass.annotations.mapNotNull { - it.accept(this@Fir2IrVisitor, null) as? IrConstructorCall - } - if (irPrimaryConstructor != null) { - declarationStorage.leaveScope(irPrimaryConstructor.descriptor) - } - } - declarationStorage.leaveScope(descriptor) - } - override fun visitRegularClass(regularClass: FirRegularClass, data: Any?): IrElement { if (regularClass.visibility == Visibilities.LOCAL) { val irParent = conversionScope.parentFromStack() @@ -151,14 +113,14 @@ class Fir2IrVisitor( if (irClass != null) { converter.processRegisteredLocalClassAndNestedClasses(regularClass, irClass) return conversionScope.withParent(irClass) { - setClassContent(regularClass) + memberGenerator.convertClassContent(irClass, regularClass) } } converter.processLocalClassAndNestedClasses(regularClass, irParent) } val irClass = classifierStorage.getCachedIrClass(regularClass)!! return conversionScope.withParent(irClass) { - setClassContent(regularClass) + memberGenerator.convertClassContent(irClass, regularClass) } } @@ -169,7 +131,7 @@ class Fir2IrVisitor( ?: classifierStorage.createIrAnonymousObject(anonymousObject, irParent = irParent) converter.processAnonymousObjectMembers(anonymousObject, irAnonymousObject) conversionScope.withParent(irAnonymousObject) { - setClassContent(anonymousObject) + memberGenerator.convertClassContent(irAnonymousObject, anonymousObject) } val anonymousClassType = irAnonymousObject.thisReceiver!!.type return anonymousObject.convertWithOffsets { startOffset, endOffset -> @@ -192,103 +154,21 @@ class Fir2IrVisitor( // ================================================================================== - private fun T.setFunctionContent(descriptor: FunctionDescriptor, firFunction: FirFunction<*>?): T { - conversionScope.withParent(this) { - if (firFunction != null) { - if (this !is IrConstructor || !this.isPrimary) { - // Scope for primary constructor should be entered before class declaration processing - with(declarationStorage) { - enterScope(descriptor) - valueParameters.forEach { symbolTable.introduceValueParameter(it) } - putParametersInScope(firFunction) - } - } - for ((valueParameter, firValueParameter) in valueParameters.zip(firFunction.valueParameters)) { - valueParameter.setDefaultValue(firValueParameter) - } - } - 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, returnType, "Cannot find delegated constructor call" - ) - } - } - if (delegatedConstructor?.isThis == false) { - val irClass = parent as IrClass - body.statements += IrInstanceInitializerCallImpl( - startOffset, endOffset, irClass.symbol, constructedClassType - ) - } - if (body.statements.isNotEmpty()) { - this.body = body - } - } else if (this !is IrConstructor) { - this.body = body - } - 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.getCachedIrConstructor(constructor)!! return conversionScope.withFunction(irConstructor) { - setFunctionContent(irConstructor.descriptor, constructor) + memberGenerator.convertFunctionContent(irConstructor, constructor) } } override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Any?): IrElement { val irAnonymousInitializer = declarationStorage.getCachedIrAnonymousInitializer(anonymousInitializer)!! declarationStorage.enterScope(irAnonymousInitializer.descriptor) - irAnonymousInitializer.body = anonymousInitializer.body!!.convertToIrBlockBody() + irAnonymousInitializer.body = convertToIrBlockBody(anonymousInitializer.body!!) declarationStorage.leaveScope(irAnonymousInitializer.descriptor) return irAnonymousInitializer } - private fun FirDelegatedConstructorCall.toIrDelegatingConstructorCall(): IrCallWithIndexedArgumentsBase? { - val constructedIrType = constructedTypeRef.toIrType() - val constructorSymbol = (this.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol - ?: return null - return convertWithOffsets { startOffset, endOffset -> - val irConstructorSymbol = declarationStorage.getIrFunctionSymbol(constructorSymbol) as IrConstructorSymbol - if (constructorSymbol.fir.isFromEnumClass || constructorSymbol.fir.returnTypeRef.isEnum) { - IrEnumConstructorCallImpl( - startOffset, endOffset, - constructedIrType, - irConstructorSymbol - ).apply { - val typeArguments = (constructedTypeRef as? FirResolvedTypeRef)?.type?.typeArguments - if (typeArguments?.isNotEmpty() == true) { - val irType = (typeArguments.first() as ConeKotlinTypeProjection).type.toIrType() - putTypeArgument(0, irType) - } - } - } else { - IrDelegatingConstructorCallImpl( - startOffset, endOffset, - constructedIrType, - irConstructorSymbol - ) - }.apply { - for ((index, argument) in arguments.withIndex()) { - val argumentExpression = argument.toIrExpression() - putValueArgument(index, argumentExpression) - } - } - } - } - override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement { val irFunction = if (simpleFunction.visibility == Visibilities.LOCAL) { val irParent = conversionScope.parent() @@ -297,7 +177,7 @@ class Fir2IrVisitor( declarationStorage.getCachedIrFunction(simpleFunction)!! } return conversionScope.withFunction(irFunction) { - setFunctionContent(irFunction.descriptor, simpleFunction) + memberGenerator.convertFunctionContent(irFunction, simpleFunction) } } @@ -305,7 +185,7 @@ class Fir2IrVisitor( return anonymousFunction.convertWithOffsets { startOffset, endOffset -> val irFunction = declarationStorage.createIrFunction(anonymousFunction, conversionScope.parent()) conversionScope.withFunction(irFunction) { - setFunctionContent(irFunction.descriptor, anonymousFunction) + memberGenerator.convertFunctionContent(irFunction, anonymousFunction) } val type = anonymousFunction.typeRef.toIrType() @@ -314,13 +194,6 @@ class Fir2IrVisitor( } } - private fun IrValueParameter.setDefaultValue(firValueParameter: FirValueParameter) { - val firDefaultValue = firValueParameter.defaultValue - if (firDefaultValue != null) { - this.defaultValue = IrExpressionBodyImpl(firDefaultValue.toIrExpression()) - } - } - private fun visitLocalVariable(variable: FirProperty): IrElement { assert(variable.isLocal) val initializer = variable.initializer @@ -331,135 +204,20 @@ class Fir2IrVisitor( variable, conversionScope.parentFromStack(), if (isNextVariable) IrDeclarationOrigin.FOR_LOOP_VARIABLE else null ) if (initializer != null) { - irVariable.initializer = initializer.toIrExpression() + irVariable.initializer = convertToIrExpression(initializer) } return irVariable } - private fun IrProperty.createBackingField( - property: FirProperty, - origin: IrDeclarationOrigin, - descriptor: PropertyDescriptor, - visibility: Visibility, - name: Name, - isFinal: Boolean, - firInitializerExpression: FirExpression?, - type: IrType? = null - ): IrField { - val inferredType = type ?: firInitializerExpression!!.typeRef.toIrType() - val irField = symbolTable.declareField( - startOffset, endOffset, origin, descriptor, inferredType - ) { symbol -> - IrFieldImpl( - startOffset, endOffset, origin, symbol, - name, inferredType, - visibility, isFinal = isFinal, isExternal = false, - isStatic = property.isStatic || parent !is IrClass, - isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE - ) - } - return conversionScope.withParent(applyParentFromStackTo(irField)) { - declarationStorage.enterScope(descriptor) - val initializerExpression = firInitializerExpression?.toIrExpression() - initializer = initializerExpression?.let { IrExpressionBodyImpl(it) } - correspondingPropertySymbol = this@createBackingField.symbol - declarationStorage.leaveScope(descriptor) - } - } - - private fun IrProperty.setPropertyContent(descriptor: PropertyDescriptor, property: FirProperty): IrProperty { - val initializer = property.initializer - val delegate = property.delegate - val irParent = this.parent - val propertyType = property.returnTypeRef.toIrType() - // TODO: this checks are very preliminary, FIR resolve should determine backing field presence itself - // TODO (2): backing field should be created inside declaration storage - if (property.modality != Modality.ABSTRACT && (irParent !is IrClass || !irParent.isInterface)) { - if (initializer != null || property.getter is FirDefaultPropertyGetter || - property.isVar && property.setter is FirDefaultPropertySetter - ) { - backingField = createBackingField( - property, IrDeclarationOrigin.PROPERTY_BACKING_FIELD, descriptor, - Visibilities.PRIVATE, property.name, property.isVal, initializer, propertyType - ) - } else if (delegate != null) { - backingField = createBackingField( - property, IrDeclarationOrigin.PROPERTY_DELEGATE, descriptor, - Visibilities.PRIVATE, Name.identifier("${property.name}\$delegate"), true, delegate - ) - } - } - getter?.setPropertyAccessorContent( - property.getter, this, propertyType, property.getter is FirDefaultPropertyGetter - ) - if (property.isVar) { - setter?.setPropertyAccessorContent( - property.setter, this, propertyType, property.setter is FirDefaultPropertySetter - ) - } - annotations = property.annotations.mapNotNull { - it.accept(this@Fir2IrVisitor, null) as? IrConstructorCall - } - return this - } - override fun visitProperty(property: FirProperty, data: Any?): IrElement { if (property.isLocal) return visitLocalVariable(property) val irProperty = declarationStorage.getCachedIrProperty(property)!! return conversionScope.withProperty(irProperty) { - setPropertyContent(irProperty.descriptor, property) - } - } - - private fun IrFieldAccessExpression.setReceiver(declaration: IrDeclaration): IrFieldAccessExpression { - if (declaration is IrFunction) { - val dispatchReceiver = declaration.dispatchReceiverParameter - if (dispatchReceiver != null) { - receiver = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.symbol) - } - } - return this - } - - private fun IrFunction.setPropertyAccessorContent( - propertyAccessor: FirPropertyAccessor?, - correspondingProperty: IrProperty, - propertyType: IrType, - isDefault: Boolean - ) { - conversionScope.withFunction(this) { - applyParentFromStackTo(this) - setFunctionContent(descriptor, propertyAccessor) - if (isDefault) { - conversionScope.withParent(this) { - declarationStorage.enterScope(descriptor) - val backingField = correspondingProperty.backingField - val fieldSymbol = symbolTable.referenceField(correspondingProperty.descriptor) - val declaration = this - if (backingField != null) { - body = IrBlockBodyImpl( - startOffset, endOffset, - listOf( - if (isSetter) { - IrSetFieldImpl(startOffset, endOffset, fieldSymbol, typeConverter.unitType).apply { - setReceiver(declaration) - value = IrGetValueImpl(startOffset, endOffset, propertyType, valueParameters.first().symbol) - } - } else { - IrReturnImpl( - startOffset, endOffset, typeConverter.nothingType, symbol, - IrGetFieldImpl(startOffset, endOffset, fieldSymbol, propertyType).setReceiver(declaration) - ) - } - ) - ) - } - declarationStorage.leaveScope(descriptor) - } - } + memberGenerator.convertPropertyContent(irProperty, property) } } + // ================================================================================== override fun visitReturnExpression(returnExpression: FirReturnExpression, data: Any?): IrElement { val irTarget = conversionScope.returnTarget(returnExpression) @@ -472,14 +230,14 @@ class Fir2IrVisitor( is ClassConstructorDescriptor -> symbolTable.referenceConstructor(descriptor) else -> symbolTable.referenceSimpleFunction(descriptor) }, - result.toIrExpression() + convertToIrExpression(result) ) } } override fun visitWrappedArgumentExpression(wrappedArgumentExpression: FirWrappedArgumentExpression, data: Any?): IrElement { // TODO: change this temporary hack to something correct - return wrappedArgumentExpression.expression.toIrExpression() + return convertToIrExpression(wrappedArgumentExpression.expression) } override fun visitVarargArgumentsExpression(varargArgumentsExpression: FirVarargArgumentsExpression, data: Any?): IrElement { @@ -487,7 +245,7 @@ class Fir2IrVisitor( return IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irReturnType, varargArgumentsExpression.varargElementType.toIrType(), varargArgumentsExpression.arguments.map { arg -> - arg.toIrExpression().run { + convertToIrExpression(arg).run { if (arg is FirSpreadArgumentExpression) IrSpreadElementImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this) else this } @@ -571,14 +329,14 @@ class Fir2IrVisitor( val valueParameters = function?.valueParameters if (valueParameters != null) { for ((argument, parameter) in argumentMapping) { - val argumentExpression = argument.toIrExpression() + val argumentExpression = convertToIrExpression(argument) putValueArgument(valueParameters.indexOf(parameter), argumentExpression) } return this } } for ((index, argument) in call.arguments.withIndex()) { - val argumentExpression = argument.toIrExpression() + val argumentExpression = convertToIrExpression(argument) putValueArgument(index, argumentExpression) } } @@ -589,14 +347,14 @@ class Fir2IrVisitor( "Cannot bind $argumentsCount arguments to $name call with $valueArgumentsCount parameters" ).apply { for (argument in call.arguments) { - addArgument(argument.toIrExpression()) + addArgument(convertToIrExpression(argument)) } } } } is IrErrorCallExpressionImpl -> apply { for (argument in call.arguments) { - addArgument(argument.toIrExpression()) + addArgument(convertToIrExpression(argument)) } } else -> this @@ -633,8 +391,8 @@ class Fir2IrVisitor( private fun FirQualifiedAccess.findIrReceiver(isDispatch: Boolean): IrExpression? { val firReceiver = if (isDispatch) dispatchReceiver else extensionReceiver if (firReceiver is FirResolvedQualifier) return firReceiver.toGetObject() - return firReceiver.takeIf { it !is FirNoReceiverExpression }?.toIrExpression() - ?: explicitReceiver?.toIrExpression() // NB: this applies to the situation when call is unresolved + return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { convertToIrExpression(it) } + ?: explicitReceiver?.let { convertToIrExpression(it) } // NB: this applies to the situation when call is unresolved ?: run { // Object case val callableReference = calleeReference as? FirResolvedNamedReference @@ -733,7 +491,7 @@ class Fir2IrVisitor( override fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: Any?): IrElement { // Generate the expression with the original type and then cast it to the smart cast type. - val value = expressionWithSmartcast.originalExpression.toIrExpression() + val value = convertToIrExpression(expressionWithSmartcast.originalExpression) val castType = expressionWithSmartcast.typeRef.toIrType() if (value.type == castType) return value return IrTypeOperatorCallImpl( @@ -796,7 +554,7 @@ class Fir2IrVisitor( is IrFieldSymbol -> IrSetFieldImpl( startOffset, endOffset, symbol, typeConverter.unitType ).apply { - value = variableAssignment.rValue.toIrExpression() + value = convertToIrExpression(variableAssignment.rValue) } is IrPropertySymbol -> { val irProperty = symbol.owner @@ -805,7 +563,7 @@ class Fir2IrVisitor( IrSetFieldImpl( startOffset, endOffset, backingField.symbol, typeConverter.unitType ).apply { - value = variableAssignment.rValue.toIrExpression() + value = convertToIrExpression(variableAssignment.rValue) } } else { generateErrorCallExpression(startOffset, endOffset, calleeReference) @@ -813,7 +571,7 @@ class Fir2IrVisitor( } is IrVariableSymbol -> { IrSetVariableImpl( - startOffset, endOffset, irBuiltIns.unitType, symbol, variableAssignment.rValue.toIrExpression(), null + startOffset, endOffset, irBuiltIns.unitType, symbol, convertToIrExpression(variableAssignment.rValue), null ) } else -> generateErrorCallExpression(startOffset, endOffset, calleeReference) @@ -852,21 +610,21 @@ class Fir2IrVisitor( private fun FirStatement.toIrStatement(): IrStatement? { if (this is FirTypeAlias) return null - if (this is FirUnitExpression) return toIrExpression() - if (this is FirBlock) return toIrExpression() + if (this is FirUnitExpression) return convertToIrExpression(this) + if (this is FirBlock) return convertToIrExpression(this) return accept(this@Fir2IrVisitor, null) as IrStatement } - private fun FirExpression.toIrExpression(): IrExpression { - return when (this) { - is FirBlock -> convertToIrExpressionOrBlock() - is FirUnitExpression -> convertWithOffsets { startOffset, endOffset -> + internal fun convertToIrExpression(expression: FirExpression): IrExpression { + return when (expression) { + is FirBlock -> expression.convertToIrExpressionOrBlock() + is FirUnitExpression -> expression.convertWithOffsets { startOffset, endOffset -> IrGetObjectValueImpl( - startOffset, endOffset, typeConverter.unitType, - symbolTable.referenceClass(irBuiltIns.builtIns.unit) + startOffset, endOffset, this.typeConverter.unitType, + this.symbolTable.referenceClass(this.irBuiltIns.builtIns.unit) ) } - else -> accept(this@Fir2IrVisitor, null) as IrExpression + else -> expression.accept(this, null) as IrExpression } } @@ -893,14 +651,14 @@ class Fir2IrVisitor( return result } - private fun FirBlock.convertToIrBlockBody(): IrBlockBody { - return convertWithOffsets { startOffset, endOffset -> - val irStatements = mapToIrStatements() + internal fun convertToIrBlockBody(block: FirBlock): IrBlockBody { + return block.convertWithOffsets { startOffset, endOffset -> + val irStatements = block.mapToIrStatements() IrBlockBodyImpl( startOffset, endOffset, if (irStatements.isNotEmpty()) { irStatements.filterNotNull().takeIf { it.isNotEmpty() } - ?: listOf(IrBlockImpl(startOffset, endOffset, typeConverter.unitType, null, emptyList())) + ?: listOf(IrBlockImpl(startOffset, endOffset, this.typeConverter.unitType, null, emptyList())) } else { emptyList() } @@ -912,7 +670,7 @@ class Fir2IrVisitor( if (statements.size == 1) { val firStatement = statements.single() if (firStatement is FirExpression) { - return firStatement.toIrExpression() + return convertToIrExpression(firStatement) } } val type = @@ -941,7 +699,7 @@ class Fir2IrVisitor( return when { subjectVariable != null -> subjectVariable.accept(this, null) as IrVariable subjectExpression != null -> { - applyParentFromStackTo(declarationStorage.declareTemporaryVariable(subjectExpression.toIrExpression(), "subject")) + applyParentFromStackTo(declarationStorage.declareTemporaryVariable(convertToIrExpression(subjectExpression), "subject")) } else -> null } @@ -986,11 +744,11 @@ class Fir2IrVisitor( override fun visitWhenBranch(whenBranch: FirWhenBranch, data: Any?): IrElement { return whenBranch.convertWithOffsets { startOffset, endOffset -> val condition = whenBranch.condition - val irResult = whenBranch.result.toIrExpression() + val irResult = convertToIrExpression(whenBranch.result) if (condition is FirElseIfTrueCondition) { IrElseBranchImpl(IrConstImpl.boolean(irResult.startOffset, irResult.endOffset, typeConverter.booleanType, true), irResult) } else { - IrBranchImpl(startOffset, endOffset, condition.toIrExpression(), irResult) + IrBranchImpl(startOffset, endOffset, convertToIrExpression(condition), irResult) } } } @@ -1013,7 +771,7 @@ class Fir2IrVisitor( loopMap[doWhileLoop] = this label = doWhileLoop.label?.name body = doWhileLoop.block.convertToIrExpressionOrBlock() - condition = doWhileLoop.condition.toIrExpression() + condition = convertToIrExpression(doWhileLoop.condition) loopMap.remove(doWhileLoop) } } @@ -1026,7 +784,7 @@ class Fir2IrVisitor( IrWhileLoopImpl(startOffset, endOffset, typeConverter.unitType, origin).apply { loopMap[whileLoop] = this label = whileLoop.label?.name - condition = whileLoop.condition.toIrExpression() + condition = convertToIrExpression(whileLoop.condition) body = whileLoop.block.convertToIrExpressionOrBlock(origin) loopMap.remove(whileLoop) } @@ -1063,7 +821,7 @@ class Fir2IrVisitor( override fun visitThrowExpression(throwExpression: FirThrowExpression, data: Any?): IrElement { return throwExpression.convertWithOffsets { startOffset, endOffset -> - IrThrowImpl(startOffset, endOffset, typeConverter.nothingType, throwExpression.exception.toIrExpression()) + IrThrowImpl(startOffset, endOffset, typeConverter.nothingType, convertToIrExpression(throwExpression.exception)) } } @@ -1133,7 +891,7 @@ class Fir2IrVisitor( return primitiveOp2( startOffset, endOffset, symbol!!, typeConverter.booleanType, origin, - comparisonExpression.left.toIrExpression(), comparisonExpression.right.toIrExpression() + convertToIrExpression(comparisonExpression.left), convertToIrExpression(comparisonExpression.right) ) } @@ -1171,9 +929,12 @@ class Fir2IrVisitor( } } val result = if (operation in UNARY_OPERATIONS) { - primitiveOp1(startOffset, endOffset, symbol, type, origin, arguments[0].toIrExpression()) + primitiveOp1(startOffset, endOffset, symbol, type, origin, convertToIrExpression(arguments[0])) } else { - primitiveOp2(startOffset, endOffset, symbol, type, origin, arguments[0].toIrExpression(), arguments[1].toIrExpression()) + primitiveOp2( + startOffset, endOffset, symbol, type, origin, + convertToIrExpression(arguments[0]), convertToIrExpression(arguments[1]) + ) } if (operation !in NEGATED_OPERATIONS) return result return primitiveOp1(startOffset, endOffset, irBuiltIns.booleanNotSymbol, typeConverter.booleanType, origin, result) @@ -1189,7 +950,7 @@ class Fir2IrVisitor( return stringConcatenationCall.convertWithOffsets { startOffset, endOffset -> IrStringConcatenationImpl( startOffset, endOffset, typeConverter.stringType, - stringConcatenationCall.arguments.map { it.toIrExpression() } + stringConcatenationCall.arguments.map { convertToIrExpression(it) } ) } } @@ -1207,7 +968,7 @@ class Fir2IrVisitor( IrTypeOperatorCallImpl( startOffset, endOffset, irType, irTypeOperator, irTypeOperand, - typeOperatorCall.argument.toIrExpression() + convertToIrExpression(typeOperatorCall.argument) ) } } @@ -1221,7 +982,7 @@ class Fir2IrVisitor( IrStatementOrigin.EXCLEXCL ).apply { putTypeArgument(0, checkNotNullCall.argument.typeRef.toIrType().makeNotNull()) - putValueArgument(0, checkNotNullCall.argument.toIrExpression()) + putValueArgument(0, convertToIrExpression(checkNotNullCall.argument)) } } } @@ -1249,7 +1010,7 @@ class Fir2IrVisitor( if (irClassReferenceSymbol != null) { IrClassReferenceImpl(startOffset, endOffset, irType, irClassReferenceSymbol, irClassType) } else { - IrGetClassImpl(startOffset, endOffset, irType, argument.toIrExpression()) + IrGetClassImpl(startOffset, endOffset, irType, convertToIrExpression(argument)) } } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt new file mode 100644 index 00000000000..98346172d36 --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt @@ -0,0 +1,289 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.backend.generators + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.fir.backend.* +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter +import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter +import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.arguments +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +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.types.IrType +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.Name + +internal class ClassMemberGenerator( + private val components: Fir2IrComponents, + private val visitor: Fir2IrVisitor, + private val conversionScope: Fir2IrConversionScope, + fakeOverrideMode: FakeOverrideMode +) : Fir2IrComponents by components { + + private val fakeOverrideGenerator = FakeOverrideGenerator(session, declarationStorage, conversionScope, fakeOverrideMode) + + private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() } + + private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() } + + private fun applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration) + + fun convertClassContent(irClass: IrClass, klass: FirClass<*>) { + declarationStorage.enterScope(irClass.descriptor) + conversionScope.withClass(irClass) { + val primaryConstructor = klass.getPrimaryConstructorIfAny() + val irPrimaryConstructor = primaryConstructor?.let { declarationStorage.getCachedIrConstructor(it)!! } + if (irPrimaryConstructor != null) { + with(declarationStorage) { + enterScope(irPrimaryConstructor.descriptor) + irPrimaryConstructor.valueParameters.forEach { symbolTable.introduceValueParameter(it) } + irPrimaryConstructor.putParametersInScope(primaryConstructor) + convertFunctionContent(irPrimaryConstructor, primaryConstructor) + } + } + val processedCallableNames = mutableListOf() + klass.declarations.forEach { + if (it !is FirTypeAlias && (it !is FirConstructor || !it.isPrimary)) { + it.accept(visitor, null) + when (it) { + is FirSimpleFunction -> processedCallableNames += it.name + is FirProperty -> processedCallableNames += it.name + } + } + } + with(fakeOverrideGenerator) { irClass.addFakeOverrides(klass, processedCallableNames) } + annotations = klass.annotations.mapNotNull { + it.accept(visitor, null) as? IrConstructorCall + } + if (irPrimaryConstructor != null) { + declarationStorage.leaveScope(irPrimaryConstructor.descriptor) + } + } + declarationStorage.leaveScope(irClass.descriptor) + } + + fun convertFunctionContent(irFunction: T, firFunction: FirFunction<*>?): T { + val descriptor = irFunction.descriptor + conversionScope.withParent(irFunction) { + if (firFunction != null) { + if (irFunction !is IrConstructor || !irFunction.isPrimary) { + // Scope for primary constructor should be entered before class declaration processing + with(declarationStorage) { + enterScope(descriptor) + irFunction.valueParameters.forEach { symbolTable.introduceValueParameter(it) } + irFunction.putParametersInScope(firFunction) + } + } + for ((valueParameter, firValueParameter) in valueParameters.zip(firFunction.valueParameters)) { + valueParameter.setDefaultValue(firValueParameter) + } + } + var body = firFunction?.body?.let { visitor.convertToIrBlockBody(it) } + if (firFunction is FirConstructor && irFunction 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, returnType, "Cannot find delegated constructor call" + ) + } + } + if (delegatedConstructor?.isThis == false) { + val irClass = parent as IrClass + body.statements += IrInstanceInitializerCallImpl( + startOffset, endOffset, irClass.symbol, irFunction.constructedClassType + ) + } + if (body.statements.isNotEmpty()) { + irFunction.body = body + } + } else if (irFunction !is IrConstructor) { + irFunction.body = body + } + if (irFunction !is IrConstructor || !irFunction.isPrimary) { + // Scope for primary constructor should be left after class declaration + declarationStorage.leaveScope(descriptor) + } + } + return irFunction + } + + fun convertPropertyContent(irProperty: IrProperty, property: FirProperty): IrProperty { + val descriptor = irProperty.descriptor + val initializer = property.initializer + val delegate = property.delegate + val irParent = irProperty.parent + val propertyType = property.returnTypeRef.toIrType() + // TODO: this checks are very preliminary, FIR resolve should determine backing field presence itself + // TODO (2): backing field should be created inside declaration storage + if (property.modality != Modality.ABSTRACT && (irParent !is IrClass || !irParent.isInterface)) { + if (initializer != null || property.getter is FirDefaultPropertyGetter || + property.isVar && property.setter is FirDefaultPropertySetter + ) { + irProperty.backingField = irProperty.createBackingField( + property, IrDeclarationOrigin.PROPERTY_BACKING_FIELD, descriptor, + Visibilities.PRIVATE, property.name, property.isVal, initializer, propertyType + ) + } else if (delegate != null) { + irProperty.backingField = irProperty.createBackingField( + property, IrDeclarationOrigin.PROPERTY_DELEGATE, descriptor, + Visibilities.PRIVATE, Name.identifier("${property.name}\$delegate"), true, delegate + ) + } + } + irProperty.getter?.setPropertyAccessorContent( + property.getter, irProperty, propertyType, property.getter is FirDefaultPropertyGetter + ) + if (property.isVar) { + irProperty.setter?.setPropertyAccessorContent( + property.setter, irProperty, propertyType, property.setter is FirDefaultPropertySetter + ) + } + irProperty.annotations = property.annotations.mapNotNull { + it.accept(visitor, null) as? IrConstructorCall + } + return irProperty + } + + private fun IrProperty.createBackingField( + property: FirProperty, + origin: IrDeclarationOrigin, + descriptor: PropertyDescriptor, + visibility: Visibility, + name: Name, + isFinal: Boolean, + firInitializerExpression: FirExpression?, + type: IrType? = null + ): IrField { + val inferredType = type ?: firInitializerExpression!!.typeRef.toIrType() + val irField = symbolTable.declareField( + startOffset, endOffset, origin, descriptor, inferredType + ) { symbol -> + IrFieldImpl( + startOffset, endOffset, origin, symbol, + name, inferredType, + visibility, isFinal = isFinal, isExternal = false, + isStatic = property.isStatic || parent !is IrClass, + isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE + ) + } + return conversionScope.withParent(applyParentFromStackTo(irField)) { + declarationStorage.enterScope(descriptor) + if (firInitializerExpression != null) { + val initializerExpression = visitor.convertToIrExpression(firInitializerExpression) + initializer = IrExpressionBodyImpl(initializerExpression) + } + correspondingPropertySymbol = this@createBackingField.symbol + declarationStorage.leaveScope(descriptor) + } + } + + private fun IrFunction.setPropertyAccessorContent( + propertyAccessor: FirPropertyAccessor?, + correspondingProperty: IrProperty, + propertyType: IrType, + isDefault: Boolean + ) { + conversionScope.withFunction(this) { + applyParentFromStackTo(this) + convertFunctionContent(this, propertyAccessor) + if (isDefault) { + conversionScope.withParent(this) { + declarationStorage.enterScope(descriptor) + val backingField = correspondingProperty.backingField + val fieldSymbol = symbolTable.referenceField(correspondingProperty.descriptor) + val declaration = this + if (backingField != null) { + body = IrBlockBodyImpl( + startOffset, endOffset, + listOf( + if (isSetter) { + IrSetFieldImpl(startOffset, endOffset, fieldSymbol, typeConverter.unitType).apply { + setReceiver(declaration) + value = IrGetValueImpl(startOffset, endOffset, propertyType, valueParameters.first().symbol) + } + } else { + IrReturnImpl( + startOffset, endOffset, typeConverter.nothingType, symbol, + IrGetFieldImpl(startOffset, endOffset, fieldSymbol, propertyType).setReceiver(declaration) + ) + } + ) + ) + } + declarationStorage.leaveScope(descriptor) + } + } + } + } + + private fun IrFieldAccessExpression.setReceiver(declaration: IrDeclaration): IrFieldAccessExpression { + if (declaration is IrFunction) { + val dispatchReceiver = declaration.dispatchReceiverParameter + if (dispatchReceiver != null) { + receiver = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.symbol) + } + } + return this + } + + private fun FirDelegatedConstructorCall.toIrDelegatingConstructorCall(): IrCallWithIndexedArgumentsBase? { + val constructedIrType = constructedTypeRef.toIrType() + val constructorSymbol = (this.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol + ?: return null + return convertWithOffsets { startOffset, endOffset -> + val irConstructorSymbol = declarationStorage.getIrFunctionSymbol(constructorSymbol) as IrConstructorSymbol + if (constructorSymbol.fir.isFromEnumClass || constructorSymbol.fir.returnTypeRef.isEnum) { + IrEnumConstructorCallImpl( + startOffset, endOffset, + constructedIrType, + irConstructorSymbol + ).apply { + val typeArguments = (constructedTypeRef as? FirResolvedTypeRef)?.type?.typeArguments + if (typeArguments?.isNotEmpty() == true) { + val irType = (typeArguments.first() as ConeKotlinTypeProjection).type.toIrType() + putTypeArgument(0, irType) + } + } + } else { + IrDelegatingConstructorCallImpl( + startOffset, endOffset, + constructedIrType, + irConstructorSymbol + ) + }.apply { + for ((index, argument) in arguments.withIndex()) { + val argumentExpression = visitor.convertToIrExpression(argument) + putValueArgument(index, argumentExpression) + } + } + } + } + + private fun IrValueParameter.setDefaultValue(firValueParameter: FirValueParameter) { + val firDefaultValue = firValueParameter.defaultValue + if (firDefaultValue != null) { + this.defaultValue = IrExpressionBodyImpl(visitor.convertToIrExpression(firDefaultValue)) + } + } +} \ No newline at end of file