[FIR2IR] Extract ClassMemberGenerator from the main visitor

This commit is contained in:
Mikhail Glukhikh
2020-03-16 13:35:56 +03:00
parent 63aa5191da
commit 5357e7b3ab
2 changed files with 345 additions and 295 deletions
@@ -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<Name>()
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 : IrFunction> 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))
}
}
}
@@ -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 <T : IrDeclaration> 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<Name>()
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 <T : IrFunction> 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))
}
}
}