Rework interop callbacks
* Do not rely on type inference and `CFunctionType`;
* Represent struct-typed parameters and return values as `CValue<*>`
(currently supported only on JVM).
This commit is contained in:
committed by
SvyatoslavScherbina
parent
cc73c7e009
commit
3f84ba462f
+1
-14
@@ -144,20 +144,7 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
|
||||
val bitsToDouble = packageScope.getContributedFunctions("bitsToDouble").single()
|
||||
|
||||
val staticCFunction = packageScope.getContributedFunctions("staticCFunction").single()
|
||||
|
||||
private val triviallyAdaptedFunctionTypeClass =
|
||||
packageScope.getContributedClassifier("CTriviallyAdaptedFunctionType") as ClassDescriptor
|
||||
|
||||
private val trivallyAdaptedFunctionTypeType =
|
||||
triviallyAdaptedFunctionTypeClass.defaultType.replace(
|
||||
newArguments = listOf(
|
||||
StarProjectionImpl(triviallyAdaptedFunctionTypeClass.declaredTypeParameters.single())
|
||||
)
|
||||
)
|
||||
|
||||
fun isTriviallyAdaptedFunctionType(type: KotlinType): Boolean =
|
||||
type.isSubtypeOf(trivallyAdaptedFunctionTypeType)
|
||||
val staticCFunction = packageScope.getContributedFunctions("staticCFunction").toSet()
|
||||
|
||||
val signExtend = packageScope.getContributedFunctions("signExtend").single()
|
||||
|
||||
|
||||
+50
-11
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
@@ -275,27 +276,42 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
builder.readValue(receiver, typeArgument) ?: expression
|
||||
}
|
||||
|
||||
interop.staticCFunction -> {
|
||||
in interop.staticCFunction -> {
|
||||
val argument = expression.getValueArgument(0)!!
|
||||
if (argument !is IrCallableReference || argument.getArguments().isNotEmpty()) {
|
||||
context.reportCompilationError(
|
||||
"${interop.staticCFunction.fqNameSafe} must take an unbound, non-capturing function",
|
||||
"${descriptor.fqNameSafe} must take an unbound, non-capturing function",
|
||||
irFile, expression
|
||||
)
|
||||
// TODO: should probably be reported during analysis.
|
||||
}
|
||||
|
||||
val cFunctionType = expression.getTypeArgument(descriptor.typeParameters[1])!!
|
||||
val target = argument.descriptor.original
|
||||
val signatureTypes = target.allParameters.map { it.type } + target.returnType!!
|
||||
|
||||
if (interop.isTriviallyAdaptedFunctionType(cFunctionType)) {
|
||||
IrCallableReferenceImpl(
|
||||
builder.startOffset, builder.endOffset,
|
||||
expression.type,
|
||||
argument.descriptor,
|
||||
typeArguments = null)
|
||||
} else {
|
||||
TODO("$cFunctionType requiring non-trivial C adapter")
|
||||
signatureTypes.forEachIndexed { index, type ->
|
||||
type.ensureSupportedInCallbacks(
|
||||
isReturnType = (index == signatureTypes.lastIndex),
|
||||
reportError = { context.reportCompilationError(it, irFile, expression) }
|
||||
)
|
||||
}
|
||||
|
||||
descriptor.typeParameters.forEachIndexed { index, typeParameterDescriptor ->
|
||||
val typeArgument = expression.getTypeArgument(typeParameterDescriptor)!!
|
||||
val signatureType = signatureTypes[index]
|
||||
if (typeArgument != signatureType) {
|
||||
context.reportCompilationError(
|
||||
"C function signature element mismatch: expected '$signatureType', got '$typeArgument'",
|
||||
irFile, expression
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IrCallableReferenceImpl(
|
||||
builder.startOffset, builder.endOffset,
|
||||
expression.type,
|
||||
target,
|
||||
typeArguments = null)
|
||||
}
|
||||
|
||||
interop.signExtend, interop.narrow -> {
|
||||
@@ -346,6 +362,29 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.ensureSupportedInCallbacks(isReturnType: Boolean, reportError: (String) -> Nothing) {
|
||||
if (isReturnType && KotlinBuiltIns.isUnit(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this)) {
|
||||
if (!this.isMarkedNullable) {
|
||||
return
|
||||
}
|
||||
reportError("Type $this must not be nullable when used in callback signature")
|
||||
}
|
||||
|
||||
if (TypeUtils.getClassDescriptor(this) == interop.cPointer) {
|
||||
if (this.isMarkedNullable) {
|
||||
return
|
||||
}
|
||||
|
||||
reportError("Type $this must be nullable when used in callback signature")
|
||||
}
|
||||
|
||||
reportError("Type $this is not supported in callback signature")
|
||||
}
|
||||
|
||||
private fun IrCall.getSingleTypeArgument(): KotlinType {
|
||||
val typeParameter = descriptor.original.typeParameters.single()
|
||||
return getTypeArgument(typeParameter)!!
|
||||
|
||||
Reference in New Issue
Block a user