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 ###
|
### Callbacks ###
|
||||||
|
|
||||||
To convert Kotlin function to pointer to C function,
|
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,
|
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
|
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 -> {
|
in interop.staticCFunction -> {
|
||||||
val argument = expression.getValueArgument(0)!!
|
val irCallableReference = unwrapStaticFunctionArgument(expression.getValueArgument(0)!!)
|
||||||
if (argument !is IrCallableReference || argument.getArguments().isNotEmpty()) {
|
|
||||||
|
if (irCallableReference == null || irCallableReference.getArguments().isNotEmpty()) {
|
||||||
context.reportCompilationError(
|
context.reportCompilationError(
|
||||||
"${descriptor.fqNameSafe} must take an unbound, non-capturing function",
|
"${descriptor.fqNameSafe} must take an unbound, non-capturing function or lambda",
|
||||||
irFile, expression
|
irFile, expression
|
||||||
)
|
)
|
||||||
// TODO: should probably be reported during analysis.
|
// 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!!
|
val signatureTypes = target.allParameters.map { it.type } + target.returnType!!
|
||||||
|
|
||||||
signatureTypes.forEachIndexed { index, type ->
|
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")
|
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 {
|
private fun IrCall.getSingleTypeArgument(): KotlinType {
|
||||||
val typeParameter = descriptor.original.typeParameters.single()
|
val typeParameter = descriptor.original.typeParameters.single()
|
||||||
return getTypeArgument(typeParameter)!!
|
return getTypeArgument(typeParameter)!!
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ fun main(args: Array<String>) {
|
|||||||
values[3] = 13
|
values[3] = 13
|
||||||
values[4] = 8
|
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) {
|
for (i in 0 .. count - 1) {
|
||||||
print(values[i])
|
print(values[i])
|
||||||
@@ -20,10 +25,3 @@ fun main(args: Array<String>) {
|
|||||||
println()
|
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