diff --git a/.run/PublishAllToLocal.run.xml b/.run/PublishAllToLocal.run.xml new file mode 100644 index 0000000..8d3e8ff --- /dev/null +++ b/.run/PublishAllToLocal.run.xml @@ -0,0 +1,29 @@ + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 9d385fe..3f035b5 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -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 { diff --git a/buildSrc/src/main/kotlin/IProject.kt b/buildSrc/src/main/kotlin/IProject.kt index 8adbfb1..2492bb3 100644 --- a/buildSrc/src/main/kotlin/IProject.kt +++ b/buildSrc/src/main/kotlin/IProject.kt @@ -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 diff --git a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt index d2474a0..ba44e2c 100644 --- a/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt +++ b/compiler/suspend-transform-plugin/src/main/kotlin/love/forte/plugin/suspendtrans/ir/SuspendTransformTransformer.kt @@ -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 @@ -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 @@ -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) @@ -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() @@ -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) + } + } + } +} diff --git a/runtime/suspend-transform-runtime/src/jvmMain/kotlin/love/forte/plugin/suspendtrans/runtime/RunInSuspendJvm.kt b/runtime/suspend-transform-runtime/src/jvmMain/kotlin/love/forte/plugin/suspendtrans/runtime/RunInSuspendJvm.kt index 53b8b5c..d344b6a 100644 --- a/runtime/suspend-transform-runtime/src/jvmMain/kotlin/love/forte/plugin/suspendtrans/runtime/RunInSuspendJvm.kt +++ b/runtime/suspend-transform-runtime/src/jvmMain/kotlin/love/forte/plugin/suspendtrans/runtime/RunInSuspendJvm.kt @@ -74,9 +74,9 @@ private val transformer: FutureTransformer = @Suppress("FunctionName") public fun `$runInAsync$`( block: suspend () -> T, - scope: CoroutineScope = `$CoroutineScope4J$` + scope: CoroutineScope? = null ): CompletableFuture { - return transformer.trans(scope, block) + return transformer.trans(scope ?: `$CoroutineScope4J$`, block) } diff --git a/suspend-transform-plugin-sample/build.gradle.kts b/suspend-transform-plugin-sample/build.gradle.kts index f7a00f6..34e2533 100644 --- a/suspend-transform-plugin-sample/build.gradle.kts +++ b/suspend-transform-plugin-sample/build.gradle.kts @@ -8,6 +8,7 @@ plugins { // id(project(":suspend-transform-plugin-gradle")) } + buildscript { this@buildscript.repositories { mavenLocal() @@ -15,7 +16,7 @@ plugins { } 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") } } @@ -24,9 +25,10 @@ plugins { // sourceCompatibility = "11" // targetCompatibility = "11" //} -//withType { -// kotlinOptions.jvmTarget = "11" -//} + +tasks.withType { + kotlinOptions.freeCompilerArgs += "-Xjvm-default=all" +} repositories { mavenLocal() @@ -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().apply { diff --git a/suspend-transform-plugin-sample/src/main/kotlin/love/forte/plugin/suspendtrans/sample/ForteScarlet.kt b/suspend-transform-plugin-sample/src/main/kotlin/love/forte/plugin/suspendtrans/sample/ForteScarlet.kt index 9c743d7..3e789a0 100644 --- a/suspend-transform-plugin-sample/src/main/kotlin/love/forte/plugin/suspendtrans/sample/ForteScarlet.kt +++ b/suspend-transform-plugin-sample/src/main/kotlin/love/forte/plugin/suspendtrans/sample/ForteScarlet.kt @@ -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() +// } + }