Generate typedef wrappers for nullable inline classes and method args (KT-36878, KT-39015, KT-39496)

Merge-request: KT-MR-6597
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
Vladimir Sukharev
2022-07-06 11:02:16 +00:00
committed by Space
parent 777aa725c9
commit f8f01941a8
11 changed files with 213 additions and 23 deletions
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.annotations.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNullable
@@ -479,12 +478,12 @@ private class ExportedElement(val kind: ElementKind,
return builder.toString()
}
private fun addUsedType(type: KotlinType, set: MutableSet<ClassDescriptor>) {
private fun addUsedType(type: KotlinType, set: MutableSet<KotlinType>) {
if (type.constructor.declarationDescriptor is TypeParameterDescriptor) return
set.addIfNotNull(TypeUtils.getClassDescriptor(type))
set.add(type)
}
fun addUsedTypes(set: MutableSet<ClassDescriptor>) {
fun addUsedTypes(set: MutableSet<KotlinType>) {
val descriptor = declaration
when (descriptor) {
is FunctionDescriptor -> {
@@ -497,7 +496,7 @@ private class ExportedElement(val kind: ElementKind,
addUsedType(original.correspondingProperty.type, set)
}
is ClassDescriptor -> {
set += descriptor
set += descriptor.defaultType
}
}
}
@@ -787,7 +786,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
if (kind == DefinitionKind.C_SOURCE_STRUCT) output("},", indent)
}
private fun defineUsedTypesImpl(scope: ExportedElementScope, set: MutableSet<ClassDescriptor>) {
private fun defineUsedTypesImpl(scope: ExportedElementScope, set: MutableSet<KotlinType>) {
scope.elements.forEach {
it.addUsedTypes(set)
}
@@ -797,23 +796,20 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
}
private fun defineUsedTypes(scope: ExportedElementScope, indent: Int) {
val set = mutableSetOf<ClassDescriptor>()
defineUsedTypesImpl(scope, set)
// Add nullable primitives.
predefinedTypes.forEach {
val nullableIt = it.makeNullable()
output("typedef struct {", indent)
output("${prefix}_KNativePtr pinned;", indent + 1)
output("} ${translateType(nullableIt)};", indent)
}
set.forEach {
val type = it.defaultType
if (isMappedToReference(type) && !it.isInlined()) {
output("typedef struct {", indent)
output("${prefix}_KNativePtr pinned;", indent + 1)
output("} ${translateType(type)};", indent)
}
}
val usedTypes = mutableSetOf<KotlinType>()
defineUsedTypesImpl(scope, usedTypes)
val usedReferenceTypes = usedTypes.filter { isMappedToReference(it) }
// Add nullable primitives, which are used in prototypes of "(*createNullable<PRIMITIVE_TYPE_NAME>)"
val predefinedNullableTypes = predefinedTypes.map { it.makeNullable() }
(predefinedNullableTypes + usedReferenceTypes)
.map { translateType(it) }
.toSet()
.forEach {
output("typedef struct {", indent)
output("${prefix}_KNativePtr pinned;", indent + 1)
output("} $it;", indent)
}
}
val exportedSymbols = mutableListOf<String>()
@@ -5181,6 +5181,27 @@ dynamicTest("kt36639") {
useGoldenData = true
}
dynamicTest("kt36878") {
disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic
source = "produce_dynamic/kt-36878/hello.kt"
cSource = "$projectDir/produce_dynamic/kt-36878/main.c"
useGoldenData = true
}
dynamicTest("kt39015") {
disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic
source = "produce_dynamic/kt-39015/hello.kt"
cSource = "$projectDir/produce_dynamic/kt-39015/main.c"
useGoldenData = true
}
dynamicTest("kt39496") {
disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic
source = "produce_dynamic/kt-39496/hello.kt"
cSource = "$projectDir/produce_dynamic/kt-39496/main.c"
useGoldenData = true
}
for (i in 0..2) {
dynamicTest("kt42796_$i") {
clangTool = "clang++"
@@ -0,0 +1,6 @@
ValueClass? = ValueClass(number=153)
UsualClass? = 128
UByteArray = UByteArray(storage=[64, -128]): 64, 128
UIntArray? = UIntArray(storage=[64, 128]): 64, 128
Foo<ValueClass> = class Foo
Foo<UsualClass> = class Foo
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
value class ValueClass(val number: Int) {}
class UsualClass(val number: UByte) {}
class Foo<T>
object ObjectForExample {
val nullableVal: ValueClass? = ValueClass(153)
val usual: UsualClass = UsualClass(128.toUByte())
val uByteArray: UByteArray = ubyteArrayOf(0x40.toUByte(), 0x80.toUByte())
val uIntArray: UIntArray = intArrayOf(0x40, 0x80).toUIntArray()
val fooValueClass = Foo<ValueClass>()
val fooUsualClass = Foo<UsualClass>()
fun fooValue(foo: ValueClass?) {
println("ValueClass? = $foo")
}
fun fooUsual(foo: UsualClass?) {
println("UsualClass? = ${foo?.number}")
}
fun fooUByteArray(foo: UByteArray) {
println("UByteArray = $foo: ${foo.joinToString()}")
}
fun fooUIntArrayNullable(foo: UIntArray?) {
println("UIntArray? = $foo: ${foo?.joinToString()}")
}
fun fooFooValue(foo: Foo<ValueClass>) {
println("Foo<ValueClass> = ${foo::class}")
}
fun fooFooUsual(foo: Foo<UsualClass>) {
println("Foo<UsualClass> = ${foo::class}")
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
#include "testlib_api.h"
#define __ testlib_symbols()->
#define T_(x) testlib_kref_ ## x
int main(int argc, char** argv) {
T_(ObjectForExample) instance = __ kotlin.root.ObjectForExample._instance ();
T_(ValueClass) value = __ kotlin.root.ObjectForExample.get_nullableVal (instance);
T_(UsualClass) usual = __ kotlin.root.ObjectForExample.get_usual (instance);
T_(kotlin_ByteArray) uByteArray = __ kotlin.root.ObjectForExample.get_uByteArray (instance);
T_(kotlin_IntArray) uIntArray = __ kotlin.root.ObjectForExample.get_uIntArray (instance);
T_(Foo) fooValueClass = __ kotlin.root.ObjectForExample.get_fooValueClass (instance);
T_(Foo) fooUsualClass = __ kotlin.root.ObjectForExample.get_fooValueClass (instance);
__ kotlin.root.ObjectForExample.fooValue (instance, value);
__ kotlin.root.ObjectForExample.fooUsual (instance, usual);
__ kotlin.root.ObjectForExample.fooUByteArray (instance, uByteArray);
__ kotlin.root.ObjectForExample.fooUIntArrayNullable (instance, uIntArray);
__ kotlin.root.ObjectForExample.fooFooValue (instance, fooValueClass);
__ kotlin.root.ObjectForExample.fooFooUsual (instance, fooUsualClass);
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
inline class Example(val number: Int) {}
object ObjectForExample {
val example: Example? = null
}
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
#include "testlib_api.h"
#define __ testlib_symbols()->
#define T_(x) testlib_kref_ ## x
#include <stdio.h>
int main(int argc, char** argv) {
T_(ObjectForExample) instance = __ kotlin.root.ObjectForExample._instance ();
T_(Example) value = __ kotlin.root.ObjectForExample.get_example (instance);
printf("%x\n", value.pinned);
}
@@ -0,0 +1,11 @@
helloChar
helloByte
helloShort
helloInt
helloLong
helloUByte
helloUShort
helloUInt
helloULong
helloFloat
helloDouble
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
fun helloChar(value: Char?) {
println("helloChar")
}
fun helloByte(value: Byte?) {
println("helloByte")
}
fun helloShort(value: Short?) {
println("helloShort")
}
fun helloInt(value: Int?) {
println("helloInt")
}
fun helloLong(value: Long?) {
println("helloLong")
}
fun helloUByte(value: UByte?) {
println("helloUByte")
}
fun helloUShort(value: UShort?) {
println("helloUShort")
}
fun helloUInt(value: UInt?) {
println("helloUInt")
}
fun helloULong(value: ULong?) {
println("helloULong")
}
fun helloFloat(value: Float?) {
println("helloFloat")
}
fun helloDouble(value: Double?) {
println("helloDouble")
}
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
#include "testlib_api.h"
#define __ testlib_symbols()->
#define T_(x) testlib_kref_ ## x
#include <stdio.h>
int main(int argc, char** argv) {
__ kotlin.root.helloChar ((T_(kotlin_Char)) {NULL});
__ kotlin.root.helloByte ((T_(kotlin_Byte)) {NULL});
__ kotlin.root.helloShort ((T_(kotlin_Short)) {NULL});
__ kotlin.root.helloInt ((T_(kotlin_Int)) {NULL});
__ kotlin.root.helloLong ((T_(kotlin_Long)) {NULL});
__ kotlin.root.helloUByte ((T_(kotlin_UByte)) {NULL});
__ kotlin.root.helloUShort ((T_(kotlin_UShort)) {NULL});
__ kotlin.root.helloUInt ((T_(kotlin_UInt)) {NULL});
__ kotlin.root.helloULong ((T_(kotlin_ULong)) {NULL});
__ kotlin.root.helloFloat ((T_(kotlin_Float)) {NULL});
__ kotlin.root.helloDouble ((T_(kotlin_Double)) {NULL});
}