Anton Bannykh
2019-03-13 18:19:22 +03:00
parent 0249e33f3e
commit a4c693ec29
4 changed files with 105 additions and 128 deletions
@@ -8,18 +8,16 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.serialization.fqNameSafe
import org.jetbrains.kotlin.backend.common.serialization.hasAnnotation
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -35,8 +33,7 @@ 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
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.resolve.inline.InlineUtil
typealias Context = JsIrBackendContext typealias Context = JsIrBackendContext
@@ -53,9 +50,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall) val callSite = arrayConstructorTransformer.transformCall(super.visitCall(expression) as IrCall)
val functionDescriptor = callSite.descriptor
if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining. if (!callSite.symbol.owner.needsInlining)
return callSite
val languageVersionSettings = context.configuration.languageVersionSettings val languageVersionSettings = context.configuration.languageVersionSettings
when { when {
@@ -76,19 +73,12 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(callSite, callee, currentScope!!, parent, context) val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
// Create inliner for this scope. return inliner.inline()
return inliner.inline() // Return newly created IrInlineBody instead of IrCall.
} }
//-------------------------------------------------------------------------//
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val descriptor = symbol.descriptor.original val descriptor = symbol.descriptor.original
// val originalDescriptor = functionDescriptor.resolveFakeOverride().original
val languageVersionSettings = context.configuration.languageVersionSettings val languageVersionSettings = context.configuration.languageVersionSettings
// TODO: Remove these hacks when coroutine intrinsics are fixed. // TODO: Remove these hacks when coroutine intrinsics are fixed.
return when { return when {
// descriptor.isBuiltInIntercepted(languageVersionSettings) -> // descriptor.isBuiltInIntercepted(languageVersionSettings) ->
@@ -104,20 +94,17 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
} }
} }
// TODO: should we keep this at all?
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor") private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
//-----------------------------------------------------------------------------// private val IrFunction.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
private inner class Inliner( private val IrFunction.needsInlining get() = isInlineConstructor || (this.isInline && !this.isExternal)
val callSite: IrCall,
val callee: IrFunction, private inner class Inliner(val callSite: IrCall,
val currentScope: ScopeWithIr, val callee: IrFunction,
val parent: IrDeclarationParent?, val currentScope: ScopeWithIr,
val context: Context val parent: IrDeclarationParent?,
) { val context: Context) {
val copyIrElement = run { val copyIrElement = run {
val typeParameters = val typeParameters =
@@ -131,7 +118,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent) DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
} }
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>() val substituteMap = mutableMapOf<IrValueParameter, IrExpression>()
fun inline() = inlineFunction(callSite, callee) fun inline() = inlineFunction(callSite, callee)
@@ -146,35 +133,42 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
} }
} }
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl { private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlock {
val copiedCallee = copyIrElement.copy(callee) as IrFunction val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee) val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements val statements = (copiedCallee.body as IrBlockBody).statements
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original) val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset val startOffset = callee.startOffset
val endOffset = callee.endOffset val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) { if (callee.isInlineConstructor) {
// Copier sets parent to be the current function but
// constructor's parent cannot be a function.
val constructedClass = callee.parentAsClass
copiedCallee.parent = constructedClass
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run { irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original val constructorCall = IrCallImpl(
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type, startOffset, endOffset,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply { callSite.type,
constructorDescriptor.valueParameters.forEach { delegatingConstructorCall.symbol, delegatingConstructorCall.descriptor,
putValueArgument( constructedClass.typeParameters.size,
it, delegatingConstructorCall.symbol.owner.valueParameters.size
delegatingConstructorCall.getValueArgument(it) ).apply {
) delegatingConstructorCall.symbol.owner.valueParameters.forEach {
putValueArgument(it.index, delegatingConstructorCall.getValueArgument(it.index))
}
constructedClass.typeParameters.forEach {
putTypeArgument(it.index, delegatingConstructorCall.getTypeArgument(it.index))
} }
} }
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter val oldThis = constructedClass.thisReceiver!!
val newThis = currentScope.scope.createTemporaryVariable( val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
irExpression = constructorCall, irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" nameHint = constructedClass.fqNameSafe.toString() + ".this"
) )
statements[0] = newThis statements[0] = newThis
substituteMap[oldThis] = irGet(newThis) substituteMap[oldThis] = irGet(newThis)
@@ -182,20 +176,25 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
} }
} }
val sourceFile = callee.file
val transformer = ParameterSubstitutor() val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) } statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements) statements.addAll(0, evaluationStatements)
val isCoroutineIntrinsicCall = callSite.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(
context.configuration.languageVersionSettings)
return IrReturnableBlockImpl( return IrReturnableBlockImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = copiedCallee.returnType, type = callSite.type,
symbol = irReturnableBlockSymbol, symbol = irReturnableBlockSymbol,
origin = null, origin = if (isCoroutineIntrinsicCall) CoroutineIntrinsicLambdaOrigin else null,
statements = statements, statements = statements,
sourceFileSymbol = callee.file.symbol sourceFileSymbol = sourceFile.symbol
).apply { ).apply {
transformChildrenVoid(object: IrElementTransformerVoid() { transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression { override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
@@ -213,8 +212,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor val argument = substituteMap[newExpression.symbol.owner] ?: return newExpression
val argument = substituteMap[descriptor] ?: return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution. argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy(argument) as IrExpression return copyIrElement.copy(argument) as IrExpression
@@ -222,57 +220,46 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
//-----------------------------------------------------------------// //-----------------------------------------------------------------//
private val IrFunctionReference.isLambda: Boolean
get() {
return symbol.owner.visibility == Visibilities.LOCAL && origin == IrStatementOrigin.LAMBDA
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression)) if (!isLambdaCall(expression))
return super.visitCall(expression) return super.visitCall(expression)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue val dispatchReceiver = expression.dispatchReceiver as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.descriptor] val functionArgument = substituteMap[dispatchReceiver.symbol.owner] ?: return super.visitCall(expression)
if (functionArgument == null) if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true)
return super.visitCall(expression) return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor
if (dispatchDescriptor is ValueParameterDescriptor &&
dispatchDescriptor.isNoinline
) return super.visitCall(expression)
if (functionArgument is IrFunctionReference) { if (functionArgument is IrFunctionReference) {
if (!functionArgument.isLambda) return super.visitCall(expression) val function = functionArgument.symbol.owner
val functionParameters = function.explicitParameters
val functionDescriptor = functionArgument.descriptor val boundFunctionParameters = functionArgument.getArgumentsWithIr()
val functionParameters = functionDescriptor.explicitParameters
val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first } val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second } val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
var unboundIndex = 0 var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet() val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver. val valueParameters = expression.getArgumentsWithIr().drop(1) // Skip dispatch receiver.
val immediateCall = IrCallImpl( val immediateCall = IrCallImpl(
startOffset = expression.startOffset, expression.startOffset, expression.endOffset,
endOffset = expression.endOffset, expression.type,
type = expression.type, functionArgument.symbol
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor
).apply { ).apply {
functionParameters.forEach { functionParameters.forEach {
val argument = val argument =
if (!unboundArgsSet.contains(it)) if (it !in unboundArgsSet)
boundFunctionParametersMap[it]!! boundFunctionParametersMap[it]!!
else else
valueParameters[unboundIndex++].second valueParameters.getOrNull(unboundIndex++)?.second
when (it) { when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument function.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument function.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument) else -> putValueArgument(it.index, argument)
} }
} }
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" } assert(unboundIndex >= valueParameters.size) { "Not all arguments of <invoke> are used" }
for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index))
} }
return this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall) return this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall)
} }
@@ -280,14 +267,8 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
return super.visitCall(expression) return super.visitCall(expression)
val functionDeclaration = functionArgument.statements[0] as IrFunction val functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction( val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
expression, return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
functionDeclaration
) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(
this,
null
) // Substitute lambda arguments with target function arguments.
} }
//-----------------------------------------------------------------// //-----------------------------------------------------------------//
@@ -295,27 +276,33 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
override fun visitElement(element: IrElement) = element.accept(this, null) override fun visitElement(element: IrElement) = element.accept(this, null)
} }
private fun isLambdaCall(irCall: IrCall) = irCall.symbol.owner.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue private fun isLambdaCall(irCall: IrCall): Boolean {
val callee = irCall.symbol.owner
val dispatchReceiver = callee.dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunction())
return (dispatchReceiver.type.isFunction() || dispatchReceiver.type.isSuspendFunction())
&& callee.name == OperatorNameConventions.INVOKE
&& irCall.dispatchReceiver is IrGetValue
}
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private inner class ParameterToArgument( private fun IrValueParameter.isInlineParameter() =
val parameter: IrValueParameter, !isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
val argumentExpression: IrExpression
) { private inner class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression: IrExpression) {
val isInlinableLambdaArgument: Boolean val isInlinableLambdaArgument: Boolean
get() { get() {
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false if (!parameter.isInlineParameter()) return false
if (argumentExpression is IrFunctionReference if (argumentExpression is IrFunctionReference) return true
&& !argumentExpression.descriptor.isSuspend
) return true // Skip suspend functions for now since it's not supported by FE anyway.
// Do pattern-matching on IR. // Do pattern-matching on IR.
if (argumentExpression !is IrBlock) return false if (argumentExpression !is IrBlock) return false
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
) return false
val statements = argumentExpression.statements val statements = argumentExpression.statements
val irFunction = statements[0] val irFunction = statements[0]
val irCallableReference = statements[1] val irCallableReference = statements[1]
@@ -326,7 +313,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
val isImmutableVariableLoad: Boolean val isImmutableVariableLoad: Boolean
get() = argumentExpression.let { get() = argumentExpression.let {
it is IrGetValue && !it.symbol.owner.let { v -> v is IrVariable && v.isVar } it is IrGetValue && !it.symbol.owner.let { it is IrVariable && it.isVar }
} }
} }
@@ -337,15 +324,14 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
val parameterToArgument = mutableListOf<ParameterToArgument>() val parameterToArgument = mutableListOf<ParameterToArgument>()
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
callee.dispatchReceiverParameter != null callee.dispatchReceiverParameter != null) // on call site and in function declaration.
) // on call site and in function declaration.
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameter = callee.dispatchReceiverParameter!!, parameter = callee.dispatchReceiverParameter!!,
argumentExpression = callSite.dispatchReceiver!! argumentExpression = callSite.dispatchReceiver!!
) )
val valueArguments = val valueArguments =
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList() callSite.symbol.owner.valueParameters.map { callSite.getValueArgument(it.index) }.toMutableList()
if (callee.extensionReceiverParameter != null) { if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
@@ -414,34 +400,25 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
val evaluationStatements = mutableListOf<IrStatement>() val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor() val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach { parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor
/* /*
* We need to create temporary variable for each argument except inlinable lambda arguments. * We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable, * For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas. * not only for those referring to inlinable lambdas.
*/ */
if (it.isInlinableLambdaArgument) { if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression substituteMap[it.parameter] = it.argumentExpression
return@forEach return@forEach
} }
if (it.isImmutableVariableLoad) { if (it.isImmutableVariableLoad) {
substituteMap[parameterDescriptor] = it.argumentExpression.transform( substituteMap[it.parameter] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
substitutor,
data = null
) // Arguments may reference the previous ones - substitute them.
return@forEach return@forEach
} }
val newVariable = currentScope.scope.createTemporaryVariable( val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform( irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
substitutor, nameHint = callee.symbol.owner.name.toString(),
data = null isMutable = false)
), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false
)
evaluationStatements.add(newVariable) evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl( val getVal = IrGetValueImpl(
@@ -450,7 +427,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
type = newVariable.type, type = newVariable.type,
symbol = newVariable.symbol symbol = newVariable.symbol
) )
substituteMap[parameterDescriptor] = getVal substituteMap[it.parameter] = getVal
} }
return evaluationStatements return evaluationStatements
} }
@@ -1,4 +1,4 @@
// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JVM_IR, JS_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,7 +1,7 @@
// !LANGUAGE: +NewInference // !LANGUAGE: +NewInference
// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS, JS_IR // IGNORE_BACKEND: JS
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: test.kt // FILE: test.kt
// We cannot use COMMON_COROUTINES_TEST here due to !LANGUAGE directive // We cannot use COMMON_COROUTINES_TEST here due to !LANGUAGE directive
@@ -1,7 +1,7 @@
// !LANGUAGE: +NewInference // !LANGUAGE: +NewInference
// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: JS, JS_IR // IGNORE_BACKEND: JS
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: test.kt // FILE: test.kt