From 49d70a762bc814f21b7bc2f1a38e62bdde405a30 Mon Sep 17 00:00:00 2001 From: Rick Clephas Date: Thu, 16 Apr 2026 14:15:34 +0200 Subject: [PATCH] [Swift Export] Resolve type parameter upper bounds ^KT-85788 Fixed --- .../swift/sir-light-classes/build.gradle.kts | 1 + .../nodes/SirFunctionFromKtSymbol.kt | 4 +- .../sir/lightclasses/utils/TypeRenderer.kt | 59 +++++++++++++++++++ .../testData/generation/generics/generics.kt | 4 ++ .../generics/golden_result/main/main.h | 4 ++ .../generics/golden_result/main/main.kt | 15 +++++ .../generics/golden_result/main/main.swift | 11 ++++ .../sir-light-classes/sir-light-classes.pom | 6 ++ 8 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/utils/TypeRenderer.kt diff --git a/native/swift/sir-light-classes/build.gradle.kts b/native/swift/sir-light-classes/build.gradle.kts index 0836bd9a07336..d7b86797d9be5 100644 --- a/native/swift/sir-light-classes/build.gradle.kts +++ b/native/swift/sir-light-classes/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { api(project(":compiler:psi:psi-api")) api(project(":analysis:analysis-api")) + implementation(project(":analysis:analysis-internal-utils")) testImplementation(platform(libs.junit.bom)) testRuntimeOnly(libs.junit.jupiter.engine) diff --git a/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/nodes/SirFunctionFromKtSymbol.kt b/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/nodes/SirFunctionFromKtSymbol.kt index c6d4f72187bea..d606123b67fa6 100644 --- a/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/nodes/SirFunctionFromKtSymbol.kt +++ b/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/nodes/SirFunctionFromKtSymbol.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.components.builtinTypes import org.jetbrains.kotlin.analysis.api.components.containingSymbol import org.jetbrains.kotlin.analysis.api.components.render import org.jetbrains.kotlin.analysis.api.export.utilities.isSuspend +import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.types.KaTypeParameterType import org.jetbrains.kotlin.sir.* @@ -140,8 +141,9 @@ internal open class SirFunctionFromKtSymbol( override val bridges: List by lazyWithSessions { bridgeProxy?.createSirBridges { val typeArgs = ktSymbol.typeParameters.map { it.upperBounds.singleOrNull() ?: builtinTypes.nullableAny } + val renderer = KaTypeRendererForSource.UPPER_BOUNDS_WITH_QUALIFIED_NAMES val typesAsString = typeArgs.takeIf { it.isNotEmpty() }?.joinToString(prefix = "<", postfix = ">") { - it.render(position = Variance.INVARIANT) + it.render(renderer, position = Variance.INVARIANT) } ?: "" val actualArgs = argNames.drop(if (extensionReceiverParameter != null) 1 else 0).dropLast(contextParameters.size) val argumentsString = actualArgs.joinToString() diff --git a/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/utils/TypeRenderer.kt b/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/utils/TypeRenderer.kt new file mode 100644 index 0000000000000..5a64ea9f1dd8b --- /dev/null +++ b/native/swift/sir-light-classes/src/org/jetbrains/sir/lightclasses/utils/TypeRenderer.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2026 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. + */ + +package org.jetbrains.sir.lightclasses.utils + +import org.jetbrains.kotlin.analysis.api.KaSession +import org.jetbrains.kotlin.analysis.api.renderer.types.KaTypeRenderer +import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource +import org.jetbrains.kotlin.analysis.api.renderer.types.renderers.KaTypeParameterTypeRenderer +import org.jetbrains.kotlin.analysis.api.renderer.types.renderers.KaTypeProjectionRenderer +import org.jetbrains.kotlin.analysis.api.types.KaStarTypeProjection +import org.jetbrains.kotlin.analysis.api.types.KaType +import org.jetbrains.kotlin.analysis.api.types.KaTypeArgumentWithVariance +import org.jetbrains.kotlin.analysis.api.types.KaTypeParameterType +import org.jetbrains.kotlin.analysis.api.types.KaTypeProjection +import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter + +internal val KaTypeRendererForSource.UPPER_BOUNDS_WITH_QUALIFIED_NAMES: KaTypeRenderer + get() = WITH_QUALIFIED_NAMES.with { + typeParameterTypeRenderer = UpperBoundTypeParameterTypeRenderer + typeProjectionRenderer = UpperBoundTypeProjectionRenderer + } + +private object UpperBoundTypeParameterTypeRenderer : KaTypeParameterTypeRenderer { + override fun renderType( + analysisSession: KaSession, + type: KaTypeParameterType, + typeRenderer: KaTypeRenderer, + printer: PrettyPrinter + ) { + val type = type.symbol.upperBounds.singleOrNull() ?: analysisSession.builtinTypes.nullableAny + typeRenderer.renderType(analysisSession, type, printer) + } +} + +private object UpperBoundTypeProjectionRenderer : KaTypeProjectionRenderer { + override fun renderTypeProjection( + analysisSession: KaSession, + projection: KaTypeProjection, + typeRenderer: KaTypeRenderer, + printer: PrettyPrinter, + ) { + when (projection) { + is KaStarTypeProjection -> printer.append('*') + is KaTypeArgumentWithVariance -> { + var type: KaType? = projection.type + while (type is KaTypeParameterType) { + type = type.symbol.upperBounds.singleOrNull() + } + if (type == null) { + type = analysisSession.builtinTypes.nullableAny + } + typeRenderer.renderType(analysisSession, type, printer) + } + } + } +} diff --git a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/generics.kt b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/generics.kt index a19b315c04893..adee4ece064c6 100644 --- a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/generics.kt +++ b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/generics.kt @@ -120,6 +120,10 @@ fun returnBFun(): BFun = TODO() class MultipleUpperBounds where T : Producer, T : Consumer +fun returnGenericConstraintToGeneric(arg1: A, arg2: B): A = TODO() + +fun > returnSomeBoxForArg(arg: A): B = TODO() + // MODULE: f_bounded_type // EXPORT_TO_SWIFT // FILE: f_bounded_type.kt diff --git a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.h b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.h index b578b243b640e..5975bdae3dca5 100644 --- a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.h +++ b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.h @@ -101,6 +101,10 @@ void * __root___returnBFun(); void * __root___returnBoxFun(); +void * _Nullable __root___returnGenericConstraintToGeneric__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(void * _Nullable arg1, void * _Nullable arg2); + +void * __root___returnSomeBoxForArg__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(void * _Nullable arg); + _Bool __root___takeBoxStarProjection__TypesOfArguments__main_Box__(void * box); _Bool __root___takeBoxUpperBound__TypesOfArguments__main_Box__(void * box); diff --git a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.kt b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.kt index bc26f0f892a27..e4ec5e1eb8413 100644 --- a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.kt +++ b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.kt @@ -376,6 +376,21 @@ public fun __root___returnBoxFun(): kotlin.native.internal.NativePtr { return kotlin.native.internal.ref.createRetainedExternalRCRef(_result) } +@ExportedBridge("__root___returnGenericConstraintToGeneric__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___") +public fun __root___returnGenericConstraintToGeneric__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(arg1: kotlin.native.internal.NativePtr, arg2: kotlin.native.internal.NativePtr): kotlin.native.internal.NativePtr { + val __arg1 = if (arg1 == kotlin.native.internal.NativePtr.NULL) null else kotlin.native.internal.ref.dereferenceExternalRCRef(arg1) as kotlin.Any + val __arg2 = if (arg2 == kotlin.native.internal.NativePtr.NULL) null else kotlin.native.internal.ref.dereferenceExternalRCRef(arg2) as kotlin.Any + val _result = run { returnGenericConstraintToGeneric(__arg1, __arg2) } + return if (_result == null) kotlin.native.internal.NativePtr.NULL else kotlin.native.internal.ref.createRetainedExternalRCRef(_result) +} + +@ExportedBridge("__root___returnSomeBoxForArg__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___") +public fun __root___returnSomeBoxForArg__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(arg: kotlin.native.internal.NativePtr): kotlin.native.internal.NativePtr { + val __arg = if (arg == kotlin.native.internal.NativePtr.NULL) null else kotlin.native.internal.ref.dereferenceExternalRCRef(arg) as kotlin.Any + val _result = run { returnSomeBoxForArg>(__arg) } + return kotlin.native.internal.ref.createRetainedExternalRCRef(_result) +} + @ExportedBridge("__root___takeBoxStarProjection__TypesOfArguments__main_Box__") public fun __root___takeBoxStarProjection__TypesOfArguments__main_Box__(box: kotlin.native.internal.NativePtr): Boolean { val __box = kotlin.native.internal.ref.dereferenceExternalRCRef(box) as Box diff --git a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.swift b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.swift index 4b73cc5b3add4..39f81ae6779f4 100644 --- a/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.swift +++ b/native/swift/swift-export-standalone-integration-tests/simple/testData/generation/generics/golden_result/main/main.swift @@ -344,6 +344,17 @@ public func returnBoxFun() -> main.BoxFun { return { return main.Box.__createClassWrapper(externalRCRef: main_internal_functional_type_caller_mainU2EBox__TypesOfArguments__Swift_UnsafeMutableRawPointer__(pointerToBlock.__externalRCRef()!)) } }() } +public func returnGenericConstraintToGeneric( + arg1: (any KotlinRuntimeSupport._KotlinBridgeable)?, + arg2: (any KotlinRuntimeSupport._KotlinBridgeable)? +) -> (any KotlinRuntimeSupport._KotlinBridgeable)? { + return { switch __root___returnGenericConstraintToGeneric__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(arg1.map { it in it.__externalRCRef() } ?? nil, arg2.map { it in it.__externalRCRef() } ?? nil) { case nil: .none; case let res: KotlinRuntime.KotlinBase.__createBridgeable(externalRCRef: res); } }() +} +public func returnSomeBoxForArg( + arg: (any KotlinRuntimeSupport._KotlinBridgeable)? +) -> main.Box { + return main.Box.__createClassWrapper(externalRCRef: __root___returnSomeBoxForArg__TypesOfArguments__Swift_Optional_anyU20KotlinRuntimeSupport__KotlinBridgeable___(arg.map { it in it.__externalRCRef() } ?? nil)) +} public func takeBoxStarProjection( box: main.Box ) -> Swift.Void { diff --git a/repo/artifacts-tests/src/test/resources/org/jetbrains/kotlin/sir-light-classes/sir-light-classes.pom b/repo/artifacts-tests/src/test/resources/org/jetbrains/kotlin/sir-light-classes/sir-light-classes.pom index 39a615ca4cf67..80db8456e6296 100644 --- a/repo/artifacts-tests/src/test/resources/org/jetbrains/kotlin/sir-light-classes/sir-light-classes.pom +++ b/repo/artifacts-tests/src/test/resources/org/jetbrains/kotlin/sir-light-classes/sir-light-classes.pom @@ -56,5 +56,11 @@ ArtifactsTest.version runtime + + org.jetbrains.kotlin + analysis-internal-utils + ArtifactsTest.version + runtime +