Skip to content

Commit 03ca25e

Browse files
committed
feat: Introduce ExperimentalReturnTypeOverrideGenericApi, add support for generic-based return type overrides, and update related configurations and annotations.
1 parent eadeffb commit 03ca25e

File tree

12 files changed

+233
-44
lines changed

12 files changed

+233
-44
lines changed

buildSrc/src/main/kotlin/IProject.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ object IProject : ProjectDetail() {
1111

1212
// Remember the libs.versions.toml!
1313
val ktVersion = "2.2.0"
14-
val pluginVersion = "0.13.1"
14+
val pluginVersion = "0.14.0"
1515

1616
override val version: String = "$ktVersion-$pluginVersion"
1717

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
3+
plugins {
4+
kotlin("jvm")
5+
id("suspend-transform.maven-publish")
6+
}
7+
8+
dependencies {
9+
testImplementation(kotlin("test"))
10+
}
11+
12+
kotlin {
13+
configGradleBuildSrcFriendly()
14+
compilerOptions {
15+
jvmTarget.set(JvmTarget.JVM_1_8)
16+
}
17+
18+
}
19+
20+
tasks.test {
21+
useJUnitPlatform()
22+
}
23+
24+
repositories {
25+
maven {
26+
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
27+
mavenContent {
28+
snapshotsOnly()
29+
}
30+
}
31+
}
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package love.forte.plugin.suspendtrans.annotation
2+
3+
/**
4+
* The API related to _return type override generic_ is experimental.
5+
* It may be changed in the future without notice.
6+
*
7+
* @since 0.14.0
8+
*/
9+
@RequiresOptIn(
10+
message = "This API is experimental. It may be changed in the future without notice.",
11+
level = RequiresOptIn.Level.ERROR
12+
)
13+
@Target(
14+
AnnotationTarget.CLASS,
15+
AnnotationTarget.CONSTRUCTOR,
16+
AnnotationTarget.FUNCTION,
17+
AnnotationTarget.PROPERTY,
18+
AnnotationTarget.VALUE_PARAMETER,
19+
)
20+
annotation class ExperimentalReturnTypeOverrideGenericApi

compiler/suspend-transform-plugin-configuration/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins {
99

1010
dependencies {
1111
api(libs.kotlinx.serialization.core)
12-
// api(libs.kotlinx.serialization.protobuf)
12+
api(project(":compiler:suspend-transform-plugin-annotation"))
1313

1414
testImplementation(kotlin("test"))
1515
}

compiler/suspend-transform-plugin-configuration/src/main/kotlin/love/forte/plugin/suspendtrans/configuration/SuspendTransformConfiguration.kt

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package love.forte.plugin.suspendtrans.configuration
22

33
import kotlinx.serialization.Serializable
4+
import love.forte.plugin.suspendtrans.annotation.ExperimentalReturnTypeOverrideGenericApi
45

56
// NOTE:
67
// 配置信息均使用 `Protobuf` 进行序列化
@@ -80,6 +81,7 @@ enum class TargetPlatform {
8081
* 用于标记的注解信息, 例如 `@JvmBlocking`, `@JvmAsync`, `@JsPromise`.
8182
*/
8283
@Serializable
84+
@OptIn(ExperimentalReturnTypeOverrideGenericApi::class)
8385
class MarkAnnotation @InternalSuspendTransformConfigurationApi constructor(
8486
/**
8587
* 注解类信息
@@ -113,12 +115,60 @@ class MarkAnnotation @InternalSuspendTransformConfigurationApi constructor(
113115
*/
114116
// 'null' is not supported for optional properties in ProtoBuf
115117
val markNameProperty: MarkNameProperty?,
118+
119+
/**
120+
* Indicates whether there is a generic type used to override the function return type
121+
* on the current mark annotation.
122+
*
123+
* If `true`, when determining the return type of the generated function,
124+
* the content of this generic type will be directly regarded as the return type of the origin function,
125+
* rather than the actual type of the origin function.
126+
*
127+
* For example, Normally, the return type of the generated function
128+
* depends on the return type of the origin function:
129+
*
130+
* ```Kotlin
131+
* @JvmBlocking
132+
* suspend fun run(): Result<String>
133+
*
134+
* // Generated
135+
*
136+
* @Api4J
137+
* fun runBlocking(): Result<String>
138+
* ```
139+
*
140+
* However, if the annotation has a generic type and `hasReturnTypeOverrideGeneric` is true:
141+
*
142+
* ```Kotlin
143+
* @JvmBlockingWithType<String?>
144+
* suspend fun run(): Result<String>
145+
*
146+
* // Generated
147+
*
148+
* @Api4J
149+
* fun runBlocking(): String?
150+
* ```
151+
*
152+
* As can be seen, the generated function ignores the actual return type of the origin function
153+
* and instead treats the generic type specified in the annotation as the return type
154+
* of the origin function.
155+
*
156+
* Note: If you want to determine the return type through type overloading,
157+
* you must ensure that the transformer function you use correctly matches the input and output parameter types.
158+
* Otherwise, it may result in compilation errors or runtime exceptions.
159+
*
160+
* @since 0.14.0
161+
*/
162+
@property:ExperimentalReturnTypeOverrideGenericApi
163+
val hasReturnTypeOverrideGeneric: Boolean,
116164
) {
165+
117166
override fun equals(other: Any?): Boolean {
118167
if (this === other) return true
119168
if (other !is MarkAnnotation) return false
120169

121170
if (defaultAsProperty != other.defaultAsProperty) return false
171+
if (hasReturnTypeOverrideGeneric != other.hasReturnTypeOverrideGeneric) return false
122172
if (classInfo != other.classInfo) return false
123173
if (baseNameProperty != other.baseNameProperty) return false
124174
if (suffixProperty != other.suffixProperty) return false
@@ -131,6 +181,7 @@ class MarkAnnotation @InternalSuspendTransformConfigurationApi constructor(
131181

132182
override fun hashCode(): Int {
133183
var result = defaultAsProperty.hashCode()
184+
result = 31 * result + hasReturnTypeOverrideGeneric.hashCode()
134185
result = 31 * result + classInfo.hashCode()
135186
result = 31 * result + baseNameProperty.hashCode()
136187
result = 31 * result + suffixProperty.hashCode()
@@ -141,7 +192,7 @@ class MarkAnnotation @InternalSuspendTransformConfigurationApi constructor(
141192
}
142193

143194
override fun toString(): String {
144-
return "MarkAnnotation(asPropertyProperty='$asPropertyProperty', classInfo=$classInfo, baseNameProperty='$baseNameProperty', suffixProperty='$suffixProperty', defaultSuffix='$defaultSuffix', defaultAsProperty=$defaultAsProperty, markName=$markNameProperty)"
195+
return "MarkAnnotation(asPropertyProperty='$asPropertyProperty', classInfo=$classInfo, baseNameProperty='$baseNameProperty', suffixProperty='$suffixProperty', defaultSuffix='$defaultSuffix', defaultAsProperty=$defaultAsProperty, markNameProperty=$markNameProperty, hasReturnTypeOverrideGeneric=$hasReturnTypeOverrideGeneric)"
145196
}
146197
}
147198

@@ -457,7 +508,8 @@ object SuspendTransformConfigurations {
457508
propertyName = "markName",
458509
annotation = jvmNameAnnotationClassInfo,
459510
annotationMarkNamePropertyName = "name"
460-
)
511+
),
512+
hasReturnTypeOverrideGeneric = false
461513
)
462514

463515
@JvmStatic
@@ -480,7 +532,8 @@ object SuspendTransformConfigurations {
480532
propertyName = "markName",
481533
annotation = jvmNameAnnotationClassInfo,
482534
annotationMarkNamePropertyName = "name"
483-
)
535+
),
536+
hasReturnTypeOverrideGeneric = false
484537
)
485538

486539
@JvmStatic
@@ -577,7 +630,8 @@ object SuspendTransformConfigurations {
577630
propertyName = "markName",
578631
annotation = jsNameAnnotationClassInfo,
579632
annotationMarkNamePropertyName = "name"
580-
)
633+
),
634+
hasReturnTypeOverrideGeneric = false
581635
)
582636

