diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 3010ef473de..6175d2f9fc3 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -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 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 visitConstExpression(constExpression: FirConstExpression, 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 { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallGenerator.kt new file mode 100644 index 00000000000..14bb8632153 --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallGenerator.kt @@ -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()}" + ) + } +} \ No newline at end of file