JVM_IR: Fix Inline CallableReferences with Varargs

- Added tests to demonstrate broken behaviour: the interaction of inline
  functions and callable references with varargs and defaults in various
  combinations.
- Refactored InlineCallableReferencesToLambdaPhase to look like and use
  some of the infrastructure from CallableReferenceLowering.
- Lifted some of this infrastructure out to be broadly reusable.
This commit is contained in:
Kristoffer Andersen
2019-10-24 15:53:43 +02:00
committed by Mikhael Bogdanov
parent 5360a7a3fe
commit 1074a0ef69
14 changed files with 311 additions and 233 deletions
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.ir
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
internal class IrInlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitorVoidWithContext() {
val inlineReferences = mutableSetOf<IrCallableReference>()
// For crossinline lambdas, the call site is null as it's probably in a separate class somewhere.
// All other lambdas are guaranteed to be inlined into the scope they are declared in.
val lambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
val function = expression.symbol.owner
if (function.isInlineFunctionCall(context)) {
for (parameter in function.valueParameters) {
if (!parameter.isInlineParameter())
continue
val valueArgument = expression.getValueArgument(parameter.index) ?: continue
if (!isInlineIrExpression(valueArgument))
continue
if (valueArgument is IrPropertyReference) {
inlineReferences.add(valueArgument)
continue
}
val reference = when (valueArgument) {
is IrFunctionReference -> valueArgument
is IrBlock -> valueArgument.statements.filterIsInstance<IrFunctionReference>().singleOrNull()
else -> null
} ?: continue
inlineReferences.add(reference)
if (valueArgument is IrBlock && valueArgument.origin.isLambda) {
lambdaToCallSite[reference.symbol.owner] =
if (parameter.isCrossinline) null else currentScope!!.irElement as IrDeclaration
}
}
}
return super.visitFunctionAccess(expression)
}
companion object {
fun scan(context: JvmBackendContext, element: IrElement) =
IrInlineReferenceLocator(context).apply { element.accept(this, null) }
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.isSuspend
@@ -15,15 +14,10 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.irArray
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
@@ -33,12 +27,10 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
@@ -49,52 +41,12 @@ internal val callableReferencePhase = makeIrFilePhase(
description = "Handle callable references"
)
internal class InlineReferenceLocator(private val context: JvmBackendContext) : IrElementVisitorVoidWithContext() {
val inlineReferences = mutableSetOf<IrFunctionReference>()
// For crossinline lambdas, the call site is null as it's probably in a separate class somewhere.
// All other lambdas are guaranteed to be inlined into the scope they are declared in.
val lambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this)
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
val function = expression.symbol.owner
if (function.isInlineFunctionCall(context)) {
for (parameter in function.valueParameters) {
if (!parameter.isInlineParameter())
continue
val valueArgument = expression.getValueArgument(parameter.index) ?: continue
if (!isInlineIrExpression(valueArgument))
continue
val reference = when (valueArgument) {
is IrFunctionReference -> valueArgument
is IrBlock -> valueArgument.statements.filterIsInstance<IrFunctionReference>().singleOrNull()
else -> null
} ?: continue
inlineReferences.add(reference)
if (valueArgument is IrBlock && valueArgument.origin.isLambda) {
lambdaToCallSite[reference.symbol.owner] =
if (parameter.isCrossinline) null else currentScope!!.irElement as IrDeclaration
}
}
}
return super.visitFunctionAccess(expression)
}
companion object {
fun scan(context: JvmBackendContext, element: IrElement) =
InlineReferenceLocator(context).apply { element.accept(this, null) }
}
}
// Originally copied from K/Native
internal class CallableReferenceLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
// This pass ignores suspend function references and function references used in inline arguments to inline functions.
private val ignoredFunctionReferences = mutableSetOf<IrFunctionReference>()
private val ignoredFunctionReferences = mutableSetOf<IrCallableReference>()
private val IrFunctionReference.isIgnored: Boolean
get() = (!type.isFunctionOrKFunction() || ignoredFunctionReferences.contains(this)) && !isSuspendCallableReference()
@@ -103,7 +55,7 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
private fun IrFunctionReference.isSuspendCallableReference(): Boolean = isSuspend && origin == null
override fun lower(irFile: IrFile) {
ignoredFunctionReferences.addAll(InlineReferenceLocator.scan(context, irFile).inlineReferences)
ignoredFunctionReferences.addAll(IrInlineReferenceLocator.scan(context, irFile).inlineReferences)
irFile.transformChildrenVoid(this)
}
@@ -7,18 +7,16 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.copyValueParametersToStatic
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.irArray
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.codegen.AsmUtil.BOUND_REFERENCE_RECEIVER
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.builders.*
@@ -28,9 +26,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
@@ -49,187 +45,139 @@ internal val inlineCallableReferenceToLambdaPhase = makeIrFilePhase(
//
// foo(::smth) -> foo { a -> smth(a) }
//
internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass {
private val inlinableCR = mutableSetOf<IrCallableReference>()
internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass,
IrElementTransformerVoidWithContext() {
private var inlinableReferences = mutableSetOf<IrCallableReference>()
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
val callee = expression.symbol.owner
if (callee.isInlineFunctionCall(context)) {
for (valueParameter in callee.valueParameters) {
if (valueParameter.isInlineParameter()) {
expression.getValueArgument(valueParameter.index)?.let { argument ->
if (argument is IrCallableReference && isInlineIrExpression(argument)) {
inlinableCR.add(argument)
}
}
}
}
}
return super.visitFunctionAccess(expression)
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
if (expression !in inlinableCR) {
return super.visitPropertyReference(expression)
}
//Use getter if field is absent...
val field =
expression.field?.owner ?: return functionReferenceToLambda(currentScope!!, expression, expression.getter!!.owner)
//..else use field itself
val irBuilder =
context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
val boundReceiver = expression.dispatchReceiver ?: expression.extensionReceiver
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
lateinit var variableForBoundReceiver: IrVariable
if (boundReceiver != null) {
variableForBoundReceiver = createTmpVariable(boundReceiver, BOUND_REFERENCE_RECEIVER)
}
val newLambda = buildFun {
setSourceRange(expression)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = Name.identifier("stub_for_inline")
visibility = Visibilities.LOCAL
returnType = field.type
isSuspend = false
}.apply {
val receiver =
when {
field.isStatic -> null
boundReceiver != null -> variableForBoundReceiver
else -> addValueParameter("receiver", field.parentAsClass.defaultType)
}
val lambdaBodyBuilder = this@InlineCallableReferenceToLambdaPhase.context.createIrBuilder(this.symbol)
body = lambdaBodyBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(irGetField(if (receiver != null) irGet(receiver) else null, field))
}
}
+newLambda
+IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset, field.type,
newLambda.symbol, newLambda.symbol.descriptor, 0,
IrStatementOrigin.LAMBDA
).apply {
copyAttributes(expression)
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
if (inlinableCR.contains(expression)) {
val referencedFunction = expression.symbol.owner
return functionReferenceToLambda(currentScope!!, expression, referencedFunction)
}
return super.visitFunctionReference(expression)
}
})
IrInlineReferenceLocator.scan(context, irFile).let {
inlinableReferences.addAll(it.inlineReferences)
}
irFile.transformChildrenVoid(this)
}
private fun functionReferenceToLambda(
scope: ScopeWithIr,
expression: IrCallableReference,
referencedFunction: IrFunction
): IrExpression {
val irBuilder =
context.createIrBuilder(scope.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
if (expression !in inlinableReferences || expression.origin.isLambda) return expression
return expandInlineFunctionReferenceToLambda(expression, expression.symbol.owner)
}
val boundReceiver = expression.dispatchReceiver ?: expression.extensionReceiver
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
if (expression !in inlinableReferences) return expression
val expectedType = expression.type
var expectedNumValueParameters: Int
if (expectedType.isFunctionOrKFunction() || expectedType.isSuspendFunction() || expectedType.isKSuspendFunction()) { // TODO: handle subtypes
expectedNumValueParameters = (expectedType as IrSimpleType).arguments.size - 1 // In ...Function classes, the last argument is return type
referencedFunction.dispatchReceiverParameter?.let { expectedNumValueParameters-- }
referencedFunction.extensionReceiverParameter?.let { expectedNumValueParameters-- }
boundReceiver?.let { expectedNumValueParameters++ }
assert(referencedFunction.valueParameters.subList(expectedNumValueParameters, referencedFunction.valueParameters.size).all {
it.defaultValue != null
})
return if (expression.field?.owner == null) {
// Use getter if field is absent ...
expandInlineFunctionReferenceToLambda(expression, expression.getter!!.owner)
} else {
assert(expectedType.classOrNull?.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) == true)
expectedNumValueParameters = 0
// ... else use field itself
expandInlineFieldReferenceToLambda(expression, expression.field!!.owner)
}
}
private fun expandInlineFieldReferenceToLambda(expression: IrPropertyReference, field: IrField): IrExpression {
val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
lateinit var variableForBoundReceiver: IrVariable
if (boundReceiver != null) {
variableForBoundReceiver = createTmpVariable(boundReceiver, BOUND_REFERENCE_RECEIVER)
}
val newLambda = buildFun {
val function = buildFun {
setSourceRange(expression)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = Name.identifier("stub_for_inline")
visibility = Visibilities.LOCAL
returnType = field.type
isSuspend = false
}.apply {
val boundReceiver = expression.dispatchReceiver ?: expression.extensionReceiver
val receiver =
when {
field.isStatic -> null
boundReceiver != null -> irGet(irTemporary(boundReceiver, BOUND_REFERENCE_RECEIVER))
else -> irGet(addValueParameter("receiver", field.parentAsClass.defaultType))
}
body = this@InlineCallableReferenceToLambdaPhase.context.createIrBuilder(symbol).run {
irExprBody(irGetField(receiver, field))
}
}
+function
+IrFunctionReferenceImpl(
expression.startOffset,
expression.endOffset,
field.type,
function.symbol,
function.symbol.descriptor,
typeArgumentsCount = 0,
origin = IrStatementOrigin.LAMBDA
).apply {
copyAttributes(expression)
}
}
}
private fun expandInlineFunctionReferenceToLambda(expression: IrCallableReference, referencedFunction: IrFunction): IrExpression {
val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) {
val parameterTypes = (expression.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
val argumentTypes = parameterTypes.dropLast(1)
val boundReceiver: Pair<IrValueParameter, IrExpression>? = expression.getArgumentsWithIr().singleOrNull()
val function = buildFun {
setSourceRange(expression)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = Name.identifier("stub_for_inlining")
visibility = Visibilities.LOCAL
returnType = referencedFunction.returnType
isSuspend = false
}.apply {
if (referencedFunction is IrConstructor) {
copyTypeParametersFrom(referencedFunction.parentAsClass)
}
copyTypeParametersFrom(referencedFunction)
if (boundReceiver == null) {
copyValueParametersToStatic(referencedFunction, origin, numValueParametersToCopy = expectedNumValueParameters)
} else {
for (oldValueParameter in referencedFunction.valueParameters) {
if (oldValueParameter.index >= expectedNumValueParameters) break
valueParameters.add(
oldValueParameter.copyTo(
this,
origin = origin,
index = oldValueParameter.index
)
)
for ((index, argumentType) in argumentTypes.withIndex()) {
addValueParameter {
name = Name.identifier("p$index")
type = argumentType
}
}
val lambdaBodyBuilder = this@InlineCallableReferenceToLambdaPhase.context.createIrBuilder(this.symbol)
body = lambdaBodyBuilder.irBlockBody(startOffset, endOffset) {
var shift = 0
val irCall =
if (expression is IrPropertyReference)
irGet(referencedFunction.returnType, null, referencedFunction.symbol)
else irCall(referencedFunction.symbol)
+irReturn(
irCall.also { call ->
for (it in this@apply.typeParameters) {
call.putTypeArgument(it.index, expression.getTypeArgument(it.index))
}
referencedFunction.dispatchReceiverParameter?.let {
call.dispatchReceiver =
irGet(if (expression.dispatchReceiver != null) variableForBoundReceiver else valueParameters[shift++])
}
referencedFunction.extensionReceiverParameter?.let {
call.extensionReceiver =
irGet(if (expression.extensionReceiver != null) variableForBoundReceiver else valueParameters[shift++])
}
for (it in referencedFunction.valueParameters.indices) {
if (it >= expectedNumValueParameters) break
call.putValueArgument(it, irGet(valueParameters[shift++]))
}
body = this@InlineCallableReferenceToLambdaPhase.context.createJvmIrBuilder(
this.symbol,
expression.startOffset,
expression.endOffset
).run {
irExprBody(irCall(referencedFunction).apply {
this@apply.descriptor.typeParameters.forEach {
putTypeArgument(it.index, expression.getTypeArgument(it.index))
}
)
var unboundIndex = 0
for (parameter in referencedFunction.explicitParameters) {
when {
boundReceiver?.first == parameter ->
irGet(irTemporary(boundReceiver.second))
parameter.isVararg && unboundIndex < argumentTypes.size && parameter.type == valueParameters[unboundIndex].type ->
irGet(valueParameters[unboundIndex++])
parameter.isVararg && (unboundIndex < argumentTypes.size || !parameter.hasDefaultValue()) ->
irArray(parameter.type) {
(unboundIndex until argumentTypes.size).forEach { +irGet(valueParameters[unboundIndex++]) }
}
unboundIndex >= argumentTypes.size ->
null
else ->
irGet(valueParameters[unboundIndex++])
}?.let { putArgument(referencedFunction, parameter, it) }
}
})
}
}
+newLambda
+function
+IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset, referencedFunction.returnType,
newLambda.symbol, newLambda.symbol.descriptor, referencedFunction.typeParameters.size,
expression.startOffset,
expression.endOffset,
referencedFunction.returnType,
function.symbol,
function.symbol.descriptor,
referencedFunction.typeParameters.size,
IrStatementOrigin.LAMBDA
).apply {
copyAttributes(expression)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.ir.isLambda
import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden
import org.jetbrains.kotlin.descriptors.Modality
@@ -46,7 +47,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
private val inlineLambdaToCallSite = mutableMapOf<IrFunction, IrDeclaration?>()
override fun lower(irFile: IrFile) {
inlineLambdaToCallSite.putAll(InlineReferenceLocator.scan(context, irFile).lambdaToCallSite)
inlineLambdaToCallSite.putAll(IrInlineReferenceLocator.scan(context, irFile).lambdaToCallSite)
irFile.transformChildrenVoid(this)
pendingTransformations.forEach { it() }
}
@@ -91,6 +91,10 @@ fun IrMemberAccessExpression.getArgumentsWithIr(): List<Pair<IrValueParameter, I
val irFunction = when (this) {
is IrFunctionAccessExpression -> this.symbol.owner
is IrFunctionReference -> this.symbol.owner
is IrPropertyReference -> {
assert(this.field == null) { "Field should be null to use `getArgumentsWithIr` on IrPropertyReference: ${this.dump()}}" }
this.getter!!.owner
}
else -> error(this)
}
@@ -0,0 +1,11 @@
// !LANGUAGE: +NewInference +FunctionReferenceWithDefaultValueAsOtherType
// WITH_RUNTIME
// IGNORE_BACKEND: JS_IR
inline fun foo(mkString: () -> String): String =
mkString()
fun bar (xs: CharArray = charArrayOf('O','K')) =
String(xs)
fun box(): String = foo(::bar)
@@ -0,0 +1,12 @@
// !LANGUAGE: +NewInference
// WITH_RUNTIME
// IGNORE_BACKEND: JS, JS_IR
inline fun foo(mkString: (Char, Char) -> String): String =
mkString('O','K')
fun bar (vararg xs: Char) =
String(xs)
fun box(): String = foo(::bar)
// -> { a, b -> bar(a, b) }
@@ -1,5 +1,5 @@
// !LANGUAGE: +NewInference +FunctionReferenceWithDefaultValueAsOtherType
// IGNORE_BACKEND: JS, JVM_IR, JS_IR
// IGNORE_BACKEND: JS, JS_IR
fun foo(vararg l: Long, s: String = "OK"): String =
if (l.size == 0) s else "Fail"
@@ -0,0 +1,12 @@
// !LANGUAGE: +NewInference
// WITH_RUNTIME
// IGNORE_BACKEND: JS, JS_IR
inline fun foo(x: (Int, Int) -> Int): Int =
x(120,3)
fun bar(vararg x: Int): Int =
x.sum()
fun box(): String =
if (foo(::bar) == 123) "OK" else "FAIL"
@@ -2632,9 +2632,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/emptyVarargAndDefault.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inline.kt");
@TestMetadata("inlineDefault.kt")
public void testInlineDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineDefault.kt");
}
@TestMetadata("inlineVararg.kt")
public void testInlineVararg() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVararg.kt");
}
@TestMetadata("inlineVarargAndDefault.kt")
public void testInlineVarargAndDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargAndDefault.kt");
}
@TestMetadata("inlineVarargInts.kt")
public void testInlineVarargInts() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargInts.kt");
}
@TestMetadata("innerConstructorWithVararg.kt")
@@ -2632,9 +2632,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/emptyVarargAndDefault.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inline.kt");
@TestMetadata("inlineDefault.kt")
public void testInlineDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineDefault.kt");
}
@TestMetadata("inlineVararg.kt")
public void testInlineVararg() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVararg.kt");
}
@TestMetadata("inlineVarargAndDefault.kt")
public void testInlineVarargAndDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargAndDefault.kt");
}
@TestMetadata("inlineVarargInts.kt")
public void testInlineVarargInts() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargInts.kt");
}
@TestMetadata("innerConstructorWithVararg.kt")
@@ -2612,9 +2612,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/emptyVarargAndDefault.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inline.kt");
@TestMetadata("inlineDefault.kt")
public void testInlineDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineDefault.kt");
}
@TestMetadata("inlineVararg.kt")
public void testInlineVararg() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVararg.kt");
}
@TestMetadata("inlineVarargAndDefault.kt")
public void testInlineVarargAndDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargAndDefault.kt");
}
@TestMetadata("inlineVarargInts.kt")
public void testInlineVarargInts() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargInts.kt");
}
@TestMetadata("innerConstructorWithVararg.kt")
@@ -2072,9 +2072,24 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/emptyVarargAndDefault.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inline.kt");
@TestMetadata("inlineDefault.kt")
public void testInlineDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineDefault.kt");
}
@TestMetadata("inlineVararg.kt")
public void testInlineVararg() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVararg.kt");
}
@TestMetadata("inlineVarargAndDefault.kt")
public void testInlineVarargAndDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargAndDefault.kt");
}
@TestMetadata("inlineVarargInts.kt")
public void testInlineVarargInts() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargInts.kt");
}
@TestMetadata("innerConstructorWithVararg.kt")
@@ -2072,9 +2072,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/emptyVarargAndDefault.kt");
}
@TestMetadata("inline.kt")
public void testInline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inline.kt");
@TestMetadata("inlineDefault.kt")
public void testInlineDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineDefault.kt");
}
@TestMetadata("inlineVararg.kt")
public void testInlineVararg() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVararg.kt");
}
@TestMetadata("inlineVarargAndDefault.kt")
public void testInlineVarargAndDefault() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargAndDefault.kt");
}
@TestMetadata("inlineVarargInts.kt")
public void testInlineVarargInts() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/varargAndDefaults/inlineVarargInts.kt");
}
@TestMetadata("innerConstructorWithVararg.kt")