Skip to content

针对 CoroutineScope 类型的参数的填充优化 #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .run/PublishAllToLocal.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="PublishAllToLocal" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="SIMBOT_LOCAL" value="true" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="publishAllPublicationsToMavenLocalRepository" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<ForceTestExec>false</ForceTestExec>
<method v="2" />
</configuration>
</component>
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repositories {
}

val kotlinVersion = "1.8.21"
val dokkaPluginVersion = "1.8.10"
val dokkaPluginVersion = "1.8.20"
val gradleCommon = "0.0.11"

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/IProject.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ object IProject : ProjectDetail() {
const val DESCRIPTION = "Generate platform-compatible functions for Kotlin suspend functions"
const val HOMEPAGE = "https://github.com/ForteScarlet/kotlin-suspend-transform-compiler-plugin"

override val version: Version = version(0, 3, 2)
override val version: Version = version(0, 4, 0)

override val homepage: String get() = HOMEPAGE

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package love.forte.plugin.suspendtrans.ir

import love.forte.plugin.suspendtrans.*
import love.forte.plugin.suspendtrans.SuspendTransformConfiguration
import love.forte.plugin.suspendtrans.SuspendTransformUserData
import love.forte.plugin.suspendtrans.SuspendTransformUserDataKey
import love.forte.plugin.suspendtrans.fqn
import love.forte.plugin.suspendtrans.utils.*
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
Expand All @@ -9,16 +12,16 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isAnnotationWithEqualFqName
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName

Expand Down Expand Up @@ -92,7 +95,8 @@ class SuspendTransformTransformer(

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

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

val syntheticFunctionIncludes = userData.transformer.originFunctionIncludeAnnotations
val syntheticFunctionIncludes = userData.transformer.originFunctionIncludeAnnotations

syntheticFunctionIncludes.forEach { include ->
val classId = include.classInfo.toClassId()
Expand Down Expand Up @@ -205,24 +209,69 @@ private fun generateTransformBodyForFunction(
//println(transformTargetFunctionCall.owner.valueParameters)
val owner = transformTargetFunctionCall.owner

if (owner.valueParameters.size > 1) {
val secondType = owner.valueParameters[1].type
val coroutineScopeTypeName = "kotlinx.coroutines.CoroutineScope".fqn
val coroutineScopeTypeClassId = ClassId.topLevel("kotlinx.coroutines.CoroutineScope".fqn)
val coroutineScopeTypeNameUnsafe = coroutineScopeTypeName.toUnsafe()
if (secondType.isClassType(coroutineScopeTypeNameUnsafe)) {
function.dispatchReceiverParameter?.also { dispatchReceiverParameter ->
context.referenceClass(coroutineScopeTypeClassId)?.also { coroutineScopeRef ->
if (dispatchReceiverParameter.type.isSubtypeOfClass(coroutineScopeRef)) {
// put 'this' to second arg
putValueArgument(1, irGet(dispatchReceiverParameter))
}
}
}
}
// CoroutineScope
val ownerValueParameters = owner.valueParameters

if (ownerValueParameters.size > 1) {
for (index in 1..ownerValueParameters.lastIndex) {
val valueParameter = ownerValueParameters[index]
val type = valueParameter.type
tryResolveCoroutineScopeValueParameter(type, context, function, owner, this@irBlockBody, index)
}
}

})
}
}

private val coroutineScopeTypeName = "kotlinx.coroutines.CoroutineScope".fqn
private val coroutineScopeTypeClassId = ClassId.topLevel("kotlinx.coroutines.CoroutineScope".fqn)
private val coroutineScopeTypeNameUnsafe = coroutineScopeTypeName.toUnsafe()

/**
* 解析类型为 CoroutineScope 的参数。
* 如果当前参数类型为 CoroutineScope:
* - 如果当前 receiver 即为 CoroutineScope 类型,将其填充
* - 如果当前 receiver 不是 CoroutineScope 类型,但是此参数可以为 null,
* 则使用 safe-cast 将 receiver 转化为 CoroutineScope ( `dispatcher as? CoroutineScope` )
* - 其他情况忽略此参数(适用于此参数有默认值的情况)
*/
private fun IrCall.tryResolveCoroutineScopeValueParameter(
type: IrType,
context: IrPluginContext,
function: IrFunction,
owner: IrSimpleFunction,
builderWithScope: IrBuilderWithScope,
index: Int
) {
if (!type.isClassType(coroutineScopeTypeNameUnsafe)) {
return
}

function.dispatchReceiverParameter?.also { dispatchReceiverParameter ->
context.referenceClass(coroutineScopeTypeClassId)?.also { coroutineScopeRef ->
if (dispatchReceiverParameter.type.isSubtypeOfClass(coroutineScopeRef)) {
// put 'this' to the arg
putValueArgument(index, builderWithScope.irGet(dispatchReceiverParameter))
} else {
val scopeType = coroutineScopeRef.defaultType

val scopeParameter = owner.valueParameters.getOrNull(1)

if (scopeParameter?.type?.isNullable() == true) {
val irSafeAs = IrTypeOperatorCallImpl(
startOffset,
endOffset,
scopeType,
IrTypeOperator.SAFE_CAST,
scopeType,
builderWithScope.irGet(dispatchReceiverParameter)
)

putValueArgument(index, irSafeAs)
}
// irAs(irGet(dispatchReceiverParameter), coroutineScopeRef.defaultType)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ private val transformer: FutureTransformer =
@Suppress("FunctionName")
public fun <T> `$runInAsync$`(
block: suspend () -> T,
scope: CoroutineScope = `$CoroutineScope4J$`
scope: CoroutineScope? = null
): CompletableFuture<T> {
return transformer.trans(scope, block)
return transformer.trans(scope ?: `$CoroutineScope4J$`, block)
}


Expand Down
17 changes: 10 additions & 7 deletions suspend-transform-plugin-sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ plugins {
// id(project(":suspend-transform-plugin-gradle"))
}


buildscript {
this@buildscript.repositories {
mavenLocal()
mavenCentral()
}
dependencies {
//this.implementation()
classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:0.3.2")
classpath("love.forte.plugin.suspend-transform:suspend-transform-plugin-gradle:0.4.0")
}
}

Expand All @@ -24,9 +25,10 @@ plugins {
// sourceCompatibility = "11"
// targetCompatibility = "11"
//}
//withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
// kotlinOptions.jvmTarget = "11"
//}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
}

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

dependencies {
api(kotlin("stdlib"))
// api("love.forte.plugin.suspend-transform:suspend-transform-runtime:0.3.2")
// api("love.forte.plugin.suspend-transform:suspend-transform-annotation:0.3.2")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0")
// val pluginVersion = "0.4.0"
// api("love.forte.plugin.suspend-transform:suspend-transform-runtime:$pluginVersion")
// api("love.forte.plugin.suspend-transform:suspend-transform-annotation:$pluginVersion")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

extensions.getByType<SuspendTransformGradleExtension>().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,37 @@ package love.forte.plugin.suspendtrans.sample
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import love.forte.plugin.suspendtrans.annotation.JvmAsync
import love.forte.plugin.suspendtrans.annotation.JvmBlocking
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext


abstract class IForteScarlet {
@JvmAsync
@JvmBlocking
abstract suspend fun stringToInt(value: String): Int
}


/**
*
* @author ForteScarlet
*/
class ForteScarlet : CoroutineScope {
class ForteScarlet : CoroutineScope, IForteScarlet() {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext

@JvmAsync
suspend fun stringToInt(value: String): Int {
@JvmBlocking
override suspend fun stringToInt(value: String): Int {
delay(5)
return value.toInt()
}

// @JvmAsync
// suspend fun stringToInt(value: String): Int {
// delay(5)
// return value.toInt()
// }

}