JVM_IR. support big arity
This commit is contained in:
@@ -169,6 +169,8 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, private val
|
||||
|
||||
abstract val coroutineSuspendedGetter: IrSimpleFunctionSymbol
|
||||
|
||||
fun getFunction(parameterCount: Int) = symbolTable.referenceClass(context.builtIns.getFunction(parameterCount))
|
||||
|
||||
val functionReference = calc { symbolTable.referenceClass(context.getInternalClass("FunctionReference")) }
|
||||
|
||||
fun getFunction(name: Name, receiverType: KotlinType, vararg argTypes: KotlinType) =
|
||||
|
||||
@@ -57,6 +57,7 @@ class JvmLower(val context: JvmBackendContext) {
|
||||
true
|
||||
).runOnFilePostfix(irFile)
|
||||
CallableReferenceLowering(context).lower(irFile)
|
||||
FunctionNVarargInvokeLowering(context).runOnFilePostfix(irFile)
|
||||
|
||||
InnerClassesLowering(context).runOnFilePostfix(irFile)
|
||||
InnerClassConstructorCallsLowering(context).runOnFilePostfix(irFile)
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class IrIllegalArgumentException : IntrinsicMethod() {
|
||||
val exceptionTypeDescriptor = Type.getInternalName(IllegalArgumentException::class.java)
|
||||
|
||||
override fun toCallable(
|
||||
expression: IrMemberAccessExpression,
|
||||
signature: JvmMethodSignature,
|
||||
context: JvmBackendContext
|
||||
): IrIntrinsicFunction {
|
||||
return object : IrIntrinsicFunction(expression, signature, context, listOf(JAVA_STRING_TYPE)) {
|
||||
override fun genInvokeInstruction(v: InstructionAdapter) {
|
||||
v.invokespecial(exceptionTypeDescriptor, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE), false)
|
||||
v.athrow()
|
||||
}
|
||||
|
||||
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
|
||||
v.anew(Type.getType(exceptionTypeDescriptor))
|
||||
v.dup()
|
||||
return super.invoke(v, codegen, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -52,6 +52,7 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
|
||||
|
||||
irMapping[irBuiltIns.enumValueOf] = IrEnumValueOf()
|
||||
irMapping[irBuiltIns.noWhenBranchMatchedException] = IrNoWhenBranchMatchedException()
|
||||
irMapping[irBuiltIns.illegalArgumentException] = IrIllegalArgumentException()
|
||||
irMapping[irBuiltIns.throwNpe] = ThrowNPE()
|
||||
}
|
||||
|
||||
|
||||
+119
-29
@@ -37,20 +37,14 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.toIrType
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
@@ -99,8 +93,41 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
}
|
||||
}
|
||||
|
||||
val argumentsCount = expression.valueArgumentsCount
|
||||
// Change calls to FunctionN with large N to varargs calls.
|
||||
val newCall = if (argumentsCount > MAX_ARGCOUNT_WITHOUT_VARARG &&
|
||||
descriptor.containingDeclaration in listOf(
|
||||
context.builtIns.getFunction(argumentsCount),
|
||||
context.reflectionTypes.getKFunction(argumentsCount)
|
||||
)
|
||||
) {
|
||||
val vararg = IrVarargImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
context.ir.symbols.array.typeWith(),
|
||||
context.ir.symbols.any.typeWith(),
|
||||
(0 until argumentsCount).map { i -> expression.getValueArgument(i)!! }
|
||||
)
|
||||
val invokeFunDescriptor = context.getClass(FqName("kotlin.jvm.functions.FunctionN"))
|
||||
.getFunction("invoke", listOf(expression.type.toKotlinType()))
|
||||
val invokeFunSymbol = context.ir.symbols.externalSymbolTable.referenceSimpleFunction(invokeFunDescriptor)
|
||||
|
||||
IrCallImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
expression.type,
|
||||
invokeFunSymbol, invokeFunDescriptor,
|
||||
1,
|
||||
expression.origin,
|
||||
expression.superQualifier?.let { context.ir.symbols.externalSymbolTable.referenceClass(it) }
|
||||
).apply {
|
||||
putTypeArgument(0, expression.type)
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
extensionReceiver = expression.extensionReceiver
|
||||
putValueArgument(0, vararg)
|
||||
}
|
||||
} else expression
|
||||
|
||||
//TODO: clean
|
||||
return super.visitCall(expression)
|
||||
return super.visitCall(newCall)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
@@ -155,6 +182,8 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
|
||||
private val functionReferenceOrLambda = if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference
|
||||
|
||||
var useVararg: Boolean = false
|
||||
|
||||
fun build(): BuiltFunctionReference {
|
||||
val startOffset = irFunctionReference.startOffset
|
||||
val endOffset = irFunctionReference.endOffset
|
||||
@@ -165,9 +194,17 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
)
|
||||
|
||||
val numberOfParameters = unboundFunctionParameters.size
|
||||
val functionClassDescriptor = context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters"))
|
||||
useVararg = (numberOfParameters > MAX_ARGCOUNT_WITHOUT_VARARG)
|
||||
|
||||
val functionClassDescriptor = if (useVararg)
|
||||
context.getClass(FqName("kotlin.jvm.functions.FunctionN"))
|
||||
else
|
||||
context.getClass(FqName("kotlin.jvm.functions.Function$numberOfParameters"))
|
||||
val functionParameterTypes = unboundFunctionParameters.map { it.type }
|
||||
val functionClassTypeParameters = functionParameterTypes + returnType
|
||||
val functionClassTypeParameters = if (useVararg)
|
||||
listOf(returnType)
|
||||
else
|
||||
functionParameterTypes + returnType
|
||||
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters)
|
||||
|
||||
var suspendFunctionClassDescriptor: ClassDescriptor? = null
|
||||
@@ -197,7 +234,17 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
endOffset = endOffset,
|
||||
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
|
||||
descriptor = functionReferenceClassDescriptor
|
||||
)
|
||||
).apply {
|
||||
createParameterDeclarations()
|
||||
val typeTranslator = TypeTranslator(context.ir.symbols.externalSymbolTable, context.state.languageVersionSettings,
|
||||
enterTableScope=true)
|
||||
val constantValueGenerator = ConstantValueGenerator(context.state.module, context.ir.symbols.externalSymbolTable)
|
||||
typeTranslator.constantValueGenerator = constantValueGenerator
|
||||
constantValueGenerator.typeTranslator = typeTranslator
|
||||
functionReferenceClassDescriptor.typeConstructor.supertypes.mapTo(this.superTypes) {
|
||||
typeTranslator.translateType(it)
|
||||
}
|
||||
}
|
||||
|
||||
val contributedDescriptors = mutableListOf<DeclarationDescriptor>()
|
||||
val constructorBuilder = createConstructorBuilder()
|
||||
@@ -205,8 +252,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null
|
||||
)
|
||||
|
||||
functionReferenceClass.createParameterDeclarations()
|
||||
|
||||
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
|
||||
|
||||
val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters)
|
||||
@@ -219,7 +264,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
invokeMethodBuilder.initialize()
|
||||
functionReferenceClass.declarations.add(invokeMethodBuilder.ir)
|
||||
|
||||
|
||||
if (!isLambda) {
|
||||
val getSignatureBuilder =
|
||||
createGetSignatureMethodBuilder(functionReferenceOrLambda.owner.descriptor.getFunction("getSignature", emptyList()))
|
||||
@@ -245,7 +289,6 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
).filterNotNull()
|
||||
)
|
||||
|
||||
|
||||
getSignatureBuilder.initialize()
|
||||
functionReferenceClass.declarations.add(getSignatureBuilder.ir)
|
||||
|
||||
@@ -391,31 +434,74 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
createParameterDeclarations()
|
||||
|
||||
body = irBuilder.irBlockBody(startOffset, endOffset) {
|
||||
val arrayGetFun = context.irBuiltIns.arrayClass.owner
|
||||
.declarations.find {
|
||||
(it as? IrSimpleFunction)?.name?.toString() == "get"
|
||||
}!! as IrSimpleFunction
|
||||
|
||||
if (useVararg) {
|
||||
val varargParam = valueParameters.single()
|
||||
val arraySizeProperty = context.irBuiltIns.arrayClass.owner.declarations.find {
|
||||
(it as? IrProperty)?.name?.toString() == "size"
|
||||
} as IrProperty
|
||||
+irIfThen(
|
||||
irNotEquals(
|
||||
irCall(arraySizeProperty.getter!!).apply {
|
||||
dispatchReceiver = irGet(varargParam)
|
||||
},
|
||||
irInt(unboundFunctionParameters.size)
|
||||
),
|
||||
irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply {
|
||||
putValueArgument(0, irString("Expected ${unboundFunctionParameters.size} arguments"))
|
||||
}
|
||||
)
|
||||
}
|
||||
+irReturn(
|
||||
irCall(irFunctionReference.symbol).apply {
|
||||
var unboundIndex = 0
|
||||
val unboundArgsSet = unboundFunctionParameters.toSet()
|
||||
functionParameters.forEach {
|
||||
val argument =
|
||||
if (!unboundArgsSet.contains(it))
|
||||
// Bound parameter - read from field.
|
||||
irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[it]!!.owner)
|
||||
else {
|
||||
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
|
||||
|
||||
functionParameters.forEach { parameter ->
|
||||
val argument = when {
|
||||
!unboundArgsSet.contains(parameter) ->
|
||||
// Bound parameter - read from field.
|
||||
irGetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter]!!.owner)
|
||||
ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size ->
|
||||
// For suspend functions the last argument is continuation and it is implicit.
|
||||
TODO()
|
||||
TODO()
|
||||
// irCall(getContinuationSymbol,
|
||||
// listOf(ourSymbol.descriptor.returnType!!))
|
||||
else
|
||||
irGet(valueParameters[unboundIndex++])
|
||||
useVararg -> {
|
||||
val type = parameter.type.toIrType()!!
|
||||
val varargParam = valueParameters.single()
|
||||
irBlock(resultType = type) {
|
||||
val argValue = irTemporary(
|
||||
irCall(arrayGetFun).apply {
|
||||
dispatchReceiver = irGet(varargParam)
|
||||
putValueArgument(0, irInt(unboundIndex++))
|
||||
}
|
||||
)
|
||||
+irIfThen(
|
||||
irNotIs(irGet(argValue), type),
|
||||
irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply {
|
||||
putValueArgument(0, irString("Wrong type, expected $type"))
|
||||
}
|
||||
)
|
||||
+irGet(argValue)
|
||||
}
|
||||
}
|
||||
when (it) {
|
||||
else -> {
|
||||
irGet(valueParameters[unboundIndex++])
|
||||
}
|
||||
}
|
||||
when (parameter) {
|
||||
functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument
|
||||
functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument
|
||||
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
|
||||
else -> putValueArgument((parameter as ValueParameterDescriptor).index, argument)
|
||||
}
|
||||
}
|
||||
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
|
||||
|
||||
if (!useVararg) assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -703,6 +789,10 @@ class CallableReferenceLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
Name.identifier("$${name.substring(1, name.length - 1)}")
|
||||
} else this
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_ARGCOUNT_WITHOUT_VARARG = 22
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from K/Native IrUtils2.kt
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.filterDeclarations
|
||||
import org.jetbrains.kotlin.ir.util.findDeclaration
|
||||
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val invokeFunctions = irClass.filterDeclarations<IrSimpleFunction> { it.name.toString() == "invoke" }
|
||||
if (invokeFunctions.isEmpty() ||
|
||||
invokeFunctions.any { it.valueParameters.size > 0 && it.valueParameters.last().varargElementType != null } ||
|
||||
invokeFunctions.all { it.valueParameters.size + (if (it.extensionReceiverParameter != null) 1 else 0) <= CallableReferenceLowering.MAX_ARGCOUNT_WITHOUT_VARARG }
|
||||
) {
|
||||
// No need to add a new vararg invoke method
|
||||
return
|
||||
}
|
||||
val functionInvokes = invokeFunctions.filter { irClass.isSubclassOf(context.ir.symbols.getFunction(it.valueParameters.size).owner) }
|
||||
if (functionInvokes.isEmpty()) return
|
||||
|
||||
irClass.declarations.add(generateVarargInvoke(irClass, functionInvokes))
|
||||
}
|
||||
|
||||
private fun generateVarargInvoke(irClass: IrClass, invokesToDelegateTo: List<IrSimpleFunction>): IrFunction {
|
||||
val backendContext = context
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
return IrFunctionImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
origin = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
|
||||
symbol = IrSimpleFunctionSymbolImpl(descriptor),
|
||||
name = Name.identifier("invoke"),
|
||||
visibility = Visibilities.PUBLIC,
|
||||
modality = Modality.OPEN,
|
||||
isInline = false,
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = false
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
returnType = context.irBuiltIns.anyNType
|
||||
dispatchReceiverParameter = irClass.thisReceiver
|
||||
val varargParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
val varargParam = IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
origin = CallableReferenceLowering.DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
|
||||
symbol = IrValueParameterSymbolImpl(varargParameterDescriptor),
|
||||
name = Name.identifier("args"),
|
||||
index = 0,
|
||||
type = context.irBuiltIns.arrayClass.typeWith(),
|
||||
varargElementType = context.irBuiltIns.anyClass.typeWith(),
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).apply {
|
||||
varargParameterDescriptor.bind(this)
|
||||
}
|
||||
valueParameters.add(varargParam)
|
||||
val irBuilder = context.createIrBuilder(symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
body = irBuilder.irBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
val arrayGetFun =
|
||||
backendContext.irBuiltIns.arrayClass.owner.findDeclaration<IrSimpleFunction> { it.name.toString() == "get" }!!
|
||||
val arraySizeProperty = context.irBuiltIns.arrayClass.owner.findDeclaration<IrProperty> { it.name.toString() == "size" }!!
|
||||
val numberOfArguments = irTemporary(irCall(arraySizeProperty.getter!!).apply {
|
||||
dispatchReceiver = irGet(varargParam)
|
||||
})
|
||||
|
||||
for (target in invokesToDelegateTo) {
|
||||
+irIfThen(
|
||||
backendContext.irBuiltIns.unitType,
|
||||
irEquals(irGet(numberOfArguments), irInt(target.valueParameters.size)),
|
||||
irReturn(
|
||||
IrTypeOperatorCallImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
backendContext.irBuiltIns.anyNType,
|
||||
IrTypeOperator.CAST,
|
||||
target.returnType,
|
||||
target.returnType.classifierOrFail,
|
||||
irCall(target).apply {
|
||||
dispatchReceiver = irGet(irClass.thisReceiver!!)
|
||||
target.valueParameters.forEachIndexed { i, irValueParameter ->
|
||||
val type = irValueParameter.type
|
||||
putValueArgument(
|
||||
i,
|
||||
irBlock(resultType = type) {
|
||||
val argValue = irTemporary(
|
||||
irCallOp(
|
||||
arrayGetFun.symbol,
|
||||
context.irBuiltIns.anyNType,
|
||||
irGet(varargParam),
|
||||
irInt(i)
|
||||
)
|
||||
)
|
||||
+irIfThen(
|
||||
irNotIs(irGet(argValue), type),
|
||||
irCall(context.irBuiltIns.illegalArgumentExceptionFun).apply {
|
||||
putValueArgument(0, irString("Wrong type, expected $type"))
|
||||
}
|
||||
)
|
||||
+irGet(argValue)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val throwMessage = invokesToDelegateTo.map { it.valueParameters.size.toString() }.joinToString(
|
||||
prefix = "Expected ",
|
||||
separator = " or ",
|
||||
postfix = " arguments to invoke call"
|
||||
)
|
||||
+irCall(context.irBuiltIns.illegalArgumentExceptionFun.symbol).apply {
|
||||
putValueArgument(0, irString(throwMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,8 @@ class IrBuiltIns(
|
||||
val stringType = string.toIrType()
|
||||
val stringClass = builtIns.string.toIrSymbol()
|
||||
|
||||
val arrayClass = builtIns.array.toIrSymbol()
|
||||
|
||||
val throwableType = builtIns.throwable.defaultType.toIrType()
|
||||
val throwableClass = builtIns.throwable.toIrSymbol()
|
||||
|
||||
@@ -152,6 +154,7 @@ class IrBuiltIns(
|
||||
val throwIseFun = defineOperator("THROW_ISE", nothing, listOf())
|
||||
val booleanNotFun = defineOperator("NOT", bool, listOf(bool))
|
||||
val noWhenBranchMatchedExceptionFun = defineOperator("noWhenBranchMatchedException", nothing, listOf())
|
||||
val illegalArgumentExceptionFun = defineOperator("illegalArgumentException", nothing, listOf(string))
|
||||
|
||||
val eqeqeq = eqeqeqFun.descriptor
|
||||
val eqeq = eqeqFun.descriptor
|
||||
@@ -159,6 +162,7 @@ class IrBuiltIns(
|
||||
val throwCce = throwCceFun.descriptor
|
||||
val booleanNot = booleanNotFun.descriptor
|
||||
val noWhenBranchMatchedException = noWhenBranchMatchedExceptionFun.descriptor
|
||||
val illegalArgumentException = illegalArgumentExceptionFun.descriptor
|
||||
|
||||
val eqeqeqSymbol = eqeqeqFun.symbol
|
||||
val eqeqSymbol = eqeqFun.symbol
|
||||
@@ -167,6 +171,7 @@ class IrBuiltIns(
|
||||
val throwIseSymbol = throwIseFun.symbol
|
||||
val booleanNotSymbol = booleanNotFun.symbol
|
||||
val noWhenBranchMatchedExceptionSymbol = noWhenBranchMatchedExceptionFun.symbol
|
||||
val illegalArgumentExceptionSymbol = illegalArgumentExceptionFun.symbol
|
||||
|
||||
val enumValueOfFun = createEnumValueOfFun()
|
||||
val enumValueOf = enumValueOfFun.descriptor
|
||||
|
||||
@@ -266,6 +266,26 @@ val IrClass.defaultType: IrType
|
||||
|
||||
val IrSimpleFunction.isReal: Boolean get() = descriptor.kind.isReal
|
||||
|
||||
fun IrClass.isImmediateSubClassOf(ancestor: IrClass) = ancestor.symbol in superTypes.mapNotNull {
|
||||
(it as? IrSimpleType)?.classifier
|
||||
}
|
||||
|
||||
fun IrClass.isSubclassOf(ancestor: IrClass): Boolean {
|
||||
|
||||
val alreadyVisited = mutableSetOf<IrClass>()
|
||||
|
||||
fun IrClass.hasAncestorInSuperTypes(): Boolean = when {
|
||||
this === ancestor -> true
|
||||
this in alreadyVisited -> false
|
||||
else -> {
|
||||
alreadyVisited.add(this)
|
||||
superTypes.mapNotNull { ((it as? IrSimpleType)?.classifier as? IrClassSymbol)?.owner }.any { it.hasAncestorInSuperTypes() }
|
||||
}
|
||||
}
|
||||
|
||||
return this.hasAncestorInSuperTypes()
|
||||
}
|
||||
|
||||
// This implementation is from kotlin-native
|
||||
// TODO: use this implementation instead of any other
|
||||
fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction? {
|
||||
@@ -339,6 +359,12 @@ fun IrDeclaration.isEffectivelyExternal(): Boolean {
|
||||
|
||||
fun IrDeclaration.isDynamic() = this is IrFunction && dispatchReceiverParameter?.type is IrDynamicType
|
||||
|
||||
inline fun <reified T : IrDeclaration> IrDeclarationContainer.findDeclaration(predicate: (T) -> Boolean): T? =
|
||||
declarations.find { it is T && predicate(it) } as? T
|
||||
|
||||
inline fun <reified T : IrDeclaration> IrDeclarationContainer.filterDeclarations(predicate: (T) -> Boolean): List<T> =
|
||||
declarations.filter { it is T && predicate(it) } as List<T>
|
||||
|
||||
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
|
||||
assert(this.descriptor.type == newDescriptor.type)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: J.java
|
||||
|
||||
import kotlin.jvm.functions.FunctionN;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// FILE: J.java
|
||||
|
||||
// import kotlin.jvm.functions.Arity;
|
||||
import kotlin.jvm.functions.FunctionN;
|
||||
import kotlin.Unit;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class J {
|
||||
// TODO: uncomment arity as soon as Arity is introduced
|
||||
public static void test(/* @Arity(30) */ FunctionN<Integer> f) {
|
||||
Object o = new Integer(0);
|
||||
for (int i = 0; i < 42; i++) {
|
||||
Object[] args = new Object[i];
|
||||
Arrays.fill(args, o);
|
||||
try {
|
||||
if (f.invoke(args).intValue() != 300 + i) {
|
||||
throw new AssertionError("Bad return value from function");
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (i == 3 || i == 13 || i == 30 || i == 33) {
|
||||
throw new AssertionError(String.format("Call with %d arguments is expected to succeed", i), e);
|
||||
}
|
||||
// OK
|
||||
|
||||
if (!e.getMessage().contains("30")) {
|
||||
throw new AssertionError("Exception must specify the expected number of arguments: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
continue;
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError(
|
||||
"Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", i = " + i, e
|
||||
);
|
||||
}
|
||||
if (i != 3 && i != 13 && i != 30 && i != 33) {
|
||||
throw new AssertionError ("IllegalArgumentException expected, but nothing was thrown, i = " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: K.kt
|
||||
|
||||
class Fun : (Int, Int, Int) -> Int,
|
||||
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int,
|
||||
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
|
||||
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int,
|
||||
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
|
||||
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int {
|
||||
override fun invoke(p00: Int, p01: Int, p02: Int): Int = 303
|
||||
|
||||
override fun invoke(
|
||||
p00: Int, p01: Int, p02: Int, p03: Int, p04: Int, p05: Int, p06: Int, p07: Int, p08: Int, p09: Int,
|
||||
p10: Int, p11: Int, p12: Int
|
||||
): Int = 313
|
||||
|
||||
override fun invoke(
|
||||
p00: Int, p01: Int, p02: Int, p03: Int, p04: Int, p05: Int, p06: Int, p07: Int, p08: Int, p09: Int,
|
||||
p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int,
|
||||
p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int
|
||||
): Int = 330
|
||||
|
||||
override fun invoke(
|
||||
p00: Int, p01: Int, p02: Int, p03: Int, p04: Int, p05: Int, p06: Int, p07: Int, p08: Int, p09: Int,
|
||||
p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int,
|
||||
p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int,
|
||||
p30: Int, p31: Int, p32: Int
|
||||
): Int = 333
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
J.test(Fun() as kotlin.jvm.functions.FunctionN<Int>)
|
||||
return "OK"
|
||||
}
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: J.java
|
||||
|
||||
// import kotlin.jvm.functions.Arity;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
class A(val value: Int) {
|
||||
// for (i in 1..254) { print("p${"%03d".format(i)}: A, "); if (i % 10 == 0) println() }; println()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
class A
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
class A(val value: Int)
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A {
|
||||
fun foo(
|
||||
p00: A, p01: A, p02: A, p03: A, p04: A, p05: A, p06: A, p07: A, p08: A, p09: A,
|
||||
p10: A, p11: A, p12: A, p13: A, p14: A, p15: A, p16: A, p17: A, p18: A, p19: A,
|
||||
p20: A, p21: A, p22: A, p23: A, p24: A, p25: A, p26: A, p27: A, p28: A, p29: A
|
||||
): String {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
val ref = a::foo
|
||||
return ref(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a)
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: J.java
|
||||
|
||||
// import kotlin.jvm.functions.Arity;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// !LANGUAGE: -FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
// This test does not make sense for JVM because a diagnostic is reported when function types with big arity are not available
|
||||
// (see diagnostics/tests/sourceCompatibility/noBigFunctionTypes.kt)
|
||||
// IGNORE_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM, JVM_IR
|
||||
|
||||
class A
|
||||
|
||||
|
||||
+5
@@ -10729,6 +10729,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeMemberCallableReference.kt")
|
||||
public void testInvokeMemberCallableReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaLambda.kt")
|
||||
public void testJavaLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
|
||||
|
||||
+5
@@ -10734,6 +10734,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeMemberCallableReference.kt")
|
||||
public void testInvokeMemberCallableReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaLambda.kt")
|
||||
public void testJavaLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
|
||||
|
||||
+10
@@ -10704,6 +10704,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/callFromJava.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("callFunViaVararg.kt")
|
||||
public void testCallFunViaVararg() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("callWithIncorrectNumberOfArguments.kt")
|
||||
public void testCallWithIncorrectNumberOfArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt");
|
||||
@@ -10729,6 +10734,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeMemberCallableReference.kt")
|
||||
public void testInvokeMemberCallableReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaLambda.kt")
|
||||
public void testJavaLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
|
||||
|
||||
+5
@@ -9279,6 +9279,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeMemberCallableReference.kt")
|
||||
public void testInvokeMemberCallableReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
|
||||
+5
@@ -10344,6 +10344,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeMemberCallableReference.kt")
|
||||
public void testInvokeMemberCallableReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeMemberCallableReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
|
||||
Reference in New Issue
Block a user