Move extension receiver to value parameters for static functions created

during InlineClassLowering phase.

This was the only place where both dispatch and extension receivers were
NOT moved to value parameters, which meant that the receivers were not
following the conventional ordering.

Merged createStaticBodilessMethod with createStaticFunctionWithReceivers
and the latter was moved to backend/common/ir/IrUtils.kt.
This commit is contained in:
Mark Punzalan
2019-06-27 21:42:44 -07:00
committed by max-kammerer
parent 1abdf0561a
commit 969478481e
13 changed files with 129 additions and 197 deletions
@@ -20,9 +20,11 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.builders.Scope
@@ -499,3 +501,58 @@ fun IrClass.addFakeOverrides() {
declarations += fakeOverriddenFunctions.values declarations += fakeOverriddenFunctions.values
} }
fun createStaticFunctionWithReceivers(
irParent: IrDeclarationParent,
name: Name,
oldFunction: IrFunction,
dispatchReceiverType: IrType? = oldFunction.dispatchReceiverParameter?.type,
origin: IrDeclarationOrigin = oldFunction.origin,
copyBody: Boolean = true
): IrSimpleFunction {
val descriptor = WrappedSimpleFunctionDescriptor(Annotations.EMPTY, oldFunction.descriptor.source)
return IrFunctionImpl(
oldFunction.startOffset, oldFunction.endOffset,
origin,
IrSimpleFunctionSymbolImpl(descriptor),
name,
oldFunction.visibility,
Modality.FINAL,
oldFunction.returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false
).apply {
descriptor.bind(this)
parent = irParent
copyTypeParametersFrom(oldFunction)
annotations.addAll(oldFunction.annotations)
var offset = 0
val dispatchReceiver = oldFunction.dispatchReceiverParameter?.copyTo(
this,
name = Name.identifier("this"),
index = offset++,
type = dispatchReceiverType!!
)
val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo(
this,
name = Name.identifier("receiver"),
index = offset++
)
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
oldFunction.valueParameters.map { it.copyTo(this, index = it.index + offset) }
)
val mapping: Map<IrValueParameter, IrValueParameter> =
(listOfNotNull(oldFunction.dispatchReceiverParameter, oldFunction.extensionReceiverParameter) + oldFunction.valueParameters)
.zip(valueParameters).toMap()
if (copyBody) {
body = oldFunction.body
?.transform(VariableRemapper(mapping), null)
?.patchDeclarationParents(this)
}
metadata = oldFunction.metadata
}
}
@@ -8,18 +8,13 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -142,10 +137,12 @@ class InlineClassLowering(val context: BackendContext) {
staticMethod.valueParameters[0] staticMethod.valueParameters[0]
function.extensionReceiverParameter -> function.extensionReceiverParameter ->
staticMethod.extensionReceiverParameter!! staticMethod.valueParameters[1]
in function.valueParameters -> in function.valueParameters -> {
staticMethod.valueParameters[valueDeclaration.index + 1] val offset = if (function.extensionReceiverParameter != null) 2 else 1
staticMethod.valueParameters[valueDeclaration.index + offset]
}
else -> return expression else -> return expression
} }
@@ -163,13 +160,14 @@ class InlineClassLowering(val context: BackendContext) {
+irReturn( +irReturn(
irCall(staticMethod).apply { irCall(staticMethod).apply {
val parameters = val parameters =
listOf(function.dispatchReceiverParameter!!) + function.valueParameters listOfNotNull(
function.dispatchReceiverParameter!!,
function.extensionReceiverParameter
) + function.valueParameters
for ((index, valueParameter) in parameters.withIndex()) { for ((index, valueParameter) in parameters.withIndex()) {
putValueArgument(index, irGet(valueParameter)) putValueArgument(index, irGet(valueParameter))
} }
extensionReceiver = function.extensionReceiverParameter?.let { irGet(it) }
} }
) )
} }
@@ -190,7 +188,7 @@ class InlineClassLowering(val context: BackendContext) {
return expression return expression
} }
return irCall(expression, getOrCreateStaticMethod(function), dispatchReceiverAsArgument = false) return irCall(expression, getOrCreateStaticMethod(function))
} }
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
@@ -208,7 +206,7 @@ class InlineClassLowering(val context: BackendContext) {
return irCall( return irCall(
expression, expression,
getOrCreateStaticMethod(function), getOrCreateStaticMethod(function),
dispatchReceiverAsArgument = (function is IrSimpleFunction) receiversAsArguments = (function is IrSimpleFunction)
) )
} }
@@ -219,11 +217,7 @@ class InlineClassLowering(val context: BackendContext) {
return when { return when {
!klass.isInline -> expression !klass.isInline -> expression
function.isPrimary -> irConstructorCall(expression, function) function.isPrimary -> irConstructorCall(expression, function)
else -> irCall(expression, getOrCreateStaticMethod(function)).apply { else -> irCall(expression, getOrCreateStaticMethod(function))
(0 until expression.valueArgumentsCount).forEach {
putValueArgument(it, expression.getValueArgument(it)!!)
}
}
} }
} }
@@ -242,36 +236,6 @@ class InlineClassLowering(val context: BackendContext) {
else -> Name.identifier(asString() + INLINE_CLASS_IMPL_SUFFIX) else -> Name.identifier(asString() + INLINE_CLASS_IMPL_SUFFIX)
} }
private fun createStaticBodilessMethod(function: IrFunction): IrSimpleFunction { private fun createStaticBodilessMethod(function: IrFunction): IrSimpleFunction =
val descriptor = WrappedSimpleFunctionDescriptor() createStaticFunctionWithReceivers(function.parent, function.name.toInlineClassImplementationName(), function, copyBody = false)
return IrFunctionImpl(
function.startOffset,
function.endOffset,
function.origin,
IrSimpleFunctionSymbolImpl(descriptor),
function.name.toInlineClassImplementationName(),
function.visibility,
Modality.FINAL,
function.returnType,
function.isInline,
function.isExternal,
(function is IrSimpleFunction && function.isTailrec),
(function is IrSimpleFunction && function.isSuspend)
).apply {
descriptor.bind(this)
copyTypeParametersFrom(function)
annotations += function.annotations
dispatchReceiverParameter = null
extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this)
if (function is IrSimpleFunction) {
valueParameters.add(function.dispatchReceiverParameter!!.let { p -> p.copyTo(this, index = p.index + 1) })
valueParameters += function.valueParameters.map { p -> p.copyTo(this, index = p.index + 1) }
} else {
valueParameters += function.valueParameters.map { p -> p.copyTo(this) }
}
parent = function.parent
assert(isStaticMethodOfClass)
}
}
} }
@@ -47,7 +47,7 @@ internal fun <K> MutableMap<K, (IrFunctionAccessExpression) -> IrExpression>.add
internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrFunctionAccessExpression) -> IrExpression> internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrFunctionAccessExpression) -> IrExpression>
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunctionSymbol) { internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunctionSymbol) {
add(type, name) { irCall(it, v, dispatchReceiverAsArgument = true) } add(type, name) { irCall(it, v, receiversAsArguments = true) }
} }
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunction) { internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunction) {
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.isStaticMethodOfClass import org.jetbrains.kotlin.ir.declarations.isStaticMethodOfClass
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
@@ -53,7 +53,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
comparator.owner.returnType, comparator.owner.returnType,
comparator comparator
).apply { ).apply {
putValueArgument(0, irCall(call, intrinsics.longCompareToLong, argumentAsDispatchReceiver = true)) putValueArgument(0, irCall(call, intrinsics.longCompareToLong, argumentsAsReceivers = true))
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 0)) putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 0))
} }
} }
@@ -95,7 +95,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
chooseEqualityOperatorForPrimitiveTypes(call) chooseEqualityOperatorForPrimitiveTypes(call)
!isLhsPrimitive && !lhs.type.isNullable() && equalsMethod != null -> !isLhsPrimitive && !lhs.type.isNullable() && equalsMethod != null ->
irCall(call, equalsMethod.symbol, argumentAsDispatchReceiver = true) irCall(call, equalsMethod.symbol, argumentsAsReceivers = true)
else -> else ->
irCall(call, intrinsics.jsEquals) irCall(call, intrinsics.jsEquals)
@@ -127,7 +127,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `compareTo` method, // Use runtime function call in case when receiverType is a primitive JS type that doesn't have `compareTo` method,
// or has a potential to be primitive type (being fake overridden from `Comparable`) // or has a potential to be primitive type (being fake overridden from `Comparable`)
function.isMethodOfPrimitiveJSType() || function.isFakeOverriddenFromComparable() -> function.isMethodOfPrimitiveJSType() || function.isFakeOverriddenFromComparable() ->
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsCompareTo, receiversAsArguments = true)
// Valid `compareTo` method must be present at this point // Valid `compareTo` method must be present at this point
else -> else ->
@@ -144,12 +144,12 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
// `Any.equals` works as identity operator // `Any.equals` works as identity operator
call.isSuperToAny() -> call.isSuperToAny() ->
irCall(call, intrinsics.jsEqeqeq, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsEqeqeq, receiversAsArguments = true)
// Use runtime function call in case when receiverType is a primitive JS type that doesn't have `equals` method, // Use runtime function call in case when receiverType is a primitive JS type that doesn't have `equals` method,
// or has a potential to be primitive type (being fake overridden from `Any`) // or has a potential to be primitive type (being fake overridden from `Any`)
function.isMethodOfPotentiallyPrimitiveJSType() -> function.isMethodOfPotentiallyPrimitiveJSType() ->
irCall(call, intrinsics.jsEquals, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsEquals, receiversAsArguments = true)
// Valid `equals` method must be present at this point // Valid `equals` method must be present at this point
else -> call else -> call
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.lower.calls
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.util.kotlinPackageFqn import org.jetbrains.kotlin.ir.util.kotlinPackageFqn
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -29,9 +29,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
put(Name.identifier("toString")) { call -> put(Name.identifier("toString")) { call ->
if (shouldReplaceToStringWithRuntimeCall(call)) { if (shouldReplaceToStringWithRuntimeCall(call)) {
if ((call as IrCall).isSuperToAny()) { if ((call as IrCall).isSuperToAny()) {
irCall(call, intrinsics.jsAnyToString, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsAnyToString, receiversAsArguments = true)
} else { } else {
irCall(call, intrinsics.jsToString, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsToString, receiversAsArguments = true)
} }
} else { } else {
call call
@@ -41,9 +41,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
put(Name.identifier("hashCode")) { call -> put(Name.identifier("hashCode")) { call ->
if (call.symbol.owner.isFakeOverriddenFromAny()) { if (call.symbol.owner.isFakeOverriddenFromAny()) {
if ((call as IrCall).isSuperToAny()) { if ((call as IrCall).isSuperToAny()) {
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsGetObjectHashCode, receiversAsArguments = true)
} else { } else {
irCall(call, intrinsics.jsHashCode, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsHashCode, receiversAsArguments = true)
} }
} else { } else {
call call
@@ -46,9 +46,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
irBuiltIns.booleanType.let { irBuiltIns.booleanType.let {
// These operators are not short-circuit -- using bitwise operators '&', '|', '^' followed by coercion to boolean // These operators are not short-circuit -- using bitwise operators '&', '|', '^' followed by coercion to boolean
add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, dispatchReceiverAsArgument = true)) } add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, receiversAsArguments = true)) }
add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, dispatchReceiverAsArgument = true)) } add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, receiversAsArguments = true)) }
add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, dispatchReceiverAsArgument = true)) } add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, receiversAsArguments = true)) }
add(it, OperatorNames.NOT, intrinsics.jsNot) add(it, OperatorNames.NOT, intrinsics.jsNot)
} }
@@ -88,9 +88,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
return with(call.symbol.owner.valueParameters[0].type) { return with(call.symbol.owner.valueParameters[0].type) {
when { when {
isByte() || isShort() || isInt() -> isByte() || isShort() || isInt() ->
irCall(call, intrinsics.jsNumberRangeToNumber, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsNumberRangeToNumber, receiversAsArguments = true)
isLong() -> isLong() ->
irCall(call, intrinsics.jsNumberRangeToLong, dispatchReceiverAsArgument = true) irCall(call, intrinsics.jsNumberRangeToLong, receiversAsArguments = true)
else -> call else -> call
} }
} }
@@ -101,7 +101,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
intrinsic: IrFunctionSymbol, intrinsic: IrFunctionSymbol,
toInt32: Boolean = false toInt32: Boolean = false
): IrExpression { ): IrExpression {
val newCall = irCall(call, intrinsic, dispatchReceiverAsArgument = true) val newCall = irCall(call, intrinsic, receiversAsArguments = true)
if (toInt32) if (toInt32)
return toInt32(newCall) return toInt32(newCall)
return newCall return newCall
@@ -152,7 +152,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
transformCrement(call, intrinsics.jsMinus) transformCrement(call, intrinsics.jsMinus)
private fun transformCrement(call: IrFunctionAccessExpression, correspondingBinaryOp: IrFunctionSymbol): IrExpression { private fun transformCrement(call: IrFunctionAccessExpression, correspondingBinaryOp: IrFunctionSymbol): IrExpression {
val operation = irCall(call, correspondingBinaryOp, dispatchReceiverAsArgument = true).apply { val operation = irCall(call, correspondingBinaryOp, receiversAsArguments = true).apply {
putValueArgument(1, buildInt(1)) putValueArgument(1, buildInt(1))
} }
@@ -161,7 +161,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
private fun transformUnaryMinus(call: IrFunctionAccessExpression) = private fun transformUnaryMinus(call: IrFunctionAccessExpression) =
convertResultToPrimitiveType( convertResultToPrimitiveType(
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsArgument = true), irCall(call, intrinsics.jsUnaryMinus, receiversAsArguments = true),
call.type call.type
) )
@@ -9,37 +9,29 @@ import org.jetbrains.kotlin.backend.common.deepCopyWithWrappedDescriptors
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.setSourceRange import org.jetbrains.kotlin.ir.builders.setSourceRange
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.org.objectweb.asm.Opcodes
import java.util.* import java.util.*
class JvmDeclarationFactory( class JvmDeclarationFactory(
@@ -205,7 +205,7 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl
if (superCallee.isDefinitelyNotDefaultImplsMethod()) return super.visitCall(expression) if (superCallee.isDefinitelyNotDefaultImplsMethod()) return super.visitCall(expression)
val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee) val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee)
val newCall = irCall(expression, redirectTarget, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true) val newCall = irCall(expression, redirectTarget, receiversAsArguments = true)
return super.visitCall(newCall) return super.visitCall(newCall)
} }
@@ -6,36 +6,27 @@
package org.jetbrains.kotlin.backend.jvm.lower package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering.Companion.clinitName import org.jetbrains.kotlin.backend.common.lower.InitializersLowering.Companion.clinitName
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
internal val interfacePhase = makeIrFilePhase( internal val interfacePhase = makeIrFilePhase(
::InterfaceLowering, ::InterfaceLowering,
@@ -127,7 +118,7 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
val newFunction = removedFunctions[expression.symbol]?.owner val newFunction = removedFunctions[expression.symbol]?.owner
return super.visitCall( return super.visitCall(
if (newFunction != null) { if (newFunction != null) {
irCall(expression, newFunction, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true) irCall(expression, newFunction, receiversAsArguments = true)
} else { } else {
expression expression
} }
@@ -148,7 +139,7 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
typeArgumentsCount, typeArgumentsCount,
origin origin
).apply { ).apply {
copyTypeAndValueArgumentsFrom(expression, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true) copyTypeAndValueArgumentsFrom(expression, receiversAsArguments = true)
} }
} }
} else { } else {
@@ -157,56 +148,3 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
) )
} }
} }
internal fun createStaticFunctionWithReceivers(
irParent: IrDeclarationParent,
name: Name,
oldFunction: IrFunction,
dispatchReceiverType: IrType? = oldFunction.dispatchReceiverParameter?.type,
origin: IrDeclarationOrigin = oldFunction.origin
): IrSimpleFunction {
val descriptor = WrappedSimpleFunctionDescriptor(Annotations.EMPTY, oldFunction.descriptor.source)
return IrFunctionImpl(
oldFunction.startOffset, oldFunction.endOffset,
origin,
IrSimpleFunctionSymbolImpl(descriptor),
name,
oldFunction.visibility,
Modality.FINAL,
oldFunction.returnType,
isInline = false, isExternal = false, isTailrec = false, isSuspend = false
).apply {
descriptor.bind(this)
parent = irParent
copyTypeParametersFrom(oldFunction)
annotations.addAll(oldFunction.annotations)
var offset = 0
val dispatchReceiver = oldFunction.dispatchReceiverParameter?.copyTo(
this,
name = Name.identifier("this"),
index = offset++,
type = dispatchReceiverType!!
)
val extensionReceiver = oldFunction.extensionReceiverParameter?.copyTo(
this,
name = Name.identifier("receiver"),
index = offset++
)
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
oldFunction.valueParameters.map { it.copyTo(this, index = it.index + offset) }
)
val mapping: Map<IrValueParameter, IrValueParameter> =
(listOfNotNull(oldFunction.dispatchReceiverParameter, oldFunction.extensionReceiverParameter) + oldFunction.valueParameters)
.zip(valueParameters).toMap()
body = oldFunction.body
?.transform(VariableRemapper(mapping), null)
?.patchDeclarationParents(this)
metadata = oldFunction.metadata
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -414,23 +414,23 @@ fun ReferenceSymbolTable.referenceFunction(callable: CallableDescriptor): IrFunc
/** /**
* Create new call based on given [call] and [newFunction] * Create new call based on given [call] and [newFunction]
* [dispatchReceiverAsFirstArgument]: optionally convert call with dispatch receiver to static call * [receiversAsArguments]: optionally convert call with dispatch receiver to static call
* [firstArgumentAsDispatchReceiver]: optionally convert static call to call with dispatch receiver * [argumentsAsReceivers]: optionally convert static call to call with dispatch receiver
*/ */
fun irConstructorCall( fun irConstructorCall(
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
newFunction: IrConstructor, newFunction: IrConstructor,
dispatchReceiverAsFirstArgument: Boolean = false, receiversAsArguments: Boolean = false,
firstArgumentAsDispatchReceiver: Boolean = false argumentsAsReceivers: Boolean = false
): IrConstructorCall = ): IrConstructorCall =
irConstructorCall(call, newFunction.symbol, dispatchReceiverAsFirstArgument, firstArgumentAsDispatchReceiver) irConstructorCall(call, newFunction.symbol, receiversAsArguments, argumentsAsReceivers)
fun irConstructorCall( fun irConstructorCall(
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
newSymbol: IrConstructorSymbol, newSymbol: IrConstructorSymbol,
dispatchReceiverAsFirstArgument: Boolean = false, receiversAsArguments: Boolean = false,
firstArgumentAsDispatchReceiver: Boolean = false argumentsAsDispatchers: Boolean = false
): IrConstructorCall = ): IrConstructorCall =
call.run { call.run {
IrConstructorCallImpl( IrConstructorCallImpl(
@@ -446,8 +446,8 @@ fun irConstructorCall(
).apply { ).apply {
copyTypeAndValueArgumentsFrom( copyTypeAndValueArgumentsFrom(
call, call,
dispatchReceiverAsFirstArgument, receiversAsArguments,
firstArgumentAsDispatchReceiver argumentsAsDispatchers
) )
} }
} }
@@ -455,27 +455,21 @@ fun irConstructorCall(
fun irCall( fun irCall(
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
newFunction: IrFunction, newFunction: IrFunction,
dispatchReceiverAsArgument: Boolean = false, receiversAsArguments: Boolean = false,
argumentAsDispatchReceiver: Boolean = false, argumentsAsReceivers: Boolean = false
extensionReceiverAsArgument: Boolean = false,
argumentAsExtensionReceiver: Boolean = false
): IrCall = ): IrCall =
irCall( irCall(
call, call,
newFunction.symbol, newFunction.symbol,
dispatchReceiverAsArgument, receiversAsArguments,
argumentAsDispatchReceiver, argumentsAsReceivers
extensionReceiverAsArgument,
argumentAsExtensionReceiver
) )
fun irCall( fun irCall(
call: IrFunctionAccessExpression, call: IrFunctionAccessExpression,
newSymbol: IrFunctionSymbol, newSymbol: IrFunctionSymbol,
dispatchReceiverAsArgument: Boolean = false, receiversAsArguments: Boolean = false,
argumentAsDispatchReceiver: Boolean = false, argumentsAsReceivers: Boolean = false
extensionReceiverAsArgument: Boolean = false,
argumentAsExtensionReceiver: Boolean = false
): IrCall = ): IrCall =
call.run { call.run {
IrCallImpl( IrCallImpl(
@@ -489,54 +483,42 @@ fun irCall(
).apply { ).apply {
copyTypeAndValueArgumentsFrom( copyTypeAndValueArgumentsFrom(
call, call,
dispatchReceiverAsArgument, receiversAsArguments,
argumentAsDispatchReceiver, argumentsAsReceivers
extensionReceiverAsArgument,
argumentAsExtensionReceiver
) )
} }
} }
fun IrFunctionAccessExpression.copyTypeAndValueArgumentsFrom( fun IrFunctionAccessExpression.copyTypeAndValueArgumentsFrom(
src: IrFunctionAccessExpression, src: IrFunctionAccessExpression,
dispatchReceiverAsArgument: Boolean = false, receiversAsArguments: Boolean = false,
argumentAsDispatchReceiver: Boolean = false, argumentsAsReceivers: Boolean = false
extensionReceiverAsArgument: Boolean = false,
argumentAsExtensionReceiver: Boolean = false
) = copyTypeAndValueArgumentsFrom( ) = copyTypeAndValueArgumentsFrom(
src, src,
src.symbol.owner, src.symbol.owner,
symbol.owner, symbol.owner,
dispatchReceiverAsArgument, receiversAsArguments,
argumentAsDispatchReceiver, argumentsAsReceivers
extensionReceiverAsArgument,
argumentAsExtensionReceiver
) )
fun IrFunctionReference.copyTypeAndValueArgumentsFrom( fun IrFunctionReference.copyTypeAndValueArgumentsFrom(
src: IrFunctionReference, src: IrFunctionReference,
dispatchReceiverAsArgument: Boolean = false, receiversAsArguments: Boolean = false,
argumentAsDispatchReceiver: Boolean = false, argumentsAsReceivers: Boolean = false
extensionReceiverAsArgument: Boolean = false,
argumentAsExtensionReceiver: Boolean = false
) = copyTypeAndValueArgumentsFrom( ) = copyTypeAndValueArgumentsFrom(
src, src,
src.symbol.owner, src.symbol.owner,
symbol.owner, symbol.owner,
dispatchReceiverAsArgument, receiversAsArguments,
argumentAsDispatchReceiver, argumentsAsReceivers
extensionReceiverAsArgument,
argumentAsExtensionReceiver
) )
private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom( private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
src: IrMemberAccessExpression, src: IrMemberAccessExpression,
srcFunction: IrFunction, srcFunction: IrFunction,
destFunction: IrFunction, destFunction: IrFunction,
dispatchReceiverAsArgument: Boolean = false, receiversAsArguments: Boolean = false,
argumentAsDispatchReceiver: Boolean = false, argumentsAsReceivers: Boolean = false
extensionReceiverAsArgument: Boolean = false,
argumentAsExtensionReceiver: Boolean = false
) { ) {
copyTypeArgumentsFrom(src) copyTypeArgumentsFrom(src)
@@ -544,10 +526,10 @@ private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
var srcValueArgumentIndex = 0 var srcValueArgumentIndex = 0
when { when {
dispatchReceiverAsArgument && srcFunction.dispatchReceiverParameter != null -> { receiversAsArguments && srcFunction.dispatchReceiverParameter != null -> {
putValueArgument(destValueArgumentIndex++, src.dispatchReceiver) putValueArgument(destValueArgumentIndex++, src.dispatchReceiver)
} }
argumentAsDispatchReceiver && destFunction.dispatchReceiverParameter != null -> { argumentsAsReceivers && destFunction.dispatchReceiverParameter != null -> {
dispatchReceiver = src.getValueArgument(srcValueArgumentIndex++) dispatchReceiver = src.getValueArgument(srcValueArgumentIndex++)
} }
else -> { else -> {
@@ -556,10 +538,10 @@ private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
} }
when { when {
extensionReceiverAsArgument && srcFunction.extensionReceiverParameter != null -> { receiversAsArguments && srcFunction.extensionReceiverParameter != null -> {
putValueArgument(destValueArgumentIndex++, src.extensionReceiver) putValueArgument(destValueArgumentIndex++, src.extensionReceiver)
} }
argumentAsExtensionReceiver && destFunction.extensionReceiverParameter != null -> { argumentsAsReceivers && destFunction.extensionReceiverParameter != null -> {
extensionReceiver = src.getValueArgument(srcValueArgumentIndex++) extensionReceiver = src.getValueArgument(srcValueArgumentIndex++)
} }
else -> { else -> {