Skip to content

Commit

Permalink
Handle lambda argument of staticCFunction
Browse files Browse the repository at this point in the history
  • Loading branch information
SvyatoslavScherbina committed Apr 21, 2017
1 parent c6ad4c3 commit ea2d7cb
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
4 changes: 3 additions & 1 deletion INTEROP.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down Expand Up @@ -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)!!
Expand Down
14 changes: 6 additions & 8 deletions backend.native/tests/interop/basics/3.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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)
}

0 comments on commit ea2d7cb

Please sign in to comment.