[FIR2IR] Extract CallGenerator from the main visitor
This commit is contained in:
@@ -5,37 +5,46 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.backend
|
package org.jetbrains.kotlin.fir.backend
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
|
import org.jetbrains.kotlin.fir.backend.generators.CallGenerator
|
||||||
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
|
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
|
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
|
||||||
import org.jetbrains.kotlin.fir.references.FirReference
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.isIteratorNext
|
import org.jetbrains.kotlin.fir.resolve.isIteratorNext
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.IntegerLiteralTypeApproximationTransformer
|
import org.jetbrains.kotlin.fir.resolve.transformers.IntegerLiteralTypeApproximationTransformer
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||||
|
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||||
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -57,9 +66,9 @@ class Fir2IrVisitor(
|
|||||||
|
|
||||||
private val memberGenerator = ClassMemberGenerator(components, this, conversionScope, fakeOverrideMode)
|
private val memberGenerator = ClassMemberGenerator(components, this, conversionScope, fakeOverrideMode)
|
||||||
|
|
||||||
private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() }
|
private val callGenerator = CallGenerator(components, this, conversionScope)
|
||||||
|
|
||||||
private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() }
|
private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() }
|
||||||
|
|
||||||
private fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration)
|
private fun <T : IrDeclaration> applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration)
|
||||||
|
|
||||||
@@ -252,200 +261,13 @@ class Fir2IrVisitor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirQualifiedAccess.toIrExpression(typeRef: FirTypeRef): IrExpression {
|
|
||||||
val type = typeRef.toIrType()
|
|
||||||
val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage)
|
|
||||||
return typeRef.convertWithOffsets { startOffset, endOffset ->
|
|
||||||
if (calleeReference is FirSuperReference) {
|
|
||||||
if (typeRef !is FirComposedSuperTypeRef) {
|
|
||||||
val dispatchReceiver = conversionScope.lastDispatchReceiverParameter()
|
|
||||||
if (dispatchReceiver != null) {
|
|
||||||
return@convertWithOffsets IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
when {
|
|
||||||
symbol is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol)
|
|
||||||
symbol is IrSimpleFunctionSymbol -> IrCallImpl(
|
|
||||||
startOffset, endOffset, type, symbol, origin = calleeReference.statementOrigin()
|
|
||||||
)
|
|
||||||
symbol is IrPropertySymbol && symbol.isBound -> {
|
|
||||||
val getter = symbol.owner.getter
|
|
||||||
if (getter != null) {
|
|
||||||
IrCallImpl(startOffset, endOffset, type, getter.symbol, origin = IrStatementOrigin.GET_PROPERTY)
|
|
||||||
} else {
|
|
||||||
IrErrorCallExpressionImpl(startOffset, endOffset, type, "No getter found for ${calleeReference.render()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
symbol is IrFieldSymbol -> IrGetFieldImpl(startOffset, endOffset, symbol, type, origin = IrStatementOrigin.GET_PROPERTY)
|
|
||||||
symbol is IrValueSymbol -> IrGetValueImpl(
|
|
||||||
startOffset, endOffset, type, symbol,
|
|
||||||
origin = calleeReference.statementOrigin()
|
|
||||||
)
|
|
||||||
symbol is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
|
||||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference, type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirAnnotationCall.toIrExpression(): IrExpression {
|
|
||||||
val coneType = (annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeLookupTagBasedType
|
|
||||||
val firSymbol = coneType?.lookupTag?.toSymbol(session) as? FirClassSymbol
|
|
||||||
val type = coneType?.toIrType()
|
|
||||||
val symbol = type?.classifierOrNull
|
|
||||||
return convertWithOffsets { startOffset, endOffset ->
|
|
||||||
when (symbol) {
|
|
||||||
is IrClassSymbol -> {
|
|
||||||
val irClass = symbol.owner
|
|
||||||
val fir = firSymbol?.fir as? FirClass<*>
|
|
||||||
val irConstructor = fir?.getPrimaryConstructorIfAny()?.let { firConstructor ->
|
|
||||||
declarationStorage.getIrConstructorSymbol(firConstructor.symbol)
|
|
||||||
}
|
|
||||||
if (irConstructor == null) {
|
|
||||||
IrErrorCallExpressionImpl(startOffset, endOffset, type, "No annotation constructor found: ${irClass.name}")
|
|
||||||
} else {
|
|
||||||
IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, irConstructor)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
IrErrorCallExpressionImpl(startOffset, endOffset, type ?: createErrorType(), "Unresolved reference: ${render()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.applyCallArguments(call: FirCall): IrExpression {
|
|
||||||
return when (this) {
|
|
||||||
is IrCallWithIndexedArgumentsBase -> {
|
|
||||||
val argumentsCount = call.arguments.size
|
|
||||||
if (argumentsCount <= valueArgumentsCount) {
|
|
||||||
apply {
|
|
||||||
val argumentMapping = call.argumentMapping
|
|
||||||
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
|
|
||||||
require(call is FirFunctionCall)
|
|
||||||
val function =
|
|
||||||
((call.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
|
||||||
val valueParameters = function?.valueParameters
|
|
||||||
if (valueParameters != null) {
|
|
||||||
for ((argument, parameter) in argumentMapping) {
|
|
||||||
val argumentExpression = convertToIrExpression(argument)
|
|
||||||
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ((index, argument) in call.arguments.withIndex()) {
|
|
||||||
val argumentExpression = convertToIrExpression(argument)
|
|
||||||
putValueArgument(index, argumentExpression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
|
||||||
IrErrorCallExpressionImpl(
|
|
||||||
startOffset, endOffset, type,
|
|
||||||
"Cannot bind $argumentsCount arguments to $name call with $valueArgumentsCount parameters"
|
|
||||||
).apply {
|
|
||||||
for (argument in call.arguments) {
|
|
||||||
addArgument(convertToIrExpression(argument))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is IrErrorCallExpressionImpl -> apply {
|
|
||||||
for (argument in call.arguments) {
|
|
||||||
addArgument(convertToIrExpression(argument))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
|
|
||||||
return when (this) {
|
|
||||||
is IrCallWithIndexedArgumentsBase -> {
|
|
||||||
val argumentsCount = access.typeArguments.size
|
|
||||||
if (argumentsCount <= typeArgumentsCount) {
|
|
||||||
apply {
|
|
||||||
for ((index, argument) in access.typeArguments.withIndex()) {
|
|
||||||
val argumentIrType = (argument as FirTypeProjectionWithVariance).typeRef.toIrType()
|
|
||||||
putTypeArgument(index, argumentIrType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
|
||||||
IrErrorExpressionImpl(
|
|
||||||
startOffset, endOffset, type,
|
|
||||||
"Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirQualifiedAccess.findIrDispatchReceiver(): IrExpression? = findIrReceiver(isDispatch = true)
|
|
||||||
|
|
||||||
private fun FirQualifiedAccess.findIrExtensionReceiver(): IrExpression? = findIrReceiver(isDispatch = false)
|
|
||||||
|
|
||||||
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 }?.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
|
|
||||||
val ownerClassId = (callableReference?.resolvedSymbol as? FirCallableSymbol<*>)?.callableId?.classId
|
|
||||||
val ownerClassSymbol = ownerClassId?.let { session.firSymbolProvider.getClassLikeSymbolByFqName(it) }
|
|
||||||
val firClass = (ownerClassSymbol?.fir as? FirClass)?.takeIf {
|
|
||||||
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
|
|
||||||
}
|
|
||||||
firClass?.convertWithOffsets { startOffset, endOffset ->
|
|
||||||
val irClass = classifierStorage.getCachedIrClass(firClass)!!
|
|
||||||
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: uncomment after fixing KT-35730
|
|
||||||
// ?: run {
|
|
||||||
// val name = if (isDispatch) "Dispatch" else "Extension"
|
|
||||||
// throw AssertionError(
|
|
||||||
// "$name receiver expected: ${render()} to ${calleeReference.render()}"
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess): IrExpression {
|
|
||||||
return when (this) {
|
|
||||||
is IrCallImpl -> {
|
|
||||||
val ownerFunction = symbol.owner
|
|
||||||
if (ownerFunction.dispatchReceiverParameter != null) {
|
|
||||||
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver()
|
|
||||||
}
|
|
||||||
if (ownerFunction.extensionReceiverParameter != null) {
|
|
||||||
extensionReceiver = qualifiedAccess.findIrExtensionReceiver()
|
|
||||||
}
|
|
||||||
this
|
|
||||||
}
|
|
||||||
is IrFieldExpressionBase -> {
|
|
||||||
val ownerField = symbol.owner
|
|
||||||
if (!ownerField.isStatic) {
|
|
||||||
receiver = qualifiedAccess.findIrDispatchReceiver()
|
|
||||||
}
|
|
||||||
this
|
|
||||||
}
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Any?): IrExpression {
|
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Any?): IrExpression {
|
||||||
val convertibleCall = if (functionCall.toResolvedCallableSymbol()?.fir is FirIntegerOperator) {
|
val convertibleCall = if (functionCall.toResolvedCallableSymbol()?.fir is FirIntegerOperator) {
|
||||||
functionCall.copy().transformSingle(integerApproximator, null)
|
functionCall.copy().transformSingle(integerApproximator, null)
|
||||||
} else {
|
} else {
|
||||||
functionCall
|
functionCall
|
||||||
}
|
}
|
||||||
return convertibleCall.toIrExpression(convertibleCall.typeRef)
|
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef)
|
||||||
.applyCallArguments(convertibleCall).applyTypeArguments(convertibleCall).applyReceivers(convertibleCall)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? {
|
private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? {
|
||||||
@@ -454,12 +276,11 @@ class Fir2IrVisitor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Any?): IrElement {
|
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Any?): IrElement {
|
||||||
return annotationCall.toIrExpression().applyCallArguments(annotationCall)
|
return callGenerator.convertToIrConstructorCall(annotationCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement {
|
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement {
|
||||||
return qualifiedAccessExpression.toIrExpression(qualifiedAccessExpression.typeRef)
|
return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef)
|
||||||
.applyTypeArguments(qualifiedAccessExpression).applyReceivers(qualifiedAccessExpression)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
|
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
|
||||||
@@ -533,53 +354,8 @@ class Fir2IrVisitor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateErrorCallExpression(
|
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
calleeReference: FirReference,
|
|
||||||
type: IrType? = null
|
|
||||||
): IrErrorCallExpression {
|
|
||||||
return IrErrorCallExpressionImpl(
|
|
||||||
startOffset, endOffset, type ?: createErrorType(),
|
|
||||||
"Unresolved reference: ${calleeReference.render()}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement {
|
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement {
|
||||||
val calleeReference = variableAssignment.calleeReference
|
return callGenerator.convertToIrSetCall(variableAssignment)
|
||||||
val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage)
|
|
||||||
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
|
||||||
if (symbol != null && symbol.isBound) {
|
|
||||||
when (symbol) {
|
|
||||||
is IrFieldSymbol -> IrSetFieldImpl(
|
|
||||||
startOffset, endOffset, symbol, typeConverter.unitType
|
|
||||||
).apply {
|
|
||||||
value = convertToIrExpression(variableAssignment.rValue)
|
|
||||||
}
|
|
||||||
is IrPropertySymbol -> {
|
|
||||||
val irProperty = symbol.owner
|
|
||||||
val backingField = irProperty.backingField
|
|
||||||
if (backingField != null) {
|
|
||||||
IrSetFieldImpl(
|
|
||||||
startOffset, endOffset, backingField.symbol, typeConverter.unitType
|
|
||||||
).apply {
|
|
||||||
value = convertToIrExpression(variableAssignment.rValue)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is IrVariableSymbol -> {
|
|
||||||
IrSetVariableImpl(
|
|
||||||
startOffset, endOffset, irBuiltIns.unitType, symbol, convertToIrExpression(variableAssignment.rValue), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
|
||||||
}
|
|
||||||
}.applyReceivers(variableAssignment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Any?): IrElement {
|
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Any?): IrElement {
|
||||||
@@ -1024,26 +800,8 @@ class Fir2IrVisitor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirResolvedQualifier.toGetObject(): IrExpression {
|
|
||||||
val irType = typeRef.toIrType()
|
|
||||||
val typeRef = typeRef as? FirResolvedTypeRef
|
|
||||||
val classSymbol = (typeRef?.type as? ConeClassLikeType)?.lookupTag?.toSymbol(session)
|
|
||||||
return convertWithOffsets { startOffset, endOffset ->
|
|
||||||
if (classSymbol != null) {
|
|
||||||
IrGetObjectValueImpl(
|
|
||||||
startOffset, endOffset, irType,
|
|
||||||
classSymbol.toSymbol(session, classifierStorage) as IrClassSymbol
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
IrErrorCallExpressionImpl(
|
|
||||||
startOffset, endOffset, irType, "Resolved qualifier ${render()} does not have correctly resolved type"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: Any?): IrElement {
|
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: Any?): IrElement {
|
||||||
return resolvedQualifier.toGetObject()
|
return callGenerator.convertToGetObject(resolvedQualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: Any?): IrElement {
|
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: Any?): IrElement {
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* 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.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.backend.*
|
||||||
|
import org.jetbrains.kotlin.fir.backend.convertWithOffsets
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrErrorCallExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
|
||||||
|
internal class CallGenerator(
|
||||||
|
private val components: Fir2IrComponents,
|
||||||
|
private val visitor: Fir2IrVisitor,
|
||||||
|
private val conversionScope: Fir2IrConversionScope
|
||||||
|
) : Fir2IrComponents by components {
|
||||||
|
|
||||||
|
private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() }
|
||||||
|
|
||||||
|
private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() }
|
||||||
|
|
||||||
|
fun convertToIrCall(qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef): IrExpression {
|
||||||
|
val type = typeRef.toIrType()
|
||||||
|
val symbol = qualifiedAccess.calleeReference.toSymbol(
|
||||||
|
session,
|
||||||
|
classifierStorage,
|
||||||
|
declarationStorage
|
||||||
|
)
|
||||||
|
return typeRef.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
if (qualifiedAccess.calleeReference is FirSuperReference) {
|
||||||
|
if (typeRef !is FirComposedSuperTypeRef) {
|
||||||
|
val dispatchReceiver = conversionScope.lastDispatchReceiverParameter()
|
||||||
|
if (dispatchReceiver != null) {
|
||||||
|
return@convertWithOffsets IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
symbol is IrConstructorSymbol -> IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, symbol)
|
||||||
|
symbol is IrSimpleFunctionSymbol -> IrCallImpl(
|
||||||
|
startOffset, endOffset, type, symbol, origin = qualifiedAccess.calleeReference.statementOrigin()
|
||||||
|
)
|
||||||
|
symbol is IrPropertySymbol && symbol.isBound -> {
|
||||||
|
val getter = symbol.owner.getter
|
||||||
|
if (getter != null) {
|
||||||
|
IrCallImpl(startOffset, endOffset, type, getter.symbol, origin = IrStatementOrigin.GET_PROPERTY)
|
||||||
|
} else {
|
||||||
|
IrErrorCallExpressionImpl(
|
||||||
|
startOffset, endOffset, type, "No getter found for ${qualifiedAccess.calleeReference.render()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbol is IrFieldSymbol -> IrGetFieldImpl(startOffset, endOffset, symbol, type, origin = IrStatementOrigin.GET_PROPERTY)
|
||||||
|
symbol is IrValueSymbol -> IrGetValueImpl(
|
||||||
|
startOffset, endOffset, type, symbol,
|
||||||
|
origin = qualifiedAccess.calleeReference.statementOrigin()
|
||||||
|
)
|
||||||
|
symbol is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
||||||
|
else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type)
|
||||||
|
}
|
||||||
|
}.applyCallArguments(qualifiedAccess as? FirCall).applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertToIrSetCall(variableAssignment: FirVariableAssignment): IrExpression {
|
||||||
|
val calleeReference = variableAssignment.calleeReference
|
||||||
|
val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage)
|
||||||
|
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
if (symbol != null && symbol.isBound) {
|
||||||
|
when (symbol) {
|
||||||
|
is IrFieldSymbol -> IrSetFieldImpl(
|
||||||
|
startOffset, endOffset, symbol, typeConverter.unitType
|
||||||
|
).apply {
|
||||||
|
value = visitor.convertToIrExpression(variableAssignment.rValue)
|
||||||
|
}
|
||||||
|
is IrPropertySymbol -> {
|
||||||
|
val irProperty = symbol.owner
|
||||||
|
val backingField = irProperty.backingField
|
||||||
|
if (backingField != null) {
|
||||||
|
IrSetFieldImpl(
|
||||||
|
startOffset, endOffset, backingField.symbol, typeConverter.unitType
|
||||||
|
).apply {
|
||||||
|
value = visitor.convertToIrExpression(variableAssignment.rValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IrVariableSymbol -> {
|
||||||
|
IrSetVariableImpl(
|
||||||
|
startOffset, endOffset, irBuiltIns.unitType, symbol,
|
||||||
|
visitor.convertToIrExpression(variableAssignment.rValue), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||||
|
}
|
||||||
|
}.applyReceivers(variableAssignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertToIrConstructorCall(annotationCall: FirAnnotationCall): IrExpression {
|
||||||
|
val coneType = (annotationCall.annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeLookupTagBasedType
|
||||||
|
val firSymbol = coneType?.lookupTag?.toSymbol(session) as? FirClassSymbol
|
||||||
|
val type = coneType?.toIrType()
|
||||||
|
val symbol = type?.classifierOrNull
|
||||||
|
return annotationCall.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
when (symbol) {
|
||||||
|
is IrClassSymbol -> {
|
||||||
|
val irClass = symbol.owner
|
||||||
|
val fir = firSymbol?.fir as? FirClass<*>
|
||||||
|
val irConstructor = fir?.getPrimaryConstructorIfAny()?.let { firConstructor ->
|
||||||
|
this.declarationStorage.getIrConstructorSymbol(firConstructor.symbol)
|
||||||
|
}
|
||||||
|
if (irConstructor == null) {
|
||||||
|
IrErrorCallExpressionImpl(startOffset, endOffset, type, "No annotation constructor found: ${irClass.name}")
|
||||||
|
} else {
|
||||||
|
IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, irConstructor)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
IrErrorCallExpressionImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
type ?: createErrorType(),
|
||||||
|
"Unresolved reference: ${annotationCall.render()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.applyCallArguments(annotationCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertToGetObject(qualifier: FirResolvedQualifier): IrExpression {
|
||||||
|
val irType = qualifier.typeRef.toIrType()
|
||||||
|
val typeRef = qualifier.typeRef as? FirResolvedTypeRef
|
||||||
|
val classSymbol = (typeRef?.type as? ConeClassLikeType)?.lookupTag?.toSymbol(session)
|
||||||
|
return qualifier.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
if (classSymbol != null) {
|
||||||
|
IrGetObjectValueImpl(
|
||||||
|
startOffset, endOffset, irType,
|
||||||
|
classSymbol.toSymbol(this.session, this.classifierStorage) as IrClassSymbol
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
IrErrorCallExpressionImpl(
|
||||||
|
startOffset, endOffset, irType,
|
||||||
|
"Resolved qualifier ${qualifier.render()} does not have correctly resolved type"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.applyCallArguments(call: FirCall?): IrExpression {
|
||||||
|
if (call == null) return this
|
||||||
|
return when (this) {
|
||||||
|
is IrCallWithIndexedArgumentsBase -> {
|
||||||
|
val argumentsCount = call.arguments.size
|
||||||
|
if (argumentsCount <= valueArgumentsCount) {
|
||||||
|
apply {
|
||||||
|
val argumentMapping = call.argumentMapping
|
||||||
|
if (argumentMapping != null && argumentMapping.isNotEmpty()) {
|
||||||
|
require(call is FirFunctionCall)
|
||||||
|
val function =
|
||||||
|
((call.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
||||||
|
val valueParameters = function?.valueParameters
|
||||||
|
if (valueParameters != null) {
|
||||||
|
for ((argument, parameter) in argumentMapping) {
|
||||||
|
val argumentExpression = visitor.convertToIrExpression(argument)
|
||||||
|
putValueArgument(valueParameters.indexOf(parameter), argumentExpression)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ((index, argument) in call.arguments.withIndex()) {
|
||||||
|
val argumentExpression = visitor.convertToIrExpression(argument)
|
||||||
|
putValueArgument(index, argumentExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
||||||
|
IrErrorCallExpressionImpl(
|
||||||
|
startOffset, endOffset, type,
|
||||||
|
"Cannot bind $argumentsCount arguments to $name call with $valueArgumentsCount parameters"
|
||||||
|
).apply {
|
||||||
|
for (argument in call.arguments) {
|
||||||
|
addArgument(visitor.convertToIrExpression(argument))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IrErrorCallExpressionImpl -> apply {
|
||||||
|
for (argument in call.arguments) {
|
||||||
|
addArgument(visitor.convertToIrExpression(argument))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
|
||||||
|
return when (this) {
|
||||||
|
is IrCallWithIndexedArgumentsBase -> {
|
||||||
|
val argumentsCount = access.typeArguments.size
|
||||||
|
if (argumentsCount <= typeArgumentsCount) {
|
||||||
|
apply {
|
||||||
|
for ((index, argument) in access.typeArguments.withIndex()) {
|
||||||
|
val argumentIrType = (argument as FirTypeProjectionWithVariance).typeRef.toIrType()
|
||||||
|
putTypeArgument(index, argumentIrType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val name = if (this is IrCallImpl) symbol.owner.name else "???"
|
||||||
|
IrErrorExpressionImpl(
|
||||||
|
startOffset, endOffset, type,
|
||||||
|
"Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirQualifiedAccess.findIrDispatchReceiver(): IrExpression? = findIrReceiver(isDispatch = true)
|
||||||
|
|
||||||
|
private fun FirQualifiedAccess.findIrExtensionReceiver(): IrExpression? = findIrReceiver(isDispatch = false)
|
||||||
|
|
||||||
|
private fun FirQualifiedAccess.findIrReceiver(isDispatch: Boolean): IrExpression? {
|
||||||
|
val firReceiver = if (isDispatch) dispatchReceiver else extensionReceiver
|
||||||
|
if (firReceiver is FirResolvedQualifier) return convertToGetObject(firReceiver)
|
||||||
|
return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { visitor.convertToIrExpression(it) }
|
||||||
|
?: explicitReceiver?.let { visitor.convertToIrExpression(it) } // NB: this applies to the situation when call is unresolved
|
||||||
|
?: run {
|
||||||
|
// Object case
|
||||||
|
val callableReference = calleeReference as? FirResolvedNamedReference
|
||||||
|
val ownerClassId = (callableReference?.resolvedSymbol as? FirCallableSymbol<*>)?.callableId?.classId
|
||||||
|
val ownerClassSymbol = ownerClassId?.let { session.firSymbolProvider.getClassLikeSymbolByFqName(it) }
|
||||||
|
val firClass = (ownerClassSymbol?.fir as? FirClass)?.takeIf {
|
||||||
|
it is FirAnonymousObject || it is FirRegularClass && it.classKind == ClassKind.OBJECT
|
||||||
|
}
|
||||||
|
firClass?.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
val irClass = classifierStorage.getCachedIrClass(firClass)!!
|
||||||
|
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: uncomment after fixing KT-35730
|
||||||
|
// ?: run {
|
||||||
|
// val name = if (isDispatch) "Dispatch" else "Extension"
|
||||||
|
// throw AssertionError(
|
||||||
|
// "$name receiver expected: ${render()} to ${calleeReference.render()}"
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess): IrExpression {
|
||||||
|
return when (this) {
|
||||||
|
is IrCallImpl -> {
|
||||||
|
val ownerFunction = symbol.owner
|
||||||
|
if (ownerFunction.dispatchReceiverParameter != null) {
|
||||||
|
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver()
|
||||||
|
}
|
||||||
|
if (ownerFunction.extensionReceiverParameter != null) {
|
||||||
|
extensionReceiver = qualifiedAccess.findIrExtensionReceiver()
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
is IrFieldExpressionBase -> {
|
||||||
|
val ownerField = symbol.owner
|
||||||
|
if (!ownerField.isStatic) {
|
||||||
|
receiver = qualifiedAccess.findIrDispatchReceiver()
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateErrorCallExpression(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
calleeReference: FirReference,
|
||||||
|
type: IrType? = null
|
||||||
|
): IrErrorCallExpression {
|
||||||
|
return IrErrorCallExpressionImpl(
|
||||||
|
startOffset, endOffset, type ?: createErrorType(),
|
||||||
|
"Unresolved reference: ${calleeReference.render()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user