Skip to content

Commit b07f630

Browse files
authored
Merge pull request #32 from ForteScarlet/support_scope_safe_cast
针对 CoroutineScope 类型的参数的填充优化
2 parents 67618da + 46bd845 commit b07f630

File tree

7 files changed

+134
-38
lines changed

7 files changed

+134
-38
lines changed

.run/PublishAllToLocal.run.xml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="PublishAllToLocal" type="GradleRunConfiguration" factoryName="Gradle">
3+
<ExternalSystemSettings>
4+
<option name="env">
5+
<map>
6+
<entry key="SIMBOT_LOCAL" value="true" />
7+
</map>
8+
</option>
9+
<option name="executionName" />
10+
<option name="externalProjectPath" value="$PROJECT_DIR$" />
11+
<option name="externalSystemIdString" value="GRADLE" />
12+
<option name="scriptParameters" value="" />
13+
<option name="taskDescriptions">
14+
<list />
15+
</option>
16+
<option name="taskNames">
17+
<list>
18+
<option value="publishAllPublicationsToMavenLocalRepository" />
19+
</list>
20+
</option>
21+
<option name="vmOptions" />
22+
</ExternalSystemSettings>
23+
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
24+
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
25+
<DebugAllEnabled>false</DebugAllEnabled>
26+
<ForceTestExec>false</ForceTestExec>
27+
<method v="2" />
28+
</configuration>
29+
</component>

buildSrc/build.gradle.kts

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

1111
val kotlinVersion = "1.8.21"
12-
val dokkaPluginVersion = "1.8.10"
12+
val dokkaPluginVersion = "1.8.20"
1313
val gradleCommon = "0.0.11"
1414

