Handle lambda argument of staticCFunction
This commit is contained in:
committed by
SvyatoslavScherbina
parent
c6ad4c3307
commit
ea2d7cbf01
+3
-1
@@ -275,7 +275,9 @@ methods available:
|
||||
### Callbacks ###
|
||||
|
||||
To convert Kotlin function to pointer to C function,
|
||||
`staticCFunction(::kotlinFunction)` can be used.
|
||||
`staticCFunction(::kotlinFunction)` can be used. It is also allowed to provide
|
||||
the lambda instead of function reference. The function or lambda must not
|
||||
capture any values.
|
||||
|
||||
Note that some function types are not supported currently. For example,
|
||||
it is not possible to get pointer to function that receives or returns structs
|
||||
|
||||
+34
-4
@@ -277,16 +277,17 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
}
|
||||
|
||||
in interop.staticCFunction -> {
|
||||
val argument = expression.getValueArgument(0)!!
|
||||
if (argument !is IrCallableReference || argument.getArguments().isNotEmpty()) {
|
||||
val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(0)!!)
|
||||
|
||||
if (irCallableReference == null || irCallableReference.getArguments().isNotEmpty()) {
|
||||
context.reportCompilationError(
|
||||
"${descriptor.fqNameSafe} must take an unbound, non-capturing function",
|
||||
"${descriptor.fqNameSafe} must take an unbound, non-capturing function or lambda",
|
||||
irFile, expression
|
||||
)
|
||||
// TODO: should probably be reported during analysis.
|
||||
}
|
||||
|
||||
val target = argument.descriptor.original
|
||||
val target = irCallableReference.descriptor.original
|
||||
val signatureTypes = target.allParameters.map { it.type } + target.returnType!!
|
||||
|
||||
signatureTypes.forEachIndexed { index, type ->
|
||||
@@ -385,6 +386,35 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
reportError("Type $this is not supported in callback signature")
|
||||
}
|
||||
|
||||
private fun unwrapStaticFunctionArgument(argument: IrExpression): IrCallableReference? {
|
||||
if (argument is IrCallableReference) {
|
||||
return argument
|
||||
}
|
||||
|
||||
// Otherwise check whether it is a lambda:
|
||||
|
||||
// 1. It is a container with two statements and expected origin:
|
||||
|
||||
if (argument !is IrContainerExpression || argument.statements.size != 2) {
|
||||
return null
|
||||
}
|
||||
if (argument.origin != IrStatementOrigin.LAMBDA && argument.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 2. First statement is an empty container (created during local functions lowering):
|
||||
|
||||
val firstStatement = argument.statements.first()
|
||||
|
||||
if (firstStatement !is IrContainerExpression || firstStatement.statements.size != 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 3. Second statement is IrCallableReference:
|
||||
|
||||
return argument.statements.last() as? IrCallableReference
|
||||
}
|
||||
|
||||
private fun IrCall.getSingleTypeArgument(): KotlinType {
|
||||
val typeParameter = descriptor.original.typeParameters.single()
|
||||
return getTypeArgument(typeParameter)!!
|
||||
|
||||
@@ -11,7 +11,12 @@ fun main(args: Array<String>) {
|
||||
values[3] = 13
|
||||
values[4] = 8
|
||||
|
||||
cstdlib.qsort(values, count.toLong(), IntVar.size, staticCFunction(::comparator))
|
||||
cstdlib.qsort(values, count.toLong(), IntVar.size, staticCFunction { a, b ->
|
||||
val aValue = a!!.reinterpret<IntVar>()[0]
|
||||
val bValue = b!!.reinterpret<IntVar>()[0]
|
||||
|
||||
(aValue - bValue)
|
||||
})
|
||||
|
||||
for (i in 0 .. count - 1) {
|
||||
print(values[i])
|
||||
@@ -20,10 +25,3 @@ fun main(args: Array<String>) {
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
private fun comparator(a: COpaquePointer?, b: COpaquePointer?): Int {
|
||||
val aValue = a!!.reinterpret<IntVar>()[0]
|
||||
val bValue = b!!.reinterpret<IntVar>()[0]
|
||||
|
||||
return (aValue - bValue)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user