[WasmJs] Fix kotlin.test AfterTest for test with Promise return type
Fix #KT-61888
This commit is contained in:
committed by
Space Team
parent
78b666bb40
commit
b6ef1e08e1
+2
@@ -35,6 +35,8 @@ interface JsCommonBackendContext : CommonBackendContext {
|
||||
|
||||
val coroutineSymbols: JsCommonCoroutineSymbols
|
||||
|
||||
val jsPromiseSymbol: IrClassSymbol?
|
||||
|
||||
val catchAllThrowableType: IrType
|
||||
get() = irBuiltIns.throwableType
|
||||
|
||||
|
||||
@@ -196,6 +196,9 @@ class JsIrBackendContext(
|
||||
override val coroutineSymbols =
|
||||
JsCommonCoroutineSymbols(symbolTable, module, this)
|
||||
|
||||
override val jsPromiseSymbol: IrClassSymbol?
|
||||
get() = intrinsics.promiseClassSymbol
|
||||
|
||||
override val enumEntries = getIrClass(ENUMS_PACKAGE_FQNAME.child(Name.identifier("EnumEntries")))
|
||||
override val createEnumEntries = getFunctions(ENUMS_PACKAGE_FQNAME.child(Name.identifier("enumEntries")))
|
||||
.find { it.valueParameters.firstOrNull()?.type?.isFunctionType == false }
|
||||
|
||||
@@ -131,7 +131,7 @@ fun compileIr(
|
||||
}
|
||||
|
||||
// TODO should be done incrementally
|
||||
generateJsTests(context, allModules.last())
|
||||
generateJsTests(context, allModules.last(), groupByPackage = false)
|
||||
|
||||
(irFactory.stageController as? WholeWorldStageController)?.let {
|
||||
lowerPreservingTags(allModules, context, phaseConfig, it)
|
||||
|
||||
@@ -58,7 +58,7 @@ class JsIrCompilerWithIC(
|
||||
moveBodilessDeclarationsToSeparatePlace(context, it)
|
||||
}
|
||||
|
||||
generateJsTests(context, mainModule)
|
||||
generateJsTests(context, mainModule, groupByPackage = false)
|
||||
|
||||
lowerPreservingTags(allModules, context, phaseConfig, context.irFactory.stageController as WholeWorldStageController)
|
||||
|
||||
|
||||
+37
-20
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
@@ -21,32 +20,36 @@ import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irString
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDynamicOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicMemberExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicOperatorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.asSimpleType
|
||||
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
|
||||
import org.jetbrains.kotlin.utils.findIsInstanceAnd
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||
|
||||
fun generateJsTests(context: JsIrBackendContext, moduleFragment: IrModuleFragment) {
|
||||
val generator = TestGenerator(context, false)
|
||||
fun generateJsTests(context: JsCommonBackendContext, moduleFragment: IrModuleFragment, groupByPackage: Boolean) {
|
||||
val generator = TestGenerator(
|
||||
context = context,
|
||||
groupByPackage = groupByPackage
|
||||
)
|
||||
|
||||
moduleFragment.files.toList().forEach {
|
||||
generator.lower(it)
|
||||
}
|
||||
}
|
||||
|
||||
class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boolean) : FileLoweringPass {
|
||||
private class TestGenerator(
|
||||
val context: JsCommonBackendContext,
|
||||
private val groupByPackage: Boolean,
|
||||
) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
// Additional copy to prevent ConcurrentModificationException
|
||||
@@ -186,9 +189,21 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (context is JsIrBackendContext && (testFun.returnType as? IrSimpleType)?.isPromise == true) {
|
||||
val refType = IrSimpleTypeImpl(context.ir.symbols.functionN(0), false, emptyList(), emptyList())
|
||||
val returnType = testFun.returnType as? IrSimpleType
|
||||
val promiseSymbol = context.jsPromiseSymbol
|
||||
if (promiseSymbol != null && returnType != null && returnType.isPromise) {
|
||||
val promiseCastedIfNeeded = if (returnType.classifier == context.jsPromiseSymbol) {
|
||||
returnStatement.value
|
||||
} else {
|
||||
IrTypeOperatorCallImpl(
|
||||
startOffset = UNDEFINED_OFFSET,
|
||||
endOffset = UNDEFINED_OFFSET,
|
||||
type = testFun.returnType,
|
||||
operator = IrTypeOperator.CAST,
|
||||
typeOperand = promiseSymbol.defaultType,
|
||||
argument = returnStatement.value
|
||||
)
|
||||
}
|
||||
|
||||
val afterFunction = context.irFactory.buildFun {
|
||||
this.name = Name.identifier("${irClass.name.asString()} after test fun")
|
||||
@@ -207,16 +222,17 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
|
||||
)
|
||||
}
|
||||
|
||||
val refType = IrSimpleTypeImpl(context.ir.symbols.functionN(0), false, emptyList(), emptyList())
|
||||
val finallyLambda = JsIrBuilder.buildFunctionExpression(refType, afterFunction)
|
||||
val finally = promiseSymbol.owner.declarations
|
||||
.findIsInstanceAnd<IrSimpleFunction> { it.name.asString() == "finally" }!!
|
||||
|
||||
val finally =
|
||||
IrDynamicMemberExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.dynamicType, "finally", returnStatement.value)
|
||||
|
||||
val returnValue =
|
||||
IrDynamicOperatorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.dynamicType, IrDynamicOperator.INVOKE).also {
|
||||
it.receiver = finally
|
||||
it.arguments.add(finallyLambda)
|
||||
}
|
||||
val returnValue = JsIrBuilder.buildCall(
|
||||
finally.symbol
|
||||
).apply {
|
||||
this.dispatchReceiver = promiseCastedIfNeeded
|
||||
putValueArgument(0, finallyLambda)
|
||||
}
|
||||
|
||||
body.statements += JsIrBuilder.buildReturn(
|
||||
fn.symbol,
|
||||
@@ -271,6 +287,7 @@ class TestGenerator(val context: JsCommonBackendContext, val groupByPackage: Boo
|
||||
|
||||
private val IrSimpleType.isPromise: Boolean
|
||||
get() {
|
||||
if (this.classifier == context.jsPromiseSymbol) return true
|
||||
val klass = classifier.owner as? IrClass ?: return false
|
||||
return klass.isExternal && klass.getJsModule() == null && klass.getJsNameOrKotlinName().asString() == "Promise"
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
@@ -73,6 +74,9 @@ class WasmBackendContext(
|
||||
override val coroutineSymbols =
|
||||
JsCommonCoroutineSymbols(symbolTable, module,this)
|
||||
|
||||
override val jsPromiseSymbol: IrClassSymbol?
|
||||
get() = if (isWasmJsTarget) wasmSymbols.jsRelatedSymbols.jsPromise else null
|
||||
|
||||
val innerClassesSupport = JsInnerClassesSupport(mapping, irFactory)
|
||||
|
||||
override val internalPackageFqn = FqName("kotlin.wasm")
|
||||
|
||||
@@ -385,6 +385,8 @@ class WasmSymbols(
|
||||
|
||||
val externRefIsNull = getInternalFunction("wasm_externref_is_null")
|
||||
|
||||
val jsPromise = getIrClass(FqName("kotlin.js.Promise"))
|
||||
|
||||
internal val throwAsJsException: IrSimpleFunctionSymbol =
|
||||
getInternalFunction("throwAsJsException")
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,17 +7,17 @@ package org.jetbrains.kotlin.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.TestGenerator
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
|
||||
fun generateWasmTests(context: WasmBackendContext, moduleFragment: IrModuleFragment) {
|
||||
val generator = TestGenerator(context, true)
|
||||
|
||||
moduleFragment.files.toList().forEach {
|
||||
generator.lower(it)
|
||||
}
|
||||
generateJsTests(
|
||||
context = context,
|
||||
moduleFragment = moduleFragment,
|
||||
groupByPackage = true
|
||||
)
|
||||
|
||||
if (context.testEntryPoints.isEmpty())
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user