583637
@JvmStatic

compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/fir/SuspendTransformFirTransformer.kt

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package love.forte.plugin.suspendtrans.fir
22

3+
import love.forte.plugin.suspendtrans.annotation.ExperimentalReturnTypeOverrideGenericApi
34
import love.forte.plugin.suspendtrans.configuration.MarkAnnotation
45
import love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration
56
import love.forte.plugin.suspendtrans.configuration.TargetPlatform
@@ -116,6 +117,42 @@ class SuspendTransformFirTransformer(
116117

117118
}
118119

120+
private fun findTransformerFunctionSymbol(transformer: Transformer): FirNamedFunctionSymbol? {
121+
val symbolProvider = session.symbolProvider
122+
val dependenciesSymbolProvider = session.dependenciesSymbolProvider
123+
124+
val transformFunctionInfo = transformer.transformFunctionInfo
125+
val packageName = transformFunctionInfo.packageName
126+
val functionName = transformFunctionInfo.functionName
127+
128+
val functionNameIdentifier = Name.identifier(functionName)
129+
130+
val transformerFunctionSymbols =
131+
symbolProvider.getTopLevelFunctionSymbols(
132+
packageName.fqn,
133+
functionNameIdentifier
134+
).ifEmpty {
135+
dependenciesSymbolProvider.getTopLevelFunctionSymbols(
136+
packageName.fqn,
137+
functionNameIdentifier
138+
)
139+
}
140+
141+
if (transformerFunctionSymbols.isNotEmpty()) {
142+
if (transformerFunctionSymbols.size == 1) {
143+
transformerFunctionSymbolMap[transformer] = transformerFunctionSymbols.first()
144+
return transformerFunctionSymbols.first()
145+
} else {
146+
error("Found multiple transformer function symbols for transformer: $transformer")
147+
}
148+
} else {
149+
// 有时候在不同平台中寻找,可能会找不到,例如在jvm中找不到js的函数
150+
// error("Cannot find transformer function symbol $packageName.$functionName (${session.moduleData.platform}) for transformer: $transformer")
151+
}
152+
153+
return null
154+
}
155+
119156
private fun initTransformerFunctionSymbolMap(
120157
classSymbol: FirClassSymbol<*>,
121158
memberScope: FirClassDeclaredMemberScope?
@@ -129,35 +166,9 @@ class SuspendTransformFirTransformer(
129166
suspendTransformConfiguration.transformers
130167
.forEach { (_, transformerList) ->
131168
for (transformer in transformerList) {
132-
val transformFunctionInfo = transformer.transformFunctionInfo
133-
val packageName = transformFunctionInfo.packageName
134-
val functionName = transformFunctionInfo.functionName
135-
136-
// TODO 校验funcs?
137-
138-
val functionNameIdentifier = Name.identifier(functionName)
139-
140-
val transformerFunctionSymbols =
141-
symbolProvider.getTopLevelFunctionSymbols(
142-
packageName.fqn,
143-
functionNameIdentifier
144-
).ifEmpty {
145-
dependenciesSymbolProvider.getTopLevelFunctionSymbols(
146-
packageName.fqn,
147-
functionNameIdentifier
148-
)
149-
}
150-
151-
if (transformerFunctionSymbols.isNotEmpty()) {
152-
if (transformerFunctionSymbols.size == 1) {
153-
transformerFunctionSymbolMap[transformer] = transformerFunctionSymbols.first()
154-
map[transformer] = transformerFunctionSymbols.first()
155-
} else {
156-
error("Found multiple transformer function symbols for transformer: $transformer")
157-
}
158-
} else {
159-
// 有时候在不同平台中寻找,可能会找不到,例如在jvm中找不到js的函数
160-
// error("Cannot find transformer function symbol $packageName.$functionName (${session.moduleData.platform}) for transformer: $transformer")
169+
val transformerFunctionSymbol = findTransformerFunctionSymbol(transformer)
170+
if (transformerFunctionSymbol != null) {
171+
map[transformer] = transformerFunctionSymbol
161172
}
162173
}
163174
}
@@ -965,8 +976,15 @@ class SuspendTransformFirTransformer(
965976
val anno = firAnnotation(func, markAnnotation, classSymbol)
966977
?: continue
967978

968-
val markAnnotationTypeArgument = anno.typeArguments.firstOrNull()
979+
@OptIn(ExperimentalReturnTypeOverrideGenericApi::class)
980+
val markAnnotationTypeArgument = if (markAnnotation.hasReturnTypeOverrideGeneric) {
981+
anno.typeArguments.firstOrNull()
982+
} else {
983+
null
984+
}
969985

986+
// TODO 也许错误延后抛出,缓存里找不到的话即用即找,可以解决无法在当前模块下使用的问题?
987+
// see https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin/issues/100
970988
val transformerFunctionSymbol = transformerFunctionSymbolMap[transformer]
971989
?: error("Cannot find transformer function symbol for transformer: $transformer in $platform")
972990

compiler/suspend-transform-plugin/src/test/love/forte/plugin/suspendtrans/services/SuspendTransformerEnvironmentConfigurator.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class SuspendTransformerEnvironmentConfigurator(testServices: TestServices) : En
3434
module: TestModule,
3535
configuration: CompilerConfiguration
3636
) {
37-
val testConfiguration = love.forte.plugin.suspendtrans.configuration.SuspendTransformConfiguration(
37+
val testConfiguration = SuspendTransformConfiguration(
3838
transformers = mapOf(
3939
TargetPlatform.JS to listOf(jsPromiseTransformer),
4040
TargetPlatform.JVM to listOf(
@@ -52,7 +52,8 @@ class SuspendTransformerEnvironmentConfigurator(testServices: TestServices) : En
5252
propertyName = "markName",
5353
annotation = jvmNameAnnotationClassInfo,
5454
annotationMarkNamePropertyName = "name"
55-
)
55+
),
56+
hasReturnTypeOverrideGeneric = true,
5657
),
5758
transformFunctionInfo = jvmBlockingTransformFunction,
5859
transformReturnType = null,

plugins/suspend-transform-plugin-gradle/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import love.forte.gradle.common.publication.configure.configPublishMaven
33
import love.forte.gradle.common.publication.configure.publishingExtension
44
import love.forte.gradle.common.publication.configure.setupPom
55
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
6-
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
76
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
87
import utils.isMainPublishable
98

@@ -32,6 +31,7 @@ dependencies {
3231
compileOnly(kotlin("gradle-plugin-api"))
3332
// compileOnly(project(":compiler:suspend-transform-plugin"))
3433
api(project(":compiler:suspend-transform-plugin-cli"))
34+
api(project(":compiler:suspend-transform-plugin-annotation"))
3535
api(project(":compiler:suspend-transform-plugin-configuration"))
3636
api(project(":compiler:suspend-transform-plugin-deprecated-configuration"))
3737
}

0 commit comments

Comments
 (0)