[FIR JS] Support dynamic type in IR
This commit is contained in:
+14
-1
@@ -205,6 +205,13 @@ class Fir2IrImplicitCastInserter(
|
||||
expectedType.isUnit -> {
|
||||
coerceToUnitIfNeeded(this, irBuiltIns)
|
||||
}
|
||||
valueType.coneTypeSafe<ConeDynamicType>() != null -> {
|
||||
if (expectedType.coneType !is ConeDynamicType && !expectedType.isNullableAny) {
|
||||
implicitCast(this, expectedType.toIrType())
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
typeCanBeEnhancedOrFlexibleNullable(valueType) && !expectedType.acceptsNullValues() -> {
|
||||
insertImplicitNotNullCastIfNeeded(expression)
|
||||
}
|
||||
@@ -326,11 +333,17 @@ class Fir2IrImplicitCastInserter(
|
||||
|
||||
companion object {
|
||||
private fun implicitCast(original: IrExpression, castType: IrType): IrExpression {
|
||||
val typeOperator = if (original.type is IrDynamicType) {
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST
|
||||
} else {
|
||||
IrTypeOperator.IMPLICIT_CAST
|
||||
}
|
||||
|
||||
return IrTypeOperatorCallImpl(
|
||||
original.startOffset,
|
||||
original.endOffset,
|
||||
castType,
|
||||
IrTypeOperator.IMPLICIT_CAST,
|
||||
typeOperator,
|
||||
castType,
|
||||
original
|
||||
)
|
||||
|
||||
@@ -20,9 +20,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeArgument
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
@@ -168,6 +166,10 @@ class Fir2IrTypeConverter(
|
||||
addRawTypeAnnotation = true
|
||||
)
|
||||
}
|
||||
is ConeDynamicType -> {
|
||||
val typeAnnotations = with(annotationGenerator) { annotations.toIrAnnotations() }
|
||||
return IrDynamicTypeImpl(null, typeAnnotations, Variance.INVARIANT)
|
||||
}
|
||||
is ConeFlexibleType -> with(session.typeContext) {
|
||||
if (upperBound is ConeClassLikeType) {
|
||||
val upper = upperBound as ConeClassLikeType
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.backend
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.KtPsiSourceElement
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -20,14 +17,9 @@ import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSealed
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
@@ -43,7 +35,7 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
@@ -54,6 +46,7 @@ import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class Fir2IrVisitor(
|
||||
private val components: Fir2IrComponents,
|
||||
@@ -373,10 +366,50 @@ class Fir2IrVisitor(
|
||||
} else convertToIrExpression(this, annotationMode)
|
||||
|
||||
private fun convertToIrCall(functionCall: FirFunctionCall, annotationMode: Boolean): IrExpression {
|
||||
val explicitReceiverExpression = convertToIrReceiverExpression(
|
||||
functionCall.explicitReceiver, functionCall.calleeReference
|
||||
if (functionCall.isCalleeDynamic &&
|
||||
functionCall.calleeReference.name == OperatorNameConventions.SET &&
|
||||
functionCall.calleeReference.source?.kind == KtFakeSourceElementKind.ArrayAccessNameReference
|
||||
) {
|
||||
return convertToIrArrayAccessDynamicCall(functionCall, annotationMode)
|
||||
}
|
||||
return convertToIrCall(functionCall, annotationMode, dynamicOperator = null)
|
||||
}
|
||||
|
||||
private fun convertToIrCall(
|
||||
functionCall: FirFunctionCall,
|
||||
annotationMode: Boolean,
|
||||
dynamicOperator: IrDynamicOperator?
|
||||
): IrExpression {
|
||||
val explicitReceiverExpression = convertToIrReceiverExpression(functionCall.explicitReceiver, functionCall.calleeReference)
|
||||
return callGenerator.convertToIrCall(
|
||||
functionCall,
|
||||
functionCall.typeRef,
|
||||
explicitReceiverExpression,
|
||||
annotationMode,
|
||||
dynamicOperator
|
||||
)
|
||||
return callGenerator.convertToIrCall(functionCall, functionCall.typeRef, explicitReceiverExpression, annotationMode)
|
||||
}
|
||||
|
||||
private fun convertToIrArrayAccessDynamicCall(functionCall: FirFunctionCall, annotationMode: Boolean): IrExpression {
|
||||
val explicitReceiverExpression = convertToIrCall(
|
||||
functionCall, annotationMode, dynamicOperator = IrDynamicOperator.ARRAY_ACCESS
|
||||
)
|
||||
if (explicitReceiverExpression is IrDynamicOperatorExpression) {
|
||||
explicitReceiverExpression.arguments.removeLast()
|
||||
}
|
||||
val result = callGenerator.convertToIrCall(
|
||||
functionCall, functionCall.typeRef, explicitReceiverExpression,
|
||||
annotationMode = annotationMode,
|
||||
dynamicOperator = IrDynamicOperator.EQ
|
||||
)
|
||||
if (result is IrDynamicOperatorExpression) {
|
||||
val arguments = result.arguments
|
||||
arguments[0] = arguments[arguments.lastIndex]
|
||||
while (arguments.size > 1) {
|
||||
arguments.removeLast()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Any?): IrExpression {
|
||||
@@ -709,7 +742,82 @@ class Fir2IrVisitor(
|
||||
return this == IrStatementOrigin.DO_WHILE_LOOP || this == IrStatementOrigin.WHILE_LOOP || this == IrStatementOrigin.FOR_LOOP
|
||||
}
|
||||
|
||||
private inline fun <reified K> List<*>.findFirst() = firstOrNull { it is K } as? K
|
||||
|
||||
private inline fun <reified K> List<*>.findLast() = lastOrNull { it is K } as? K
|
||||
|
||||
private fun extractOperationFromDynamicSetCall(functionCall: FirFunctionCall) =
|
||||
functionCall.dynamicVarargArguments?.lastOrNull() as? FirFunctionCall
|
||||
|
||||
private val FirExpression.isIncrementOrDecrementCall: Boolean
|
||||
get() {
|
||||
val name = safeAs<FirFunctionCall>()?.calleeReference?.resolved?.name
|
||||
return name == OperatorNameConventions.INC || name == OperatorNameConventions.DEC
|
||||
}
|
||||
|
||||
private fun FirBlock.tryConvertDynamicIncrementOrDecrementToIr(): IrExpression? {
|
||||
val receiver = statements.findFirst<FirProperty>() ?: return null
|
||||
val receiverValue = receiver.initializer ?: return null
|
||||
|
||||
if (receiverValue.typeRef.coneType !is ConeDynamicType) {
|
||||
return null
|
||||
}
|
||||
|
||||
val savedValue = statements.findLast<FirProperty>()?.initializer ?: return null
|
||||
val isPrefix = savedValue.isIncrementOrDecrementCall
|
||||
|
||||
val (operationReceiver, operationCall) = if (isPrefix) {
|
||||
val operation = savedValue as? FirFunctionCall ?: return null
|
||||
val operationReceiver = operation.explicitReceiver ?: return null
|
||||
operationReceiver to operation
|
||||
} else {
|
||||
val operation = statements.findLast<FirVariableAssignment>()?.rValue as? FirFunctionCall
|
||||
?: statements.findLast<FirFunctionCall>()?.let { extractOperationFromDynamicSetCall(it) }
|
||||
?: return null
|
||||
savedValue to operation
|
||||
}
|
||||
|
||||
val isArrayAccess = receiver.name == SpecialNames.ARRAY
|
||||
|
||||
val explicitReceiverExpression = if (isArrayAccess) {
|
||||
val arrayAccess = operationReceiver as? FirFunctionCall ?: return null
|
||||
val originalVararg = arrayAccess.resolvedArgumentMapping?.keys?.filterIsInstance<FirVarargArgumentsExpression>()?.firstOrNull()
|
||||
(callGenerator.convertToIrCall(
|
||||
arrayAccess, arrayAccess.typeRef,
|
||||
convertToIrReceiverExpression(receiverValue, arrayAccess.calleeReference),
|
||||
noArguments = true
|
||||
) as IrDynamicOperatorExpression).apply {
|
||||
originalVararg?.arguments?.forEach {
|
||||
val that = (it as? FirPropertyAccessExpression)?.calleeReference?.resolvedSymbol?.fir as? FirProperty
|
||||
val initializer = that?.initializer ?: return@forEach
|
||||
arguments.add(convertToIrExpression(initializer))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val qualifiedAccess = operationReceiver as? FirQualifiedAccessExpression ?: return null
|
||||
val receiverExpression = if (receiverValue != qualifiedAccess) {
|
||||
receiverValue
|
||||
} else {
|
||||
null
|
||||
}
|
||||
callGenerator.convertToIrCall(
|
||||
qualifiedAccess,
|
||||
qualifiedAccess.typeRef,
|
||||
convertToIrReceiverExpression(receiverExpression, qualifiedAccess.calleeReference),
|
||||
annotationMode = false
|
||||
)
|
||||
}
|
||||
return callGenerator.convertToIrCall(
|
||||
operationCall, operationCall.typeRef, explicitReceiverExpression, annotationMode = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun FirBlock.convertToIrExpressionOrBlock(origin: IrStatementOrigin? = null): IrExpression {
|
||||
if (this.source?.kind == KtFakeSourceElementKind.DesugaredIncrementOrDecrement) {
|
||||
tryConvertDynamicIncrementOrDecrementToIr()?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
return statements.convertToIrExpressionOrBlock(source, origin)
|
||||
}
|
||||
|
||||
@@ -1205,11 +1313,26 @@ class Fir2IrVisitor(
|
||||
return callGenerator.convertToGetObject(resolvedQualifier)
|
||||
}
|
||||
|
||||
private fun LogicOperationKind.toIrDynamicOperator() = when (this) {
|
||||
LogicOperationKind.AND -> IrDynamicOperator.ANDAND
|
||||
LogicOperationKind.OR -> IrDynamicOperator.OROR
|
||||
}
|
||||
|
||||
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: Any?): IrElement {
|
||||
return binaryLogicExpression.convertWithOffsets<IrElement> { startOffset, endOffset ->
|
||||
val leftOperand = binaryLogicExpression.leftOperand.accept(this, data) as IrExpression
|
||||
val rightOperand = binaryLogicExpression.rightOperand.accept(this, data) as IrExpression
|
||||
when (binaryLogicExpression.kind) {
|
||||
if (leftOperand.type is IrDynamicType) {
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
irBuiltIns.booleanType,
|
||||
binaryLogicExpression.kind.toIrDynamicOperator(),
|
||||
).apply {
|
||||
receiver = leftOperand
|
||||
arguments.add(rightOperand)
|
||||
}
|
||||
} else when (binaryLogicExpression.kind) {
|
||||
LogicOperationKind.AND -> {
|
||||
IrIfThenElseImpl(startOffset, endOffset, irBuiltIns.booleanType, IrStatementOrigin.ANDAND).apply {
|
||||
branches.add(IrBranchImpl(leftOperand, rightOperand))
|
||||
|
||||
+220
-9
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
@@ -43,10 +44,13 @@ import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.isMethodOfAny
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
||||
import org.jetbrains.kotlin.psi2ir.generators.isUnchanging
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class CallAndReferenceGenerator(
|
||||
private val components: Fir2IrComponents,
|
||||
@@ -269,12 +273,98 @@ class CallAndReferenceGenerator(
|
||||
return null
|
||||
}
|
||||
|
||||
private val Name.dynamicOperator
|
||||
get() = when (this) {
|
||||
OperatorNameConventions.UNARY_PLUS -> IrDynamicOperator.UNARY_PLUS
|
||||
OperatorNameConventions.UNARY_MINUS -> IrDynamicOperator.UNARY_MINUS
|
||||
OperatorNameConventions.NOT -> IrDynamicOperator.EXCL
|
||||
OperatorNameConventions.PLUS -> IrDynamicOperator.BINARY_PLUS
|
||||
OperatorNameConventions.MINUS -> IrDynamicOperator.BINARY_MINUS
|
||||
OperatorNameConventions.TIMES -> IrDynamicOperator.MUL
|
||||
OperatorNameConventions.DIV -> IrDynamicOperator.DIV
|
||||
OperatorNameConventions.REM -> IrDynamicOperator.MOD
|
||||
OperatorNameConventions.AND -> IrDynamicOperator.ANDAND
|
||||
OperatorNameConventions.OR -> IrDynamicOperator.OROR
|
||||
OperatorNameConventions.EQUALS -> IrDynamicOperator.EQEQ
|
||||
OperatorNameConventions.PLUS_ASSIGN -> IrDynamicOperator.PLUSEQ
|
||||
OperatorNameConventions.MINUS_ASSIGN -> IrDynamicOperator.MINUSEQ
|
||||
OperatorNameConventions.TIMES_ASSIGN -> IrDynamicOperator.MULEQ
|
||||
OperatorNameConventions.DIV_ASSIGN -> IrDynamicOperator.DIVEQ
|
||||
OperatorNameConventions.REM_ASSIGN -> IrDynamicOperator.MODEQ
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val FirQualifiedAccess.dynamicOperator
|
||||
get() = when (calleeReference.source?.kind) {
|
||||
is KtFakeSourceElementKind.ArrayAccessNameReference -> when (calleeReference.resolved?.name) {
|
||||
OperatorNameConventions.SET -> IrDynamicOperator.EQ
|
||||
OperatorNameConventions.GET -> IrDynamicOperator.ARRAY_ACCESS
|
||||
else -> error("Unexpected name")
|
||||
}
|
||||
is KtFakeSourceElementKind.DesugaredPrefixNameReference -> when (calleeReference.resolved?.name) {
|
||||
OperatorNameConventions.INC -> IrDynamicOperator.PREFIX_INCREMENT
|
||||
OperatorNameConventions.DEC -> IrDynamicOperator.PREFIX_DECREMENT
|
||||
else -> error("Unexpected name")
|
||||
}
|
||||
is KtFakeSourceElementKind.DesugaredPostfixNameReference -> when (calleeReference.resolved?.name) {
|
||||
OperatorNameConventions.INC -> IrDynamicOperator.POSTFIX_INCREMENT
|
||||
OperatorNameConventions.DEC -> IrDynamicOperator.POSTFIX_DECREMENT
|
||||
else -> error("Unexpected name")
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun convertToIrCallForDynamic(
|
||||
qualifiedAccess: FirQualifiedAccess,
|
||||
explicitReceiverExpression: IrExpression,
|
||||
type: IrType,
|
||||
calleeReference: FirReference,
|
||||
symbol: FirBasedSymbol<*>,
|
||||
annotationMode: Boolean = false,
|
||||
dynamicOperator: IrDynamicOperator? = null,
|
||||
noArguments: Boolean = false,
|
||||
): IrExpression {
|
||||
var convertedExplicitReceiver = explicitReceiverExpression
|
||||
|
||||
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
||||
when (symbol) {
|
||||
is FirFunctionSymbol<*> -> {
|
||||
val name = calleeReference.resolved?.name
|
||||
?: error("Must have a name")
|
||||
val operator = dynamicOperator
|
||||
?: name.dynamicOperator
|
||||
?: qualifiedAccess.dynamicOperator
|
||||
?: IrDynamicOperator.INVOKE
|
||||
val theType = if (name == OperatorNameConventions.COMPARE_TO) {
|
||||
typeConverter.irBuiltIns.booleanType
|
||||
} else {
|
||||
type
|
||||
}
|
||||
if (operator == IrDynamicOperator.INVOKE && qualifiedAccess !is FirImplicitInvokeCall) {
|
||||
convertedExplicitReceiver = IrDynamicMemberExpressionImpl(
|
||||
startOffset, endOffset, type, name.identifier, explicitReceiverExpression
|
||||
)
|
||||
}
|
||||
IrDynamicOperatorExpressionImpl(startOffset, endOffset, theType, operator)
|
||||
}
|
||||
is FirPropertySymbol -> {
|
||||
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
||||
IrDynamicMemberExpressionImpl(startOffset, endOffset, type, name.identifier, explicitReceiverExpression)
|
||||
}
|
||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference, type)
|
||||
}
|
||||
}.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, convertedExplicitReceiver)
|
||||
.applyCallArguments((qualifiedAccess as? FirCall)?.takeIf { !noArguments }, annotationMode)
|
||||
}
|
||||
|
||||
fun convertToIrCall(
|
||||
qualifiedAccess: FirQualifiedAccess,
|
||||
typeRef: FirTypeRef,
|
||||
explicitReceiverExpression: IrExpression?,
|
||||
annotationMode: Boolean = false,
|
||||
variableAsFunctionMode: Boolean = false
|
||||
dynamicOperator: IrDynamicOperator? = null,
|
||||
variableAsFunctionMode: Boolean = false,
|
||||
noArguments: Boolean = false
|
||||
): IrExpression {
|
||||
try {
|
||||
val type = typeRef.toIrType()
|
||||
@@ -283,10 +373,45 @@ class CallAndReferenceGenerator(
|
||||
|
||||
val dispatchReceiver = qualifiedAccess.dispatchReceiver
|
||||
val calleeReference = qualifiedAccess.calleeReference
|
||||
|
||||
val firSymbol = calleeReference.resolvedSymbol
|
||||
val isDynamicAccess = firSymbol?.origin == FirDeclarationOrigin.DynamicScope
|
||||
|
||||
if (isDynamicAccess) {
|
||||
return convertToIrCallForDynamic(
|
||||
qualifiedAccess,
|
||||
explicitReceiverExpression ?: error("Must've had a receiver"),
|
||||
type,
|
||||
calleeReference,
|
||||
firSymbol ?: error("Must have had a symbol"),
|
||||
annotationMode,
|
||||
dynamicOperator,
|
||||
noArguments,
|
||||
)
|
||||
}
|
||||
|
||||
val symbol = calleeReference.toSymbolForCall(
|
||||
dispatchReceiver,
|
||||
conversionScope
|
||||
)
|
||||
|
||||
// We might have had a dynamic receiver, but resolved
|
||||
// into a non-fake member. For example, we can
|
||||
// resolve into members of `Any`.
|
||||
val convertedExplicitReceiver = if (explicitReceiverExpression?.type is IrDynamicType) {
|
||||
qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
||||
val targetType = (firSymbol?.fir as? FirCallableDeclaration)?.dispatchReceiverType?.toIrType()
|
||||
?: error("Couldn't get the proper receiver")
|
||||
IrTypeOperatorCallImpl(
|
||||
startOffset, endOffset, targetType,
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST,
|
||||
targetType, explicitReceiverExpression,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
explicitReceiverExpression
|
||||
}
|
||||
|
||||
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
|
||||
if (calleeReference is FirSuperReference) {
|
||||
if (dispatchReceiver !is FirNoReceiverExpression) {
|
||||
@@ -339,15 +464,17 @@ class CallAndReferenceGenerator(
|
||||
origin = IrStatementOrigin.GET_PROPERTY.takeIf { calleeReference !is FirDelegateFieldReference },
|
||||
superQualifierSymbol = dispatchReceiver.superQualifierSymbol()
|
||||
)
|
||||
is IrValueSymbol -> IrGetValueImpl(
|
||||
startOffset, endOffset, type, symbol,
|
||||
origin = if (variableAsFunctionMode) IrStatementOrigin.VARIABLE_AS_FUNCTION
|
||||
else calleeReference.statementOrigin()
|
||||
)
|
||||
is IrValueSymbol -> {
|
||||
IrGetValueImpl(
|
||||
startOffset, endOffset, type, symbol,
|
||||
origin = if (variableAsFunctionMode) IrStatementOrigin.VARIABLE_AS_FUNCTION
|
||||
else calleeReference.statementOrigin()
|
||||
)
|
||||
}
|
||||
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference, type)
|
||||
}
|
||||
}.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, explicitReceiverExpression)
|
||||
}.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, convertedExplicitReceiver)
|
||||
.applyCallArguments(qualifiedAccess, annotationMode)
|
||||
} catch (e: Throwable) {
|
||||
throw IllegalStateException(
|
||||
@@ -357,16 +484,58 @@ class CallAndReferenceGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertToIrSetCallForDynamic(
|
||||
variableAssignment: FirVariableAssignment,
|
||||
explicitReceiverExpression: IrExpression,
|
||||
type: IrType,
|
||||
calleeReference: FirReference,
|
||||
symbol: FirBasedSymbol<*>,
|
||||
assignedValue: IrExpression,
|
||||
): IrExpression {
|
||||
var convertedExplicitReceiver = explicitReceiverExpression
|
||||
|
||||
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
||||
when (symbol) {
|
||||
is FirPropertySymbol -> {
|
||||
val name = calleeReference.resolved?.name ?: error("There must be a name")
|
||||
convertedExplicitReceiver = IrDynamicMemberExpressionImpl(
|
||||
startOffset, endOffset, type, name.identifier, explicitReceiverExpression
|
||||
)
|
||||
IrDynamicOperatorExpressionImpl(startOffset, endOffset, type, IrDynamicOperator.EQ).apply {
|
||||
arguments.add(assignedValue)
|
||||
}
|
||||
}
|
||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||
}
|
||||
}.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment, convertedExplicitReceiver)
|
||||
}
|
||||
|
||||
fun convertToIrSetCall(variableAssignment: FirVariableAssignment, explicitReceiverExpression: IrExpression?): IrExpression {
|
||||
try {
|
||||
val type = irBuiltIns.unitType
|
||||
val calleeReference = variableAssignment.calleeReference
|
||||
val assignedValue = visitor.convertToIrExpression(variableAssignment.rValue)
|
||||
|
||||
val firSymbol = calleeReference.resolvedSymbol
|
||||
val isDynamicAccess = firSymbol?.origin == FirDeclarationOrigin.DynamicScope
|
||||
|
||||
if (isDynamicAccess) {
|
||||
return convertToIrSetCallForDynamic(
|
||||
variableAssignment,
|
||||
explicitReceiverExpression ?: error("Must've had a receiver"),
|
||||
type,
|
||||
calleeReference,
|
||||
firSymbol ?: error("Must've had a symbol"),
|
||||
assignedValue,
|
||||
)
|
||||
}
|
||||
|
||||
val symbol = calleeReference.toSymbolForCall(
|
||||
variableAssignment.dispatchReceiver, conversionScope, preferGetter = false
|
||||
)
|
||||
val origin = variableAssignment.getIrAssignmentOrigin()
|
||||
|
||||
return variableAssignment.convertWithOffsets { startOffset, endOffset ->
|
||||
val assignedValue = visitor.convertToIrExpression(variableAssignment.rValue)
|
||||
when (symbol) {
|
||||
is IrFieldSymbol -> IrSetFieldImpl(startOffset, endOffset, symbol, type, origin).apply {
|
||||
value = assignedValue
|
||||
@@ -421,7 +590,9 @@ class CallAndReferenceGenerator(
|
||||
putValueArgument(0, assignedValue)
|
||||
}
|
||||
}
|
||||
is IrVariableSymbol -> IrSetValueImpl(startOffset, endOffset, type, symbol, assignedValue, origin)
|
||||
is IrVariableSymbol -> {
|
||||
IrSetValueImpl(startOffset, endOffset, type, symbol, assignedValue, origin)
|
||||
}
|
||||
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
|
||||
}
|
||||
}.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment, explicitReceiverExpression)
|
||||
@@ -551,6 +722,28 @@ class CallAndReferenceGenerator(
|
||||
return ConeSubstitutorByMap(map, session)
|
||||
}
|
||||
|
||||
private fun extractArgumentsMapping(
|
||||
call: FirCall
|
||||
): Triple<List<FirValueParameter>?, Map<FirExpression, FirValueParameter>?, ConeSubstitutor> {
|
||||
val calleeReference = when (call) {
|
||||
is FirFunctionCall -> call.calleeReference
|
||||
is FirDelegatedConstructorCall -> call.calleeReference
|
||||
is FirAnnotationCall -> call.calleeReference
|
||||
else -> null
|
||||
}
|
||||
val function = if (calleeReference == FirReferencePlaceholderForResolvedAnnotations) {
|
||||
val coneClassLikeType = (call as FirAnnotation).annotationTypeRef.coneTypeSafe<ConeClassLikeType>()
|
||||
val firClass = (coneClassLikeType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol)?.fir
|
||||
firClass?.declarations?.filterIsInstance<FirConstructor>()?.firstOrNull()
|
||||
} else {
|
||||
((calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirFunctionSymbol<*>)?.fir
|
||||
}
|
||||
val valueParameters = function?.valueParameters
|
||||
val argumentMapping = call.resolvedArgumentMapping
|
||||
val substitutor = (call as? FirFunctionCall)?.buildSubstitutorByCalledFunction(function) ?: ConeSubstitutor.Empty
|
||||
return Triple(valueParameters, argumentMapping, substitutor)
|
||||
}
|
||||
|
||||
internal fun IrExpression.applyCallArguments(
|
||||
statement: FirStatement?,
|
||||
annotationMode: Boolean
|
||||
@@ -613,6 +806,21 @@ class CallAndReferenceGenerator(
|
||||
}
|
||||
}
|
||||
}
|
||||
is IrDynamicOperatorExpression -> apply {
|
||||
if (call == null) return@apply
|
||||
val (valueParameters, argumentMapping, substitutor) = extractArgumentsMapping(call)
|
||||
if (argumentMapping != null && (annotationMode || argumentMapping.isNotEmpty())) {
|
||||
if (valueParameters != null) {
|
||||
val dynamicCallVarargArgument = argumentMapping.keys.firstOrNull()
|
||||
?.safeAs<FirVarargArgumentsExpression>()
|
||||
?: error("Dynamic call must have a single vararg argument")
|
||||
for (argument in dynamicCallVarargArgument.arguments) {
|
||||
val irArgument = convertArgument(argument, null, substitutor, annotationMode)
|
||||
arguments.add(irArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is IrErrorCallExpressionImpl -> apply {
|
||||
for (argument in call?.arguments.orEmpty()) {
|
||||
addArgument(visitor.convertToIrExpression(argument))
|
||||
@@ -857,6 +1065,9 @@ class CallAndReferenceGenerator(
|
||||
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
|
||||
}
|
||||
}
|
||||
is IrDynamicOperatorExpression -> {
|
||||
receiver = explicitReceiverExpression ?: error("No receiver for dynamic")
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
+89
-10
@@ -7,17 +7,14 @@ package org.jetbrains.kotlin.fir.backend.generators
|
||||
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.fir.types.isNullable
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.ir.builders.primitiveOp1
|
||||
import org.jetbrains.kotlin.ir.builders.primitiveOp2
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.getSimpleFunction
|
||||
@@ -45,6 +42,24 @@ internal class OperatorExpressionGenerator(
|
||||
comparisonExpression: FirComparisonExpression
|
||||
): IrExpression {
|
||||
val operation = comparisonExpression.operation
|
||||
val receiver = comparisonExpression.compareToCall.explicitReceiver
|
||||
|
||||
if (receiver?.typeRef?.coneType is ConeDynamicType) {
|
||||
val dynamicOperator = operation.toIrDynamicOperator()
|
||||
?: throw Exception("Can't convert to the corresponding IrDynamicOperator")
|
||||
val argument = comparisonExpression.compareToCall.dynamicVarargArguments?.firstOrNull()
|
||||
?: throw Exception("Comparison with a dynamic function should have a vararg with the rhs-argument")
|
||||
|
||||
return IrDynamicOperatorExpressionImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
irBuiltIns.booleanType,
|
||||
dynamicOperator,
|
||||
).apply {
|
||||
this.receiver = receiver.accept(visitor, null) as IrExpression
|
||||
arguments.add(argument.accept(visitor, null) as IrExpression)
|
||||
}
|
||||
}
|
||||
|
||||
fun fallbackToRealCall(): IrExpression {
|
||||
val (symbol, origin) = getSymbolAndOriginForComparison(operation, irBuiltIns.intType.classifierOrFail)
|
||||
@@ -92,6 +107,14 @@ internal class OperatorExpressionGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirOperation.toIrDynamicOperator() = when (this) {
|
||||
FirOperation.LT -> IrDynamicOperator.LT
|
||||
FirOperation.LT_EQ -> IrDynamicOperator.LE
|
||||
FirOperation.GT -> IrDynamicOperator.GT
|
||||
FirOperation.GT_EQ -> IrDynamicOperator.GE
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun generateEqualityOperatorCall(
|
||||
startOffset: Int, endOffset: Int, operation: FirOperation, arguments: List<FirExpression>
|
||||
): IrExpression = when (operation) {
|
||||
@@ -100,6 +123,37 @@ internal class OperatorExpressionGenerator(
|
||||
else -> error("Unexpected operation: $operation")
|
||||
}
|
||||
|
||||
private fun IrStatementOrigin.toIrDynamicOperator() = when (this) {
|
||||
is IrStatementOrigin.EQEQ -> IrDynamicOperator.EQEQ
|
||||
is IrStatementOrigin.EXCLEQ -> IrDynamicOperator.EXCLEQ
|
||||
is IrStatementOrigin.EQEQEQ -> IrDynamicOperator.EQEQEQ
|
||||
is IrStatementOrigin.EXCLEQEQ -> IrDynamicOperator.EXCLEQEQ
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun tryGenerateDynamicOperatorCall(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
firstArgument: IrExpression,
|
||||
secondArgument: IrExpression,
|
||||
origin: IrStatementOrigin,
|
||||
) = if (firstArgument.type is IrDynamicType) {
|
||||
val dynamicOperator = origin.toIrDynamicOperator()
|
||||
?: throw Exception("Couldn't convert to the corresponding IrDynamicOperator")
|
||||
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
irBuiltIns.booleanType,
|
||||
dynamicOperator,
|
||||
).apply {
|
||||
receiver = firstArgument
|
||||
arguments.add(secondArgument)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private fun transformEqualityOperatorCall(
|
||||
startOffset: Int, endOffset: Int, operation: FirOperation, arguments: List<FirExpression>
|
||||
): IrExpression {
|
||||
@@ -109,6 +163,20 @@ internal class OperatorExpressionGenerator(
|
||||
else -> error("Not an equality operation: $operation")
|
||||
}
|
||||
val comparisonInfo = inferPrimitiveNumericComparisonInfo(arguments[0], arguments[1])
|
||||
|
||||
val convertedLeft = arguments[0].convertToIrExpression(comparisonInfo, isLeftType = true)
|
||||
val convertedRight = arguments[1].convertToIrExpression(comparisonInfo, isLeftType = false)
|
||||
|
||||
tryGenerateDynamicOperatorCall(
|
||||
startOffset,
|
||||
endOffset,
|
||||
convertedLeft,
|
||||
convertedRight,
|
||||
origin,
|
||||
)?.let {
|
||||
return it
|
||||
}
|
||||
|
||||
val comparisonType = comparisonInfo?.comparisonType
|
||||
val eqeqSymbol = comparisonType?.let { typeConverter.classIdToSymbolMap[it.lookupTag.classId] }
|
||||
?.let { irBuiltIns.ieee754equalsFunByOperandType[it] } ?: irBuiltIns.eqeqSymbol
|
||||
@@ -119,8 +187,8 @@ internal class OperatorExpressionGenerator(
|
||||
eqeqSymbol,
|
||||
irBuiltIns.booleanType,
|
||||
origin,
|
||||
arguments[0].convertToIrExpression(comparisonInfo, isLeftType = true),
|
||||
arguments[1].convertToIrExpression(comparisonInfo, isLeftType = false)
|
||||
convertedLeft,
|
||||
convertedRight
|
||||
)
|
||||
return if (operation == FirOperation.EQ) {
|
||||
equalsCall
|
||||
@@ -137,13 +205,24 @@ internal class OperatorExpressionGenerator(
|
||||
FirOperation.NOT_IDENTITY -> IrStatementOrigin.EXCLEQEQ
|
||||
else -> error("Not an identity operation: $operation")
|
||||
}
|
||||
val convertedLeft = visitor.convertToIrExpression(arguments[0])
|
||||
val convertedRight = visitor.convertToIrExpression(arguments[1])
|
||||
tryGenerateDynamicOperatorCall(
|
||||
startOffset,
|
||||
endOffset,
|
||||
convertedLeft,
|
||||
convertedRight,
|
||||
origin,
|
||||
)?.let {
|
||||
return it
|
||||
}
|
||||
val identityCall = primitiveOp2(
|
||||
startOffset, endOffset,
|
||||
irBuiltIns.eqeqeqSymbol,
|
||||
irBuiltIns.booleanType,
|
||||
origin,
|
||||
visitor.convertToIrExpression(arguments[0]),
|
||||
visitor.convertToIrExpression(arguments[1])
|
||||
convertedLeft,
|
||||
convertedRight
|
||||
)
|
||||
return if (operation == FirOperation.IDENTITY) {
|
||||
identityCall
|
||||
|
||||
Reference in New Issue
Block a user