1515
dependencies {

buildSrc/src/main/kotlin/IProject.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object IProject : ProjectDetail() {
88
const val DESCRIPTION = "Generate platform-compatible functions for Kotlin suspend functions"
99
const val HOMEPAGE = "https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin"
1010

11-
override val version: Version = version(0, 3, 2)
11+
override val version: Version = version(0, 4, 0)
1212

1313
override val homepage: String get() = HOMEPAGE
1414

compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package love.forte.plugin.suspendtrans.ir
22

3-
import love.forte.plugin.suspendtrans.*
3+
import love.forte.plugin.suspendtrans.SuspendTransformConfiguration
4+
import love.forte.plugin.suspendtrans.SuspendTransformUserData
5+
import love.forte.plugin.suspendtrans.SuspendTransformUserDataKey
6+
import love.forte.plugin.suspendtrans.fqn
47
import love.forte.plugin.suspendtrans.utils.*
58
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
69
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
@@ -9,16 +12,16 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
912
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
1013
import org.jetbrains.kotlin.ir.IrStatement
1114
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
12-
import org.jetbrains.kotlin.ir.builders.irBlockBody
13-
import org.jetbrains.kotlin.ir.builders.irCall
14-
import org.jetbrains.kotlin.ir.builders.irGet
15-
import org.jetbrains.kotlin.ir.builders.irReturn
15+
import org.jetbrains.kotlin.ir.builders.*
1616
import org.jetbrains.kotlin.ir.declarations.*
1717
import org.jetbrains.kotlin.ir.expressions.IrBody
18+
import org.jetbrains.kotlin.ir.expressions.IrCall
19+
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
20+
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
1821
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
19-
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
20-
import org.jetbrains.kotlin.ir.types.typeWith
21-
import org.jetbrains.kotlin.ir.util.*
22+
import org.jetbrains.kotlin.ir.types.*
23+
import org.jetbrains.kotlin.ir.util.isAnnotationWithEqualFqName
24+
import org.jetbrains.kotlin.ir.util.primaryConstructor
2225
import org.jetbrains.kotlin.name.ClassId
2326
import org.jetbrains.kotlin.name.FqName
2427

@@ -92,7 +95,8 @@ class SuspendTransformTransformer(
9295

9396
private fun resolveFunctionBodyByDescriptor(declaration: IrFunction, descriptor: CallableDescriptor): IrFunction? {
9497
val userData = descriptor.getUserData(SuspendTransformUserDataKey) ?: return null
95-
val callableFunction = pluginContext.referenceFunctions(userData.transformer.transformFunctionInfo.toCallableId()).firstOrNull()
98+
val callableFunction =
99+
pluginContext.referenceFunctions(userData.transformer.transformFunctionInfo.toCallableId()).firstOrNull()
96100
?: throw IllegalStateException("Transform function ${userData.transformer.transformFunctionInfo} not found")
97101

98102
val generatedOriginFunction = resolveFunctionBody(declaration, userData.originFunction, callableFunction)
@@ -112,7 +116,7 @@ class SuspendTransformTransformer(
112116
currentAnnotations.any { a -> a.isAnnotationWithEqualFqName(name) }
113117
addAll(currentAnnotations)
114118

115-
val syntheticFunctionIncludes = userData.transformer.originFunctionIncludeAnnotations
119+
val syntheticFunctionIncludes = userData.transformer.originFunctionIncludeAnnotations
116120

117121
syntheticFunctionIncludes.forEach { include ->
118122
val classId = include.classInfo.toClassId()
@@ -205,24 +209,69 @@ private fun generateTransformBodyForFunction(
205209
//println(transformTargetFunctionCall.owner.valueParameters)
206210
val owner = transformTargetFunctionCall.owner
207211

208-
if (owner.valueParameters.size > 1) {
209-
val secondType = owner.valueParameters[1].type
210-
val coroutineScopeTypeName = "kotlinx.coroutines.CoroutineScope".fqn
211-
val coroutineScopeTypeClassId = ClassId.topLevel("kotlinx.coroutines.CoroutineScope".fqn)
212-
val coroutineScopeTypeNameUnsafe = coroutineScopeTypeName.toUnsafe()
213-
if (secondType.isClassType(coroutineScopeTypeNameUnsafe)) {
214-
function.dispatchReceiverParameter?.also { dispatchReceiverParameter ->
215-
context.referenceClass(coroutineScopeTypeClassId)?.also { coroutineScopeRef ->
216-
if (dispatchReceiverParameter.type.isSubtypeOfClass(coroutineScopeRef)) {
217-
// put 'this' to second arg
218-
putValueArgument(1, irGet(dispatchReceiverParameter))
219-
}
220-
}
221-
}
222-
}
212+
// CoroutineScope
213+
val ownerValueParameters = owner.valueParameters
223214

215+
if (ownerValueParameters.size > 1) {
216+
for (index in 1..ownerValueParameters.lastIndex) {
217+
val valueParameter = ownerValueParameters[index]
218+
val type = valueParameter.type
219+
tryResolveCoroutineScopeValueParameter(type, context, function, owner, this@irBlockBody, index)
220+
}
224221
}
225222

226223
})
227224
}
228225
}
226+
227+
private val coroutineScopeTypeName = "kotlinx.coroutines.CoroutineScope".fqn
228+
private val coroutineScopeTypeClassId = ClassId.topLevel("kotlinx.coroutines.CoroutineScope".fqn)
229+
private val coroutineScopeTypeNameUnsafe = coroutineScopeTypeName.toUnsafe()
230+
231+
/**
232+
* 解析类型为 CoroutineScope 的参数。
233+
* 如果当前参数类型为 CoroutineScope:
234+
* - 如果当前 receiver 即为 CoroutineScope 类型,将其填充
235+
* - 如果当前 receiver 不是 CoroutineScope 类型,但是此参数可以为 null,
236+
* 则使用 safe-cast 将 receiver 转化为 CoroutineScope ( `dispatcher as? CoroutineScope` )
237+
* - 其他情况忽略此参数(适用于此参数有默认值的情况)
238+
*/
239+
private fun IrCall.tryResolveCoroutineScopeValueParameter(
240+
type: IrType,
241+
context: IrPluginContext,
242+
function: IrFunction,
243+
owner: IrSimpleFunction,
244+
builderWithScope: IrBuilderWithScope,
245+
index: Int
246+
) {
247+
if (!type.isClassType(coroutineScopeTypeNameUnsafe)) {
248+
return
249+
}
250+
251+
function.dispatchReceiverParameter?.also { dispatchReceiverParameter ->
252+
context.referenceClass(coroutineScopeTypeClassId)?.also { coroutineScopeRef ->
253+
if (dispatchReceiverParameter.type.isSubtypeOfClass(coroutineScopeRef)) {
254+
// put 'this' to the arg
255+
putValueArgument(index, builderWithScope.irGet(dispatchReceiverParameter))
256+
} else {
257+
val scopeType = coroutineScopeRef.defaultType
258+
259+
val scopeParameter = owner.valueParameters.getOrNull(1)
260+
261+
if (scopeParameter?.type?.isNullable() == true) {
262+
val irSafeAs = IrTypeOperatorCallImpl(
263+
startOffset,
264+
endOffset,
265+
scopeType,
266+
IrTypeOperator.SAFE_CAST,
267+
scopeType,
268+
builderWithScope.irGet(dispatchReceiverParameter)
269+
)
270+
271+
putValueArgument(index, irSafeAs)
272+
}
273+
// irAs(irGet(dispatchReceiverParameter), coroutineScopeRef.defaultType)
274+
}
275+
}
276+
}
277+
}

runtime/suspend-transform-runtime/src/jvmMain/kotlin/love/forte/plugin/suspendtrans/runtime/RunInSuspendJvm.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ private val transformer: FutureTransformer =
7474
@Suppress("FunctionName")
7575
public fun <T> `$runInAsync$`(
7676
block: suspend () -> T,
77-
scope: CoroutineScope = `$CoroutineScope4J$`
77+
scope: CoroutineScope? = null
7878
): CompletableFuture<T> {
79-
return transformer.trans(scope, block)
79+
return transformer.trans(scope ?: `$CoroutineScope4J$`, block)
8080
}
8181

8282

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ plugins {
88
// id(project(":suspend-transform-plugin-gradle"))
99
}
1010

11+
1112
buildscript {
1213
this@buildscript.repositories {
1314
mavenLocal()
1415
mavenCentral()
1516
}
1617
dependencies {
1718
//this.implementation()
18-
classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:0.3.2")
19+
classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:0.4.0")
1920
}
2021
}
2122

@@ -24,9 +25,10 @@ plugins {
2425
// sourceCompatibility = "11"
2526
// targetCompatibility = "11"
2627
//}
27-
//withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
28-
// kotlinOptions.jvmTarget = "11"
29-
//}
28+
29+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
30+
kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
31+
}
3032

3133
repositories {
3234
mavenLocal()
@@ -36,9 +38,10 @@ apply(plugin = "love.forte.plugin.suspend-transform")
3638

3739
dependencies {
3840
api(kotlin("stdlib"))
39-
// api("love.forte.plugin.suspend-transform:suspend-transform-runtime:0.3.2")
40-
// api("love.forte.plugin.suspend-transform:suspend-transform-annotation:0.3.2")
41-
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0")
41+
// val pluginVersion = "0.4.0"
42+
// api("love.forte.plugin.suspend-transform:suspend-transform-runtime:$pluginVersion")
43+
// api("love.forte.plugin.suspend-transform:suspend-transform-annotation:$pluginVersion")
44+
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
4245
}
4346

4447
extensions.getByType<SuspendTransformGradleExtension>().apply {

suspend-transform-plugin-sample/src/main/kotlin/love/forte/plugin/suspendtrans/sample/ForteScarlet.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,37 @@ package love.forte.plugin.suspendtrans.sample
33
import kotlinx.coroutines.CoroutineScope
44
import kotlinx.coroutines.delay
55
import love.forte.plugin.suspendtrans.annotation.JvmAsync
6+
import love.forte.plugin.suspendtrans.annotation.JvmBlocking
67
import kotlin.coroutines.CoroutineContext
78
import kotlin.coroutines.EmptyCoroutineContext
89

910

11+
abstract class IForteScarlet {
12+
@JvmAsync
13+
@JvmBlocking
14+
abstract suspend fun stringToInt(value: String): Int
15+
}
16+
17+
1018
/**
1119
*
1220
* @author ForteScarlet
1321
*/
14-
class ForteScarlet : CoroutineScope {
22+
class ForteScarlet : CoroutineScope, IForteScarlet() {
1523
override val coroutineContext: CoroutineContext
1624
get() = EmptyCoroutineContext
1725

1826
@JvmAsync
19-
suspend fun stringToInt(value: String): Int {
27+
@JvmBlocking
28+
override suspend fun stringToInt(value: String): Int {
2029
delay(5)
2130
return value.toInt()
2231
}
2332

33+
// @JvmAsync
34+
// suspend fun stringToInt(value: String): Int {
35+
// delay(5)
36+
// return value.toInt()
37+
// }
38+
2439
}

0 commit comments

Comments
 (0)