[FIR2IR] Extract CallGenerator from the main visitor

This commit is contained in:
Mikhail Glukhikh
2020-03-16 13:57:55 +03:00
parent 5357e7b3ab
commit b6fdd6197a
2 changed files with 337 additions and 268 deletions
@@ -5,37 +5,46 @@
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.backend.generators.CallGenerator
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
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.references.FirReference
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.isIteratorNext
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.IntegerLiteralTypeApproximationTransformer
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
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.transformSingle
import org.jetbrains.kotlin.ir.IrElement
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.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.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.types.IrType
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.psi.*
import java.util.*
@@ -57,9 +66,9 @@ class Fir2IrVisitor(
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)
@@ -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 {
val convertibleCall = if (functionCall.toResolvedCallableSymbol()?.fir is FirIntegerOperator) {
functionCall.copy().transformSingle(integerApproximator, null)
} else {
functionCall
}
return convertibleCall.toIrExpression(convertibleCall.typeRef)
.applyCallArguments(convertibleCall).applyTypeArguments(convertibleCall).applyReceivers(convertibleCall)
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef)
}
private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? {
@@ -454,12 +276,11 @@ class Fir2IrVisitor(
}
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 {
return qualifiedAccessExpression.toIrExpression(qualifiedAccessExpression.typeRef)
.applyTypeArguments(qualifiedAccessExpression).applyReceivers(qualifiedAccessExpression)
return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef)
}
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 {
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 = 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)
return callGenerator.convertToIrSetCall(variableAssignment)
}
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 {
return resolvedQualifier.toGetObject()
return callGenerator.convertToGetObject(resolvedQualifier)
}
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()}"
)
}
}