Skip to content

Commit

Permalink
Merge pull request #32 from ForteScarlet/support_scope_safe_cast
Browse files Browse the repository at this point in the history
针对 CoroutineScope 类型的参数的填充优化
  • Loading branch information
ForteScarlet authored Aug 9, 2023
2 parents 67618da + 46bd845 commit b07f630
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 38 deletions.
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()
// }

}

0 comments on commit b07f630

Please sign in to comment.