Generate synthetic functions for local functions with default values, by
re-ordering the lowering phases. The changes in InterfaceLowering are necessary so that IrElements that target the removed functions are re-targeted to the new functions in DefaultImpls. This affects local functions in interface functions since now LocalDeclarationsLowering comes before InterfaceLowering.
This commit is contained in:
committed by
max-kammerer
parent
d2f1852c5e
commit
1abdf0561a
+2
-2
@@ -190,7 +190,7 @@ class InlineClassLowering(val context: BackendContext) {
|
||||
return expression
|
||||
}
|
||||
|
||||
return irCall(expression, getOrCreateStaticMethod(function), dispatchReceiverAsFirstArgument = false)
|
||||
return irCall(expression, getOrCreateStaticMethod(function), dispatchReceiverAsArgument = false)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
@@ -208,7 +208,7 @@ class InlineClassLowering(val context: BackendContext) {
|
||||
return irCall(
|
||||
expression,
|
||||
getOrCreateStaticMethod(function),
|
||||
dispatchReceiverAsFirstArgument = (function is IrSimpleFunction)
|
||||
dispatchReceiverAsArgument = (function is IrSimpleFunction)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
@@ -48,7 +47,7 @@ internal fun <K> MutableMap<K, (IrFunctionAccessExpression) -> IrExpression>.add
|
||||
internal typealias MemberToTransformer = HashMap<SimpleMemberKey, (IrFunctionAccessExpression) -> IrExpression>
|
||||
|
||||
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunctionSymbol) {
|
||||
add(type, name) { irCall(it, v, dispatchReceiverAsFirstArgument = true) }
|
||||
add(type, name) { irCall(it, v, dispatchReceiverAsArgument = true) }
|
||||
}
|
||||
|
||||
internal fun MemberToTransformer.add(type: IrType, name: Name, v: IrFunction) {
|
||||
|
||||
+5
-5
@@ -53,7 +53,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
comparator.owner.returnType,
|
||||
comparator
|
||||
).apply {
|
||||
putValueArgument(0, irCall(call, intrinsics.longCompareToLong, firstArgumentAsDispatchReceiver = true))
|
||||
putValueArgument(0, irCall(call, intrinsics.longCompareToLong, argumentAsDispatchReceiver = true))
|
||||
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, 0))
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
chooseEqualityOperatorForPrimitiveTypes(call)
|
||||
|
||||
!isLhsPrimitive && !lhs.type.isNullable() && equalsMethod != null ->
|
||||
irCall(call, equalsMethod.symbol, firstArgumentAsDispatchReceiver = true)
|
||||
irCall(call, equalsMethod.symbol, argumentAsDispatchReceiver = true)
|
||||
|
||||
else ->
|
||||
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,
|
||||
// or has a potential to be primitive type (being fake overridden from `Comparable`)
|
||||
function.isMethodOfPrimitiveJSType() || function.isFakeOverriddenFromComparable() ->
|
||||
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsCompareTo, dispatchReceiverAsArgument = true)
|
||||
|
||||
// Valid `compareTo` method must be present at this point
|
||||
else ->
|
||||
@@ -144,12 +144,12 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
|
||||
// `Any.equals` works as identity operator
|
||||
call.isSuperToAny() ->
|
||||
irCall(call, intrinsics.jsEqeqeq, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsEqeqeq, dispatchReceiverAsArgument = true)
|
||||
|
||||
// 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`)
|
||||
function.isMethodOfPotentiallyPrimitiveJSType() ->
|
||||
irCall(call, intrinsics.jsEquals, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsEquals, dispatchReceiverAsArgument = true)
|
||||
|
||||
// Valid `equals` method must be present at this point
|
||||
else -> call
|
||||
|
||||
+4
-5
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverriddenFromAny
|
||||
import org.jetbrains.kotlin.ir.util.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.isSuperToAny
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@@ -30,9 +29,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
|
||||
put(Name.identifier("toString")) { call ->
|
||||
if (shouldReplaceToStringWithRuntimeCall(call)) {
|
||||
if ((call as IrCall).isSuperToAny()) {
|
||||
irCall(call, intrinsics.jsAnyToString, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsAnyToString, dispatchReceiverAsArgument = true)
|
||||
} else {
|
||||
irCall(call, intrinsics.jsToString, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsToString, dispatchReceiverAsArgument = true)
|
||||
}
|
||||
} else {
|
||||
call
|
||||
@@ -42,9 +41,9 @@ class MethodsOfAnyCallsTransformer(context: JsIrBackendContext) : CallsTransform
|
||||
put(Name.identifier("hashCode")) { call ->
|
||||
if (call.symbol.owner.isFakeOverriddenFromAny()) {
|
||||
if ((call as IrCall).isSuperToAny()) {
|
||||
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsArgument = true)
|
||||
} else {
|
||||
irCall(call, intrinsics.jsHashCode, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsHashCode, dispatchReceiverAsArgument = true)
|
||||
}
|
||||
} else {
|
||||
call
|
||||
|
||||
+8
-8
@@ -46,9 +46,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
|
||||
irBuiltIns.booleanType.let {
|
||||
// These operators are not short-circuit -- using bitwise operators '&', '|', '^' followed by coercion to boolean
|
||||
add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, dispatchReceiverAsFirstArgument = true)) }
|
||||
add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, dispatchReceiverAsFirstArgument = true)) }
|
||||
add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, dispatchReceiverAsFirstArgument = true)) }
|
||||
add(it, OperatorNames.AND) { call -> toBoolean(irCall(call, intrinsics.jsBitAnd, dispatchReceiverAsArgument = true)) }
|
||||
add(it, OperatorNames.OR) { call -> toBoolean(irCall(call, intrinsics.jsBitOr, dispatchReceiverAsArgument = true)) }
|
||||
add(it, OperatorNames.XOR) { call -> toBoolean(irCall(call, intrinsics.jsBitXor, dispatchReceiverAsArgument = true)) }
|
||||
|
||||
add(it, OperatorNames.NOT, intrinsics.jsNot)
|
||||
}
|
||||
@@ -88,9 +88,9 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
return with(call.symbol.owner.valueParameters[0].type) {
|
||||
when {
|
||||
isByte() || isShort() || isInt() ->
|
||||
irCall(call, intrinsics.jsNumberRangeToNumber, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsNumberRangeToNumber, dispatchReceiverAsArgument = true)
|
||||
isLong() ->
|
||||
irCall(call, intrinsics.jsNumberRangeToLong, dispatchReceiverAsFirstArgument = true)
|
||||
irCall(call, intrinsics.jsNumberRangeToLong, dispatchReceiverAsArgument = true)
|
||||
else -> call
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
intrinsic: IrFunctionSymbol,
|
||||
toInt32: Boolean = false
|
||||
): IrExpression {
|
||||
val newCall = irCall(call, intrinsic, dispatchReceiverAsFirstArgument = true)
|
||||
val newCall = irCall(call, intrinsic, dispatchReceiverAsArgument = true)
|
||||
if (toInt32)
|
||||
return toInt32(newCall)
|
||||
return newCall
|
||||
@@ -152,7 +152,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
transformCrement(call, intrinsics.jsMinus)
|
||||
|
||||
private fun transformCrement(call: IrFunctionAccessExpression, correspondingBinaryOp: IrFunctionSymbol): IrExpression {
|
||||
val operation = irCall(call, correspondingBinaryOp, dispatchReceiverAsFirstArgument = true).apply {
|
||||
val operation = irCall(call, correspondingBinaryOp, dispatchReceiverAsArgument = true).apply {
|
||||
putValueArgument(1, buildInt(1))
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ class NumberOperatorCallsTransformer(context: JsIrBackendContext) : CallsTransfo
|
||||
|
||||
private fun transformUnaryMinus(call: IrFunctionAccessExpression) =
|
||||
convertResultToPrimitiveType(
|
||||
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsFirstArgument = true),
|
||||
irCall(call, intrinsics.jsUnaryMinus, dispatchReceiverAsArgument = true),
|
||||
call.type
|
||||
)
|
||||
|
||||
|
||||
@@ -20,7 +20,12 @@ import org.jetbrains.kotlin.name.NameUtils
|
||||
|
||||
private fun makePatchParentsPhase(number: Int) = namedIrFilePhase(
|
||||
lower = object : SameTypeCompilerPhase<CommonBackendContext, IrFile> {
|
||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrFile>, context: CommonBackendContext, input: IrFile): IrFile {
|
||||
override fun invoke(
|
||||
phaseConfig: PhaseConfig,
|
||||
phaserState: PhaserState<IrFile>,
|
||||
context: CommonBackendContext,
|
||||
input: IrFile
|
||||
): IrFile {
|
||||
input.acceptVoid(PatchDeclarationParentsVisitor())
|
||||
return input
|
||||
}
|
||||
@@ -59,12 +64,6 @@ private val propertiesPhase = makeIrFilePhase<CommonBackendContext>(
|
||||
stickyPostconditions = setOf((PropertiesLowering)::checkNoProperties)
|
||||
)
|
||||
|
||||
private val defaultArgumentStubPhase = makeIrFilePhase<CommonBackendContext>(
|
||||
{ context -> DefaultArgumentStubGenerator(context, false) },
|
||||
name = "DefaultArgumentsStubGenerator",
|
||||
description = "Generate synthetic stubs for functions with default parameter values"
|
||||
)
|
||||
|
||||
private val localDeclarationsPhase = makeIrFilePhase<CommonBackendContext>(
|
||||
{ context ->
|
||||
LocalDeclarationsLowering(context, object : LocalNameProvider {
|
||||
@@ -77,6 +76,13 @@ private val localDeclarationsPhase = makeIrFilePhase<CommonBackendContext>(
|
||||
prerequisite = setOf(sharedVariablesPhase)
|
||||
)
|
||||
|
||||
private val defaultArgumentStubPhase = makeIrFilePhase<CommonBackendContext>(
|
||||
{ context -> DefaultArgumentStubGenerator(context, false) },
|
||||
name = "DefaultArgumentsStubGenerator",
|
||||
description = "Generate synthetic stubs for functions with default parameter values",
|
||||
prerequisite = setOf(localDeclarationsPhase)
|
||||
)
|
||||
|
||||
private val innerClassesPhase = makeIrFilePhase(
|
||||
::InnerClassesLowering,
|
||||
name = "InnerClasses",
|
||||
@@ -105,11 +111,7 @@ val jvmPhases = namedIrFilePhase<JvmBackendContext>(
|
||||
tailrecPhase then
|
||||
|
||||
jvmInlineClassPhase then
|
||||
defaultArgumentStubPhase then
|
||||
|
||||
interfacePhase then
|
||||
interfaceDelegationPhase then
|
||||
interfaceSuperCallsPhase then
|
||||
sharedVariablesPhase then
|
||||
|
||||
makePatchParentsPhase(1) then
|
||||
@@ -117,6 +119,12 @@ val jvmPhases = namedIrFilePhase<JvmBackendContext>(
|
||||
enumWhenPhase then
|
||||
singletonReferencesPhase then
|
||||
localDeclarationsPhase then
|
||||
defaultArgumentStubPhase then
|
||||
|
||||
interfacePhase then
|
||||
interfaceDelegationPhase then
|
||||
interfaceSuperCallsPhase then
|
||||
|
||||
singleAbstractMethodPhase then
|
||||
addContinuationPhase then
|
||||
callableReferencePhase then
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl
|
||||
if (superCallee.isDefinitelyNotDefaultImplsMethod()) return super.visitCall(expression)
|
||||
|
||||
val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee)
|
||||
val newCall = irCall(expression, redirectTarget, dispatchReceiverAsFirstArgument = true)
|
||||
val newCall = irCall(expression, redirectTarget, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true)
|
||||
|
||||
return super.visitCall(newCall)
|
||||
}
|
||||
|
||||
+62
-6
@@ -22,11 +22,15 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
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.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
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.irCall
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
@@ -42,6 +46,7 @@ internal val interfacePhase = makeIrFilePhase(
|
||||
private class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||
|
||||
val state = context.state
|
||||
val removedFunctions = hashMapOf<IrFunctionSymbol, IrFunctionSymbol>()
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!irClass.isInterface) return
|
||||
@@ -54,7 +59,10 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
||||
if (function !is IrSimpleFunction) continue
|
||||
|
||||
if (function.modality != Modality.ABSTRACT && function.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||
val element = context.declarationFactory.getDefaultImplsFunction(function)
|
||||
val element = context.declarationFactory.getDefaultImplsFunction(function).also {
|
||||
if (shouldRemoveFunction(function))
|
||||
removedFunctions[function.symbol] = it.symbol
|
||||
}
|
||||
members.add(element)
|
||||
element.body = function.body?.patchDeclarationParents(element)
|
||||
if (function.hasJvmDefault() &&
|
||||
@@ -69,10 +77,11 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
||||
}
|
||||
}
|
||||
|
||||
// Update IrElements (e.g., IrCalls) to point to the new functions.
|
||||
irClass.transformChildrenVoid(this)
|
||||
|
||||
irClass.declarations.removeAll {
|
||||
it is IrFunction && shouldRemoveFunction(it)
|
||||
it is IrFunction && removedFunctions.containsKey(it.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +94,7 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
||||
val startOffset = interfaceMethod.startOffset
|
||||
val endOffset = interfaceMethod.endOffset
|
||||
|
||||
return IrCallImpl(interfaceMethod.startOffset, interfaceMethod.endOffset, interfaceMethod.returnType, defaultImpls.symbol).apply {
|
||||
return IrCallImpl(startOffset, endOffset, interfaceMethod.returnType, defaultImpls.symbol).apply {
|
||||
passTypeArgumentsFrom(interfaceMethod)
|
||||
|
||||
var offset = 0
|
||||
@@ -100,6 +109,53 @@ private class InterfaceLowering(val context: JvmBackendContext) : IrElementTrans
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
val newFunction = removedFunctions[expression.returnTargetSymbol]?.owner
|
||||
return super.visitReturn(
|
||||
if (newFunction != null) {
|
||||
with(expression) {
|
||||
IrReturnImpl(startOffset, endOffset, type, newFunction.symbol, value)
|
||||
}
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val newFunction = removedFunctions[expression.symbol]?.owner
|
||||
return super.visitCall(
|
||||
if (newFunction != null) {
|
||||
irCall(expression, newFunction, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true)
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val newFunction = removedFunctions[expression.symbol]?.owner
|
||||
return super.visitFunctionReference(
|
||||
if (newFunction != null) {
|
||||
with(expression) {
|
||||
IrFunctionReferenceImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type,
|
||||
newFunction.symbol,
|
||||
newFunction.descriptor,
|
||||
typeArgumentsCount,
|
||||
origin
|
||||
).apply {
|
||||
copyTypeAndValueArgumentsFrom(expression, dispatchReceiverAsArgument = true, extensionReceiverAsArgument = true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -349,6 +349,7 @@ fun IrDeclaration.isEffectivelyExternal(): Boolean {
|
||||
is IrSimpleFunction -> correspondingProperty ?: parent as? IrDeclaration
|
||||
else -> parent as? IrDeclaration
|
||||
}
|
||||
|
||||
val parent = parent
|
||||
return when (this) {
|
||||
is IrFunction -> isExternal || (effectiveParentDeclaration()?.isEffectivelyExternal() ?: false)
|
||||
@@ -418,7 +419,7 @@ fun ReferenceSymbolTable.referenceFunction(callable: CallableDescriptor): IrFunc
|
||||
*/
|
||||
|
||||
fun irConstructorCall(
|
||||
call: IrMemberAccessExpression,
|
||||
call: IrFunctionAccessExpression,
|
||||
newFunction: IrConstructor,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
@@ -426,7 +427,7 @@ fun irConstructorCall(
|
||||
irConstructorCall(call, newFunction.symbol, dispatchReceiverAsFirstArgument, firstArgumentAsDispatchReceiver)
|
||||
|
||||
fun irConstructorCall(
|
||||
call: IrMemberAccessExpression,
|
||||
call: IrFunctionAccessExpression,
|
||||
newSymbol: IrConstructorSymbol,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
@@ -452,18 +453,29 @@ fun irConstructorCall(
|
||||
}
|
||||
|
||||
fun irCall(
|
||||
call: IrMemberAccessExpression,
|
||||
call: IrFunctionAccessExpression,
|
||||
newFunction: IrFunction,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
dispatchReceiverAsArgument: Boolean = false,
|
||||
argumentAsDispatchReceiver: Boolean = false,
|
||||
extensionReceiverAsArgument: Boolean = false,
|
||||
argumentAsExtensionReceiver: Boolean = false
|
||||
): IrCall =
|
||||
irCall(call, newFunction.symbol, dispatchReceiverAsFirstArgument, firstArgumentAsDispatchReceiver)
|
||||
irCall(
|
||||
call,
|
||||
newFunction.symbol,
|
||||
dispatchReceiverAsArgument,
|
||||
argumentAsDispatchReceiver,
|
||||
extensionReceiverAsArgument,
|
||||
argumentAsExtensionReceiver
|
||||
)
|
||||
|
||||
fun irCall(
|
||||
call: IrMemberAccessExpression,
|
||||
call: IrFunctionAccessExpression,
|
||||
newSymbol: IrFunctionSymbol,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
dispatchReceiverAsArgument: Boolean = false,
|
||||
argumentAsDispatchReceiver: Boolean = false,
|
||||
extensionReceiverAsArgument: Boolean = false,
|
||||
argumentAsExtensionReceiver: Boolean = false
|
||||
): IrCall =
|
||||
call.run {
|
||||
IrCallImpl(
|
||||
@@ -477,46 +489,95 @@ fun irCall(
|
||||
).apply {
|
||||
copyTypeAndValueArgumentsFrom(
|
||||
call,
|
||||
dispatchReceiverAsFirstArgument,
|
||||
firstArgumentAsDispatchReceiver
|
||||
dispatchReceiverAsArgument,
|
||||
argumentAsDispatchReceiver,
|
||||
extensionReceiverAsArgument,
|
||||
argumentAsExtensionReceiver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
|
||||
call: IrMemberAccessExpression,
|
||||
dispatchReceiverAsFirstArgument: Boolean = false,
|
||||
firstArgumentAsDispatchReceiver: Boolean = false
|
||||
) {
|
||||
copyTypeArgumentsFrom(call)
|
||||
fun IrFunctionAccessExpression.copyTypeAndValueArgumentsFrom(
|
||||
src: IrFunctionAccessExpression,
|
||||
dispatchReceiverAsArgument: Boolean = false,
|
||||
argumentAsDispatchReceiver: Boolean = false,
|
||||
extensionReceiverAsArgument: Boolean = false,
|
||||
argumentAsExtensionReceiver: Boolean = false
|
||||
) = copyTypeAndValueArgumentsFrom(
|
||||
src,
|
||||
src.symbol.owner,
|
||||
symbol.owner,
|
||||
dispatchReceiverAsArgument,
|
||||
argumentAsDispatchReceiver,
|
||||
extensionReceiverAsArgument,
|
||||
argumentAsExtensionReceiver
|
||||
)
|
||||
|
||||
var toValueArgumentIndex = 0
|
||||
var fromValueArgumentIndex = 0
|
||||
fun IrFunctionReference.copyTypeAndValueArgumentsFrom(
|
||||
src: IrFunctionReference,
|
||||
dispatchReceiverAsArgument: Boolean = false,
|
||||
argumentAsDispatchReceiver: Boolean = false,
|
||||
extensionReceiverAsArgument: Boolean = false,
|
||||
argumentAsExtensionReceiver: Boolean = false
|
||||
) = copyTypeAndValueArgumentsFrom(
|
||||
src,
|
||||
src.symbol.owner,
|
||||
symbol.owner,
|
||||
dispatchReceiverAsArgument,
|
||||
argumentAsDispatchReceiver,
|
||||
extensionReceiverAsArgument,
|
||||
argumentAsExtensionReceiver
|
||||
)
|
||||
|
||||
private fun IrMemberAccessExpression.copyTypeAndValueArgumentsFrom(
|
||||
src: IrMemberAccessExpression,
|
||||
srcFunction: IrFunction,
|
||||
destFunction: IrFunction,
|
||||
dispatchReceiverAsArgument: Boolean = false,
|
||||
argumentAsDispatchReceiver: Boolean = false,
|
||||
extensionReceiverAsArgument: Boolean = false,
|
||||
argumentAsExtensionReceiver: Boolean = false
|
||||
) {
|
||||
copyTypeArgumentsFrom(src)
|
||||
|
||||
var destValueArgumentIndex = 0
|
||||
var srcValueArgumentIndex = 0
|
||||
|
||||
when {
|
||||
dispatchReceiverAsFirstArgument -> {
|
||||
putValueArgument(toValueArgumentIndex++, call.dispatchReceiver)
|
||||
dispatchReceiverAsArgument && srcFunction.dispatchReceiverParameter != null -> {
|
||||
putValueArgument(destValueArgumentIndex++, src.dispatchReceiver)
|
||||
}
|
||||
firstArgumentAsDispatchReceiver -> {
|
||||
dispatchReceiver = call.getValueArgument(fromValueArgumentIndex++)
|
||||
argumentAsDispatchReceiver && destFunction.dispatchReceiverParameter != null -> {
|
||||
dispatchReceiver = src.getValueArgument(srcValueArgumentIndex++)
|
||||
}
|
||||
else -> {
|
||||
dispatchReceiver = call.dispatchReceiver
|
||||
dispatchReceiver = src.dispatchReceiver
|
||||
}
|
||||
}
|
||||
|
||||
extensionReceiver = call.extensionReceiver
|
||||
when {
|
||||
extensionReceiverAsArgument && srcFunction.extensionReceiverParameter != null -> {
|
||||
putValueArgument(destValueArgumentIndex++, src.extensionReceiver)
|
||||
}
|
||||
argumentAsExtensionReceiver && destFunction.extensionReceiverParameter != null -> {
|
||||
extensionReceiver = src.getValueArgument(srcValueArgumentIndex++)
|
||||
}
|
||||
else -> {
|
||||
extensionReceiver = src.extensionReceiver
|
||||
}
|
||||
}
|
||||
|
||||
while (fromValueArgumentIndex < call.valueArgumentsCount) {
|
||||
putValueArgument(toValueArgumentIndex++, call.getValueArgument(fromValueArgumentIndex++))
|
||||
while (srcValueArgumentIndex < src.valueArgumentsCount) {
|
||||
putValueArgument(destValueArgumentIndex++, src.getValueArgument(srcValueArgumentIndex++))
|
||||
}
|
||||
}
|
||||
|
||||
val IrDeclaration.file: IrFile get() = parent.let {
|
||||
when (it) {
|
||||
is IrFile -> it
|
||||
is IrPackageFragment -> TODO("Unknown file")
|
||||
is IrDeclaration -> it.file
|
||||
else -> TODO("Unexpected declaration parent")
|
||||
val IrDeclaration.file: IrFile
|
||||
get() = parent.let {
|
||||
when (it) {
|
||||
is IrFile -> it
|
||||
is IrPackageFragment -> TODO("Unknown file")
|
||||
is IrDeclaration -> it.file
|
||||
else -> TODO("Unexpected declaration parent")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// IGNORE_BACKEND: JVM_IR, JS
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
fun call0(f: (String) -> String, x: String): String = f(x)
|
||||
fun call1(f: (String, String) -> String, x: String, y: String): String = f(x, y)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun box(): String {
|
||||
val x = "OK"
|
||||
fun bar(y: String = x): String = y
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun box() : String {
|
||||
|
||||
|
||||
fun local(i: Int = 1) : Int {
|
||||
return i
|
||||
}
|
||||
|
||||
return if (local() != 1) "fail" else "OK"
|
||||
}
|
||||
if (local() != 1) return "Fail 1"
|
||||
if (local(2) != 2) return "Fail 2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class C() {
|
||||
fun box(): Int {
|
||||
fun local(i: Int = 1): Int {
|
||||
return i
|
||||
}
|
||||
return local()
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return if (C().box() != 1) "fail" else "OK"
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun foo(): String {
|
||||
fun bar(x: String, y: String = x): String {
|
||||
return y
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_RUNTIME
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
fun box(): String {
|
||||
val s = "captured";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: 1.kt
|
||||
|
||||
package test
|
||||
|
||||
+5
@@ -11504,6 +11504,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3978_2.kt")
|
||||
public void testKt3978_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4119.kt")
|
||||
public void testKt4119() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt4119.kt");
|
||||
|
||||
+5
@@ -11504,6 +11504,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3978_2.kt")
|
||||
public void testKt3978_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4119.kt")
|
||||
public void testKt4119() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt4119.kt");
|
||||
|
||||
+5
@@ -10394,6 +10394,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3978_2.kt")
|
||||
public void testKt3978_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4119.kt")
|
||||
public void testKt4119() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt4119.kt");
|
||||
|
||||
Generated
+5
@@ -9019,6 +9019,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3978_2.kt")
|
||||
public void testKt3978_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4119.kt")
|
||||
public void testKt4119() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt4119.kt");
|
||||
|
||||
+5
@@ -10104,6 +10104,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt3978_2.kt")
|
||||
public void testKt3978_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt3978_2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt4119.kt")
|
||||
public void testKt4119() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/localFunctions/kt4119.kt");
|
||||
|
||||
Reference in New Issue
Block a user